Initial revision
[cacao.git] / comp / block.c
1 /***************************** comp/block.c ************************************
2
3         Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst
4
5         See file COPYRIGHT for information on usage and disclaimer of warranties
6
7         Basic block handling functions.
8
9         Authors: Reinhard Grafl      EMAIL: cacao@complang.tuwien.ac.at
10
11         Last Change: 1997/01/18
12
13 *******************************************************************************/
14
15
16 static u2 creatornum;  /* Fortlaufende Nummerierung f"ur vom Compiler
17                           generierte BasicBlocks (nur zu Debug-Zwecken) */
18
19 static subroutineinfo *actual_subroutine;
20 static u2 subroutinecounter=0;
21
22
23 /********************** Funktion: block_new ***********************************
24
25         erzeugt eine neue 'basicblock'-Struktur und initialisiert alle 
26         Komponenten 
27
28 ******************************************************************************/
29
30 static basicblock *block_new (u2 type, u4 codepos)
31 {
32         basicblock *b = DNEW (basicblock);
33         
34         b -> type = type;
35         b -> reached = false;
36         b -> finished = false;
37         b -> subroutine = NULL;
38         b -> jpc = codepos;
39         b -> stack = NULL;
40         list_init (&(b->pcmdlist), OFFSET (pcmd, linkage) );
41         b -> mpc = 0;
42         
43         b -> exproto = NULL;
44         b -> throwpos = 0;
45         return b;
46 }
47
48
49
50 /******************* Funktion: block_find *************************************
51
52         Sucht den Basicblock, der an einer gew"unschten Stelle im JavaVM-Code
53         anf"angt.
54         Wenn dort kein Block anf"angt  -> Fehler
55         
56 ******************************************************************************/
57
58 static basicblock *block_find (u4 codepos)
59 {
60         basicblock *b = blocks[codepos];
61         if (!b) panic ("Accessed JAVA-Command on no block boundary"); 
62         return b;
63 }
64
65
66 /****************** Funktion: block_isany *************************************
67
68         "uberpr"uft, ob an einer Stelle ein Basicblock anf"angt
69         
70 ******************************************************************************/
71
72 static bool block_isany (u4 codepos)
73 {
74         return (blocks[codepos] != NULL);
75 }
76
77
78 /***************** Funktion: block_reach **************************************
79
80         H"angt einen Basicblock in die Liste der schon erreichten Bl"ocke ein,
81         und setzt seinen Blockeintrittsstack auf den aktuellen Stack und
82         setzt den Unterprogramminfoblock auf das aktuelle Unterprogramminfo
83         
84         Wenn der Block bereits vorher als erreicht markiert war (und er deshalb
85         schon einen definierten Stack hatte), dann wird im derzeit vom 
86         Parser durchlaufenen Block (also dort, von wo dieser Block aus 
87         angesprungen wird) ein entsprechende Codest"uck hinzugef"ugt, der
88         die beiden Stacks aufeinander abstimmt.
89         
90 ******************************************************************************/
91
92 static void block_reach (basicblock *b)
93 {
94         if (!b->reached) {
95                 list_addlast (&reachedblocks, b);
96                 b -> reached = true;
97                 b -> subroutine = actual_subroutine;
98                 b -> stack = stack_get();
99                 }
100         else {
101                 if (b->subroutine != actual_subroutine) 
102                    panic ("Try to merge different subroutines");
103                 stack_addjoincode (b->stack);
104                 }
105 }
106
107 /*********************** Funktion: subroutine_set *****************************
108
109         setzt den aktuellen Subroutine-Infoblock 
110         
111 *******************************************************************************/
112
113 static void subroutine_set (subroutineinfo *s)
114 {
115         actual_subroutine = s;
116 }
117
118
119
120 /*********************** Funktion: subroutine_new *****************************
121
122         erzeugt einen neuen Subroutine-Infoblock
123         
124 *******************************************************************************/
125
126 static subroutineinfo *subroutine_new ()
127 {
128         subroutineinfo *s = DNEW (subroutineinfo);
129         s -> returnfinished = false;
130         s -> returnstack = NULL;
131         s -> callers = chain_dnew();
132         s -> counter = subroutinecounter++;
133         return s;
134 }
135
136
137
138
139
140
141 /********************** Funktion: block_insert ********************************
142
143         Erzeugt einen neuen Block, der an einer gew"unschten JavaVM-Code- Stelle
144         anf"angt.
145         Der Zeiger auf diesen Block wird im (globalen) 'blocks'-Array 
146         abgelegt.
147         
148 ******************************************************************************/ 
149
150 static void block_insert (u4 codepos)
151 {
152         if (codepos>=jcodelength) {
153                 sprintf (logtext,"Basic block border (%d) out of bounds",(int) codepos);
154                 error ();
155                 }
156
157         if (blocks[codepos]) return;
158
159         blocks[codepos] = block_new (BLOCKTYPE_JAVA, codepos);
160 }
161
162
163
164 /******************** Funktion: block_createexcreator *************************
165
166         erzeugt einen neuen Basicblock vom Typ EXCREATOR (=Exception Creator)
167         
168 ******************************************************************************/
169
170 static basicblock *block_createexcreator (java_objectheader *exproto, u4 throwpos)
171 {
172         basicblock *b;
173
174         b = block_new (BLOCKTYPE_EXCREATOR, creatornum++);
175         
176         b -> reached = true;
177         list_addlast (&reachedblocks, b);
178         b -> subroutine = actual_subroutine;
179         b -> exproto = exproto;
180         b -> throwpos = throwpos;
181         return b;
182 }
183
184
185 /******************* Funktion: block_createexforwarder ***********************
186
187         erzeugt einen neuen Basicblock vom Typ EXFORWARDER (=Exception Forwarder)
188         
189 *****************************************************************************/
190
191 static basicblock *block_createexforwarder (varid exvar, u4 throwpos)
192 {
193         basicblock *b;
194
195         b = block_new (BLOCKTYPE_EXFORWARDER, creatornum++);
196         
197         b -> reached = true;
198         list_addlast (&reachedblocks, b);
199         b -> subroutine = actual_subroutine;
200         b -> exvar = exvar;
201         b -> throwpos = throwpos;
202         return b;
203 }
204
205
206 /********************** Funktion: block_genmcode ******************************
207
208         generiert f"ur einen vom Parser fertig abgearbeiteten Block den
209         Maschinencode.
210         Hintereinanderliegende Bl"ocke durch die der Kontrollflu"s ohne
211         Sprungbefehle durchgeht, m"ussen hier auch hintereinander 
212         abgearbeitet werden.
213         
214 ******************************************************************************/
215
216 /* definition of block_genmcode moved to gen.c for inlining by andi          */
217
218
219 /************************ Funktion: block_firstscann **************************
220
221         Liest den JavaVM-Code der ganzen Methode durch und erzeugt soviele
222         neue Bl"ocke, wie es verschiedene Sprungziele gibt.
223         
224 ******************************************************************************/
225
226 static void block_firstscann ()
227 {
228         u4 p,nextp;
229         int i;
230         u1 opcode;
231         bool blockend;
232
233
234         creatornum=10001;
235
236
237         block_insert (0);
238
239         for (i=0; i<exceptiontablelength; i++) block_insert(extable[i].handlerpc);
240
241         p=0;
242         blockend = false;
243         while (p<jcodelength) {
244                 if (blockend) {
245                         block_insert (p);
246                         blockend = false;
247                         }
248
249                 opcode = jcode[p];
250                 nextp = p + jcommandsize[opcode];
251
252                 switch ( opcode ) {
253                         case CMD_IFEQ:
254                         case CMD_IFNULL:
255                         case CMD_IFLT:
256                         case CMD_IFLE:
257                         case CMD_IFNE:
258                         case CMD_IFNONNULL:
259                         case CMD_IFGT:
260                         case CMD_IFGE:
261                         case CMD_IF_ICMPEQ:
262                         case CMD_IF_ICMPNE:
263                         case CMD_IF_ICMPLT:
264                         case CMD_IF_ICMPGT:
265                         case CMD_IF_ICMPLE:
266                         case CMD_IF_ICMPGE:
267                         case CMD_IF_ACMPEQ:
268                         case CMD_IF_ACMPNE:
269                                 block_insert ( p + code_get_s2 (p+1) );
270                                 break;
271
272                         case CMD_GOTO:
273                                 block_insert ( p + code_get_s2 (p+1) );
274                                 blockend = true;
275                                 break;
276
277                         case CMD_GOTO_W:
278                                 block_insert ( p + code_get_s4 (p+1) );
279                                 blockend = true;
280                                 break;
281                                 
282                         case CMD_JSR:
283                                 block_insert ( p + code_get_s2 (p+1) );
284                                 blockend = true;
285                                 break;
286                         
287                         case CMD_JSR_W:
288                                 block_insert ( p + code_get_s4 (p+1) );
289                                 blockend = true;
290                                 break;
291
292                         case CMD_RET:
293                                 blockend = true;
294                                 break;
295
296                         case CMD_IRETURN:
297                         case CMD_LRETURN:
298                         case CMD_FRETURN:
299                         case CMD_DRETURN:
300                         case CMD_ARETURN:
301                         case CMD_RETURN:
302                                 blockend = true;
303                                 break;
304
305                         case CMD_ATHROW:
306                                 blockend = true;
307                                 break;
308                                 
309
310                         case CMD_WIDE:
311                                 switch (code_get_u1(p+1)) {
312                                 case CMD_RET:   nextp = p+4;
313                                                 blockend = true;
314                                                 break;
315                                 case CMD_IINC:  nextp = p+6;
316                                                 break;
317                                 default:        nextp = p+4;
318                                                 break;
319                                 }
320                                 break;
321                                                         
322                         case CMD_LOOKUPSWITCH:
323                                 { u4 num,p2,i;
324                                         p2 = ALIGN ((p+1),4);
325                                         num = code_get_u4 (p2+4);
326                                         nextp = p2 + 8 + 8*num;
327
328                                         block_insert ( p + code_get_s4(p2) );
329                                         for (i=0; i<num; i++) 
330                                                 block_insert ( p + code_get_s4(p2+12+8*i) );
331                                         
332                                         blockend = true;
333                                 }
334                                 break;
335
336                         case CMD_TABLESWITCH:
337                                 { u4 num,p2,i;
338                                         p2 = ALIGN ((p+1),4);
339                                         num= code_get_u4(p2+8) - code_get_u4 (p2+4) + 1;
340                                         nextp = p2 + 12 + 4*num;
341
342                                         block_insert ( p + code_get_s4(p2) );
343                                         
344                                         for (i=0; i<num; i++) 
345                                                 block_insert ( p + code_get_s4(p2+12+4*i) );
346                                                 
347                                         blockend = true;
348                                 }       
349                                 break;
350
351                         case CMD_LDC1:
352                                 i = code_get_u1(p+1);
353                                 goto pushconstantitem;
354                         case CMD_LDC2:
355                         case CMD_LDC2W:
356                                 i = code_get_u2(p + 1);
357                         pushconstantitem:
358                                 if (class_constanttype(class, i) == CONSTANT_String) {
359                                         unicode *s;
360                                         s = class_getconstant(class, i, CONSTANT_String);
361                                         (void) literalstring_new(s);
362                                         }
363                                 break;
364                         }
365
366                 if (nextp > jcodelength) panic ("Command-sequence crosses code-boundary");
367                 p = nextp;
368                 }
369         
370         if (!blockend) panic ("Code does not end with branch/return/athrow - stmt");    
371         
372 }
373
374
375
376 /************* Funktion: block_display (nur zu Debug-Zwecken) ****************/
377
378 void block_display (basicblock *b)
379 {
380         pcmd *p;
381         
382         if (b->subroutine) {
383                 printf ("\n%ld in subroutine: %d", (long int) b->jpc, (int) b->subroutine->counter);
384                 }
385         else {
386                 printf ("\n%ld:", (long int) b->jpc);
387                 }
388
389         switch (b->type) {
390                 case BLOCKTYPE_JAVA:        printf ("(JavaVM code)\n"); break;
391                 case BLOCKTYPE_EXCREATOR:   printf ("(Exception creator)\n"); break;
392                 case BLOCKTYPE_EXFORWARDER: printf ("(Exception forwarder)\n"); break;
393                 }
394                 
395         printf ("binding of stack:  "); 
396         stack_display (b->stack); printf ("\n");
397         
398         p = list_first (&(b->pcmdlist));
399         while (p) {
400                 pcmd_display (p);
401                 p = list_next (&(b->pcmdlist), p);
402                 }
403 }
404
405