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