* src/vm/jit/s390/codegen.c,
[cacao.git] / src / vm / jit / s390 / md.c
1 /* src/vm/jit/s390/md.c - machine dependent s390 Linux functions
2
3    Copyright (C) 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 #define _GNU_SOURCE
29
30 #include "config.h"
31
32 #include <assert.h>
33 #include <stdint.h>
34 #include <stdlib.h>
35 #include <ucontext.h>
36
37 #include "vm/jit/s390/md-abi.h"
38
39 #if defined(ENABLE_THREADS)
40 # include "threads/threads-common.h"
41 # include "threads/native/threads.h"
42 #endif
43
44 #include "vm/exceptions.h"
45 #include "vm/signallocal.h"
46 #include "vm/jit/asmpart.h"
47 #include "vm/jit/abi.h"
48 #include "vm/jit/methodheader.h"
49 #include "vm/jit/stacktrace.h"
50
51 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
52 #include "vmcore/options.h" /* XXX debug */
53 #include "vm/jit/disass.h" /* XXX debug */
54 #endif
55
56 #include "vm/jit/codegen-common.h"
57 #include "vm/jit/s390/codegen.h"
58
59 #include <assert.h>
60
61 /* prototypes *****************************************************************/
62
63 u1 *exceptions_handle_exception(java_object_t *xptro, u1 *xpc, u1 *pv, u1 *sp);
64
65 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p);
66
67 void md_dump_context(u1 *pc, mcontext_t *mc);
68
69 /* md_init *********************************************************************
70
71    Do some machine dependent initialization.
72
73 *******************************************************************************/
74
75 void md_init(void)
76 {
77 }
78
79 /* md_dump_context ************************************************************
80  
81    Logs the machine context
82   
83 *******************************************************************************/
84
85 void md_dump_context(u1 *pc, mcontext_t *mc) {
86         int i;
87         u1 *pv;
88         methodinfo *m;
89
90         union {
91                 u8 l;
92                 fpreg_t fr;
93         } freg;
94
95         log_println("Dumping context.");
96
97         log_println("Program counter: 0x%08X", pc);
98
99         pv = codegen_get_pv_from_pc_nocheck(pc);
100         if (pv == NULL) {
101                 log_println("No java method found at location.");
102         } else {
103                 m = (*(codeinfo **)(pv + CodeinfoPointer))->m;
104                 log_println(
105                         "Java method: class %s, method %s, descriptor %s.",
106                         m->class->name->text, m->name->text, m->descriptor->text
107                 );
108         }
109
110 #if defined(ENABLE_DISASSEMBLER)
111         log_println("Printing instruction at program counter:");
112         disassinstr(pc);
113 #endif
114
115         log_println("General purpose registers:");
116
117         for (i = 0; i < 16; i++) {
118                 log_println("\tr%d:\t0x%08X\t%d", i, mc->gregs[i], mc->gregs[i]);
119         }
120
121         log_println("Floating point registers:");
122
123         for (i = 0; i < 16; i++) {
124                 freg.fr.d = mc->fpregs.fprs[i].d;
125                 log_println("\tf%d\t0x%016llX\t(double)%e\t(float)%f", i, freg.l, freg.fr.d, freg.fr.f);
126         }
127
128 #if defined(ENABLE_THREADS)
129         log_println("Dumping the current stacktrace:");
130         threads_print_stacktrace();
131 #endif
132
133 }
134
135 /* md_signal_handler_sigsegv ***************************************************
136
137    NullPointerException signal handler for hardware null pointer
138    check.
139
140 *******************************************************************************/
141
142 void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
143 {
144         ucontext_t     *_uc;
145         mcontext_t     *_mc;
146         u1             *pv;
147         u1             *sp;
148         u1             *ra;
149         u1             *xpc;
150         int             type;
151         intptr_t        val;
152         void           *p;
153         s4              base;
154         s4              is_null;
155
156         _uc = (ucontext_t *) _p;
157         _mc = &_uc->uc_mcontext;
158
159         xpc = (u1 *)_mc->psw.addr;
160
161         /* Check opcodes and verify it is a null pointer exception */
162
163         switch (N_RX_GET_OPC(xpc)) {
164                 case OPC_L:
165                 case OPC_ST:
166                 case OPC_CL: /* array size check on NULL array */
167                         base = N_RX_GET_BASE(xpc);
168                         if (base == 0) {
169                                 is_null = 1;
170                         } else if (_mc->gregs[base] == 0) {
171                                 is_null = 1;
172                         } else {
173                                 is_null = 0;
174                         }
175                         break;
176                 default:
177                         is_null = 0;
178                         break;
179         }
180
181         if (! is_null) {
182 #if !defined(NDEBUG)
183                 md_dump_context(xpc, _mc);
184 #endif
185                 vm_abort("%s: segmentation fault at %p, aborting.", __FUNCTION__, xpc);
186         }
187
188         pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
189         sp = (u1 *)_mc->gregs[REG_SP];
190         ra = xpc;
191         type = EXCEPTION_HARDWARE_NULLPOINTER;
192         val = 0;
193
194         /* Handle the type. */
195
196         p = signal_handle(type, val, pv, sp, ra, xpc, _p);
197
198         if (p != NULL) {
199                 _mc->gregs[REG_ITMP3_XPTR] = (intptr_t) p;
200                 _mc->gregs[REG_ITMP1_XPC]  = (intptr_t) xpc;
201                 _mc->psw.addr              = (intptr_t) asm_handle_exception;
202         }
203         else {
204                 _mc->psw.addr              = (intptr_t) xpc;
205         }
206 }
207
208 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p)
209 {
210         ucontext_t     *_uc;
211         mcontext_t     *_mc;
212         u1             *xpc;
213         u1             *ra;
214         u1             *pv;
215         u1             *sp;
216         int             type;
217         intptr_t        val;
218         void           *p;
219         s4              reg;
220
221         _uc = (ucontext_t *) _p;
222         _mc = &_uc->uc_mcontext;
223         xpc = ra = siginfo->si_addr;
224
225         /* Our trap instruction has the format: { 0x02, one_byte_of_data }. */
226
227         if ((siginfo->si_code == ILL_ILLOPC) && (N_RR_GET_OPC(xpc) == OPC_ILL)) {
228
229                 /* bits 7-4 contain a register holding a value */
230                 reg = N_ILL_GET_REG(xpc);
231
232                 /* bits 3-0 designate the exception type */
233                 type = N_ILL_GET_TYPE(xpc);
234
235                 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
236                 sp = (u1 *)_mc->gregs[REG_SP];
237                 val = (ptrint)_mc->gregs[reg];
238
239                 /* Handle the type. */
240
241                 p = signal_handle(type, val, pv, sp, ra, xpc, _p);
242
243                 if (p != NULL) {
244                         _mc->gregs[REG_ITMP3_XPTR] = (intptr_t) p;
245                         _mc->gregs[REG_ITMP1_XPC]  = (intptr_t) xpc;
246                         _mc->psw.addr              = (intptr_t) asm_handle_exception;
247                 }
248                 else {
249                         _mc->psw.addr              = (intptr_t) xpc;
250                 }
251         } else {
252 #if !defined(NDEBUG)
253                 md_dump_context(xpc, _mc);
254 #endif
255                 vm_abort("%s: illegal instruction at %p, aborting.", __FUNCTION__, xpc);
256         }
257 }
258
259 /* md_signal_handler_sigfpe ****************************************************
260
261    ArithmeticException signal handler for hardware divide by zero
262    check.
263
264 *******************************************************************************/
265
266 void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
267 {
268         ucontext_t     *_uc;
269         mcontext_t     *_mc;
270         u1             *pv;
271         u1             *sp;
272         u1             *ra;
273         u1             *xpc;
274         u1             *pc;
275         int             r1, r2;
276         int             type;
277         intptr_t        val;
278         void           *p;
279
280         _uc = (ucontext_t *) _p;
281         _mc = &_uc->uc_mcontext;
282
283         /* Instruction that raised signal */
284         xpc = siginfo->si_addr;
285
286         /* Check opcodes */
287
288         if (N_RR_GET_OPC(xpc) == OPC_DR) { /* DR */
289
290                 r1 = N_RR_GET_REG1(xpc);
291                 r2 = N_RR_GET_REG2(xpc);
292
293                 if (
294                         (_mc->gregs[r1] == 0xFFFFFFFF) &&
295                         (_mc->gregs[r1 + 1] == 0x80000000) && 
296                         (_mc->gregs[r2] == 0xFFFFFFFF)
297                 ) {
298                         /* handle special case 0x80000000 / 0xFFFFFFFF that fails on hardware */
299                         /* next instruction */
300                         pc = (u1 *)_mc->psw.addr;
301                         /* reminder */
302                         _mc->gregs[r1] = 0;
303                         /* quotient */
304                         _mc->gregs[r1 + 1] = 0x80000000;
305                         /* continue at next instruction */
306                         _mc->psw.addr = (ptrint) pc;
307
308                         return;
309                 }
310                 else if (_mc->gregs[r2] == 0) {
311                         /* division by 0 */
312
313                         pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
314                         sp = (u1 *)_mc->gregs[REG_SP];
315                         ra = xpc;
316
317                         type = EXCEPTION_HARDWARE_ARITHMETIC;
318                         val = 0;
319
320                         /* Handle the type. */
321
322                         p = signal_handle(type, val, pv, sp, ra, xpc, _p);
323
324                         _mc->gregs[REG_ITMP3_XPTR] = (intptr_t) p;
325                         _mc->gregs[REG_ITMP1_XPC]  = (intptr_t) xpc;
326                         _mc->psw.addr              = (intptr_t) asm_handle_exception;
327
328                         return;
329                 }
330         }
331
332         /* Could not handle signal */
333
334 #if !defined(NDEBUG)
335         md_dump_context(xpc, _mc);
336 #endif
337         vm_abort("%s: floating point exception at %p, aborting.", __FUNCTION__, xpc);
338 }
339
340
341 /* md_signal_handler_sigusr2 ***************************************************
342
343    Signal handler for profiling sampling.
344
345 *******************************************************************************/
346
347 #if defined(ENABLE_THREADS)
348 void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
349 {
350         threadobject *t;
351         ucontext_t   *_uc;
352         mcontext_t   *_mc;
353         u1           *pc;
354
355         t = THREADOBJECT;
356
357         _uc = (ucontext_t *) _p;
358         _mc = &_uc->uc_mcontext;
359
360         /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
361            different to the ones in <ucontext.h>. */
362
363         pc = (u1 *) _mc->psw.addr;
364
365         t->pc = pc;
366 }
367 #endif
368
369
370 #if defined(ENABLE_THREADS)
371 void md_critical_section_restart(ucontext_t *_uc)
372 {
373         mcontext_t *_mc;
374         u1         *pc;
375         void       *npc;
376
377         _mc = &_uc->uc_mcontext;
378
379         pc = (u1 *)_mc->psw.addr;
380
381         npc = critical_find_restart_point(pc);
382
383         if (npc != NULL) {
384                 log_println("%s: pc=%p, npc=%p", __FUNCTION__, pc, npc);
385                 _mc->psw.addr = (ptrint) npc;
386         }
387 }
388 #endif
389
390
391 /* md_stacktrace_get_returnaddress *********************************************
392
393    Returns the return address of the current stackframe, specified by
394    the passed stack pointer and the stack frame size.
395
396 *******************************************************************************/
397
398 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
399 {
400         u1 *ra;
401
402         /* on S390 the return address is located on the top of the stackframe */
403
404         ra = *((u1 **) (sp + framesize - 8));
405
406         return ra;
407 }
408
409
410 /* md_jit_method_patch_address *************************************************
411
412    Gets the patch address of the currently compiled method. The offset
413    is extracted from the load instruction(s) before the jump and added
414    to the right base address (PV or REG_METHODPTR).
415
416    INVOKESTATIC/SPECIAL:
417
418 0x7748d7b2:   a7 18 ff d4                      lhi      %r1,-44  
419 (load dseg offset)
420 0x7748d7b6:   58 d1 d0 00                      l        %r13,0(%r1,%r13)
421 (load pv)
422 0x7748d7ba:   0d ed                            basr     %r14,%r13
423 (jump to pv)
424
425    INVOKEVIRTUAL:
426
427 0x7748d82a:   58 c0 20 00                      l        %r12,0(%r2)
428 (load mptr)
429 0x7748d82e:   58 d0 c0 00                      l        %r13,0(%r12)
430 (load pv from mptr)
431 0x7748d832:   0d ed                            basr     %r14,%r13
432 (jump to pv)
433
434
435    INVOKEINTERFACE:
436
437 last 2 instructions the same as in invokevirtual
438
439 *******************************************************************************/
440
441 void *md_jit_method_patch_address(void* pv, void *ra, void *mptr)
442 {
443         uint8_t *pc;
444         uint8_t  base, index;
445         int32_t  offset;
446         void    *pa;                        /* patch address                      */
447
448         /* go back to the load before the call instruction */
449
450         pc = ((uint8_t *) ra) - SZ_BCR - SZ_L;
451
452         /* get the base register of the load */
453
454         base  = N_RX_GET_BASE(pc);
455         index = N_RX_GET_INDEX(pc);
456
457         /* check for the different calls */
458
459         switch (base) {
460                 case REG_PV:
461                         /* INVOKESTATIC/SPECIAL */
462
463                         switch (index) {
464                                 case R0:
465                                         /* the offset is in the load instruction */
466                                         offset = N_RX_GET_DISP(pc) + N_PV_OFFSET;
467                                         break;
468                                 case REG_ITMP1:
469                                         /* the offset is in the immediate load before the load */
470                                         offset = N_RI_GET_IMM(pc - SZ_L);
471                                         break;
472                                 default:
473                                         assert(0);
474                         }
475
476                         /* add the offset to the procedure vector */
477
478                         pa = ((uint8_t *) pv) + offset;
479                         break;
480
481                 case REG_METHODPTR:
482                         /* mptr relative */
483                         /* INVOKEVIRTUAL/INTERFACE */
484
485                         offset = N_RX_GET_DISP(pc);
486
487                         /* return NULL if no mptr was specified (used for replacement) */
488
489                         if (mptr == NULL)
490                                 return NULL;
491
492                         /* add offset to method pointer */
493                         
494                         pa = (uint8_t *)mptr + offset;
495                         break;
496
497                 default:
498                         /* catch any problems */
499                         vm_abort("md_jit_method_patch_address");
500                         break;
501         }
502
503         return pa;
504 }
505
506
507 /* md_codegen_get_pv_from_pc ***************************************************
508
509    On this architecture just a wrapper function to
510    codegen_get_pv_from_pc.
511
512 *******************************************************************************/
513
514 u1 *md_codegen_get_pv_from_pc(u1 *ra)
515 {
516         u1 *pv;
517
518         /* Get the start address of the function which contains this
519        address from the method table. */
520
521         pv = codegen_get_pv_from_pc(ra);
522
523         return pv;
524 }
525
526
527 /* md_cacheflush ***************************************************************
528
529    Calls the system's function to flush the instruction and data
530    cache.
531
532 *******************************************************************************/
533
534 void md_cacheflush(u1 *addr, s4 nbytes)
535 {
536         /* do nothing */
537 }
538
539
540 /* md_icacheflush **************************************************************
541
542    Calls the system's function to flush the instruction cache.
543
544 *******************************************************************************/
545
546 void md_icacheflush(u1 *addr, s4 nbytes)
547 {
548         /* do nothing */
549 }
550
551
552 /* md_dcacheflush **************************************************************
553
554    Calls the system's function to flush the data cache.
555
556 *******************************************************************************/
557
558 void md_dcacheflush(u1 *addr, s4 nbytes)
559 {
560         /* do nothing */
561 }
562
563
564 /* md_patch_replacement_point **************************************************
565
566    Patch the given replacement point.
567
568 *******************************************************************************/
569 #if defined(ENABLE_REPLACEMENT)
570 void md_patch_replacement_point(u1 *pc, u1 *savedmcode, bool revert)
571 {
572         assert(0);
573 }
574 #endif
575
576 void md_handle_exception(int32_t *regs, int64_t *fregs, int32_t *out) {
577
578         uint8_t *xptr;
579         uint8_t *xpc;
580         uint8_t *sp;
581         uint8_t *pv;
582         uint8_t *ra;
583         uint8_t *handler;
584         int32_t framesize;
585         int32_t intsave;
586         int32_t fltsave;
587         int64_t *savearea;
588         int i;
589         int reg;
590         int loops = 0;
591
592         /* get registers */
593
594         xptr = *(uint8_t **)(regs + REG_ITMP3_XPTR);
595         xpc = *(uint8_t **)(regs + REG_ITMP1_XPC);
596         sp = *(uint8_t **)(regs + REG_SP);
597
598
599         /* initialize number of calle saved int regs to restore to 0 */
600         out[0] = 0;
601
602         /* initialize number of calle saved flt regs to restore to 0 */
603         out[1] = 0;
604
605         do {
606
607                 ++loops;
608
609                 pv = codegen_get_pv_from_pc(xpc);
610
611                 handler = exceptions_handle_exception((java_object_t *)xptr, xpc, pv, sp);
612
613                 if (handler == NULL) {
614
615                         /* exception was not handled
616                          * get values of calee saved registers and remove stack frame 
617                          */
618
619                         /* read stuff from data segment */
620
621                         framesize = *(int32_t *)(pv + FrameSize);
622
623                         intsave = *(int32_t *)(pv + IntSave);
624                         if (intsave > out[0]) {
625                                 out[0] = intsave;
626                         }
627
628                         fltsave = *(int32_t *)(pv + FltSave);
629                         if (fltsave > out[1]) {
630                                 out[1] = fltsave;
631                         }
632
633                         /* pointer to register save area */
634
635                         savearea = (int64_t *)(sp + framesize - 8);
636
637                         /* return address */
638
639                         ra = *(uint8_t **)(sp + framesize - 8);
640
641                         /* restore saved registers */
642
643                         for (i = 0; i < intsave; ++i) {
644                                 --savearea;
645                                 reg = abi_registers_integer_saved[INT_SAV_CNT - 1 - i];
646                                 regs[reg] = *(int32_t *)(savearea);
647                         }
648
649                         for (i = 0; i < fltsave; ++i) {
650                                 --savearea;
651                                 reg = abi_registers_float_saved[FLT_SAV_CNT - 1 - i];
652                                 fregs[reg] = *savearea;
653                         }
654
655                         /* remove stack frame */
656
657                         sp += framesize;
658
659                         /* new xpc is call before return address */
660
661                         xpc = ra;
662
663                 } else {
664                         xpc = handler;
665                 }
666         } while (handler == NULL);
667
668         /* write new values for registers */
669
670         *(uint8_t **)(regs + REG_ITMP3_XPTR) = xptr;
671         *(uint8_t **)(regs + REG_ITMP1_XPC) = xpc;
672         *(uint8_t **)(regs + REG_SP) = sp;
673         *(uint8_t **)(regs + REG_PV) = pv - 0XFFC;
674
675         /* maybe leaf flag */
676
677         out[2] = (loops == 1);
678 }
679
680 /*
681  * These are local overrides for various environment variables in Emacs.
682  * Please do not remove this and leave it at the end of the file, where
683  * Emacs will automagically detect them.
684  * ---------------------------------------------------------------------
685  * Local variables:
686  * mode: c
687  * indent-tabs-mode: t
688  * c-basic-offset: 4
689  * tab-width: 4
690  * End:
691  * vim:noexpandtab:sw=4:ts=4:
692  */