* src/vm/jit/linenumbertable.c (linenumbertable_create, linenumbertable_linenumber_fo...
[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                 if (EXCEPTION_HARDWARE_COMPILER == type) {
240                         /* The PV from the compiler stub is equal to the XPC. */
241
242                         pv = xpc;
243
244                         /* The return address in is REG_RA */
245
246                         ra = (u1 *)_mc->gregs[REG_RA];
247
248                         xpc = ra - 2;
249                 }
250
251                 /* Handle the type. */
252
253                 p = signal_handle(type, val, pv, sp, ra, xpc, _p);
254
255                 if (EXCEPTION_HARDWARE_COMPILER == type) {
256                         if (NULL == p) {
257                                 _mc->gregs[REG_ITMP3_XPTR] = (intptr_t) builtin_retrieve_exception();
258                                 _mc->gregs[REG_ITMP1_XPC]  = (intptr_t) ra - 2;
259                                 _mc->gregs[REG_PV]         = (intptr_t) md_codegen_get_pv_from_pc(ra);
260                                 _mc->psw.addr              = (intptr_t) asm_handle_exception;
261                         } else {
262                                 _mc->gregs[REG_PV]         = (intptr_t) p;
263                                 _mc->psw.addr              = (intptr_t) p;
264                         }
265                 } else {
266                         if (p != NULL) {
267                                 _mc->gregs[REG_ITMP3_XPTR] = (intptr_t) p;
268                                 _mc->gregs[REG_ITMP1_XPC]  = (intptr_t) xpc;
269                                 _mc->psw.addr              = (intptr_t) asm_handle_exception;
270                         }
271                         else {
272                                 _mc->psw.addr              = (intptr_t) xpc;
273                         }
274                 }
275         } else {
276 #if !defined(NDEBUG)
277                 md_dump_context(xpc, _mc);
278 #endif
279                 vm_abort("%s: illegal instruction at %p, aborting.", __FUNCTION__, xpc);
280         }
281 }
282
283 /* md_signal_handler_sigfpe ****************************************************
284
285    ArithmeticException signal handler for hardware divide by zero
286    check.
287
288 *******************************************************************************/
289
290 void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
291 {
292         ucontext_t     *_uc;
293         mcontext_t     *_mc;
294         u1             *pv;
295         u1             *sp;
296         u1             *ra;
297         u1             *xpc;
298         u1             *pc;
299         int             r1, r2;
300         int             type;
301         intptr_t        val;
302         void           *p;
303
304         _uc = (ucontext_t *) _p;
305         _mc = &_uc->uc_mcontext;
306
307         /* Instruction that raised signal */
308         xpc = siginfo->si_addr;
309
310         /* Check opcodes */
311
312         if (N_RR_GET_OPC(xpc) == OPC_DR) { /* DR */
313
314                 r1 = N_RR_GET_REG1(xpc);
315                 r2 = N_RR_GET_REG2(xpc);
316
317                 if (
318                         (_mc->gregs[r1] == 0xFFFFFFFF) &&
319                         (_mc->gregs[r1 + 1] == 0x80000000) && 
320                         (_mc->gregs[r2] == 0xFFFFFFFF)
321                 ) {
322                         /* handle special case 0x80000000 / 0xFFFFFFFF that fails on hardware */
323                         /* next instruction */
324                         pc = (u1 *)_mc->psw.addr;
325                         /* reminder */
326                         _mc->gregs[r1] = 0;
327                         /* quotient */
328                         _mc->gregs[r1 + 1] = 0x80000000;
329                         /* continue at next instruction */
330                         _mc->psw.addr = (ptrint) pc;
331
332                         return;
333                 }
334                 else if (_mc->gregs[r2] == 0) {
335                         /* division by 0 */
336
337                         pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
338                         sp = (u1 *)_mc->gregs[REG_SP];
339                         ra = xpc;
340
341                         type = EXCEPTION_HARDWARE_ARITHMETIC;
342                         val = 0;
343
344                         /* Handle the type. */
345
346                         p = signal_handle(type, val, pv, sp, ra, xpc, _p);
347
348                         _mc->gregs[REG_ITMP3_XPTR] = (intptr_t) p;
349                         _mc->gregs[REG_ITMP1_XPC]  = (intptr_t) xpc;
350                         _mc->psw.addr              = (intptr_t) asm_handle_exception;
351
352                         return;
353                 }
354         }
355
356         /* Could not handle signal */
357
358 #if !defined(NDEBUG)
359         md_dump_context(xpc, _mc);
360 #endif
361         vm_abort("%s: floating point exception at %p, aborting.", __FUNCTION__, xpc);
362 }
363
364
365 /* md_signal_handler_sigusr2 ***************************************************
366
367    Signal handler for profiling sampling.
368
369 *******************************************************************************/
370
371 #if defined(ENABLE_THREADS)
372 void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
373 {
374         threadobject *t;
375         ucontext_t   *_uc;
376         mcontext_t   *_mc;
377         u1           *pc;
378
379         t = THREADOBJECT;
380
381         _uc = (ucontext_t *) _p;
382         _mc = &_uc->uc_mcontext;
383
384         /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
385            different to the ones in <ucontext.h>. */
386
387         pc = (u1 *) _mc->psw.addr;
388
389         t->pc = pc;
390 }
391 #endif
392
393
394 #if defined(ENABLE_THREADS)
395 void md_critical_section_restart(ucontext_t *_uc)
396 {
397         mcontext_t *_mc;
398         u1         *pc;
399         void       *npc;
400
401         _mc = &_uc->uc_mcontext;
402
403         pc = (u1 *)_mc->psw.addr;
404
405         npc = critical_find_restart_point(pc);
406
407         if (npc != NULL) {
408                 log_println("%s: pc=%p, npc=%p", __FUNCTION__, pc, npc);
409                 _mc->psw.addr = (ptrint) npc;
410         }
411 }
412 #endif
413
414
415 /* md_stacktrace_get_returnaddress *********************************************
416
417    Returns the return address of the current stackframe, specified by
418    the passed stack pointer and the stack frame size.
419
420 *******************************************************************************/
421
422 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
423 {
424         u1 *ra;
425
426         /* on S390 the return address is located on the top of the stackframe */
427
428         ra = *((u1 **) (sp + framesize - 8));
429
430         return ra;
431 }
432
433
434 /* md_jit_method_patch_address *************************************************
435
436    Gets the patch address of the currently compiled method. The offset
437    is extracted from the load instruction(s) before the jump and added
438    to the right base address (PV or REG_METHODPTR).
439
440    INVOKESTATIC/SPECIAL:
441
442 0x7748d7b2:   a7 18 ff d4                      lhi      %r1,-44  
443 (load dseg offset)
444 0x7748d7b6:   58 d1 d0 00                      l        %r13,0(%r1,%r13)
445 (load pv)
446 0x7748d7ba:   0d ed                            basr     %r14,%r13
447 (jump to pv)
448
449    INVOKEVIRTUAL:
450
451 0x7748d82a:   58 c0 20 00                      l        %r12,0(%r2)
452 (load mptr)
453 0x7748d82e:   58 d0 c0 00                      l        %r13,0(%r12)
454 (load pv from mptr)
455 0x7748d832:   0d ed                            basr     %r14,%r13
456 (jump to pv)
457
458
459    INVOKEINTERFACE:
460
461 last 2 instructions the same as in invokevirtual
462
463 *******************************************************************************/
464
465 void *md_jit_method_patch_address(void* pv, void *ra, void *mptr)
466 {
467         uint8_t *pc;
468         uint8_t  base, index;
469         int32_t  offset;
470         void    *pa;                        /* patch address                      */
471
472         /* go back to the load before the call instruction */
473
474         pc = ((uint8_t *) ra) - SZ_BCR - SZ_L;
475
476         /* get the base register of the load */
477
478         base  = N_RX_GET_BASE(pc);
479         index = N_RX_GET_INDEX(pc);
480
481         /* check for the different calls */
482
483         switch (base) {
484                 case REG_PV:
485                         /* INVOKESTATIC/SPECIAL */
486
487                         switch (index) {
488                                 case R0:
489                                         /* the offset is in the load instruction */
490                                         offset = N_RX_GET_DISP(pc) + N_PV_OFFSET;
491                                         break;
492                                 case REG_ITMP1:
493                                         /* the offset is in the immediate load before the load */
494                                         offset = N_RI_GET_IMM(pc - SZ_L);
495                                         break;
496                                 default:
497                                         assert(0);
498                         }
499
500                         /* add the offset to the procedure vector */
501
502                         pa = ((uint8_t *) pv) + offset;
503                         break;
504
505                 case REG_METHODPTR:
506                         /* mptr relative */
507                         /* INVOKEVIRTUAL/INTERFACE */
508
509                         offset = N_RX_GET_DISP(pc);
510
511                         /* return NULL if no mptr was specified (used for replacement) */
512
513                         if (mptr == NULL)
514                                 return NULL;
515
516                         /* add offset to method pointer */
517                         
518                         pa = (uint8_t *)mptr + offset;
519                         break;
520
521                 default:
522                         /* catch any problems */
523                         vm_abort("md_jit_method_patch_address");
524                         break;
525         }
526
527         return pa;
528 }
529
530
531 /* md_codegen_get_pv_from_pc ***************************************************
532
533    On this architecture just a wrapper function to
534    codegen_get_pv_from_pc.
535
536 *******************************************************************************/
537
538 u1 *md_codegen_get_pv_from_pc(u1 *ra)
539 {
540         u1 *pv;
541
542         /* Get the start address of the function which contains this
543        address from the method table. */
544
545         pv = codegen_get_pv_from_pc(ra);
546
547         return pv;
548 }
549
550
551 /* md_cacheflush ***************************************************************
552
553    Calls the system's function to flush the instruction and data
554    cache.
555
556 *******************************************************************************/
557
558 void md_cacheflush(u1 *addr, s4 nbytes)
559 {
560         /* do nothing */
561 }
562
563
564 /* md_icacheflush **************************************************************
565
566    Calls the system's function to flush the instruction cache.
567
568 *******************************************************************************/
569
570 void md_icacheflush(u1 *addr, s4 nbytes)
571 {
572         /* do nothing */
573 }
574
575
576 /* md_dcacheflush **************************************************************
577
578    Calls the system's function to flush the data cache.
579
580 *******************************************************************************/
581
582 void md_dcacheflush(u1 *addr, s4 nbytes)
583 {
584         /* do nothing */
585 }
586
587
588 /* md_patch_replacement_point **************************************************
589
590    Patch the given replacement point.
591
592 *******************************************************************************/
593 #if defined(ENABLE_REPLACEMENT)
594 void md_patch_replacement_point(u1 *pc, u1 *savedmcode, bool revert)
595 {
596         assert(0);
597 }
598 #endif
599
600 void md_handle_exception(int32_t *regs, int64_t *fregs, int32_t *out) {
601
602         uint8_t *xptr;
603         uint8_t *xpc;
604         uint8_t *sp;
605         uint8_t *pv;
606         uint8_t *ra;
607         uint8_t *handler;
608         int32_t framesize;
609         int32_t intsave;
610         int32_t fltsave;
611         int64_t *savearea;
612         int i;
613         int reg;
614         int loops = 0;
615
616         /* get registers */
617
618         xptr = *(uint8_t **)(regs + REG_ITMP3_XPTR);
619         xpc = *(uint8_t **)(regs + REG_ITMP1_XPC);
620         sp = *(uint8_t **)(regs + REG_SP);
621
622
623         /* initialize number of calle saved int regs to restore to 0 */
624         out[0] = 0;
625
626         /* initialize number of calle saved flt regs to restore to 0 */
627         out[1] = 0;
628
629         do {
630
631                 ++loops;
632
633                 pv = codegen_get_pv_from_pc(xpc);
634
635                 handler = exceptions_handle_exception((java_object_t *)xptr, xpc, pv, sp);
636
637                 if (handler == NULL) {
638
639                         /* exception was not handled
640                          * get values of calee saved registers and remove stack frame 
641                          */
642
643                         /* read stuff from data segment */
644
645                         framesize = *(int32_t *)(pv + FrameSize);
646
647                         intsave = *(int32_t *)(pv + IntSave);
648                         if (intsave > out[0]) {
649                                 out[0] = intsave;
650                         }
651
652                         fltsave = *(int32_t *)(pv + FltSave);
653                         if (fltsave > out[1]) {
654                                 out[1] = fltsave;
655                         }
656
657                         /* pointer to register save area */
658
659                         savearea = (int64_t *)(sp + framesize - 8);
660
661                         /* return address */
662
663                         ra = *(uint8_t **)(sp + framesize - 8);
664
665                         /* restore saved registers */
666
667                         for (i = 0; i < intsave; ++i) {
668                                 --savearea;
669                                 reg = abi_registers_integer_saved[INT_SAV_CNT - 1 - i];
670                                 regs[reg] = *(int32_t *)(savearea);
671                         }
672
673                         for (i = 0; i < fltsave; ++i) {
674                                 --savearea;
675                                 reg = abi_registers_float_saved[FLT_SAV_CNT - 1 - i];
676                                 fregs[reg] = *savearea;
677                         }
678
679                         /* remove stack frame */
680
681                         sp += framesize;
682
683                         /* new xpc is call before return address */
684
685                         xpc = ra - 2;
686
687                 } else {
688                         xpc = handler;
689                 }
690         } while (handler == NULL);
691
692         /* write new values for registers */
693
694         *(uint8_t **)(regs + REG_ITMP3_XPTR) = xptr;
695         *(uint8_t **)(regs + REG_ITMP1_XPC) = xpc;
696         *(uint8_t **)(regs + REG_SP) = sp;
697         *(uint8_t **)(regs + REG_PV) = pv - 0XFFC;
698
699         /* maybe leaf flag */
700
701         out[2] = (loops == 1);
702 }
703
704 /*
705  * These are local overrides for various environment variables in Emacs.
706  * Please do not remove this and leave it at the end of the file, where
707  * Emacs will automagically detect them.
708  * ---------------------------------------------------------------------
709  * Local variables:
710  * mode: c
711  * indent-tabs-mode: t
712  * c-basic-offset: 4
713  * tab-width: 4
714  * End:
715  * vim:noexpandtab:sw=4:ts=4:
716  */