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