* src/mm/cacao-gc/rootset.h (rootset_entry_t) Added. Rootsets can be resized.
[cacao.git] / src / vm / jit / s390 / md.c
1 /* src/vm/jit/x86_64/md.c - machine dependent x86_64 Linux functions
2
3    Copyright (C) 1996-2005, 2006 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    Contact: cacao@cacaojvm.org
26
27    Authors: Christian Thalinger
28
29    Changes: Edwin Steiner
30
31    $Id: md.c 8027 2007-06-07 10:30:33Z michi $
32
33 */
34
35 #define _GNU_SOURCE
36
37 #include "config.h"
38
39 #include <assert.h>
40 #include <stdlib.h>
41 #include <ucontext.h>
42
43 #include "vm/jit/s390/md-abi.h"
44
45 #if defined(ENABLE_THREADS)
46 # include "threads/threads-common.h"
47 # include "threads/native/threads.h"
48 #endif
49
50 #include "vm/exceptions.h"
51 #include "vm/signallocal.h"
52 #include "vm/jit/asmpart.h"
53 #include "vm/jit/stacktrace.h"
54
55 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
56 #include "vmcore/options.h" /* XXX debug */
57 #include "vm/jit/disass.h" /* XXX debug */
58 #endif
59
60 #include "vm/jit/codegen-common.h"
61 #include "vm/jit/s390/codegen.h"
62
63 #include <assert.h>
64 #define OOPS() assert(0);
65
66 /* prototypes *****************************************************************/
67
68 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p);
69
70 void md_dump_context(u1 *pc, mcontext_t *mc);
71
72 /* md_init *********************************************************************
73
74    Do some machine dependent initialization.
75
76 *******************************************************************************/
77
78 void md_init(void)
79 {
80 }
81
82 /* md_dump_context ************************************************************
83  
84    Logs the machine context
85   
86 *******************************************************************************/
87
88 void md_dump_context(u1 *pc, mcontext_t *mc) {
89         int i;
90         
91         union {
92                 u8 l;
93                 fpreg_t fr;
94         } freg;
95
96         log_println("Dumping context.");
97
98         log_println("Program counter: 0x%08X", pc);
99
100 #if defined(ENABLE_DISASSEMBLER)
101         log_println("Printing instruction at program counter:");
102         disassinstr(pc);
103 #endif
104
105         log_println("General purpose registers:");
106
107         for (i = 0; i < 16; i++) {
108                 log_println("\tr%d:\t0x%08X\t%d", i, mc->gregs[i], mc->gregs[i]);
109         }
110
111         log_println("Floating point registers:");
112
113         for (i = 0; i < 16; i++) {
114                 freg.fr.d = mc->fpregs.fprs[i].d;
115                 log_println("\tf%d\t0x%016llX\t(double)%e\t(float)%f", i, freg.l, freg.fr.d, freg.fr.f);
116         }
117
118 #if defined(ENABLE_THREADS)
119         log_println("Dumping the current stacktrace:");
120         threads_print_stacktrace();
121 #endif
122
123 }
124
125 /* md_signal_handler_sigsegv ***************************************************
126
127    NullPointerException signal handler for hardware null pointer
128    check.
129
130 *******************************************************************************/
131
132 void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
133 {
134         ucontext_t        *_uc;
135         mcontext_t        *_mc;
136         u1                *pv;
137         u1                *sp;
138         u1                *ra;
139         u1                *xpc;
140         s4                 type;
141         ptrint             val;
142         java_objectheader *e;
143         s4                 base;
144         s4                 is_null;
145
146         _uc = (ucontext_t *) _p;
147         _mc = &_uc->uc_mcontext;
148
149         xpc = (u1 *)_mc->psw.addr;
150
151         /* Check opcodes and verify it is a null pointer exception */
152
153         switch (xpc[0]) {
154                 case 0x58: /* L */
155                 case 0x50: /* ST */
156                         base = (xpc[2] >> 4) & 0xF;
157                         if (base == 0) {
158                                 is_null = 1;
159                         } else if (_mc->gregs[base] == 0) {
160                                 is_null = 1;
161                         } else {
162                                 is_null = 0;
163                         }
164                         break;
165         }
166
167         if (! is_null) {
168 #if !defined(NDEBUG)
169                 md_dump_context(xpc, _mc);
170 #endif
171                 vm_abort("%s: segmentation fault at %p, aborting.", __FUNCTION__, xpc);
172         }
173
174         pv = (u1 *)_mc->gregs[REG_PV];
175         sp = (u1 *)_mc->gregs[REG_SP];
176         ra = xpc;
177         type = EXCEPTION_HARDWARE_NULLPOINTER;
178         val = 0;
179
180         e = exceptions_new_hardware_exception(pv, sp, ra, xpc, type, val);
181
182         _mc->gregs[REG_ITMP2_XPC] = (ptrint) xpc;
183         _mc->gregs[REG_ITMP1_XPTR] = (ptrint) e;
184         _mc->psw.addr = (ptrint) asm_handle_exception;
185 }
186
187 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p) {
188         ucontext_t        *_uc;
189         mcontext_t        *_mc;
190         u1                *xpc;
191         u1                *ra;
192         u1                *pv;
193         u1                *sp;
194         s4                 type;
195         ptrint             val;
196         java_objectheader *e;
197         s4                 reg;
198
199         _uc = (ucontext_t *) _p;
200         _mc = &_uc->uc_mcontext;
201         xpc = ra = siginfo->si_addr;
202
203         /* Our trap instruction has the format: { 0x02, one_byte_of_data }. */
204
205         if ((siginfo->si_code == ILL_ILLOPC) && (xpc[0] == 0x02)) {
206
207                 /* bits 7-4 contain a register holding a value */
208                 reg = (xpc[1] >> 4) & 0xF;
209
210                 /* bits 3-0 designate the exception type */
211                 type = xpc[1] & 0xF;  
212
213                 pv = (u1 *)_mc->gregs[REG_PV];
214                 sp = (u1 *)_mc->gregs[REG_SP];
215                 val = (ptrint)_mc->gregs[reg];
216
217                 e = exceptions_new_hardware_exception(pv, sp, ra, xpc, type, val);
218
219                 _mc->gregs[REG_ITMP1_XPTR] = (ptrint)e;
220                 _mc->gregs[REG_ITMP2_XPC] = (ptrint)xpc;
221                 _mc->psw.addr = (ptrint) asm_handle_exception;
222
223         } else {
224 #if !defined(NDEBUG)
225                 md_dump_context(xpc, _mc);
226 #endif
227                 vm_abort("%s: illegal instruction at %p, aborting.", __FUNCTION__, xpc);
228         }
229 }
230
231 /* md_signal_handler_sigfpe ****************************************************
232
233    ArithmeticException signal handler for hardware divide by zero
234    check.
235
236 *******************************************************************************/
237
238 void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
239 {
240         ucontext_t         *_uc;
241         mcontext_t         *_mc;
242         u1                 *pv;
243         u1                 *sp;
244         u1                 *ra;
245         u1                 *xpc;
246         u1                 *pc;
247         s4                  r1, r2;
248         s4                  type;
249         ptrint              val;
250         java_objectheader  *e;
251
252         _uc = (ucontext_t *) _p;
253         _mc = &_uc->uc_mcontext;
254
255         /* Instruction that raised signal */
256         xpc = siginfo->si_addr;
257
258         /* Check opcodes */
259
260         if (xpc[0] == 0x1D) { /* DR */
261
262                 r1 = (xpc[1] >> 4) & 0xF;
263                 r2 = xpc[1] & 0xF;
264
265                 if (
266                         (_mc->gregs[r1] == 0xFFFFFFFF) &&
267                         (_mc->gregs[r1 + 1] == 0x80000000) && 
268                         (_mc->gregs[r2] == 0xFFFFFFFF)
269                 ) {
270                         /* handle special case */
271                         /* next instruction */
272                         pc = (u1 *)_mc->psw.addr;
273                         /* reminder */
274                         _mc->gregs[r1] = 0;
275                         /* quotient */
276                         _mc->gregs[r1 + 1] = 0x80000000;
277                         /* continue at next instruction */
278                         _mc->psw.addr = (ptrint) pc;
279
280                         return;
281                 } else if (_mc->gregs[r2] == 0) {
282                         /* division by 0 */
283
284                         pv = (u1 *)_mc->gregs[REG_PV];
285                         sp = (u1 *)_mc->gregs[REG_SP];
286                         ra = xpc;
287
288                         type = EXCEPTION_HARDWARE_ARITHMETIC;
289                         val = 0;
290
291                         e = exceptions_new_hardware_exception(pv, sp, ra, xpc, type, val);
292
293                         _mc->gregs[REG_ITMP1_XPTR] = (ptrint)e;
294                         _mc->gregs[REG_ITMP2_XPC] = (ptrint)xpc;
295                         _mc->psw.addr = (ptrint) asm_handle_exception;
296
297                         return;
298                 }
299         }
300
301         /* Could not handle signal */
302
303 #if !defined(NDEBUG)
304         md_dump_context(xpc, _mc);
305 #endif
306         vm_abort("%s: floating point exception at %p, aborting.", __FUNCTION__, xpc);
307 }
308
309
310 /* md_signal_handler_sigusr2 ***************************************************
311
312    Signal handler for profiling sampling.
313
314 *******************************************************************************/
315
316 #if defined(ENABLE_THREADS)
317 void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
318 {
319         threadobject *t;
320         ucontext_t   *_uc;
321         mcontext_t   *_mc;
322         u1           *pc;
323
324         t = THREADOBJECT;
325
326         _uc = (ucontext_t *) _p;
327         _mc = &_uc->uc_mcontext;
328
329         /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
330            different to the ones in <ucontext.h>. */
331
332         pc = (u1 *) _mc->psw.addr;
333
334         t->pc = pc;
335 }
336 #endif
337
338
339 #if defined(ENABLE_THREADS)
340 void md_critical_section_restart(ucontext_t *_uc)
341 {
342         mcontext_t *_mc;
343         u1         *pc;
344         void       *npc;
345
346         _mc = &_uc->uc_mcontext;
347
348         pc = (u1 *)_mc->psw.addr;
349
350         npc = critical_find_restart_point(pc);
351
352         if (npc != NULL) {
353                 log_println("%s: pc=%p, npc=%p", __FUNCTION__, pc, npc);
354                 _mc->psw.addr = (ptrint) npc;
355         }
356 }
357 #endif
358
359
360 /* md_codegen_patch_branch *****************************************************
361
362    Back-patches a branch instruction.
363
364 *******************************************************************************/
365
366 void md_codegen_patch_branch(codegendata *cd, s4 branchmpc, s4 targetmpc)
367 {
368
369         s4 *mcodeptr;
370         s4  disp;                           /* branch displacement                */
371
372         /* calculate the patch position */
373
374         mcodeptr = (s4 *) (cd->mcodebase + branchmpc);
375
376         /* Calculate the branch displacement. */
377
378         disp = targetmpc - branchmpc;
379         disp += 4; /* size of branch */
380         disp /= 2; /* specified in halfwords */
381
382         ASSERT_VALID_BRANCH(disp);      
383
384         /* patch the branch instruction before the mcodeptr */
385
386         mcodeptr[-1] |= (disp & 0xFFFF);
387 }
388
389
390 /* md_stacktrace_get_returnaddress *********************************************
391
392    Returns the return address of the current stackframe, specified by
393    the passed stack pointer and the stack frame size.
394
395 *******************************************************************************/
396
397 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
398 {
399         u1 *ra;
400
401         /* on S390 the return address is located on the top of the stackframe */
402
403         ra = *((u1 **) (sp + framesize - SIZEOF_VOID_P));
404
405         return ra;
406 }
407
408
409 /* md_get_method_patch_address *************************************************
410
411    Gets the patch address of the currently compiled method. The offset
412    is extracted from the load instruction(s) before the jump and added
413    to the right base address (PV or REG_METHODPTR).
414
415    INVOKESTATIC/SPECIAL:
416
417 0x7748d7b2:   a7 18 ff d4                      lhi      %r1,-44  
418 (load dseg offset)
419 0x7748d7b6:   58 d1 d0 00                      l        %r13,0(%r1,%r13)
420 (load pv)
421 0x7748d7ba:   0d ed                            basr     %r14,%r13
422 (jump to pv)
423
424    INVOKEVIRTUAL:
425
426 0x7748d82a:   58 c0 20 00                      l        %r12,0(%r2)
427 (load mptr)
428 0x7748d82e:   58 d0 c0 00                      l        %r13,0(%r12)
429 (load pv from mptr)
430 0x7748d832:   0d ed                            basr     %r14,%r13
431 (jump to pv)
432
433
434    INVOKEINTERFACE:
435
436 last 2 instructions the same as in invokevirtual
437
438 *******************************************************************************/
439
440 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
441 {
442         u1  base;
443         s4  offset;
444         u1 *pa;                             /* patch address                      */
445
446         /* go back to the load before the call instruction */
447
448         ra = ra - 2 /* sizeof bcr */ - 4 /* sizeof l */;
449
450         /* get the base register of the load */
451
452         base = ra[2] >> 4;
453
454         /* check for the different calls */
455
456         if (base == 0xd) { /* pv relative */
457                 /* INVOKESTATIC/SPECIAL */
458
459                 /* the offset is in the load before the load */
460
461                 offset = *((s2 *) (ra - 2));
462
463                 /* add the offset to the procedure vector */
464
465                 pa = sfi->pv + offset;
466         }
467         else if (base == 0xc) { /* mptr relative */
468                 /* INVOKEVIRTUAL/INTERFACE */
469
470                 offset = *((u2 *)(ra + 2)) & 0xFFF;
471
472                 /* add offset to method pointer */
473                 
474                 pa = mptr + offset;
475         }
476         else {
477                 /* catch any problems */
478                 assert(0); 
479         }
480
481         return pa;
482 }
483
484
485 /* md_codegen_get_pv_from_pc ***************************************************
486
487    On this architecture just a wrapper function to
488    codegen_get_pv_from_pc.
489
490 *******************************************************************************/
491
492 u1 *md_codegen_get_pv_from_pc(u1 *ra)
493 {
494         u1 *pv;
495
496         /* Get the start address of the function which contains this
497        address from the method table. */
498
499         pv = codegen_get_pv_from_pc(ra);
500
501         return pv;
502 }
503
504
505 /* md_cacheflush ***************************************************************
506
507    Calls the system's function to flush the instruction and data
508    cache.
509
510 *******************************************************************************/
511
512 void md_cacheflush(u1 *addr, s4 nbytes)
513 {
514         /* do nothing */
515 }
516
517
518 /* md_icacheflush **************************************************************
519
520    Calls the system's function to flush the instruction cache.
521
522 *******************************************************************************/
523
524 void md_icacheflush(u1 *addr, s4 nbytes)
525 {
526         /* do nothing */
527 }
528
529
530 /* md_dcacheflush **************************************************************
531
532    Calls the system's function to flush the data cache.
533
534 *******************************************************************************/
535
536 void md_dcacheflush(u1 *addr, s4 nbytes)
537 {
538         /* do nothing */
539 }
540
541
542 /* md_patch_replacement_point **************************************************
543
544    Patch the given replacement point.
545
546 *******************************************************************************/
547 #if 0
548 void md_patch_replacement_point(rplpoint *rp)
549 {
550     u8 mcode;
551
552         /* XXX this is probably unsafe! */
553
554         /* save the current machine code */
555         mcode = *(u8*)rp->pc;
556
557         /* write spinning instruction */
558         *(u2*)(rp->pc) = 0xebfe;
559
560         /* write 5th byte */
561         rp->pc[4] = (rp->mcode >> 32);
562
563         /* write first word */
564     *(u4*)(rp->pc) = (u4) rp->mcode;
565
566         /* store saved mcode */
567         rp->mcode = mcode;
568         
569 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
570         {
571                 u1* u1ptr = rp->pc;
572                 DISASSINSTR(u1ptr);
573                 fflush(stdout);
574         }
575 #endif
576                         
577     /* XXX if required asm_cacheflush(rp->pc,8); */
578 }
579 #endif
580 /*
581  * These are local overrides for various environment variables in Emacs.
582  * Please do not remove this and leave it at the end of the file, where
583  * Emacs will automagically detect them.
584  * ---------------------------------------------------------------------
585  * Local variables:
586  * mode: c
587  * indent-tabs-mode: t
588  * c-basic-offset: 4
589  * tab-width: 4
590  * End:
591  * vim:noexpandtab:sw=4:ts=4:
592  */