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