22c37b58f544cc21c16042f396bcb35ff2aec470
[cacao.git] / src / vm / jit / replace.c
1 /* vm/jit/replace.c - on-stack replacement of methods
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: Edwin Steiner
28
29    Changes:
30
31    $Id$
32
33 */
34
35 #include "config.h"
36 #include "vm/types.h"
37
38 #include <assert.h>
39
40 #include "mm/memory.h"
41 #include "vm/options.h"
42 #include "vm/jit/replace.h"
43
44 /* replace_create_replacement_points *******************************************
45  
46    Create the replacement points for the given code.
47   
48    IN:
49        code.............codeinfo where replacement points should be stored
50                             code->rplpoints must be NULL.
51                                                 code->rplpointcount must be 0.
52            rd...............registerdata containing allocation info.
53   
54    OUT:
55        code->rplpoints.......set to the list of replacement points
56            code->rplpointcount...number of replacement points
57            code->regalloc........list of allocation info
58            code->regalloccount...total length of allocation info list
59            code->globalcount.....number of global allocations at the
60                                  start of code->regalloc
61   
62    RETURN VALUE:
63        true.............everything ok 
64        false............an exception has been thrown
65    
66 *******************************************************************************/
67
68 bool replace_create_replacement_points(codeinfo *code,registerdata *rd)
69 {
70         basicblock *bptr;
71         int count;
72         methodinfo *m;
73         rplpoint *rplpoints;
74         rplpoint *rp;
75         int alloccount;
76         int globalcount;
77         s2 *regalloc;
78         s2 *ra;
79         int i;
80         stackptr sp;
81
82         /* assert that we wont overwrite already allocated data */
83         
84         assert(code);
85         assert(code->m);
86         assert(code->rplpoints == NULL);
87         assert(code->rplpointcount == 0);
88         assert(code->regalloc == NULL);
89         assert(code->regalloccount == 0);
90         assert(code->globalcount == 0);
91
92         /* iterate over the basic block list to find replacement points */
93
94         m = code->m;
95
96         count = 0;
97         alloccount = 0;
98         for (bptr = m->basicblocks; bptr; bptr = bptr->next) {
99                 if (!(bptr->bitflags & BBFLAG_REPLACEMENT))
100                         continue;
101
102                 /* there will be a replacement point at the start of this block */
103                 
104                 count++;
105                 alloccount += bptr->indepth;
106         }
107
108         /* if no points were found, there's nothing to do */
109         
110         if (!count)
111                 return true;
112
113         /* count global register allocations */
114
115         globalcount = m->maxlocals;
116         alloccount += globalcount;
117
118         /* allocate replacement point array and allocation array */
119         
120         rplpoints = MNEW(rplpoint,count);
121         regalloc = MNEW(s2,alloccount);
122         ra = regalloc;
123
124         /* store global register allocations */
125
126         for (i=0; i<m->maxlocals; ++i) {
127 #if defined(ENABLE_INTRP)
128                 if (!opt_intrp) {
129 #endif
130                 *ra++ = rd->locals[i][0].regoff; /* XXX */
131 #if defined(ENABLE_INTRP)
132                 }
133                 else {
134                         *ra++ = 0;
135                 }
136 #endif
137         }
138
139         /* initialize replacement point structs */
140
141         rp = rplpoints;
142         for (bptr = m->basicblocks; bptr; bptr = bptr->next) {
143                 if (!(bptr->bitflags & BBFLAG_REPLACEMENT))
144                         continue;
145
146                 /* there will be a replacement point at the start of this block */
147
148                 rp->pc = NULL;        /* set by codegen */
149                 rp->outcode = NULL;   /* set by codegen */
150                 rp->hashlink = NULL;
151                 rp->code = code;
152                 rp->target = NULL;
153                 rp->regalloc = ra;
154
155                 /* store local allocation info */
156
157                 for (sp = bptr->instack; sp; sp = sp->prev) {
158                         *ra++ = sp->regoff; /* XXX */
159                 }
160
161                 rp->regalloccount = ra - rp->regalloc;
162                 
163                 rp++;
164         }
165
166         /* store the data in the codeinfo */
167
168         code->rplpoints = rplpoints;
169         code->rplpointcount = count;
170         code->regalloc = regalloc;
171         code->regalloccount = alloccount;
172         code->globalcount = globalcount;
173
174         /* everything alright */
175
176         return true;
177 }
178
179 /* replace_free_replacement_points *********************************************
180  
181    Free memory used by replacement points.
182   
183    IN:
184        code.............codeinfo whose replacement points should be freed.
185   
186 *******************************************************************************/
187
188 void replace_free_replacement_points(codeinfo *code)
189 {
190         assert(code);
191
192         if (code->rplpoints)
193                 MFREE(code->rplpoints,rplpoint,code->rplpointcount);
194
195         if (code->regalloc)
196                 MFREE(code->regalloc,s2,code->regalloccount);
197
198         code->rplpoints = NULL;
199         code->rplpointcount = 0;
200         code->regalloc = NULL;
201         code->regalloccount = 0;
202         code->globalcount = 0;
203 }
204
205 /* replace_activate_replacement_point ******************************************
206  
207    Activate a replacement point. When this function returns, the
208    replacement point is "armed", that is each thread reaching this point
209    will be replace to `target`.
210    
211    IN:
212        rp...............replacement point to activate
213            target...........target of replacement
214   
215 *******************************************************************************/
216
217 void replace_activate_replacement_point(rplpoint *rp,rplpoint *target)
218 {
219         assert(rp->target == NULL);
220         
221 #ifndef NDEBUG
222         printf("activate replacement point: ");
223         replace_replacement_point_println(rp);
224         fflush(stdout);
225 #endif
226         
227         rp->target = target;
228         
229 #if defined(__I386__) && defined(ENABLE_JIT)
230         md_patch_replacement_point(rp);
231 #endif
232 }
233
234 /* replace_deactivate_replacement_point ****************************************
235  
236    Deactivate a replacement point. When this function returns, the
237    replacement point is "un-armed", that is a each thread reaching this point
238    will just continue normally.
239    
240    IN:
241        rp...............replacement point to deactivate
242   
243 *******************************************************************************/
244
245 void replace_deactivate_replacement_point(rplpoint *rp)
246 {
247         assert(rp->target);
248         
249 #ifndef NDEBUG
250         printf("deactivate replacement point: ");
251         replace_replacement_point_println(rp);
252         fflush(stdout);
253 #endif
254         
255         rp->target = NULL;
256         
257 #if defined(__I386__) && defined(ENABLE_JIT)
258         md_patch_replacement_point(rp);
259 #endif
260 }
261
262 /* replace_me ******************************************************************
263  
264    This function is called by asm_replacement_out when a thread reaches
265    a replacement point. `replace_me` must map the execution state to the
266    target replacement point and let execution continue there.
267
268    This function never returns!
269   
270    IN:
271        rp...............replacement point that has been reached
272            es...............executions state read by asm_replacement_out
273   
274 *******************************************************************************/
275
276 void replace_me(rplpoint *rp,executionstate *es)
277 {
278         rplpoint *target;
279         
280         target = rp->target;
281         
282 #ifndef NDEBUG
283         printf("replace_me(%p,%p)\n",(void*)rp,(void*)es);
284         fflush(stdout);
285         replace_replacement_point_println(rp);
286         replace_executionstate_println(es);
287 #endif
288
289         es->pc = rp->target->pc;
290 }
291
292 /* replace_replacement_point_println *******************************************
293  
294    Print replacement point info.
295   
296    IN:
297        rp...............the replacement point to print
298   
299 *******************************************************************************/
300
301 #ifndef NDEBUG
302 void replace_replacement_point_println(rplpoint *rp)
303 {
304         int j;
305
306         if (!rp) {
307                 printf("(rplpoint *)NULL\n");
308                 return;
309         }
310
311         printf("rplpoint %p pc:%p out:%p target:%p mcode:%016llx allocs:%d = [",
312                         (void*)rp,rp->pc,rp->outcode,(void*)rp->target,
313                         rp->mcode,rp->regalloccount);
314
315         for (j=0; j<rp->regalloccount; ++j)
316                 printf(" %02d",rp->regalloc[j]);
317
318         printf("] method:");
319         method_print(rp->code->m);
320
321         printf("\n");
322 }
323 #endif
324
325 /* replace_show_replacement_points *********************************************
326  
327    Print replacement point info.
328   
329    IN:
330        code.............codeinfo whose replacement points should be printed.
331   
332 *******************************************************************************/
333
334 #ifndef NDEBUG
335 void replace_show_replacement_points(codeinfo *code)
336 {
337         int i;
338         rplpoint *rp;
339         
340         if (!code) {
341                 printf("(codeinfo *)NULL\n");
342                 return;
343         }
344
345         printf("\treplacement points: %d\n",code->rplpointcount);
346         printf("\tglobal allocations: %d\n",code->globalcount);
347         printf("\ttotal allocations : %d\n",code->regalloccount);
348         printf("\n");
349
350         for (i=0; i<code->rplpointcount; ++i) {
351                 rp = code->rplpoints + i;
352
353                 assert(rp->code == code);
354                 
355                 replace_replacement_point_println(rp);
356         }
357 }
358 #endif
359
360 /* replace_executionstate_println **********************************************
361  
362    Print execution state
363   
364    IN:
365        es...............the execution state to print
366   
367 *******************************************************************************/
368
369 #ifndef NDEBUG
370 void replace_executionstate_println(executionstate *es)
371 {
372         int i;
373
374         if (!es) {
375                 printf("(executionstate *)NULL\n");
376                 return;
377         }
378
379         printf("executionstate %p:\n",(void*)es);
380         printf("\tpc = %p\n",(void*)es->pc);
381         for (i=0; i<3; ++i) {
382                 printf("\tregs[%2d] = %016llx\n",i,(u8)es->regs[i]);
383         }
384
385         printf("\n");
386 }
387 #endif
388
389 /*
390  * These are local overrides for various environment variables in Emacs.
391  * Please do not remove this and leave it at the end of the file, where
392  * Emacs will automagically detect them.
393  * ---------------------------------------------------------------------
394  * Local variables:
395  * mode: c
396  * indent-tabs-mode: t
397  * c-basic-offset: 4
398  * tab-width: 4
399  * End:
400  * vim:noexpandtab:sw=4:ts=4:
401  */