* src/vm/jit/i386/asmpart.S (asm_replacement_out): Added pv.
[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 #include <stdlib.h>
40
41 #include "mm/memory.h"
42 #include "toolbox/logging.h"
43 #include "vm/options.h"
44 #include "vm/jit/jit.h"
45 #include "vm/jit/replace.h"
46 #include "vm/jit/asmpart.h"
47 #include "vm/jit/disass.h"
48 #include "arch.h"
49
50 /*** constants used internally ************************************************/
51
52 #define TOP_IS_NORMAL    0
53 #define TOP_IS_ON_STACK  1
54 #define TOP_IS_IN_ITMP1  2
55
56 /* replace_create_replacement_points *******************************************
57  
58    Create the replacement points for the given code.
59   
60    IN:
61        code.............codeinfo where replacement points should be stored
62                             code->rplpoints must be NULL.
63                                                 code->rplpointcount must be 0.
64            rd...............registerdata containing allocation info.
65   
66    OUT:
67        code->rplpoints.......set to the list of replacement points
68            code->rplpointcount...number of replacement points
69            code->regalloc........list of allocation info
70            code->regalloccount...total length of allocation info list
71            code->globalcount.....number of global allocations at the
72                                  start of code->regalloc
73   
74    RETURN VALUE:
75        true.............everything ok 
76        false............an exception has been thrown
77    
78 *******************************************************************************/
79
80 bool replace_create_replacement_points(codeinfo *code,registerdata *rd)
81 {
82         basicblock *bptr;
83         int count;
84         methodinfo *m;
85         rplpoint *rplpoints;
86         rplpoint *rp;
87         int alloccount;
88         int globalcount;
89         rplalloc *regalloc;
90         rplalloc *ra;
91         int i;
92         int t;
93         stackptr sp;
94         bool indexused;
95
96         /* assert that we wont overwrite already allocated data */
97         
98         assert(code);
99         assert(code->m);
100         assert(code->rplpoints == NULL);
101         assert(code->rplpointcount == 0);
102         assert(code->regalloc == NULL);
103         assert(code->regalloccount == 0);
104         assert(code->globalcount == 0);
105
106         /* iterate over the basic block list to find replacement points */
107
108         m = code->m;
109
110         count = 0;
111         alloccount = 0;
112         for (bptr = m->basicblocks; bptr; bptr = bptr->next) {
113                 if (!(bptr->bitflags & BBFLAG_REPLACEMENT))
114                         continue;
115
116                 /* there will be a replacement point at the start of this block */
117                 
118                 count++;
119                 alloccount += bptr->indepth;
120         }
121
122         /* if no points were found, there's nothing to do */
123         
124         if (!count)
125                 return true;
126
127         /* count global register allocations */
128
129         globalcount = 0;
130
131         for (i=0; i<m->maxlocals; ++i) {
132                 indexused = false;
133                 for (t=0; t<5; ++t) {
134 #if defined(ENABLE_INTRP)
135                         if (!opt_intrp) {
136 #endif
137                                 if (rd->locals[i][t].type == t) {
138                                         globalcount++;
139                                         indexused = true;
140                                 }
141 #if defined(ENABLE_INTRP)
142                         }
143 #endif
144                 }
145                 if (!indexused)
146                         globalcount++; /* dummy rplalloc */
147         }
148
149         alloccount += globalcount;
150
151         /* allocate replacement point array and allocation array */
152         
153         rplpoints = MNEW(rplpoint,count);
154         regalloc = MNEW(rplalloc,alloccount);
155         ra = regalloc;
156
157         /* store global register allocations */
158
159         for (i=0; i<m->maxlocals; ++i) {
160                 indexused = false;
161                 for (t=0; t<5; ++t) {
162 #if defined(ENABLE_INTRP)
163                         if (!opt_intrp) {
164 #endif
165                                 if (rd->locals[i][t].type == t) {
166                                         ra->flags = rd->locals[i][t].flags & (INMEMORY);
167                                         ra->index = rd->locals[i][t].regoff;
168                                         ra->type  = t;
169                                         ra->next = (indexused) ? 0 : 1;
170                                         ra++;
171                                         indexused = true;
172                                 }
173 #if defined(ENABLE_INTRP)
174                         }
175 #endif
176                 }
177                 if (!indexused) {
178                         /* dummy rplalloc */
179                         ra->type = -1;
180                         ra->flags = 0;
181                         ra->index = 0;
182                         ra->next = 1;
183                         ra++;
184                 }
185         }
186
187         /* initialize replacement point structs */
188
189         rp = rplpoints;
190         for (bptr = m->basicblocks; bptr; bptr = bptr->next) {
191                 if (!(bptr->bitflags & BBFLAG_REPLACEMENT))
192                         continue;
193
194                 /* there will be a replacement point at the start of this block */
195
196                 rp->pc = NULL;        /* set by codegen */
197                 rp->outcode = NULL;   /* set by codegen */
198                 rp->code = code;
199                 rp->target = NULL;
200                 rp->regalloc = ra;
201                 rp->flags = 0;
202                 rp->type = bptr->type;
203
204                 /* store local allocation info */
205
206                 for (sp = bptr->instack; sp; sp = sp->prev) {
207                         ra->flags = sp->flags & (INMEMORY);
208                         ra->index = sp->regoff;
209                         ra->type  = sp->type;
210                         ra->next  = 1;
211                         ra++;
212                 }
213
214                 rp->regalloccount = ra - rp->regalloc;
215                 
216                 rp++;
217         }
218
219         /* store the data in the codeinfo */
220
221         code->rplpoints = rplpoints;
222         code->rplpointcount = count;
223         code->regalloc = regalloc;
224         code->regalloccount = alloccount;
225         code->globalcount = globalcount;
226         code->savedintcount = INT_SAV_CNT - rd->savintreguse;
227         code->savedfltcount = FLT_SAV_CNT - rd->savfltreguse;
228         code->memuse = rd->memuse;
229
230         /* everything alright */
231
232         return true;
233 }
234
235 /* replace_free_replacement_points *********************************************
236  
237    Free memory used by replacement points.
238   
239    IN:
240        code.............codeinfo whose replacement points should be freed.
241   
242 *******************************************************************************/
243
244 void replace_free_replacement_points(codeinfo *code)
245 {
246         assert(code);
247
248         if (code->rplpoints)
249                 MFREE(code->rplpoints,rplpoint,code->rplpointcount);
250
251         if (code->regalloc)
252                 MFREE(code->regalloc,rplalloc,code->regalloccount);
253
254         code->rplpoints = NULL;
255         code->rplpointcount = 0;
256         code->regalloc = NULL;
257         code->regalloccount = 0;
258         code->globalcount = 0;
259 }
260
261 /* replace_activate_replacement_point ******************************************
262  
263    Activate a replacement point. When this function returns, the
264    replacement point is "armed", that is each thread reaching this point
265    will be replace to `target`.
266    
267    IN:
268        rp...............replacement point to activate
269            target...........target of replacement
270   
271 *******************************************************************************/
272
273 void replace_activate_replacement_point(rplpoint *rp,rplpoint *target)
274 {
275         assert(rp->target == NULL);
276         
277 #ifndef NDEBUG
278         printf("activate replacement point: ");
279         replace_replacement_point_println(rp);
280         fflush(stdout);
281 #endif
282         
283         rp->target = target;
284         
285 #if (defined(__I386__) || defined(__X86_64__)) && defined(ENABLE_JIT)
286         md_patch_replacement_point(rp);
287 #endif
288 }
289
290 /* replace_deactivate_replacement_point ****************************************
291  
292    Deactivate a replacement point. When this function returns, the
293    replacement point is "un-armed", that is a each thread reaching this point
294    will just continue normally.
295    
296    IN:
297        rp...............replacement point to deactivate
298   
299 *******************************************************************************/
300
301 void replace_deactivate_replacement_point(rplpoint *rp)
302 {
303         assert(rp->target);
304         
305 #ifndef NDEBUG
306         printf("deactivate replacement point: ");
307         replace_replacement_point_println(rp);
308         fflush(stdout);
309 #endif
310         
311         rp->target = NULL;
312         
313 #if (defined(__I386__) || defined(__X86_64__)) && defined(ENABLE_JIT)
314         md_patch_replacement_point(rp);
315 #endif
316 }
317
318 /* replace_read_executionstate *************************************************
319
320    Read the given executions state and translate it to a source state.
321    
322    IN:
323        rp...............replacement point at which `es` was taken
324            es...............execution state
325            ss...............where to put the source state
326
327    OUT:
328        *ss..............the source state derived from the execution state
329   
330 *******************************************************************************/
331
332 static void replace_read_executionstate(rplpoint *rp,executionstate *es,
333                                                                          sourcestate *ss)
334 {
335         methodinfo *m;
336         codeinfo *code;
337         int count;
338         int i;
339         int t;
340         int allocs;
341         rplalloc *ra;
342         methoddesc *md;
343         int topslot;
344 #ifdef HAS_4BYTE_STACKSLOT
345         u4 *sp;
346         u4 *basesp;
347 #else
348         u8 *sp;
349         u8 *basesp;
350 #endif
351
352         code = rp->code;
353         m = code->m;
354         md = m->parseddesc;
355         topslot = TOP_IS_NORMAL;
356
357         /* stack pointers */
358
359 #ifdef HAS_4BYTE_STACKSLOT
360         sp = (u4*) es->sp;
361 #else
362         sp = (u8*) es->sp;
363 #endif
364
365         /* on some architectures the returnAddress is passed on the stack by JSR */
366
367 #if defined(__I386__) || defined(__X86_64__)
368         if (rp->type == BBTYPE_SBR) {
369                 sp++;
370                 topslot = TOP_IS_ON_STACK;
371         }
372 #endif
373
374         /* in some cases the top stack slot is passed in REG_ITMP1 */
375
376         if (  (rp->type == BBTYPE_EXH)
377 #if defined(__ALPHA__)
378            || (rp->type == BBTYPE_SBR)
379 #endif
380            )
381         {
382                 topslot = TOP_IS_IN_ITMP1;
383         }
384
385         /* calculate base stack pointer */
386         
387         basesp = sp + code_get_stack_frame_size(code);
388
389         ss->stackbase = (u1*) basesp;
390
391         /* read local variables */
392
393         count = m->maxlocals;
394         ss->javalocalcount = count;
395         ss->javalocals = DMNEW(u8,count * 5);
396
397 #ifndef NDEBUG
398         /* mark values as undefined */
399         for (i=0; i<count*5; ++i)
400                 ss->javalocals[i] = (u8) 0x00dead0000dead00ULL;
401
402         /* some entries in the intregs array are not meaningful */
403         es->intregs[REG_ITMP3] = (u8) 0x11dead1111dead11ULL;
404         es->intregs[REG_SP   ] = (u8) 0x11dead1111dead11ULL;
405 #ifdef REG_PV
406         es->intregs[REG_PV   ] = (u8) 0x11dead1111dead11ULL;
407 #endif
408 #endif /* NDEBUG */
409         
410         ra = code->regalloc;
411
412         i = -1;
413         for (allocs = code->globalcount; allocs--; ra++) {
414                 if (ra->next)
415                         i++;
416                 t = ra->type;
417                 if (t == -1)
418                         continue; /* dummy rplalloc */
419
420 #ifdef HAS_4BYTE_STACKSLOT
421                 if (IS_2_WORD_TYPE(ra->type)) {
422                         if (ra->flags & INMEMORY) {
423                                 ss->javalocals[i*5+t] = *(u8*)(sp + ra->index);
424                         }
425                         else {
426                                 dolog("XXX split 2-word types in registers are not supported");
427                                 assert(0);
428                         }
429                 }
430                 else {
431 #endif
432                         if (ra->flags & INMEMORY) {
433                                 ss->javalocals[i*5+t] = sp[ra->index];
434                         }
435                         else {
436                                 ss->javalocals[i*5+t] = es->intregs[ra->index];
437                         }
438 #ifdef HAS_4BYTE_STACKSLOT
439                 }
440 #endif
441         }
442
443         /* read stack slots */
444
445         count = rp->regalloccount;
446         ss->javastackdepth = count;
447         ss->javastack = DMNEW(u8,count);
448
449 #ifndef NDEBUG
450         /* mark values as undefined */
451         for (i=0; i<count; ++i)
452                 ss->javastack[i] = (u8) 0x00dead0000dead00ULL;
453 #endif
454         
455         i = 0;
456         ra = rp->regalloc;
457
458         /* the first stack slot is special in SBR and EXH blocks */
459
460         if (topslot == TOP_IS_ON_STACK) {
461                 assert(count);
462                 
463                 ss->javastack[i] = sp[-1];
464                 count--;
465                 i++;
466                 ra++;
467         }
468         else if (topslot == TOP_IS_IN_ITMP1) {
469                 assert(count);
470
471                 ss->javastack[i] = es->intregs[REG_ITMP1];
472                 count--;
473                 i++;
474                 ra++;
475         }
476         
477         /* read remaining stack slots */
478         
479         for (; count--; ra++, i++) {
480                 assert(ra->next);
481
482                 if (ra->flags & INMEMORY) {
483                         ss->javastack[i] = sp[ra->index];
484                 }
485                 else {
486                         ss->javastack[i] = es->intregs[ra->index];
487                 }
488         }
489
490         /* read unused callee saved int regs */
491         
492         count = INT_SAV_CNT;
493         for (i=0; count > code->savedintcount; ++i) {
494                 assert(i < INT_REG_CNT);
495                 if (nregdescint[i] == REG_SAV)
496                         ss->savedintregs[--count] = es->intregs[i];
497         }
498
499         /* read saved int regs */
500
501         for (i=0; i<code->savedintcount; ++i) {
502                 ss->savedintregs[i] = *--basesp;
503         }
504
505         /* read unused callee saved flt regs */
506         
507         count = FLT_SAV_CNT;
508         for (i=0; count > code->savedfltcount; ++i) {
509                 assert(i < FLT_REG_CNT);
510                 if (nregdescfloat[i] == REG_SAV)
511                         ss->savedfltregs[--count] = es->fltregs[i];
512         }
513
514         /* read saved flt regs */
515
516         for (i=0; i<code->savedfltcount; ++i) {
517 #ifdef HAS_4BYTE_STACKSLOT
518                 basesp -= 2;
519 #else
520                 basesp--;
521 #endif
522                 ss->savedfltregs[i] = *(u8*)basesp;
523         }
524
525         /* read slots used for synchronization */
526
527         count = code_get_sync_slot_count(code);
528         ss->syncslotcount = count;
529         ss->syncslots = DMNEW(u8,count);
530         for (i=0; i<count; ++i) {
531                 ss->syncslots[i] = *--basesp;
532         }
533 }
534
535 /* replace_write_executionstate ************************************************
536
537    Translate the given source state into an execution state.
538    
539    IN:
540        rp...............replacement point for which execution state should be
541                             creates
542            es...............where to put the execution state
543            ss...............the given source state
544
545    OUT:
546        *es..............the execution state derived from the source state
547   
548 *******************************************************************************/
549
550 static void replace_write_executionstate(rplpoint *rp,executionstate *es,
551                                                                                  sourcestate *ss)
552 {
553         methodinfo *m;
554         codeinfo *code;
555         int count;
556         int i;
557         int t;
558         int allocs;
559         rplalloc *ra;
560         methoddesc *md;
561         int topslot;
562 #ifdef HAS_4BYTE_STACKSLOT
563         u4 *sp;
564         u4 *basesp;
565 #else
566         u8 *sp;
567         u8 *basesp;
568 #endif
569
570         code = rp->code;
571         m = code->m;
572         md = m->parseddesc;
573         
574         /* calculate stack pointer */
575         
576 #ifdef HAS_4BYTE_STACKSLOT
577         basesp = (u4*) ss->stackbase;
578 #else
579         basesp = (u8*) ss->stackbase;
580 #endif
581         
582         sp = basesp - code_get_stack_frame_size(code);
583
584         /* on some architectures the returnAddress is passed on the stack by JSR */
585
586 #if defined(__I386__) || defined(__X86_64__)
587         if (rp->type == BBTYPE_SBR) {
588                 topslot = TOP_IS_ON_STACK;
589         }
590 #endif
591         
592         /* in some cases the top stack slot is passed in REG_ITMP1 */
593
594         if (  (rp->type == BBTYPE_EXH)
595 #if defined(__ALPHA__)
596            || (rp->type == BBTYPE_SBR) 
597 #endif
598            )
599         {
600                 topslot = TOP_IS_IN_ITMP1;
601         }
602
603         /* in debug mode, invalidate stack frame first */
604
605 #ifndef NDEBUG
606         for (i=0; i<(basesp - sp); ++i) {
607                 sp[i] = 0xdeaddeadU;
608         }
609 #endif
610
611         /* write local variables */
612
613         count = m->maxlocals;
614
615         ra = code->regalloc;
616
617         i = -1;
618         for (allocs = code->globalcount; allocs--; ra++) {
619                 if (ra->next)
620                         i++;
621
622                 assert(i >= 0 && i < m->maxlocals);
623                 
624                 t = ra->type;
625                 if (t == -1)
626                         continue; /* dummy rplalloc */
627
628 #ifdef HAS_4BYTE_STACKSLOT
629                 if (IS_2_WORD_TYPE(ra->type)) {
630                         if (ra->flags & INMEMORY) {
631                                 *(u8*)(sp + ra->index) = ss->javalocals[i*5+t];
632                         }
633                         else {
634                                 dolog("XXX split 2-word types in registers are not supported");
635                                 assert(0);
636                         }
637                 }
638                 else {
639 #endif
640                         if (ra->flags & INMEMORY) {
641                                 sp[ra->index] = ss->javalocals[i*5+t];
642                         }
643                         else {
644                                 es->intregs[ra->index] = ss->javalocals[i*5+t];
645                         }
646 #ifdef HAS_4BYTE_STACKSLOT
647                 }
648 #endif
649         }
650
651         /* write stack slots */
652
653         count = rp->regalloccount;
654
655         i = 0;
656         ra = rp->regalloc;
657
658         /* the first stack slot is special in SBR and EXH blocks */
659
660         if (topslot == TOP_IS_ON_STACK) {
661                 assert(count);
662                 
663                 sp[-1] = ss->javastack[i];
664                 count--;
665                 i++;
666                 ra++;
667         }
668         else if (topslot == TOP_IS_IN_ITMP1) {
669                 assert(count);
670
671                 es->intregs[REG_ITMP1] = ss->javastack[i];
672                 count--;
673                 i++;
674                 ra++;
675         }
676
677         /* write remaining stack slots */
678         
679         for (; count--; ra++, i++) {
680                 assert(ra->next);
681
682                 if (ra->flags & INMEMORY) {
683                         sp[ra->index] = ss->javastack[i];
684                 }
685                 else {
686                         es->intregs[ra->index] = ss->javastack[i];
687                 }
688         }
689         
690         /* write unused callee saved int regs */
691         
692         count = INT_SAV_CNT;
693         for (i=0; count > code->savedintcount; ++i) {
694                 assert(i < INT_REG_CNT);
695                 if (nregdescint[i] == REG_SAV)
696                         es->intregs[i] = ss->savedintregs[--count];
697         }
698
699         /* write saved int regs */
700
701         for (i=0; i<code->savedintcount; ++i) {
702                 *--basesp = ss->savedintregs[i];
703         }
704
705         /* write unused callee saved flt regs */
706         
707         count = FLT_SAV_CNT;
708         for (i=0; count > code->savedfltcount; ++i) {
709                 assert(i < FLT_REG_CNT);
710                 if (nregdescfloat[i] == REG_SAV)
711                         es->fltregs[i] = ss->savedfltregs[--count];
712         }
713
714         /* write saved flt regs */
715
716         for (i=0; i<code->savedfltcount; ++i) {
717 #ifdef HAS_4BYTE_STACKSLOT
718                 basesp -= 2;
719 #else
720                 basesp--;
721 #endif
722                 *(u8*)basesp = ss->savedfltregs[i];
723         }
724
725         /* write slots used for synchronization */
726
727         count = code_get_sync_slot_count(code);
728         assert(count == ss->syncslotcount);
729         for (i=0; i<count; ++i) {
730                 *--basesp = ss->syncslots[i];
731         }
732
733         /* set new pc */
734
735         es->pc = rp->pc;
736 }
737
738 /* replace_me ******************************************************************
739  
740    This function is called by asm_replacement_out when a thread reaches
741    a replacement point. `replace_me` must map the execution state to the
742    target replacement point and let execution continue there.
743
744    This function never returns!
745   
746    IN:
747        rp...............replacement point that has been reached
748            es...............execution state read by asm_replacement_out
749   
750 *******************************************************************************/
751
752 void replace_me(rplpoint *rp,executionstate *es)
753 {
754         rplpoint *target;
755         sourcestate ss;
756         s4 dumpsize;
757         
758         /* mark start of dump memory area */
759
760         dumpsize = dump_size();
761
762         /* fetch the target of the replacement */
763
764         target = rp->target;
765
766         /* XXX DEBUG turn of self-replacement */
767         if (target == rp)
768                 replace_deactivate_replacement_point(rp);
769         
770 #ifndef NDEBUG
771         printf("replace_me(%p,%p)\n",(void*)rp,(void*)es);
772         fflush(stdout);
773         replace_replacement_point_println(rp);
774         replace_executionstate_println(es,rp->code);
775 #endif
776
777         /* read execution state of old code */
778
779         replace_read_executionstate(rp,es,&ss);
780
781 #ifndef NDEBUG
782         replace_sourcestate_println(&ss);
783 #endif
784
785         /* write execution state of new code */
786
787         replace_write_executionstate(target,es,&ss);
788
789 #ifndef NDEBUG
790         replace_executionstate_println(es,target->code);
791 #endif
792         
793         /* release dump area */
794
795         dump_release(dumpsize);
796
797         /* enter new code */
798
799 #if (defined(__I386__) || defined(__X86_64__)) && defined(ENABLE_JIT)
800         asm_replacement_in(es);
801 #endif
802         abort();
803 }
804
805 /* replace_replacement_point_println *******************************************
806  
807    Print replacement point info.
808   
809    IN:
810        rp...............the replacement point to print
811   
812 *******************************************************************************/
813
814 #ifndef NDEBUG
815 static const char *type_char = "IJFDA";
816
817 #define TYPECHAR(t)  (((t) >= 0 && (t) <= 4) ? type_char[t] : '?')
818
819 void replace_replacement_point_println(rplpoint *rp)
820 {
821         int j;
822
823         if (!rp) {
824                 printf("(rplpoint *)NULL\n");
825                 return;
826         }
827
828         printf("rplpoint %p pc:%p out:%p target:%p mcode:%016llx type:%01d flags:%01x ra:%d = [",
829                         (void*)rp,rp->pc,rp->outcode,(void*)rp->target,
830                         (unsigned long long)rp->mcode,rp->type,rp->flags,rp->regalloccount);
831
832         for (j=0; j<rp->regalloccount; ++j)
833                 printf("%c%1c%01x:%02d",
834                                 (rp->regalloc[j].next) ? '^' : ' ',
835                                 TYPECHAR(rp->regalloc[j].type),
836                                 rp->regalloc[j].flags,
837                                 rp->regalloc[j].index);
838
839         printf("]\n          method: ");
840         method_print(rp->code->m);
841
842         printf("\n");
843 }
844 #endif
845
846 /* replace_show_replacement_points *********************************************
847  
848    Print replacement point info.
849   
850    IN:
851        code.............codeinfo whose replacement points should be printed.
852   
853 *******************************************************************************/
854
855 #ifndef NDEBUG
856 void replace_show_replacement_points(codeinfo *code)
857 {
858         int i;
859         rplpoint *rp;
860         
861         if (!code) {
862                 printf("(codeinfo *)NULL\n");
863                 return;
864         }
865
866         printf("\treplacement points: %d\n",code->rplpointcount);
867         printf("\tglobal allocations: %d = [",code->globalcount);
868
869         for (i=0; i<code->globalcount; ++i)
870                 printf("%c%1c%01x:%02d",
871                                 (code->regalloc[i].next) ? '^' : ' ',
872                                 TYPECHAR(code->regalloc[i].type),
873                                 code->regalloc[i].flags,code->regalloc[i].index);
874
875         printf("]\n");
876
877         printf("\ttotal allocations : %d\n",code->regalloccount);
878         printf("\tsaved int regs    : %d\n",code->savedintcount);
879         printf("\tsaved flt regs    : %d\n",code->savedfltcount);
880         printf("\tmemuse            : %d\n",code->memuse);
881
882         printf("\n");
883
884         for (i=0; i<code->rplpointcount; ++i) {
885                 rp = code->rplpoints + i;
886
887                 assert(rp->code == code);
888                 
889                 printf("\t");
890                 replace_replacement_point_println(rp);
891         }
892 }
893 #endif
894
895 /* replace_executionstate_println **********************************************
896  
897    Print execution state
898   
899    IN:
900        es...............the execution state to print
901            code.............the codeinfo for which this execution state is meant
902                             (may be NULL)
903   
904 *******************************************************************************/
905
906 #ifndef NDEBUG
907 void replace_executionstate_println(executionstate *es,codeinfo *code)
908 {
909         int i;
910         int slots;
911 #ifdef HAS_4BYTE_STACKSLOT
912         u4 *sp;
913 #else
914         u8 *sp;
915 #endif
916
917         if (!es) {
918                 printf("(executionstate *)NULL\n");
919                 return;
920         }
921
922         printf("executionstate %p:\n",(void*)es);
923         printf("\tpc = %p\n",(void*)es->pc);
924         printf("\tsp = %p\n",(void*)es->sp);
925         printf("\tpv = %p\n",(void*)es->pv);
926         for (i=0; i<INT_REG_CNT; ++i) {
927                 printf("\t%-3s = %016llx\n",regs[i],(unsigned long long)es->intregs[i]);
928         }
929         for (i=0; i<FLT_REG_CNT; ++i) {
930                 printf("\tfltregs[%2d] = %016llx\n",i,(unsigned long long)es->fltregs[i]);
931         }
932
933 #ifdef HAS_4BYTE_STACKSLOT
934         sp = (u4*) es->sp;
935 #else
936         sp = (u8*) es->sp;
937 #endif
938
939         if (code)
940                 slots = code_get_stack_frame_size(code);
941         else
942                 slots = 0;
943
944         printf("\tstack slots at sp:\n");
945         for (i=0; i<slots; ++i) {
946 #ifdef HAS_4BYTE_STACKSLOT
947                 printf("\t\t%08lx\n",(unsigned long)*sp++);
948 #else
949                 printf("\t\t%016llx\n",(unsigned long long)*sp++);
950 #endif
951         }
952
953         printf("\n");
954 }
955 #endif
956
957 /* replace_sourcestate_println *************************************************
958  
959    Print source state
960   
961    IN:
962        ss...............the source state to print
963   
964 *******************************************************************************/
965
966 #ifndef NDEBUG
967 void replace_sourcestate_println(sourcestate *ss)
968 {
969         int i;
970         int t;
971         int reg;
972
973         if (!ss) {
974                 printf("(sourcestate *)NULL\n");
975                 return;
976         }
977
978         printf("sourcestate %p: stackbase=%p\n",(void*)ss,(void*)ss->stackbase);
979
980         printf("\tlocals (%d):\n",ss->javalocalcount);
981         for (i=0; i<ss->javalocalcount; ++i) {
982                 for (t=0; t<5; ++t) {
983                         if (ss->javalocals[i*5+t] != 0x00dead0000dead00ULL) {
984                                 printf("\tlocal[%c%2d] = ",TYPECHAR(t),i);
985                                 printf("%016llx\n",(unsigned long long) ss->javalocals[i*5+t]);
986                         }
987                 }
988         }
989
990         printf("\n");
991
992         printf("\tstack (depth %d):\n",ss->javastackdepth);
993         for (i=0; i<ss->javastackdepth; ++i) {
994                 printf("\tstack[%2d] = ",i);
995                 printf("%016llx\n",(unsigned long long) ss->javastack[i]);
996         }
997
998         printf("\n");
999
1000         printf("\tsaved int registers (%d):\n",INT_SAV_CNT);
1001         reg = INT_REG_CNT;
1002         for (i=0; i<INT_SAV_CNT; ++i) {
1003                 while (nregdescint[--reg] != REG_SAV)
1004                         ;
1005                 if (ss->savedintregs[i] != 0x00dead0000dead00ULL) {
1006                         printf("\t%-3s = ",regs[reg]);
1007                         printf("%016llx\n",(unsigned long long) ss->savedintregs[i]);
1008                 }
1009         }
1010
1011         printf("\n");
1012
1013         printf("\tsaved float registers (%d):\n",FLT_SAV_CNT);
1014         for (i=0; i<FLT_SAV_CNT; ++i) {
1015                 if (ss->savedfltregs[i] != 0x00dead0000dead00ULL) {
1016                         printf("\tsavedfltreg[%2d] = ",i);
1017                         printf("%016llx\n",(unsigned long long) ss->savedfltregs[i]);
1018                 }
1019         }
1020         
1021         printf("\n");
1022
1023         printf("\tsynchronization slots (%d):\n",ss->syncslotcount);
1024         for (i=0; i<ss->syncslotcount; ++i) {
1025                 printf("\tslot[%2d] = ",i);
1026 #ifdef HAS_4BYTE_STACKSLOT
1027                 printf("%08lx\n",(unsigned long) ss->syncslots[i]);
1028 #else
1029                 printf("%016llx\n",(unsigned long long) ss->syncslots[i]);
1030 #endif
1031         }
1032         
1033         printf("\n");
1034 }
1035 #endif
1036
1037 /*
1038  * These are local overrides for various environment variables in Emacs.
1039  * Please do not remove this and leave it at the end of the file, where
1040  * Emacs will automagically detect them.
1041  * ---------------------------------------------------------------------
1042  * Local variables:
1043  * mode: c
1044  * indent-tabs-mode: t
1045  * c-basic-offset: 4
1046  * tab-width: 4
1047  * End:
1048  * vim:noexpandtab:sw=4:ts=4:
1049  */