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