Initial revision
[cacao.git] / compiler.c
1 /****************************** compiler.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         Enth"alt die Funktionen mit denen die JavaVM - Methoden in Maschinencode
8         "ubersetzt werden.
9         Ein Aufruf vom compiler_compile "ubersetzt genau eine Methode.
10         Alle in diesem Modul global definierten Variablen gelten nur f"ur 
11         eben diese gerade in der "Ubersetzung befindlichen Methode.
12
13         Authors: Reinhard Grafl      EMAIL: cacao@complang.tuwien.ac.at
14                  Andreas  Krall      EMAIL: cacao@complang.tuwien.ac.at
15         Changes: Mark Probst         EMAIL: cacao@complang.tuwien.ac.at
16
17         Last Change: 1997/10/22
18
19 *******************************************************************************/
20
21 #include "global.h"
22 #include "compiler.h"
23
24 #include "loader.h"
25 #include "tables.h"
26 #include "builtin.h"
27 #include "native.h"
28 #include "asmpart.h"
29
30 #include "threads/thread.h"              /* schani */
31
32
33 /*************************** globale Schalter ********************************/
34
35 extern int newcompiler;                 
36 methodptr new_compile (methodinfo *m);  /* compile a method with new compiler */
37
38 /**************************  no all in newcomp.c
39
40 bool compileverbose = false;
41 bool showstack = false;
42 bool showintermediate = false;
43 bool showdisassemble = false; 
44 int  optimizelevel = 0;
45
46 bool checkbounds = true;
47 bool checknull = true;
48 bool checkfloats = true;
49 bool checksync = true;
50
51 bool getcompilingtime = false;
52 long int compilingtime = 0;
53 int  has_ext_instr_set = 0;
54
55 bool statistics = false;         
56
57 int count_jit_calls = 0;
58 int count_methods = 0;
59 int count_spills = 0;
60 int count_pcmd_activ = 0;
61 int count_pcmd_drop = 0;
62 int count_pcmd_zero = 0;
63 int count_pcmd_const_store = 0;
64 int count_pcmd_const_alu = 0;
65 int count_pcmd_const_bra = 0;
66 int count_pcmd_load = 0;
67 int count_pcmd_move = 0;
68 int count_pcmd_store = 0;
69 int count_pcmd_store_comb = 0;
70 int count_pcmd_op = 0;
71 int count_pcmd_mem = 0;
72 int count_pcmd_met = 0;
73 int count_pcmd_bra = 0;
74 int count_pcmd_table = 0;
75 int count_pcmd_return = 0;
76 int count_pcmd_returnx = 0;
77 int count_check_null = 0;
78 int count_javainstr = 0;
79 int count_javacodesize = 0;
80 int count_javaexcsize = 0;
81 int count_calls = 0;
82 int count_tryblocks = 0;
83 int count_code_len = 0;
84 int count_data_len = 0;
85 int count_cstub_len = 0;
86 int count_nstub_len = 0;
87
88 ********************/
89
90
91 /************************ die Datentypen f"ur den Compiler *******************/ 
92
93 #include "comp/defines.c"
94
95
96
97 /******************* globale Variablen fuer den Compiler *********************/
98
99 static methodinfo *method;      /* Zeiger auf die Methodenstruktur */
100 static unicode   *descriptor;   /* Typbeschreibung der Methode */
101 static classinfo *class;        /* Klasse, in der die Methode steht */
102         
103 static s4 maxstack;             /* maximale Gr"osse des JavaVM-Stacks */
104 static s4 maxlocals;            /* maximale Anzahl der JavaVM-Variablen */
105 static u4 jcodelength;          /* L"ange des JavaVM-Codes */
106 static u1 *jcode;               /* Zeiger auf den JavaVM-Code */
107 static s4 exceptiontablelength; /* L"ange der Exceptiontable */
108 static exceptiontable *extable; /* Zeiger auf die Exceptiontable */
109
110
111 static list reachedblocks;      /* Die Listenstruktur f"ur alle vom Parser 
112                                    bereits irgendwie erreichten Bl"ocke */
113 static list finishedblocks;     /* Die Listenstruktur f"ur alle Bl"ocke, die
114                                    vom Parser bereits durchgearbeitet wurden */
115
116 static basicblock **blocks;     /* Eine Tabelle, so lang wie der JavaVM-Code, */
117                                 /* in der an jeder Stelle, an der ein */
118                                 /* Basicblock beginnt, der Zeiger auf die */
119                                 /* ensprechende Basicblock-Struktur einge- */
120                                 /* tragen ist. */
121
122 static bool isleafmethod;       /* true, wenn die Methode KEINE weiteren 
123                                    Unterprogramme mehr aufruft */
124
125 static s4        mparamnum;     /* Die Anzahl der Parameter (incl. this) */
126 static u1       *mparamtypes;   /* Die Typen aller Parameter (TYPE_INT,...) */
127 static s4        mreturntype;   /* R"uckgabewert der Methode */
128 static varinfo **mparamvars;    /* Die PCMD-Variablen, die die Parameter */
129                                 /*   zu Methodenstart enthalten sollen */
130
131
132 static chain *uninitializedclasses;  
133                                 /* Eine Tabelle aller von der Methode */
134                                 /* irgendwie ben"otigten Klassen, die */
135                                 /* vor dem Start der Methode initialisiert */
136                                 /* werden m"ussen (wenn sie es noch nicht */
137                                 /* sind) */
138                                 
139
140 /************************ Subsysteme des Compilers ***************************/
141
142
143 #include "comp/tools.c"    /* ein paar n"utzliche Hilfsfunktionen */
144 #include "comp/mcode.c"    /* systemUNabh"angiger Teil des Codegenerators */
145
146 #include "comp/reg.c"      /* Registerverwaltung */
147 #include "comp/var.c"      /* Die Verwaltung der PCMD-Variblen */
148 #include "comp/pcmd.c"     /* Funktionen f"ur die Pseudocommandos (=PCMD) */
149 #include "comp/local.c"    /* Verwaltung der lokalen JavaVM-Variablen */
150 #include "comp/stack.c"    /* Verwaltung des JavaVM-Stacks */
151 #include "comp/regalloc.c" /* Registerallokator */
152
153 #include "sysdep/gen.c"    /* systemABh"angiger Codegenerator */
154 #include "sysdep/disass.c" /* Disassembler (nur zu Debug-Zwecken) */ 
155
156 #include "comp/block.c"    /* Verwaltung der basic blocks */ 
157 #include "comp/parse.c"    /* JavaVM - parser */
158
159
160
161
162 /****** Die Dummy-Function (wird verwendet, wenn kein Code vorhanden ist) ****/
163
164 static void* do_nothing_function() 
165 {
166         return NULL;
167 }
168
169
170
171
172 /******************************************************************************/
173 /*********************** eine Methode compilieren *****************************/
174 /******************************************************************************/
175
176
177 methodptr compiler_compile (methodinfo *m)
178 {
179         u4 i;
180         basicblock *b;
181         long int starttime=0,stoptime=0;
182         long int dumpsize;
183         
184         if (newcompiler) {
185                 return new_compile(m);
186                 }
187
188         /*** Wenn schon ein Maschinencode vorliegt, dann sofort beenden ****/
189
190         count_jit_calls++;             /* andi   */
191         if (m->entrypoint) return m->entrypoint;
192
193         intsDisable();                 /* schani */
194         
195
196         /**************** Marke fuer den DUMP-Speicher aufheben *****************/
197
198         dumpsize = dump_size ();
199
200
201         /**************** Zeit messen *******************************************/
202
203         count_methods++;             /* andi   */
204         if (getcompilingtime) starttime=getcputime();
205
206         /*** Meldung ausgeben. Wenn kein JavaVM-Code vorhanden ist, beenden ****/
207
208         if (m->jcode) {
209                 if (compileverbose) {
210                         sprintf (logtext, "Compiling: ");
211                         unicode_sprint (logtext+strlen(logtext), m->class->name);
212                         strcpy (logtext+strlen(logtext), ".");
213                         unicode_sprint (logtext+strlen(logtext), m->name);
214                         unicode_sprint (logtext+strlen(logtext), m->descriptor);
215                         dolog ();
216                         }
217                 }
218         else {
219                 sprintf (logtext, "No code given for: ");
220                 unicode_sprint (logtext+strlen(logtext), m->class->name);
221                 strcpy (logtext+strlen(logtext), ".");
222                 unicode_sprint (logtext+strlen(logtext), m->name);
223                 unicode_sprint (logtext+strlen(logtext), m->descriptor);
224                 dolog ();
225                 intsRestore();           /* schani */
226                 return (methodptr) do_nothing_function;
227                 }
228
229
230         /*********** Initialisieren der Variablen und Subsysteme *****************/
231
232         isleafmethod = true;              /* bis sich das Gegenteil herausstellt */
233
234         method = m;
235         descriptor = m->descriptor;
236         class = m->class;
237         
238         maxstack = m->maxstack;
239         maxlocals = m->maxlocals;
240         jcodelength = m->jcodelength;
241         jcode = m->jcode;
242         count_tryblocks += (exceptiontablelength = m->exceptiontablelength);
243         extable = m->exceptiontable;
244
245 #ifdef STATISTICS
246         count_javacodesize += jcodelength + 18;
247         count_javaexcsize += exceptiontablelength * 8;
248 #endif
249
250         list_init (&reachedblocks,   OFFSET(basicblock, linkage) );
251         list_init (&finishedblocks,  OFFSET(basicblock, linkage) );
252
253         blocks = DMNEW (basicblock*, jcodelength);
254         for (i=0; i<jcodelength; i++) blocks[i] = NULL;
255
256
257         descriptor2types (descriptor, (m->flags & ACC_STATIC) != 0,
258                           &mparamnum, &mparamtypes, &mreturntype);
259         m->paramcount = mparamnum;
260         m->returntype = mreturntype;
261         mparamvars = DMNEW (varid, mparamnum);
262
263         reg_init ();
264         mcode_init ();
265         var_init();
266         local_init();
267
268         uninitializedclasses = chain_new(); 
269                 /* aktuelle Klasse zur Liste der m"oglicherweise zu 
270                    initialisierenden Klassen dazugeben */
271         compiler_addinitclass (m->class);
272
273
274         /************************ Compilieren  ************************/
275         
276             /* Fuer jedes Sprungziel einen eigenen Block erzeugen */
277         block_firstscann ();
278
279                         /* Den ersten Block als erreicht markieren, der Stack ist leer */
280         stack_init();
281         subroutine_set(NULL);
282         block_reach ( block_find(0) );
283         
284                         /* Alle schon erreichten Bl"ocke durchgehen und fertig machen */
285         while ( (b = list_first (&reachedblocks)) ) {
286                 list_remove (&reachedblocks, b);
287                 list_addlast (&finishedblocks, b);
288                 b -> finished = true;
289
290                 pcmd_init ( &(b->pcmdlist) );
291                 parse (b);
292                 }
293         
294         input_args_prealloc ();
295
296                         /* F"ur alle Bl"ocke die Registerbelegung durchfuehren */
297         b = list_first (&finishedblocks);
298         while (b) {
299                 regalloc (b);
300                 b = list_next (&finishedblocks, b);
301                 }
302
303
304                     /* Registerbelegung fuer die lokalen JAVA-Variablen */
305         local_regalloc ();
306
307         
308
309         
310         /**************** Maschinencode generieren **********************/
311
312         gen_computestackframe ();
313         gen_header ();
314
315
316         for (i=0; i<jcodelength; i++) {
317                 b = blocks[i];
318                 if (b) if (b->reached) block_genmcode (b);
319                 }
320         
321         b = list_first (&finishedblocks);
322         while (b) {
323                 if (b->type != BLOCKTYPE_JAVA) block_genmcode (b);
324                 b = list_next (&finishedblocks, b);
325                 }
326
327         
328         mcode_finish ();
329
330         
331         /*********** Zwischendarstellungen auf Wunsch ausgeben **********/
332                 
333         if (showintermediate) {
334                 printf ("Leaf-method: %s\n", isleafmethod ? "YES":"NO");
335                 printf ("Parameters: ");
336                 for (i=0; i<mparamnum; i++) var_display (mparamvars[i]);
337                 printf ("\n");
338                 printf ("Max locals: %d\n", (int) maxlocals);
339                 printf ("Max stack:  %d\n", (int) maxstack);
340
341                 for (i=0; i<jcodelength; i++) {
342                         b = blocks[i];
343                         if (b) if (b->reached) block_display (b);
344                         }
345                 b = list_first (&finishedblocks);
346                 while (b) {
347                         if (b->type != BLOCKTYPE_JAVA) block_display (b);
348                         b = list_next (&finishedblocks, b);
349                         }
350                         
351                 var_displayall();
352                 fflush (stdout);
353                 }
354
355         if (showdisassemble) {
356                 dseg_display ();
357                 disassemble ( (void*) (m->mcode + dseglen), mcodelen);
358                 fflush (stdout);
359                 }
360
361
362
363         /***************** Dump-Speicher zurueckgeben *************/
364
365         dump_release (dumpsize);
366
367
368         /******************* Zeit messen **************************/
369         
370         if (getcompilingtime) {
371                 stoptime = getcputime();
372                 compilingtime += (stoptime-starttime); 
373                 }
374
375         /******** Alle Klassen initialisieren, die gebraucht wurden *******/
376
377         {
378                 chain *u = uninitializedclasses;    /* wegen reentrant-F"ahigkeit */ 
379                 classinfo *c;                       /* d"urfen ab hier keine */
380                                                     /* globalen Variablen verwendet */
381                 while ( (c = chain_first(u)) ) {    /* werden */
382                         chain_remove (u);
383                         
384                         class_init (c);                         /* ruft unter Umst"anden wieder */
385                                                         /* den Compiler auf */
386                         }
387                 chain_free (u);
388         }
389
390         intsRestore();                   /* schani */
391
392
393
394         /****** Return pointer to the methods entry point **********/
395                 
396         return m -> entrypoint;
397
398 }
399
400
401
402 /***************** Funktionen zum Initialisieren und Terminieren *************/
403
404 void compiler_init ()
405 {
406         u4 i;
407
408         has_ext_instr_set = ! has_no_x_instr_set();
409
410         for (i=0; i<256;i++) stdopdescriptors[i]=NULL;
411
412         for (i=0; i<sizeof(stdopdescriptortable)/sizeof(stdopdescriptor); i++) {
413                 
414                 if (stdopdescriptortable[i].isfloat && checkfloats) {
415                         stdopdescriptortable[i].supported = false;
416                         }
417
418                 stdopdescriptors[stdopdescriptortable[i].opcode] = 
419                    &(stdopdescriptortable[i]);
420                 }
421 }
422
423
424 void compiler_close()
425 {
426         reg_close ();
427         mcode_close();
428 }
429