* src/vm/jits/390/codegen.h (N_BRC_BACK_PATCH, N_LTEBR, N_LTDBR, N_LTXBR, DD_0, ...
[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 8068 2007-06-12 15:50:35Z 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         ucontext_t        *_uc;
149         mcontext_t        *_mc;
150         u1                *pv;
151         u1                *sp;
152         u1                *ra;
153         u1                *xpc;
154         s4                 type;
155         ptrint             val;
156         java_objectheader *e;
157         s4                 base;
158         s4                 is_null;
159
160         _uc = (ucontext_t *) _p;
161         _mc = &_uc->uc_mcontext;
162
163         xpc = (u1 *)_mc->psw.addr;
164
165         /* Check opcodes and verify it is a null pointer exception */
166
167         switch (xpc[0]) {
168                 case 0x58: /* L */
169                 case 0x50: /* ST */
170                         base = (xpc[2] >> 4) & 0xF;
171                         if (base == 0) {
172                                 is_null = 1;
173                         } else if (_mc->gregs[base] == 0) {
174                                 is_null = 1;
175                         } else {
176                                 is_null = 0;
177                         }
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];
189         sp = (u1 *)_mc->gregs[REG_SP];
190         ra = xpc;
191         type = EXCEPTION_HARDWARE_NULLPOINTER;
192         val = 0;
193
194         e = exceptions_new_hardware_exception(pv, sp, ra, xpc, type, val);
195
196         _mc->gregs[REG_ITMP2_XPC] = (ptrint) xpc;
197         _mc->gregs[REG_ITMP1_XPTR] = (ptrint) e;
198         _mc->psw.addr = (ptrint) asm_handle_exception;
199 }
200
201 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p) {
202         ucontext_t        *_uc;
203         mcontext_t        *_mc;
204         u1                *xpc;
205         u1                *ra;
206         u1                *pv;
207         u1                *sp;
208         s4                 type;
209         ptrint             val;
210         java_objectheader *e;
211         s4                 reg;
212
213         _uc = (ucontext_t *) _p;
214         _mc = &_uc->uc_mcontext;
215         xpc = ra = siginfo->si_addr;
216
217         /* Our trap instruction has the format: { 0x02, one_byte_of_data }. */
218
219         if ((siginfo->si_code == ILL_ILLOPC) && (xpc[0] == 0x02)) {
220
221                 /* bits 7-4 contain a register holding a value */
222                 reg = (xpc[1] >> 4) & 0xF;
223
224                 /* bits 3-0 designate the exception type */
225                 type = xpc[1] & 0xF;  
226
227                 pv = (u1 *)_mc->gregs[REG_PV];
228                 sp = (u1 *)_mc->gregs[REG_SP];
229                 val = (ptrint)_mc->gregs[reg];
230
231                 e = exceptions_new_hardware_exception(pv, sp, ra, xpc, type, val);
232
233                 _mc->gregs[REG_ITMP1_XPTR] = (ptrint)e;
234                 _mc->gregs[REG_ITMP2_XPC] = (ptrint)xpc;
235                 _mc->psw.addr = (ptrint) asm_handle_exception;
236
237         } else {
238 #if !defined(NDEBUG)
239                 md_dump_context(xpc, _mc);
240 #endif
241                 vm_abort("%s: illegal instruction at %p, aborting.", __FUNCTION__, xpc);
242         }
243 }
244
245 /* md_signal_handler_sigfpe ****************************************************
246
247    ArithmeticException signal handler for hardware divide by zero
248    check.
249
250 *******************************************************************************/
251
252 void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
253 {
254         ucontext_t         *_uc;
255         mcontext_t         *_mc;
256         u1                 *pv;
257         u1                 *sp;
258         u1                 *ra;
259         u1                 *xpc;
260         u1                 *pc;
261         s4                  r1, r2;
262         s4                  type;
263         ptrint              val;
264         java_objectheader  *e;
265
266         _uc = (ucontext_t *) _p;
267         _mc = &_uc->uc_mcontext;
268
269         /* Instruction that raised signal */
270         xpc = siginfo->si_addr;
271
272         /* Check opcodes */
273
274         if (xpc[0] == 0x1D) { /* DR */
275
276                 r1 = (xpc[1] >> 4) & 0xF;
277                 r2 = xpc[1] & 0xF;
278
279                 if (
280                         (_mc->gregs[r1] == 0xFFFFFFFF) &&
281                         (_mc->gregs[r1 + 1] == 0x80000000) && 
282                         (_mc->gregs[r2] == 0xFFFFFFFF)
283                 ) {
284                         /* handle special case */
285                         /* next instruction */
286                         pc = (u1 *)_mc->psw.addr;
287                         /* reminder */
288                         _mc->gregs[r1] = 0;
289                         /* quotient */
290                         _mc->gregs[r1 + 1] = 0x80000000;
291                         /* continue at next instruction */
292                         _mc->psw.addr = (ptrint) pc;
293
294                         return;
295                 } else if (_mc->gregs[r2] == 0) {
296                         /* division by 0 */
297
298                         pv = (u1 *)_mc->gregs[REG_PV];
299                         sp = (u1 *)_mc->gregs[REG_SP];
300                         ra = xpc;
301
302                         type = EXCEPTION_HARDWARE_ARITHMETIC;
303                         val = 0;
304
305                         e = exceptions_new_hardware_exception(pv, sp, ra, xpc, type, val);
306
307                         _mc->gregs[REG_ITMP1_XPTR] = (ptrint)e;
308                         _mc->gregs[REG_ITMP2_XPC] = (ptrint)xpc;
309                         _mc->psw.addr = (ptrint) asm_handle_exception;
310
311                         return;
312                 }
313         }
314
315         /* Could not handle signal */
316
317 #if !defined(NDEBUG)
318         md_dump_context(xpc, _mc);
319 #endif
320         vm_abort("%s: floating point exception at %p, aborting.", __FUNCTION__, xpc);
321 }
322
323
324 /* md_signal_handler_sigusr2 ***************************************************
325
326    Signal handler for profiling sampling.
327
328 *******************************************************************************/
329
330 #if defined(ENABLE_THREADS)
331 void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
332 {
333         threadobject *t;
334         ucontext_t   *_uc;
335         mcontext_t   *_mc;
336         u1           *pc;
337
338         t = THREADOBJECT;
339
340         _uc = (ucontext_t *) _p;
341         _mc = &_uc->uc_mcontext;
342
343         /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
344            different to the ones in <ucontext.h>. */
345
346         pc = (u1 *) _mc->psw.addr;
347
348         t->pc = pc;
349 }
350 #endif
351
352
353 #if defined(ENABLE_THREADS)
354 void md_critical_section_restart(ucontext_t *_uc)
355 {
356         mcontext_t *_mc;
357         u1         *pc;
358         void       *npc;
359
360         _mc = &_uc->uc_mcontext;
361
362         pc = (u1 *)_mc->psw.addr;
363
364         npc = critical_find_restart_point(pc);
365
366         if (npc != NULL) {
367                 log_println("%s: pc=%p, npc=%p", __FUNCTION__, pc, npc);
368                 _mc->psw.addr = (ptrint) npc;
369         }
370 }
371 #endif
372
373
374 /* md_codegen_patch_branch *****************************************************
375
376    Back-patches a branch instruction.
377
378 *******************************************************************************/
379
380 void md_codegen_patch_branch(codegendata *cd, s4 branchmpc, s4 targetmpc)
381 {
382
383         s4 *mcodeptr;
384         s4  disp;                           /* branch displacement                */
385
386         /* calculate the patch position */
387
388         mcodeptr = (s4 *) (cd->mcodebase + branchmpc);
389
390         /* Calculate the branch displacement. */
391
392         disp = targetmpc - branchmpc;
393         disp += 4; /* size of branch */
394         disp /= 2; /* specified in halfwords */
395
396         ASSERT_VALID_BRANCH(disp);      
397
398         /* patch the branch instruction before the mcodeptr */
399
400         mcodeptr[-1] |= (disp & 0xFFFF);
401 }
402
403
404 /* md_stacktrace_get_returnaddress *********************************************
405
406    Returns the return address of the current stackframe, specified by
407    the passed stack pointer and the stack frame size.
408
409 *******************************************************************************/
410
411 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
412 {
413         u1 *ra;
414
415         /* on S390 the return address is located on the top of the stackframe */
416
417         ra = *((u1 **) (sp + framesize - SIZEOF_VOID_P));
418
419         return ra;
420 }
421
422
423 /* md_get_method_patch_address *************************************************
424
425    Gets the patch address of the currently compiled method. The offset
426    is extracted from the load instruction(s) before the jump and added
427    to the right base address (PV or REG_METHODPTR).
428
429    INVOKESTATIC/SPECIAL:
430
431 0x7748d7b2:   a7 18 ff d4                      lhi      %r1,-44  
432 (load dseg offset)
433 0x7748d7b6:   58 d1 d0 00                      l        %r13,0(%r1,%r13)
434 (load pv)
435 0x7748d7ba:   0d ed                            basr     %r14,%r13
436 (jump to pv)
437
438    INVOKEVIRTUAL:
439
440 0x7748d82a:   58 c0 20 00                      l        %r12,0(%r2)
441 (load mptr)
442 0x7748d82e:   58 d0 c0 00                      l        %r13,0(%r12)
443 (load pv from mptr)
444 0x7748d832:   0d ed                            basr     %r14,%r13
445 (jump to pv)
446
447
448    INVOKEINTERFACE:
449
450 last 2 instructions the same as in invokevirtual
451
452 *******************************************************************************/
453
454 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
455 {
456         u1  base;
457         s4  offset;
458         u1 *pa;                             /* patch address                      */
459
460         /* go back to the load before the call instruction */
461
462         ra = ra - 2 /* sizeof bcr */ - 4 /* sizeof l */;
463
464         /* get the base register of the load */
465
466         base = ra[2] >> 4;
467
468         /* check for the different calls */
469
470         if (base == 0xd) { /* pv relative */
471                 /* INVOKESTATIC/SPECIAL */
472
473                 /* the offset is in the load before the load */
474
475                 offset = *((s2 *) (ra - 2));
476
477                 /* add the offset to the procedure vector */
478
479                 pa = sfi->pv + offset;
480         }
481         else if (base == 0xc) { /* mptr relative */
482                 /* INVOKEVIRTUAL/INTERFACE */
483
484                 offset = *((u2 *)(ra + 2)) & 0xFFF;
485
486                 /* add offset to method pointer */
487                 
488                 pa = mptr + offset;
489         }
490         else {
491                 /* catch any problems */
492                 assert(0); 
493         }
494
495         return pa;
496 }
497
498
499 /* md_codegen_get_pv_from_pc ***************************************************
500
501    On this architecture just a wrapper function to
502    codegen_get_pv_from_pc.
503
504 *******************************************************************************/
505
506 u1 *md_codegen_get_pv_from_pc(u1 *ra)
507 {
508         u1 *pv;
509
510         /* Get the start address of the function which contains this
511        address from the method table. */
512
513         pv = codegen_get_pv_from_pc(ra);
514
515         return pv;
516 }
517
518
519 /* md_cacheflush ***************************************************************
520
521    Calls the system's function to flush the instruction and data
522    cache.
523
524 *******************************************************************************/
525
526 void md_cacheflush(u1 *addr, s4 nbytes)
527 {
528         /* do nothing */
529 }
530
531
532 /* md_icacheflush **************************************************************
533
534    Calls the system's function to flush the instruction cache.
535
536 *******************************************************************************/
537
538 void md_icacheflush(u1 *addr, s4 nbytes)
539 {
540         /* do nothing */
541 }
542
543
544 /* md_dcacheflush **************************************************************
545
546    Calls the system's function to flush the data cache.
547
548 *******************************************************************************/
549
550 void md_dcacheflush(u1 *addr, s4 nbytes)
551 {
552         /* do nothing */
553 }
554
555
556 /* md_patch_replacement_point **************************************************
557
558    Patch the given replacement point.
559
560 *******************************************************************************/
561 #if 0
562 void md_patch_replacement_point(rplpoint *rp)
563 {
564     u8 mcode;
565
566         /* XXX this is probably unsafe! */
567
568         /* save the current machine code */
569         mcode = *(u8*)rp->pc;
570
571         /* write spinning instruction */
572         *(u2*)(rp->pc) = 0xebfe;
573
574         /* write 5th byte */
575         rp->pc[4] = (rp->mcode >> 32);
576
577         /* write first word */
578     *(u4*)(rp->pc) = (u4) rp->mcode;
579
580         /* store saved mcode */
581         rp->mcode = mcode;
582         
583 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
584         {
585                 u1* u1ptr = rp->pc;
586                 DISASSINSTR(u1ptr);
587                 fflush(stdout);
588         }
589 #endif
590                         
591     /* XXX if required asm_cacheflush(rp->pc,8); */
592 }
593 #endif
594 /*
595  * These are local overrides for various environment variables in Emacs.
596  * Please do not remove this and leave it at the end of the file, where
597  * Emacs will automagically detect them.
598  * ---------------------------------------------------------------------
599  * Local variables:
600  * mode: c
601  * indent-tabs-mode: t
602  * c-basic-offset: 4
603  * tab-width: 4
604  * End:
605  * vim:noexpandtab:sw=4:ts=4:
606  */