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