* jit/patcher.h: Added #error if included on s390.
[cacao.git] / src / vm / jit / s390 / md.c
1 /* src/vm/jit/x86_64/md.c - machine dependent x86_64 Linux functions
2
3    Copyright (C) 1996-2005, 2006 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    Contact: cacao@cacaojvm.org
26
27    Authors: Christian Thalinger
28
29    Changes: Edwin Steiner
30
31    $Id: md.c 8251 2007-08-01 15:26:59Z pm $
32
33 */
34
35 #define _GNU_SOURCE
36
37 #include "config.h"
38
39 #include <assert.h>
40 #include <stdlib.h>
41 #include <ucontext.h>
42
43 #include "vm/jit/s390/md-abi.h"
44
45 #if defined(ENABLE_THREADS)
46 # include "threads/threads-common.h"
47 # include "threads/native/threads.h"
48 #endif
49
50 #include "vm/exceptions.h"
51 #include "vm/signallocal.h"
52 #include "vm/jit/asmpart.h"
53 #include "vm/jit/methodheader.h"
54 #include "vm/jit/stacktrace.h"
55
56 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
57 #include "vmcore/options.h" /* XXX debug */
58 #include "vm/jit/disass.h" /* XXX debug */
59 #endif
60
61 #include "vm/jit/codegen-common.h"
62 #include "vm/jit/s390/codegen.h"
63
64 #include <assert.h>
65 #define OOPS() assert(0);
66
67 /* prototypes *****************************************************************/
68
69 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p);
70
71 void md_dump_context(u1 *pc, mcontext_t *mc);
72
73 /* md_init *********************************************************************
74
75    Do some machine dependent initialization.
76
77 *******************************************************************************/
78
79 void md_init(void)
80 {
81 }
82
83 /* md_dump_context ************************************************************
84  
85    Logs the machine context
86   
87 *******************************************************************************/
88
89 void md_dump_context(u1 *pc, mcontext_t *mc) {
90         int i;
91         u1 *pv;
92         methodinfo *m;
93         
94         union {
95                 u8 l;
96                 fpreg_t fr;
97         } freg;
98
99         log_println("Dumping context.");
100
101         log_println("Program counter: 0x%08X", pc);
102
103         pv = codegen_get_pv_from_pc_nocheck(pc);
104         if (pv == NULL) {
105                 log_println("No java method found at location.");
106         } else {
107                 m = ((codeinfo *)(pv + CodeinfoPointer))->m;
108                 log_println(
109                         "Java method: class %s, method %s, descriptor %s.",
110                         utf_bytes(m->class->name), utf_bytes(m->name), utf_bytes(m->descriptor)
111                 );
112         }
113
114 #if defined(ENABLE_DISASSEMBLER)
115         log_println("Printing instruction at program counter:");
116         disassinstr(pc);
117 #endif
118
119         log_println("General purpose registers:");
120
121         for (i = 0; i < 16; i++) {
122                 log_println("\tr%d:\t0x%08X\t%d", i, mc->gregs[i], mc->gregs[i]);
123         }
124
125         log_println("Floating point registers:");
126
127         for (i = 0; i < 16; i++) {
128                 freg.fr.d = mc->fpregs.fprs[i].d;
129                 log_println("\tf%d\t0x%016llX\t(double)%e\t(float)%f", i, freg.l, freg.fr.d, freg.fr.f);
130         }
131
132 #if defined(ENABLE_THREADS)
133         log_println("Dumping the current stacktrace:");
134         threads_print_stacktrace();
135 #endif
136
137 }
138
139 /* md_signal_handler_sigsegv ***************************************************
140
141    NullPointerException signal handler for hardware null pointer
142    check.
143
144 *******************************************************************************/
145
146 void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
147 {
148         stackframeinfo     sfi;
149         ucontext_t        *_uc;
150         mcontext_t        *_mc;
151         u1                *pv;
152         u1                *sp;
153         u1                *ra;
154         u1                *xpc;
155         s4                 type;
156         ptrint             val;
157         java_objectheader *e;
158         s4                 base;
159         s4                 is_null;
160
161         _uc = (ucontext_t *) _p;
162         _mc = &_uc->uc_mcontext;
163
164         xpc = (u1 *)_mc->psw.addr;
165
166         /* Check opcodes and verify it is a null pointer exception */
167
168         switch (xpc[0]) {
169                 case 0x58: /* L */
170                 case 0x50: /* ST */
171                 case 0x55: /* CL (array size check on NULL array) */
172                         base = (xpc[2] >> 4) & 0xF;
173                         if (base == 0) {
174                                 is_null = 1;
175                         } else if (_mc->gregs[base] == 0) {
176                                 is_null = 1;
177                         } else {
178                                 is_null = 0;
179                         }
180                         break;
181         }
182
183         if (! is_null) {
184 #if !defined(NDEBUG)
185                 md_dump_context(xpc, _mc);
186 #endif
187                 vm_abort("%s: segmentation fault at %p, aborting.", __FUNCTION__, xpc);
188         }
189
190         pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
191         sp = (u1 *)_mc->gregs[REG_SP];
192         ra = xpc;
193         type = EXCEPTION_HARDWARE_NULLPOINTER;
194         val = 0;
195
196         /* create stackframeinfo */
197
198         stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
199
200         /* generate appropriate exception */
201
202         e = exceptions_new_hardware_exception(xpc, type, val);
203
204         /* remove stackframeinfo */
205
206         stacktrace_remove_stackframeinfo(&sfi);
207
208         if (e != NULL) {
209                 _mc->gregs[REG_ITMP2_XPC] = (ptrint) xpc;
210                 _mc->gregs[REG_ITMP1_XPTR] = (ptrint) e;
211                 _mc->psw.addr = (ptrint) asm_handle_exception;
212         } else {
213                 _mc->psw.addr = xpc;
214         }
215 }
216
217 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p) {
218         stackframeinfo     sfi;
219         ucontext_t        *_uc;
220         mcontext_t        *_mc;
221         u1                *xpc;
222         u1                *ra;
223         u1                *pv;
224         u1                *sp;
225         s4                 type;
226         ptrint             val;
227         java_objectheader *e;
228         s4                 reg;
229
230         _uc = (ucontext_t *) _p;
231         _mc = &_uc->uc_mcontext;
232         xpc = ra = siginfo->si_addr;
233
234         /* Our trap instruction has the format: { 0x02, one_byte_of_data }. */
235
236         if ((siginfo->si_code == ILL_ILLOPC) && (xpc[0] == 0x02)) {
237
238                 /* bits 7-4 contain a register holding a value */
239                 reg = (xpc[1] >> 4) & 0xF;
240
241                 /* bits 3-0 designate the exception type */
242                 type = xpc[1] & 0xF;  
243
244                 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
245                 sp = (u1 *)_mc->gregs[REG_SP];
246                 val = (ptrint)_mc->gregs[reg];
247
248                 /* create stackframeinfo */
249
250                 stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
251
252                 /* generate appropriate exception */
253
254                 e = exceptions_new_hardware_exception(xpc, type, val);
255
256                 /* remove stackframeinfo */
257
258                 stacktrace_remove_stackframeinfo(&sfi);
259
260                 if (e != NULL) {
261                         _mc->gregs[REG_ITMP1_XPTR] = (ptrint)e;
262                         _mc->gregs[REG_ITMP2_XPC] = (ptrint)xpc;
263                         _mc->psw.addr = (ptrint) asm_handle_exception;
264                 } else {
265                         _mc->psw.addr = xpc;
266                 }
267         } else {
268 #if !defined(NDEBUG)
269                 md_dump_context(xpc, _mc);
270 #endif
271                 vm_abort("%s: illegal instruction at %p, aborting.", __FUNCTION__, xpc);
272         }
273 }
274
275 /* md_signal_handler_sigfpe ****************************************************
276
277    ArithmeticException signal handler for hardware divide by zero
278    check.
279
280 *******************************************************************************/
281
282 void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
283 {
284         stackframeinfo      sfi;
285         ucontext_t         *_uc;
286         mcontext_t         *_mc;
287         u1                 *pv;
288         u1                 *sp;
289         u1                 *ra;
290         u1                 *xpc;
291         u1                 *pc;
292         s4                  r1, r2;
293         s4                  type;
294         ptrint              val;
295         java_objectheader  *e;
296
297         _uc = (ucontext_t *) _p;
298         _mc = &_uc->uc_mcontext;
299
300         /* Instruction that raised signal */
301         xpc = siginfo->si_addr;
302
303         /* Check opcodes */
304
305         if (xpc[0] == 0x1D) { /* DR */
306
307                 r1 = (xpc[1] >> 4) & 0xF;
308                 r2 = xpc[1] & 0xF;
309
310                 if (
311                         (_mc->gregs[r1] == 0xFFFFFFFF) &&
312                         (_mc->gregs[r1 + 1] == 0x80000000) && 
313                         (_mc->gregs[r2] == 0xFFFFFFFF)
314                 ) {
315                         /* handle special case */
316                         /* next instruction */
317                         pc = (u1 *)_mc->psw.addr;
318                         /* reminder */
319                         _mc->gregs[r1] = 0;
320                         /* quotient */
321                         _mc->gregs[r1 + 1] = 0x80000000;
322                         /* continue at next instruction */
323                         _mc->psw.addr = (ptrint) pc;
324
325                         return;
326                 } else if (_mc->gregs[r2] == 0) {
327                         /* division by 0 */
328
329                         pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
330                         sp = (u1 *)_mc->gregs[REG_SP];
331                         ra = xpc;
332
333                         type = EXCEPTION_HARDWARE_ARITHMETIC;
334                         val = 0;
335
336                         /* create stackframeinfo */
337
338                         stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
339
340                         /* generate appropriate exception */
341
342                         e = exceptions_new_hardware_exception(xpc, type, val);
343
344                         /* remove stackframeinfo */
345
346                         stacktrace_remove_stackframeinfo(&sfi);
347
348                         _mc->gregs[REG_ITMP1_XPTR] = (ptrint)e;
349                         _mc->gregs[REG_ITMP2_XPC] = (ptrint)xpc;
350                         _mc->psw.addr = (ptrint) 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_codegen_patch_branch *****************************************************
416
417    Back-patches a branch instruction.
418
419 *******************************************************************************/
420
421 void md_codegen_patch_branch(codegendata *cd, s4 branchmpc, s4 targetmpc)
422 {
423
424         s4 *mcodeptr;
425         s4  disp;                           /* branch displacement                */
426
427         /* calculate the patch position */
428
429         mcodeptr = (s4 *) (cd->mcodebase + branchmpc);
430
431         /* Calculate the branch displacement. */
432
433         disp = targetmpc - branchmpc;
434         disp += 4; /* size of branch */
435         disp /= 2; /* specified in halfwords */
436
437         ASSERT_VALID_BRANCH(disp);      
438
439         /* patch the branch instruction before the mcodeptr */
440
441         mcodeptr[-1] |= (disp & 0xFFFF);
442 }
443
444
445 /* md_stacktrace_get_returnaddress *********************************************
446
447    Returns the return address of the current stackframe, specified by
448    the passed stack pointer and the stack frame size.
449
450 *******************************************************************************/
451
452 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
453 {
454         u1 *ra;
455
456         /* on S390 the return address is located on the top of the stackframe */
457
458         ra = *((u1 **) (sp + framesize - SIZEOF_VOID_P));
459
460         return ra;
461 }
462
463
464 /* md_get_method_patch_address *************************************************
465
466    Gets the patch address of the currently compiled method. The offset
467    is extracted from the load instruction(s) before the jump and added
468    to the right base address (PV or REG_METHODPTR).
469
470    INVOKESTATIC/SPECIAL:
471
472 0x7748d7b2:   a7 18 ff d4                      lhi      %r1,-44  
473 (load dseg offset)
474 0x7748d7b6:   58 d1 d0 00                      l        %r13,0(%r1,%r13)
475 (load pv)
476 0x7748d7ba:   0d ed                            basr     %r14,%r13
477 (jump to pv)
478
479    INVOKEVIRTUAL:
480
481 0x7748d82a:   58 c0 20 00                      l        %r12,0(%r2)
482 (load mptr)
483 0x7748d82e:   58 d0 c0 00                      l        %r13,0(%r12)
484 (load pv from mptr)
485 0x7748d832:   0d ed                            basr     %r14,%r13
486 (jump to pv)
487
488
489    INVOKEINTERFACE:
490
491 last 2 instructions the same as in invokevirtual
492
493 *******************************************************************************/
494
495 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
496 {
497         u1  base, index;
498         s4  offset;
499         u1 *pa;                             /* patch address                      */
500
501         /* go back to the load before the call instruction */
502
503         ra = ra - 2 /* sizeof bcr */ - 4 /* sizeof l */;
504
505         /* get the base register of the load */
506
507         base = ra[2] >> 4;
508         index = ra[1] & 0xF;
509
510         /* check for the different calls */
511
512         switch (base) {
513                 case 0xd:
514                         /* INVOKESTATIC/SPECIAL */
515
516                 
517                         switch (index) {
518                                 case 0x0:
519                                         /* the offset is in the load instruction */
520                                         offset = ((*(u2 *)(ra + 2)) & 0xFFF) + N_PV_OFFSET;
521                                         break;
522                                 case 0x1:
523                                         /* the offset is in the immediate load before the load */
524                                         offset = *((s2 *) (ra - 2));
525                                         break;
526                                 default:
527                                         assert(0);
528                         }
529
530                         /* add the offset to the procedure vector */
531
532                         pa = sfi->pv + offset;
533
534                         break;
535
536                 case 0xc:
537                         /* mptr relative */
538                         /* INVOKEVIRTUAL/INTERFACE */
539
540                         offset = *((u2 *)(ra + 2)) & 0xFFF;
541
542                         /* return NULL if no mptr was specified (used for replacement) */
543
544                         if (mptr == NULL)
545                                 return NULL;
546
547                         /* add offset to method pointer */
548                         
549                         pa = mptr + offset;
550                         break;
551                 default:
552                         /* catch any problems */
553                         assert(0); 
554                         break;
555         }
556
557         return pa;
558 }
559
560
561 /* md_codegen_get_pv_from_pc ***************************************************
562
563    On this architecture just a wrapper function to
564    codegen_get_pv_from_pc.
565
566 *******************************************************************************/
567
568 u1 *md_codegen_get_pv_from_pc(u1 *ra)
569 {
570         u1 *pv;
571
572         /* Get the start address of the function which contains this
573        address from the method table. */
574
575         pv = codegen_get_pv_from_pc(ra);
576
577         return pv;
578 }
579
580
581 /* md_cacheflush ***************************************************************
582
583    Calls the system's function to flush the instruction and data
584    cache.
585
586 *******************************************************************************/
587
588 void md_cacheflush(u1 *addr, s4 nbytes)
589 {
590         /* do nothing */
591 }
592
593
594 /* md_icacheflush **************************************************************
595
596    Calls the system's function to flush the instruction cache.
597
598 *******************************************************************************/
599
600 void md_icacheflush(u1 *addr, s4 nbytes)
601 {
602         /* do nothing */
603 }
604
605
606 /* md_dcacheflush **************************************************************
607
608    Calls the system's function to flush the data cache.
609
610 *******************************************************************************/
611
612 void md_dcacheflush(u1 *addr, s4 nbytes)
613 {
614         /* do nothing */
615 }
616
617
618 /* md_patch_replacement_point **************************************************
619
620    Patch the given replacement point.
621
622 *******************************************************************************/
623 #if defined(ENABLE_REPLACEMENT)
624 void md_patch_replacement_point(codeinfo *code, s4 index, rplpoint *rp, u1 *savedmcode)
625 {
626         assert(0);
627 }
628 #endif
629
630 /*
631  * These are local overrides for various environment variables in Emacs.
632  * Please do not remove this and leave it at the end of the file, where
633  * Emacs will automagically detect them.
634  * ---------------------------------------------------------------------
635  * Local variables:
636  * mode: c
637  * indent-tabs-mode: t
638  * c-basic-offset: 4
639  * tab-width: 4
640  * End:
641  * vim:noexpandtab:sw=4:ts=4:
642  */