*** empty log message ***
[cacao.git] / tables.c
1 /* -*- mode: c; tab-width: 4; c-basic-offset: 4 -*- */
2 /****************************** tables.c ***************************************
3
4         Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst
5
6         See file COPYRIGHT for information on usage and disclaimer of warranties
7
8         Enth"alt Supportfunktionen f"ur:
9                 - Lesen von JavaClass-Files
10             - unicode-Symbole
11                 - den Heap 
12                 - zus"atzliche Support-Funktionen
13
14         Authors: Reinhard Grafl      EMAIL: cacao@complang.tuwien.ac.at
15         Changes: Mark Probst         EMAIL: cacao@complang.tuwien.ac.at
16                  Andreas  Krall      EMAIL: cacao@complang.tuwien.ac.at
17
18         Last Change: 1998/03/24
19
20 *******************************************************************************/
21
22 #include <assert.h>
23 #include <sys/mman.h>
24 #include <unistd.h>
25 #include "global.h"
26 #include "tables.h"
27 #include "asmpart.h"
28 #include "callargs.h"
29
30 #include "threads/thread.h"                  /* schani */
31 #include "threads/locks.h"
32
33
34 bool runverbose = false;
35
36 int count_unicode_len = 0;
37
38
39 /******************************************************************************
40 ************************* Der Dateien-Sauger **********************************
41 *******************************************************************************
42
43         dient zum Behandeln von Java-ClassFiles ("offnen, schlie"sen, 
44         einlesen von 8-, 16-, 32-, 64-bit Integers und 32-, 64- bit Floats)
45
46 ******************************************************************************/
47
48 static FILE *classfile = NULL;   /* File-handle der gerade gelesenen Datei */
49 static char *classpath = "";     /* Suchpfad f"ur die ClassFiles */
50
51
52
53 /************************** Funktion: suck_init ******************************
54
55         Wird zu Programmstart einmal aufgerufen und setzt den Suchpfad f"ur
56         Klassenfiles
57
58 ******************************************************************************/
59
60 void suck_init (char *cpath)
61 {
62         classfile = NULL;
63         classpath = cpath;
64 }
65
66
67 /************************** Funktion: suck_start ******************************
68
69         "Offnet die Datei f"ur die Klasse des gegebenen Namens zum Lesen.
70         Dabei werden alle im Suchpfad angegebenen Verzeichnisse durchsucht,
71         bis eine entsprechende Datei  ( <classname>.class) gefunden wird. 
72         
73 ******************************************************************************/
74
75 bool suck_start (unicode *classname)
76 {
77 #define MAXFILENAME 1000           /* Maximale Langes des Dateinamens plus Pfad */
78
79         char filename[MAXFILENAME+10];   /* Platz fuer '.class' */
80         u2 filenamelen;
81         char *pathpos;
82         u2 i,c;
83
84
85         pathpos = classpath;
86
87         while (*pathpos) {
88                 while ( *pathpos == ':' ) pathpos++;
89  
90                 filenamelen=0;
91                 while ( (*pathpos) && (*pathpos!=':') ) {
92                     PANICIF (filenamelen >= MAXFILENAME, "Filename too long") ;
93                         
94                         filename[filenamelen++] = *(pathpos++);
95                         }
96
97                 filename[filenamelen++] = '/';
98    
99                 for (i=0; i < classname -> length; i++) {
100                         PANICIF (filenamelen >= MAXFILENAME, "Filename too long");
101                         
102                         c = classname -> text [i];
103                         if (c=='/') c = '/';     /* Slashes im Namen passen zu UNIX */
104                         else {
105                                 if ( c<=' ' || c>'z') {
106                                         c = '?';
107                                         }
108                                 }
109                         
110                         filename[filenamelen++] = c;    
111                         }
112       
113                 strcpy (filename+filenamelen, ".class");
114
115                 classfile = fopen(filename, "r");
116                 if (classfile) {
117                         return true;
118                         }
119
120                 
121                 }
122                    
123         sprintf (logtext,"Can not open class file '%s'", filename);
124         error();
125         return false;
126 }
127
128
129 /************************** Funktion: suck_stop *******************************
130
131         Schlie"st die offene Datei wieder.
132         
133 ******************************************************************************/
134
135 void suck_stop ()
136 {
137         u4 rest=0;
138         u1 dummy;
139         
140         while ( fread (&dummy, 1,1, classfile) > 0) rest++;
141         if (rest) {
142                 sprintf (logtext,"There are %d access bytes at end of classfile",
143                                  (int) rest);
144                 dolog();
145                 }
146                         
147         fclose (classfile);
148         classfile = NULL;
149 }
150       
151
152
153 /************************** Lesefunktionen ***********************************
154
155         Lesen von der Datei in verschieden grossen Paketen
156         (8,16,32,64-bit Integer oder Float)
157
158 *****************************************************************************/
159
160 void suck_nbytes (u1 *buffer, u4 len)
161 {
162         if ( fread (buffer, 1, len, classfile) != len) panic ("Unexpected EOF");
163 }
164
165
166 void skip_nbytes (u4 len)
167 {
168         u4 i;
169         for (i=0; i<len; i++) suck_u1 ();
170 }
171
172
173 u1 suck_u1 ()
174 {
175         u1 b;
176         if ( fread (&b, 1,1, classfile) != 1) panic ("Unexpected EOF");
177         return b;
178 }
179
180 s1 suck_s1 ()
181 {
182         s1 b;
183         if ( fread (&b, 1,1, classfile) != 1) panic ("Unexpected EOF");
184         return b;
185 }
186
187
188 u2 suck_u2 ()
189 {
190         u1 b[2];
191         if ( fread (b, 1,2, classfile) != 2) panic ("Unexpected EOF");
192         return (b[0]<<8) + b[1];
193 }
194
195 s2 suck_s2 ()
196 {
197         return suck_u2 ();
198 }
199
200
201 u4 suck_u4 ()
202 {
203         u1 b[4];
204         u4 v;
205         if ( fread (b, 1,4, classfile) != 4) panic ("Unexpected EOF");
206         v = ( ((u4)b[0]) <<24) + ( ((u4)b[1])<<16) + ( ((u4)b[2])<<8) + ((u4)b[3]);
207         return v;
208 }
209
210 s4 suck_s4 ()
211 {
212         s4 v = suck_u4 ();
213         return v;
214 }
215
216 u8 suck_u8 ()
217 {
218 #if U8_AVAILABLE
219         u8 lo,hi;
220         hi = suck_u4();
221         lo = suck_u4();
222         return (hi<<32) + lo;
223 #else
224         u8 v;
225         v.high = suck_u4();
226         v.low = suck_u4();
227         return v;
228 #endif
229 }
230
231 s8 suck_s8 ()
232 {
233         return suck_u8 ();
234 }
235         
236
237 float suck_float ()
238 {
239         float f;
240
241 #if !WORDS_BIGENDIAN 
242                 u1 buffer[4];
243                 u2 i;
244                 for (i=0; i<4; i++) buffer[3-i] = suck_u1 ();
245                 memcpy ( (u1*) (&f), buffer, 4);
246 #else 
247                 suck_nbytes ( (u1*) (&f), 4 );
248 #endif
249
250         PANICIF (sizeof(float) != 4, "Incompatible float-format");
251         
252         return f;
253 }
254
255
256 double suck_double ()
257 {
258         double d;
259
260 #if !WORDS_BIGENDIAN 
261                 u1 buffer[8];
262                 u2 i;   
263                 for (i=0; i<8; i++) buffer[7-i] = suck_u1 ();
264                 memcpy ( (u1*) (&d), buffer, 8);
265 #else 
266                 suck_nbytes ( (u1*) (&d), 8 );
267 #endif
268
269         PANICIF (sizeof(double) != 8, "Incompatible double-format" );
270         
271         return d;
272 }
273
274
275
276
277 /******************************************************************************
278 ******************** Der Unicode-Symbol-Verwalter *****************************
279 *******************************************************************************
280
281         legt eine Hashtabelle f"ur unicode-Symbole an und verwaltet
282         das Eintragen neuer Symbole
283         
284 ******************************************************************************/
285
286
287
288 #define UNICODESTART  2187      /* Startgr"osse: moeglichst gross und prim */
289
290 static u4 unicodeentries;       /* Anzahl der Eintr"age in der Tabelle */
291 static u4 unicodehashsize;      /* Gr"osse der Tabelle */
292 static unicode ** unicodehash;  /* Zeiger auf die Tabelle selbst */
293
294
295 /*********************** Funktion: unicode_init ******************************
296
297         Initialisiert die unicode-Symboltabelle (muss zu Systemstart einmal
298         aufgerufen werden)
299         
300 *****************************************************************************/
301
302 void unicode_init ()
303 {
304         u4 i;
305         
306 #ifdef STATISTICS
307         count_unicode_len += sizeof(unicode*) * unicodehashsize;
308 #endif
309
310         unicodeentries = 0;
311         unicodehashsize = UNICODESTART;
312         unicodehash = MNEW (unicode*, unicodehashsize);
313         for (i=0; i<unicodehashsize; i++) unicodehash[i] = NULL;
314 }
315
316
317 /*********************** Funktion: unicode_close *****************************
318
319         Gibt allen Speicher der Symboltabellen frei.
320         Parameter: Ein Zeiger auf eine Funktion, die dazu n"otig ist, 
321                    Stringkonstanten (die mit 'unicode_setstringlink' 
322                    Unicode-Symbole gebunden wurden) wieder freizugeben
323         
324 *****************************************************************************/
325
326 void unicode_close (stringdeleter del)
327 {
328         unicode *u;
329         u4 i;
330         
331         for (i=0; i<unicodehashsize; i++) {
332                 u = unicodehash[i];
333                 while (u) {
334                         unicode *nextu = u->hashlink;
335
336                         if (u->string) del (u->string);
337                         
338                         MFREE (u->text, u2, u->length);
339                         FREE (u, unicode);
340                         u = nextu;
341                         }       
342                 }
343         MFREE (unicodehash, unicode*, unicodehashsize);
344 }
345
346
347 /********************* Funktion: unicode_display ******************************
348         
349         Gibt ein unicode-Symbol auf stdout aus (zu Debugzwecken)
350
351 ******************************************************************************/
352
353 void unicode_display (unicode *u)
354 {
355         u2 i,c;
356         for (i=0; i < u->length; i++) {
357                 c = u->text[i];
358                 if (c>=32 && c<=127) printf ("%c",c);
359                                 else printf ("?");
360                 }
361         fflush (stdout);
362 }
363
364
365 /********************* Funktion: unicode_sprint ******************************
366         
367         Schreibt ein unicode-Symbol in einen C-String
368
369 ******************************************************************************/ 
370
371 void unicode_sprint (char *buffer, unicode *u)
372 {
373         u2 i;
374         for (i=0; i < u->length; i++) buffer[i] = u->text[i];
375         buffer[i] = '\0';
376 }
377
378
379 /********************* Funktion: unicode_fprint ******************************
380         
381         Schreibt ein unicode-Symbol auf eine Datei aus
382
383 ******************************************************************************/ 
384
385 void unicode_fprint (FILE *file, unicode *u)
386 {
387         u2 i;
388         for (i=0; i < u->length; i++) putc (u->text[i], file);
389
390
391
392 /****************** interne Funktion: u_hashkey ******************************/
393
394 static u4 u_hashkey (u2 *text, u2 length)
395 {
396         u4 k = 0;
397         u2 i,sh=0;
398         
399         for (i=0; i<length; i++) {
400                 k ^=  ( ((u4) (text[i])) << sh );
401                 if (sh<16) sh++;
402                      else  sh=0;
403                 }
404                 
405         return k;
406 }
407
408 /*************** interne Funktion: u_reorganizehash **************************/
409
410 static void u_reorganizehash ()
411 {
412         u4 i;
413         unicode *u;
414
415         u4 newhashsize = unicodehashsize*2;
416         unicode **newhash = MNEW (unicode*, newhashsize);
417
418 #ifdef STATISTICS
419         count_unicode_len += sizeof(unicode*) * unicodehashsize;
420 #endif
421
422         for (i=0; i<newhashsize; i++) newhash[i] = NULL;
423
424         for (i=0; i<unicodehashsize; i++) {
425                 u = unicodehash[i];
426                 while (u) {
427                         unicode *nextu = u -> hashlink;
428                         u4 slot = (u->key) % newhashsize;
429                                                 
430                         u->hashlink = newhash[slot];
431                         newhash[slot] = u;
432
433                         u = nextu;
434                         }
435                 }
436         
437         MFREE (unicodehash, unicode*, unicodehashsize);
438         unicodehash = newhash;
439         unicodehashsize = newhashsize;
440 }
441
442
443 /****************** Funktion: unicode_new_u2 **********************************
444
445         Legt ein neues unicode-Symbol an. Der Text des Symbols wird dieser
446         Funktion als u2-Array "ubergeben
447
448 ******************************************************************************/
449
450 unicode *unicode_new_u2 (u2 *text, u2 length)
451 {
452         u4 key = u_hashkey (text, length);
453         u4 slot = key % unicodehashsize;
454         unicode *u = unicodehash[slot];
455         u2 i;
456
457         while (u) {
458                 if (u->key == key) {
459                         if (u->length == length) {
460                                 for (i=0; i<length; i++) {
461                                         if (text[i] != u->text[i]) goto nomatch;
462                                         }       
463                                         return u;
464                                 }
465                         }
466                 nomatch:
467                 u = u->hashlink;
468                 }
469
470 #ifdef STATISTICS
471         count_unicode_len += sizeof(unicode) + 2 * length;
472 #endif
473
474         u = NEW (unicode);
475         u->key = key;
476         u->length = length;
477         u->text = MNEW (u2, length);
478         u->class = NULL;
479         u->string = NULL;
480         u->hashlink = unicodehash[slot];
481         unicodehash[slot] = u;
482         for (i=0; i<length; i++) u->text[i] = text[i];
483
484         unicodeentries++;
485         
486         if ( unicodeentries > (unicodehashsize/2)) u_reorganizehash();
487         
488         return u;
489 }
490
491
492 /********************* Funktion: unicode_new_char *****************************
493
494         Legt ein neues unicode-Symbol an. Der Text des Symbols wird dieser
495         Funktion als C-String ( = char* ) "ubergeben
496
497 ******************************************************************************/
498
499 unicode *unicode_new_char (char *text)
500 {
501 #define MAXNEWCHAR 500
502         u2 buffer[MAXNEWCHAR];
503         u2 length = 0;
504         u1 c;
505         
506         while ( (c = *text) != '\0' ) {
507                 if (length>=MAXNEWCHAR) panic ("Text too long in unicode_new_char");
508                 buffer[length++] = c;
509                 text ++;
510                 }
511         return unicode_new_u2 (buffer, length);
512 }
513
514
515 /********************** Funktion: unicode_setclasslink ************************
516
517         H"angt einen Verweis auf eine Klasse an ein unicode-Symbol an.
518
519 ******************************************************************************/
520
521 void unicode_setclasslink (unicode *u, classinfo *class)
522 {
523         PANICIF (u->class, "Attempt to attach class to already attached symbol");
524         u->class = class;
525 }
526
527 /********************** Funktion: unicode_getclasslink ************************
528
529         Sucht den Verweis von einem unicode-Symbol auf eine Klasse.
530         Wenn keine solche Klasse existiert, dann wird ein Fehler
531         ausgegeben.
532
533 ******************************************************************************/
534
535 classinfo *unicode_getclasslink (unicode *u)
536 {
537         PANICIF (!u->class, "Attempt to get unknown class-reference");
538         return u->class;
539 }
540
541
542
543 /********************* Funktion: unicode_unlinkclass *************************
544
545         Entfernt den Verweis auf eine Klasse wieder von einem Symbol
546         
547 ******************************************************************************/
548
549 void unicode_unlinkclass (unicode *u)
550 {
551         PANICIF (!u->class, "Attempt to unlink not yet linked symbol");
552         u -> class = NULL;
553 }
554
555
556
557 /******************* Funktion> unicode_setstringlink *********************
558
559         H"angt einen Verweis auf einen konstanten String an ein 
560         Unicode-Symbol
561         
562 *************************************************************************/
563
564 void unicode_setstringlink (unicode *u, java_objectheader *str)
565 {
566         PANICIF (u->string, "Attempt to attach string to already attached symbol");
567         u->string = str;
568 }
569
570
571 /********************* Funktion: unicode_unlinkstring *************************
572
573         Entfernt den Verweis auf einen String wieder von einem Symbol
574         
575 ******************************************************************************/
576
577 void unicode_unlinkstring (unicode *u)
578 {
579         PANICIF (!u->class, "Attempt to unlink not yet linked symbol");
580         u -> string = NULL;
581 }
582
583
584
585 /*********************** Funktion: unicode_show ******************************
586
587         gibt eine Aufstellung aller Symbol im unicode-hash auf stdout aus.
588         (nur f"ur Debug-Zwecke)
589         
590 *****************************************************************************/
591
592 void unicode_show ()
593 {
594         unicode *u;
595         u4 i;
596
597         printf ("UNICODE-HASH: %d slots for %d entries\n", 
598                  (int) unicodehashsize, (int) unicodeentries );
599                   
600         for (i=0; i<unicodehashsize; i++) {
601                 u = unicodehash[i];
602                 if (u) {
603                         printf ("SLOT %d: ", (int) i);
604                         while (u) {
605                                 printf ("'");
606                                 unicode_display (u);
607                                 printf ("' ");
608                                 if (u->string) printf ("(string)  ");
609                                 u = u->hashlink;
610                                 }       
611                         printf ("\n");
612                         }
613                 
614                 }
615 }
616
617
618
619 /******************************************************************************
620 *********************** Diverse Support-Funktionen ****************************
621 ******************************************************************************/
622
623
624 /******************** Funktion: desc_to_type **********************************
625
626         Findet zu einem gegebenen Typdescriptor den entsprechenden 
627         Java-Grunddatentyp.
628         
629 ******************************************************************************/
630
631 u2 desc_to_type (unicode *descriptor)
632 {
633         if (descriptor->length < 1) panic ("Type-Descriptor is empty string");
634         
635         switch (descriptor->text[0]) {
636         case 'B': 
637         case 'C':
638         case 'I':
639         case 'S':  
640         case 'Z':  return TYPE_INT;
641         case 'D':  return TYPE_DOUBLE;
642         case 'F':  return TYPE_FLOAT;
643         case 'J':  return TYPE_LONG;
644         case 'L':
645         case '[':  return TYPE_ADDRESS;
646         }
647                         
648         sprintf (logtext, "Invalid Type-Descriptor: "); 
649         unicode_sprint (logtext+strlen(logtext), descriptor);
650         error (); 
651         return 0;
652 }
653
654
655 /********************** Funktion: desc_typesize *******************************
656
657         Berechnet die L"ange (in Byte) eines Datenelements gegebenen Typs,
658         der durch den Typdescriptor gegeben ist.
659         
660 ******************************************************************************/
661
662 u2 desc_typesize (unicode *descriptor)
663 {
664         switch (desc_to_type(descriptor)) {
665         case TYPE_INT:     return 4;
666         case TYPE_LONG:    return 8;
667         case TYPE_FLOAT:   return 4;
668         case TYPE_DOUBLE:  return 8;
669         case TYPE_ADDRESS: return sizeof(voidptr);
670         default:           return 0;
671         }
672 }
673
674
675
676