* src/threads/thread.c: Moved to .cpp.
[cacao.git] / src / vm / jit / powerpc / linux / md-os.c
1 /* src/vm/jit/powerpc/linux/md-os.c - machine dependent PowerPC Linux functions
2
3    Copyright (C) 1996-2005, 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 #include "config.h"
27
28 #include <assert.h>
29 #include <stdint.h>
30 #include <ucontext.h>
31
32 #include "vm/types.h"
33
34 #include "vm/jit/powerpc/codegen.h"
35 #include "vm/jit/powerpc/md.h"
36 #include "vm/jit/powerpc/linux/md-abi.h"
37
38 #include "threads/thread.hpp"
39
40 #include "vm/builtin.h"
41 #include "vm/exceptions.h"
42 #include "vm/signallocal.h"
43 #include "vm/stringlocal.h"
44
45 #include "vm/jit/asmpart.h"
46 #include "vm/jit/executionstate.h"
47
48 #if defined(ENABLE_PROFILING)
49 # include "vm/jit/optimizing/profile.h"
50 #endif
51
52 #include "vm/jit/trap.h"
53
54 #include "vmcore/system.h"
55
56
57 /* md_signal_handler_sigsegv ***************************************************
58
59    Signal handler for hardware-exceptions.
60
61 *******************************************************************************/
62
63 void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
64 {
65         ucontext_t     *_uc;
66         mcontext_t     *_mc;
67         unsigned long  *_gregs;
68         u1             *pv;
69         u1             *sp;
70         u1             *ra;
71         u1             *xpc;
72         u4              mcode;
73         int             s1;
74         int16_t         disp;
75         int             d;
76         intptr_t        addr;
77         intptr_t        val;
78         int             type;
79         void           *p;
80
81         _uc = (ucontext_t *) _p;
82
83 #if defined(__UCLIBC__)
84         _mc    = &(_uc->uc_mcontext);
85         _gregs = _mc->regs->gpr;
86 #else
87         _mc    = _uc->uc_mcontext.uc_regs;
88         _gregs = _mc->gregs;
89 #endif
90
91         pv  = (u1 *) _gregs[REG_PV];
92         sp  = (u1 *) _gregs[REG_SP];
93         ra  = (u1 *) _gregs[PT_LNK];                 /* this is correct for leafs */
94         xpc = (u1 *) _gregs[PT_NIP];
95
96         /* get exception-throwing instruction */
97
98         mcode = *((u4 *) xpc);
99
100         s1   = M_INSTR_OP2_IMM_A(mcode);
101         disp = M_INSTR_OP2_IMM_I(mcode);
102         d    = M_INSTR_OP2_IMM_D(mcode);
103
104         val  = _gregs[d];
105
106         /* check for special-load */
107
108         if (s1 == REG_ZERO) {
109                 /* we use the exception type as load displacement */
110
111                 type = disp;
112
113                 if (type == TRAP_COMPILER) {
114                         /* The XPC is the RA minus 4, because the RA points to the
115                            instruction after the call. */
116
117                         xpc = ra - 4;
118                 }
119         }
120         else {
121                 /* This is a normal NPE: addr must be NULL and the NPE-type
122                    define is 0. */
123
124                 addr = _gregs[s1];
125                 type = addr;
126         }
127
128         /* Handle the trap. */
129
130         p = trap_handle(type, val, pv, sp, ra, xpc, _p);
131
132         /* Set registers. */
133
134         switch (type) {
135         case TRAP_COMPILER:
136                 if (p != NULL) {
137                         _gregs[REG_PV] = (uintptr_t) p;
138                         _gregs[PT_NIP] = (uintptr_t) p;
139                         break;
140                 }
141
142                 /* Get and set the PV from the parent Java method. */
143
144                 pv = md_codegen_get_pv_from_pc(ra);
145
146                 _gregs[REG_PV] = (uintptr_t) pv;
147
148                 /* Get the exception object. */
149
150                 p = builtin_retrieve_exception();
151
152                 assert(p != NULL);
153
154                 /* fall-through */
155
156         case TRAP_PATCHER:
157                 if (p == NULL)
158                         break;
159
160                 /* fall-through */
161                 
162         default:
163                 _gregs[REG_ITMP1_XPTR] = (uintptr_t) p;
164                 _gregs[REG_ITMP2_XPC]  = (uintptr_t) xpc;
165                 _gregs[PT_NIP]         = (uintptr_t) asm_handle_exception;
166         }
167 }
168
169
170 /* md_signal_handler_sigtrap ***************************************************
171
172    Signal handler for hardware-traps.
173
174 *******************************************************************************/
175
176 void md_signal_handler_sigtrap(int sig, siginfo_t *siginfo, void *_p)
177 {
178         ucontext_t     *_uc;
179         mcontext_t     *_mc;
180         unsigned long  *_gregs;
181         u1             *pv;
182         u1             *sp;
183         u1             *ra;
184         u1             *xpc;
185         u4              mcode;
186         int             s1;
187         intptr_t        val;
188         int             type;
189         void           *p;
190
191         _uc = (ucontext_t *) _p;
192
193 #if defined(__UCLIBC__)
194         _mc    = &(_uc->uc_mcontext);
195         _gregs = _mc->regs->gpr;
196 #else
197         _mc    = _uc->uc_mcontext.uc_regs;
198         _gregs = _mc->gregs;
199 #endif
200
201         pv  = (u1 *) _gregs[REG_PV];
202         sp  = (u1 *) _gregs[REG_SP];
203         ra  = (u1 *) _gregs[PT_LNK];                 /* this is correct for leafs */
204         xpc = (u1 *) _gregs[PT_NIP];
205
206         /* get exception-throwing instruction */
207
208         mcode = *((u4 *) xpc);
209
210         s1 = M_OP3_GET_A(mcode);
211
212         /* For now we only handle ArrayIndexOutOfBoundsException. */
213
214         type = TRAP_ArrayIndexOutOfBoundsException;
215         val  = _gregs[s1];
216
217         /* Handle the trap. */
218
219         p = trap_handle(type, val, pv, sp, ra, xpc, _p);
220
221         /* Set registers. */
222
223         _gregs[REG_ITMP1_XPTR] = (uintptr_t) p;
224         _gregs[REG_ITMP2_XPC]  = (uintptr_t) xpc;
225         _gregs[PT_NIP]         = (uintptr_t) asm_handle_exception;
226 }
227
228
229 /* md_signal_handler_sigusr1 ***************************************************
230
231    Signal handler for suspending threads.
232
233 *******************************************************************************/
234
235 #if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
236 void md_signal_handler_sigusr1(int sig, siginfo_t *siginfo, void *_p)
237 {
238         ucontext_t    *_uc;
239         mcontext_t    *_mc;
240         unsigned long *_gregs;
241         u1            *pc;
242         u1            *sp;
243
244         _uc = (ucontext_t *) _p;
245
246 #if defined(__UCLIBC__)
247         _mc    = &(_uc->uc_mcontext);
248         _gregs = _mc->regs->gpr;
249 #else
250         _mc    = _uc->uc_mcontext.uc_regs;
251         _gregs = _mc->gregs;
252 #endif
253
254         /* get the PC and SP for this thread */
255
256         pc = (u1 *) _gregs[PT_NIP];
257         sp = (u1 *) _gregs[REG_SP];
258
259         /* now suspend the current thread */
260
261         threads_suspend_ack(pc, sp);
262 }
263 #endif
264
265
266 /* md_signal_handler_sigusr2 ***************************************************
267
268    Signal handler for profiling sampling.
269
270 *******************************************************************************/
271
272 #if defined(ENABLE_THREADS)
273 void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
274 {
275         threadobject  *tobj;
276         ucontext_t    *_uc;
277         mcontext_t    *_mc;
278         unsigned long *_gregs;
279         u1            *pc;
280
281         tobj = THREADOBJECT;
282
283         _uc = (ucontext_t *) _p;
284
285 #if defined(__UCLIBC__)
286         _mc    = &(_uc->uc_mcontext);
287         _gregs = _mc->regs->gpr;
288 #else
289         _mc    = _uc->uc_mcontext.uc_regs;
290         _gregs = _mc->gregs;
291 #endif
292
293         pc = (u1 *) _gregs[PT_NIP];
294
295         tobj->pc = pc;
296 }
297 #endif
298
299
300 /* md_executionstate_read ******************************************************
301
302    Read the given context into an executionstate.
303
304 *******************************************************************************/
305
306 void md_executionstate_read(executionstate_t *es, void *context)
307 {
308         ucontext_t    *_uc;
309         mcontext_t    *_mc;
310         unsigned long *_gregs;
311         s4              i;
312
313         _uc = (ucontext_t *) context;
314
315 #if defined(__UCLIBC__)
316 #error Please port md_executionstate_read to __UCLIBC__
317 #else
318         _mc    = _uc->uc_mcontext.uc_regs;
319         _gregs = _mc->gregs;
320 #endif
321
322         /* read special registers */
323         es->pc = (u1 *) _gregs[PT_NIP];
324         es->sp = (u1 *) _gregs[REG_SP];
325         es->pv = (u1 *) _gregs[REG_PV];
326         es->ra = (u1 *) _gregs[PT_LNK];
327
328         /* read integer registers */
329         for (i = 0; i < INT_REG_CNT; i++)
330                 es->intregs[i] = _gregs[i];
331
332         /* read float registers */
333         /* Do not use the assignment operator '=', as the type of
334          * the _mc->fpregs[i] can cause invalid conversions. */
335
336         assert(sizeof(_mc->fpregs.fpregs) == sizeof(es->fltregs));
337         system_memcpy(&es->fltregs, &_mc->fpregs.fpregs, sizeof(_mc->fpregs.fpregs));
338 }
339
340
341 /* md_executionstate_write *****************************************************
342
343    Write the given executionstate back to the context.
344
345 *******************************************************************************/
346
347 void md_executionstate_write(executionstate_t *es, void *context)
348 {
349         ucontext_t    *_uc;
350         mcontext_t    *_mc;
351         unsigned long *_gregs;
352         s4              i;
353
354         _uc = (ucontext_t *) context;
355
356 #if defined(__UCLIBC__)
357 #error Please port md_executionstate_write to __UCLIBC__
358 #else
359         _mc    = _uc->uc_mcontext.uc_regs;
360         _gregs = _mc->gregs;
361 #endif
362
363         /* write integer registers */
364         for (i = 0; i < INT_REG_CNT; i++)
365                 _gregs[i] = es->intregs[i];
366
367         /* write float registers */
368         /* Do not use the assignment operator '=', as the type of
369          * the _mc->fpregs[i] can cause invalid conversions. */
370
371         assert(sizeof(_mc->fpregs.fpregs) == sizeof(es->fltregs));
372         system_memcpy(&_mc->fpregs.fpregs, &es->fltregs, sizeof(_mc->fpregs.fpregs));
373
374         /* write special registers */
375         _gregs[PT_NIP] = (ptrint) es->pc;
376         _gregs[REG_SP] = (ptrint) es->sp;
377         _gregs[REG_PV] = (ptrint) es->pv;
378         _gregs[PT_LNK] = (ptrint) es->ra;
379 }
380
381
382 /*
383  * These are local overrides for various environment variables in Emacs.
384  * Please do not remove this and leave it at the end of the file, where
385  * Emacs will automagically detect them.
386  * ---------------------------------------------------------------------
387  * Local variables:
388  * mode: c
389  * indent-tabs-mode: t
390  * c-basic-offset: 4
391  * tab-width: 4
392  * End:
393  */