Fixed a bug in threads that occured when switching from a thread
[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         Contains support functions for:
9                 - Reading of Java class files
10                 - Unicode symbols
11                 - the heap
12                 - additional support functions
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/types.h>
24 #include <sys/mman.h>
25 #include <unistd.h>
26 #include "global.h"
27 #include "tables.h"
28 #include "asmpart.h"
29 #include "callargs.h"
30
31 #include "threads/thread.h"                  /* schani */
32 #include "threads/locks.h"
33
34 bool runverbose = false;
35
36 /* statistics */
37 int count_utf_len = 0;         /* size of utf hash                  */
38 int count_utf_new = 0;         /* calls of utf_new                  */
39 int count_utf_new_found  = 0;  /* calls of utf_new with fast return */
40
41 hashtable utf_hash;     /* hashtable for utf8-symbols */
42 hashtable string_hash;  /* hashtable for javastrings  */
43 hashtable class_hash;   /* hashtable for classes      */
44
45 /******************************************************************************
46  *********************** hashtable functions **********************************
47  ******************************************************************************/
48
49 /* hashsize must be power of 2 */
50
51 #define UTF_HASHSTART   16384   /* initial size of utf-hash */    
52 #define HASHSTART        2048   /* initial size of javastring and class-hash */
53
54
55 /******************** function: init_hashtable ******************************
56
57     Initializes a hashtable structure and allocates memory.
58     The parameter size specifies the initial size of the hashtable.
59         
60 *****************************************************************************/
61
62 void init_hashtable(hashtable *hash, u4 size)
63 {
64         u4 i;
65
66         hash->entries = 0;
67         hash->size    = size;
68         hash->ptr     = MNEW (void*, size);
69
70         /* clear table */
71         for (i=0; i<size; i++) hash->ptr[i] = NULL;
72 }
73
74 /*********************** function: tables_init  *****************************
75
76     creates hashtables for symboltables 
77         (called once at startup)                         
78         
79 *****************************************************************************/
80
81 void tables_init ()
82 {
83         init_hashtable(&utf_hash,    UTF_HASHSTART);  /* hashtable for utf8-symbols */
84         init_hashtable(&string_hash, HASHSTART);      /* hashtable for javastrings */
85         init_hashtable(&class_hash,  HASHSTART);      /* hashtable for classes */ 
86         
87 #ifdef STATISTICS
88         count_utf_len += sizeof(utf*) * utf_hash.size;
89 #endif
90
91 }
92
93 /********************** function: tables_close ******************************
94
95         free memory for hashtables                    
96         
97 *****************************************************************************/
98
99 void tables_close (stringdeleter del)
100 {
101         utf *u; 
102         literalstring *s;
103         u4 i;
104         
105         /* dispose utf symbols */
106         for (i=0; i<utf_hash.size; i++) {
107         u = utf_hash.ptr[i];
108                 while (u) {
109                         /* process elements in external hash chain */
110                         utf *nextu = u->hashlink;
111                         MFREE (u->text, u1, u->blength);
112                         FREE (u, utf);
113                         u = nextu;
114                         }       
115                 }
116
117         /* dispose javastrings */
118         for (i=0; i<string_hash.size; i++) {
119                 s = string_hash.ptr[i];
120                 while (u) {
121                         /* process elements in external hash chain */
122                         literalstring *nexts = s->hashlink;
123                         del(s->string);
124                         FREE(s, literalstring);
125                         s = nexts;
126                         }       
127                 }
128
129         /* dispose hashtable structures */
130         MFREE (utf_hash.ptr,    void*, utf_hash.size);
131         MFREE (string_hash.ptr, void*, string_hash.size);
132         MFREE (class_hash.ptr,  void*, class_hash.size);
133 }
134
135 /********************* function: utf_display *********************************
136
137         write utf symbol to stdout (debugging purposes)
138
139 ******************************************************************************/
140
141 void utf_display (utf *u)
142 {
143     char *endpos  = utf_end(u);  /* points behind utf string       */
144     char *utf_ptr = u->text;     /* current position in utf text   */
145
146     while (utf_ptr<endpos) {
147
148                 /* read next unicode character */                
149                 u2 c = utf_nextu2(&utf_ptr);                            
150                 if (c>=32 && c<=127) printf ("%c",c);
151                                 else printf ("?");
152         }
153
154         fflush (stdout);
155 }
156
157 /************************ function: utf_sprint *******************************
158         
159     write utf symbol into c-string (debugging purposes)                                          
160
161 ******************************************************************************/ 
162
163 void utf_sprint (char *buffer, utf *u)
164 {
165     char *endpos  = utf_end(u);  /* points behind utf string       */
166     char *utf_ptr = u->text;     /* current position in utf text   */ 
167     u2 pos = 0;                  /* position in c-string           */
168
169     while (utf_ptr<endpos) 
170                 /* copy next unicode character */       
171                 buffer[pos++] = utf_nextu2(&utf_ptr);
172
173     /* terminate string */
174     buffer[pos] = '\0';
175 }
176
177
178 /********************* Funktion: utf_fprint **********************************
179         
180     write utf symbol into file          
181
182 ******************************************************************************/ 
183
184 void utf_fprint (FILE *file, utf *u)
185 {
186     char *endpos  = utf_end(u);  /* points behind utf string       */
187     char *utf_ptr = u->text;     /* current position in utf text   */ 
188
189     while (utf_ptr<endpos) 
190                 /* write next unicode character */       
191                 putc ( utf_nextu2(&utf_ptr), file );
192
193
194
195 /****************** internal function: utf_hashkey ***************************
196
197         The hashkey is computed from the utf-text by using up to 8 characters.
198         For utf-symbols longer than 15 characters 3 characters are taken from
199         the beginning and the end, 2 characters are taken from the middle.
200
201 ******************************************************************************/ 
202
203 #define nbs(val) ((u4) *(++text) << val) /* get next byte, left shift by val  */
204 #define fbs(val) ((u4) *(  text) << val) /* get first byte, left shift by val */
205
206 static u4 utf_hashkey (char *text, u4 length)
207 {
208         char *start_pos = text; /* pointer to utf text */
209         u4 a;
210
211         switch (length) {               
212                 
213         case 0: /* empty string */
214                 return 0;
215
216         case 1: return fbs(0);
217         case 2: return fbs(0) ^ nbs(3);
218         case 3: return fbs(0) ^ nbs(3) ^ nbs(5);
219         case 4: return fbs(0) ^ nbs(2) ^ nbs(4) ^ nbs(6);
220         case 5: return fbs(0) ^ nbs(2) ^ nbs(3) ^ nbs(4) ^ nbs(6);
221         case 6: return fbs(0) ^ nbs(1) ^ nbs(2) ^ nbs(3) ^ nbs(5) ^ nbs(6);
222         case 7: return fbs(0) ^ nbs(1) ^ nbs(2) ^ nbs(3) ^ nbs(4) ^ nbs(5) ^ nbs(6);
223         case 8: return fbs(0) ^ nbs(1) ^ nbs(2) ^ nbs(3) ^ nbs(4) ^ nbs(5) ^ nbs(6) ^ nbs(7);
224
225         case 9: a = fbs(0) ^ nbs(1) ^ nbs(2);                
226                 text++; 
227                 return a ^ nbs(4) ^ nbs(5) ^ nbs(6) ^ nbs(7) ^ nbs(8);
228
229         case 10: a = fbs(0);
230                  text++;
231                  a^= nbs(2) ^ nbs(3) ^ nbs(4);
232                  text++;
233                  return a ^ nbs(6) ^ nbs(7) ^ nbs(8) ^ nbs(9);
234
235         case 11: a = fbs(0);
236                  text++;
237                  a^= nbs(2) ^ nbs(3) ^ nbs(4);
238                  text++;
239                  return a ^ nbs(6) ^ nbs(7) ^ nbs(8) ^ nbs(9) ^ nbs(10);
240
241         case 12: a = fbs(0);
242                  text+=2;
243                  a^= nbs(2) ^ nbs(3);
244                  text+=1;
245                  a^= nbs(5) ^ nbs(6) ^ nbs(7);
246                  text+=1;
247                  return a ^ nbs(9) ^ nbs(10);      
248
249         case 13: a = fbs(0) ^ nbs(1);
250                  text+=1;       
251                  a^= nbs(3) ^ nbs(4);
252                  text+=2;       
253                  a^= nbs(7) ^ nbs(8);
254                  text+=2;
255                  return a ^ nbs(9) ^ nbs(10);
256
257         case 14: a = fbs(0);
258                  text+=2;       
259                  a^= nbs(3) ^ nbs(4);
260                  text+=2;       
261                  a^= nbs(7) ^ nbs(8);
262                  text+=2;
263                  return a ^ nbs(9) ^ nbs(10) ^ nbs(11);
264
265         case 15: a = fbs(0);
266                  text+=2;       
267                  a^= nbs(3) ^ nbs(4);
268                  text+=2;       
269                  a^= nbs(7) ^ nbs(8);
270                  text+=2;
271                  return a ^ nbs(9) ^ nbs(10) ^ nbs(11);
272
273         default:  /* 3 characters from beginning */
274                   a = fbs(0);
275                   text+=2;
276                   a^= nbs(3) ^ nbs(4);
277
278                   /* 2 characters from middle */
279                   text = start_pos + (length / 2);
280                   a^= fbs(5);
281                   text+=2;
282                   a^= nbs(6);   
283
284                   /* 3 characters from end */
285                   text = start_pos + length - 4;
286
287                   a^= fbs(7);
288                   text+=1;
289
290                   return a ^ nbs(10) ^ nbs(11);
291     }
292 }
293
294
295 /*************************** function: utf_hashkey ***************************
296
297     compute the hashkey of a unicode string
298
299 ******************************************************************************/ 
300
301 u4 unicode_hashkey (u2 *text, u2 len)
302 {
303         return utf_hashkey((char*) text, len);
304 }
305
306 /************************ function: utf_new **********************************
307
308         Creates a new utf-symbol, the text of the symbol is passed as a 
309         u1-array. The function searches the utf-hashtable for a utf-symbol 
310         with this text. On success the element returned, otherwise a new 
311         hashtable element is created.
312
313         If the number of entries in the hashtable exceeds twice the size of the
314         hashtable slots a reorganization of the hashtable is done and the utf 
315         symbols are copied to a new hashtable with doubled size.
316
317 ******************************************************************************/
318
319 utf *utf_new (char *text, u2 length)
320 {
321         u4 key;            /* hashkey computed from utf-text */
322         u4 slot;           /* slot in hashtable */
323         utf *u;            /* hashtable element */
324         u2 i;
325         
326 #ifdef STATISTICS
327         count_utf_new++;
328 #endif
329
330         key  = utf_hashkey (text, length);
331         slot = key & (utf_hash.size-1);
332         u    = utf_hash.ptr[slot];
333
334         /* search external hash chain for utf-symbol */
335         while (u) {
336                 if (u->blength == length) {
337
338                         /* compare text of hashtable elements */
339                         for (i=0; i<length; i++)
340                                 if (text[i] != u->text[i]) goto nomatch;
341                         
342 #ifdef STATISTICS
343                         count_utf_new_found++;
344 #endif
345                         /* symbol found in hashtable */                                 
346                         return u;
347                 }
348                 nomatch:
349                 u = u->hashlink; /* next element in external chain */
350         }
351
352 #ifdef STATISTICS
353         count_utf_len += sizeof(utf) + length;
354 #endif
355
356         /* location in hashtable found, create new utf element */
357         u = NEW (utf);
358         u->blength  = length;             /* length in bytes of utfstring */
359         u->hashlink = utf_hash.ptr[slot]; /* link in external hashchain   */            
360         u->text     = mem_alloc(length);  /* allocate memory for utf-text */
361         memcpy(u->text,text,length);      /* copy utf-text                */
362         utf_hash.ptr[slot] = u;           /* insert symbol into table     */ 
363
364         utf_hash.entries++;               /* update number of entries     */
365
366         if ( utf_hash.entries > (utf_hash.size*2)) { 
367
368         /* reorganization of hashtable, average length of 
369            the external chains is approx. 2                */  
370
371           u4 i;
372           utf *u;
373           hashtable newhash; /* the new hashtable */
374
375           /* create new hashtable, double the size */
376           init_hashtable(&newhash, utf_hash.size*2);
377           newhash.entries=utf_hash.entries;
378
379 #ifdef STATISTICS
380           count_utf_len += sizeof(utf*) * utf_hash.size;
381 #endif
382
383           /* transfer elements to new hashtable */
384           for (i=0; i<utf_hash.size; i++) {
385                 u = (utf*) utf_hash.ptr[i];
386                 while (u) {
387                         utf *nextu = u -> hashlink;
388                         u4 slot = (utf_hashkey(u->text,u->blength)) & (newhash.size-1);
389                                                 
390                         u->hashlink = (utf*) newhash.ptr[slot];
391                         newhash.ptr[slot] = u;
392
393                         /* follow link in external hash chain */
394                         u = nextu;
395                         }
396                 }
397         
398           /* dispose old table */
399           MFREE (utf_hash.ptr, void*, utf_hash.size);
400           utf_hash = newhash;
401         }
402         
403         return u;
404 }
405
406
407 /********************* function: utf_new_char ********************************
408
409     creates a new utf symbol, the text for this symbol is passed
410     as a c-string ( = char* )
411
412 ******************************************************************************/
413
414 utf *utf_new_char (char *text)
415 {
416         return utf_new(text, strlen(text));
417 }
418
419 /************************** Funktion: utf_show ******************************
420
421     writes the utf symbols in the utfhash to stdout and
422     displays the number of external hash chains grouped 
423     according to the chainlength
424     (debugging purposes)
425
426 *****************************************************************************/
427
428 void utf_show ()
429 {
430
431 #define CHAIN_LIMIT 20               /* limit for seperated enumeration */
432
433         u4 chain_count[CHAIN_LIMIT]; /* numbers of chains */
434         u4 max_chainlength = 0;      /* maximum length of the chains */
435         u4 sum_chainlength = 0;      /* sum of the chainlengths */
436         u4 beyond_limit = 0;         /* number of utf-symbols in chains with length>=CHAIN_LIMIT-1 */
437         u4 i;
438
439         printf ("UTF-HASH:\n");
440
441         /* show element of utf-hashtable */
442         for (i=0; i<utf_hash.size; i++) {
443                 utf *u = utf_hash.ptr[i];
444                 if (u) {
445                         printf ("SLOT %d: ", (int) i);
446                         while (u) {
447                                 printf ("'");
448                                 utf_display (u);
449                                 printf ("' ");
450                                 u = u->hashlink;
451                                 }       
452                         printf ("\n");
453                         }
454                 
455                 }
456
457         printf ("UTF-HASH: %d slots for %d entries\n", 
458                  (int) utf_hash.size, (int) utf_hash.entries );
459
460
461         if (utf_hash.entries == 0)
462                 return;
463
464         printf("chains:\n  chainlength    number of chains    %% of utfstrings\n");
465
466         for (i=0;i<CHAIN_LIMIT;i++)
467                 chain_count[i]=0;
468
469         /* count numbers of hashchains according to their length */
470         for (i=0; i<utf_hash.size; i++) {
471                   
472                 utf *u = (utf*) utf_hash.ptr[i];
473                 u4 chain_length = 0;
474
475                 /* determine chainlength */
476                 while (u) {
477                         u = u->hashlink;
478                         chain_length++;
479                         }
480
481                 /* update sum of all chainlengths */
482                 sum_chainlength+=chain_length;
483
484                 /* determine the maximum length of the chains */
485                 if (chain_length>max_chainlength)
486                         max_chainlength = chain_length;
487
488                 /* update number of utf-symbols in chains with length>=CHAIN_LIMIT-1 */
489                 if (chain_length>=CHAIN_LIMIT) {
490                         beyond_limit+=chain_length;
491                         chain_length=CHAIN_LIMIT-1;
492                 }
493
494                 /* update number of hashchains of current length */
495                 chain_count[chain_length]++;
496                 }
497
498         /* display results */  
499         for (i=1;i<CHAIN_LIMIT-1;i++) 
500                 printf("       %2d %17d %18.2f%%\n",i,chain_count[i],(((float) chain_count[i]*i*100)/utf_hash.entries));
501           
502         printf("     >=%2d %17d %18.2f%%\n",CHAIN_LIMIT-1,chain_count[CHAIN_LIMIT-1],((float) beyond_limit*100)/utf_hash.entries);
503
504
505         printf("max. chainlength:%5d\n",max_chainlength);
506
507         /* avg. chainlength = sum of chainlengths / number of chains */
508         printf("avg. chainlength:%5.2f\n",(float) sum_chainlength / (utf_hash.size-chain_count[0]));
509 }
510
511 /******************************************************************************
512 *********************** Misc support functions ********************************
513 ******************************************************************************/
514
515
516 /******************** Function: desc_to_type **********************************
517    
518         Determines the corresponding Java base data type for a given type
519         descriptor.
520         
521 ******************************************************************************/
522
523 u2 desc_to_type (utf *descriptor)
524 {
525         char *utf_ptr = descriptor->text;  /* current position in utf text */
526
527         if (descriptor->blength < 1) panic ("Type-Descriptor is empty string");
528         
529         switch (*utf_ptr++) {
530         case 'B': 
531         case 'C':
532         case 'I':
533         case 'S':  
534         case 'Z':  return TYPE_INT;
535         case 'D':  return TYPE_DOUBLE;
536         case 'F':  return TYPE_FLOAT;
537         case 'J':  return TYPE_LONG;
538         case 'L':
539         case '[':  return TYPE_ADDRESS;
540         }
541                         
542         sprintf (logtext, "Invalid Type-Descriptor: "); 
543         utf_sprint (logtext+strlen(logtext), descriptor);
544         error (); 
545         return 0;
546 }
547
548
549 /********************** Function: desc_typesize *******************************
550
551         Calculates the lenght in bytes needed for a data element of the type given
552         by its type descriptor.
553         
554 ******************************************************************************/
555
556 u2 desc_typesize (utf *descriptor)
557 {
558         switch (desc_to_type(descriptor)) {
559         case TYPE_INT:     return 4;
560         case TYPE_LONG:    return 8;
561         case TYPE_FLOAT:   return 4;
562         case TYPE_DOUBLE:  return 8;
563         case TYPE_ADDRESS: return sizeof(voidptr);
564         default:           return 0;
565         }
566 }
567
568
569 /********************** function: utf_nextu2 *********************************
570
571     read the next unicode character from the utf string and
572     increment the utf-string pointer accordingly
573
574 ******************************************************************************/
575
576 u2 utf_nextu2(char **utf_ptr) 
577 {
578     /* uncompressed unicode character */
579     u2 unicode_char;    
580     /* current position in utf text */  
581     unsigned char *utf = (unsigned char *) (*utf_ptr);  
582     /* bytes representing the unicode character */
583     unsigned char ch1, ch2, ch3;
584     /* number of bytes used to represent the unicode character */
585     int len;            
586         
587     switch ((ch1 = utf[0]) >> 4) {
588       default: /* 1 byte */
589                (*utf_ptr)++;
590                return ch1;
591        case 0xC: 
592        case 0xD: /* 2 bytes */
593                  if (((ch2 = utf[1]) & 0xC0) == 0x80) {
594                    unsigned char high = ch1 & 0x1F;
595                    unsigned char low  = ch2 & 0x3F;
596                    unicode_char = (high << 6) + low;
597                    len = 2;
598                  } 
599                  break;
600
601        case 0xE: /* 2 or 3 bytes */
602                  if (((ch2 = utf[1]) & 0xC0) == 0x80) {
603                     if (((ch3 = utf[2]) & 0xC0) == 0x80) {
604                        unsigned char low  = ch3 & 0x3f;
605                        unsigned char mid  = ch2 & 0x3f;
606                        unsigned char high = ch1 & 0x0f;
607                        unicode_char = (((high << 6) + mid) << 6) + low;
608                        len = 3;
609                     } else
610                        len = 2;                                    
611                  }
612                  break;
613     }
614
615     /* update position in utf-text */
616     *utf_ptr = (char *) (utf + len);
617     return unicode_char;
618 }
619  
620 /******************** Function: class_new **************************************
621
622     searches for the class with the specified name in the classes hashtable,
623     if there is no such class a new classinfo structure is created and inserted
624     into the list of classes to be loaded
625
626 *******************************************************************************/
627
628 classinfo *class_new (utf *u)
629 {
630         classinfo *c;     /* hashtable element */ 
631         u4 key;           /* hashkey computed from classname */   
632         u4 slot;          /* slot in hashtable */
633         u2 i;
634
635         key  = utf_hashkey (u->text, u->blength);
636         slot = key & (class_hash.size-1);
637         c    = class_hash.ptr[slot];
638
639         /* search external hash chain for the class */
640         while (c) {
641                 if (c->name->blength == u->blength) {
642                         for (i=0; i<u->blength; i++) 
643                                 if (u->text[i] != c->name->text[i]) goto nomatch;
644                                                 
645                                 /* class found in hashtable */                                                                  
646                                 return c;
647                         }
648                         
649                 nomatch:
650                 c = c->hashlink; /* next element in external chain */
651                 }
652
653         /* location in hashtable found, create new classinfo structure */
654
655 #ifdef STATISTICS
656         count_class_infos += sizeof(classinfo);
657 #endif
658
659         c = NEW (classinfo);
660         c -> flags = 0;
661         c -> name = u;
662         c -> cpcount = 0;
663         c -> cptags = NULL;
664         c -> cpinfos = NULL;
665         c -> super = NULL;
666         c -> sub = NULL;
667         c -> nextsub = NULL;
668         c -> interfacescount = 0;
669         c -> interfaces = NULL;
670         c -> fieldscount = 0;
671         c -> fields = NULL;
672         c -> methodscount = 0;
673         c -> methods = NULL;
674         c -> linked = false;
675         c -> index = 0;
676         c -> instancesize = 0;
677         c -> header.vftbl = NULL;
678         c -> innerclasscount = 0;
679         c -> innerclass = NULL;
680         c -> vftbl = NULL;
681         c -> initialized = false;
682         c -> classvftbl = false;
683         
684         /* prepare loading of the class */
685         list_addlast (&unloadedclasses, c);
686
687         /* insert class into the hashtable */
688         c->hashlink = class_hash.ptr[slot];
689         class_hash.ptr[slot] = c;
690
691         /* update number of hashtable-entries */
692         class_hash.entries++;
693
694         if ( class_hash.entries > (class_hash.size*2)) {  
695
696           /* reorganization of hashtable, average length of 
697              the external chains is approx. 2                */  
698
699           u4 i;
700           classinfo *c;
701           hashtable newhash;  /* the new hashtable */
702
703           /* create new hashtable, double the size */
704           init_hashtable(&newhash, class_hash.size*2);
705           newhash.entries = class_hash.entries;
706
707           /* transfer elements to new hashtable */
708           for (i=0; i<class_hash.size; i++) {
709                 c = (classinfo*) class_hash.ptr[i];
710                 while (c) {
711                         classinfo *nextc = c -> hashlink;
712                         u4 slot = (utf_hashkey(c->name->text,c->name->blength)) & (newhash.size-1);
713                                                 
714                         c->hashlink = newhash.ptr[slot];
715                         newhash.ptr[slot] = c;
716
717                         c = nextc;
718                         }
719                 }
720         
721           /* dispose old table */       
722           MFREE (class_hash.ptr, void*, class_hash.size);
723           class_hash = newhash;
724         }
725                         
726         return c;
727 }
728
729 /******************** Function: class_get **************************************
730
731     searches for the class with the specified name in the classes hashtable
732     if there is no such class NULL is returned
733
734 *******************************************************************************/
735
736 classinfo *class_get (utf *u)
737 {
738         classinfo *c;  /* hashtable element */ 
739         u4 key;        /* hashkey computed from classname */   
740         u4 slot;       /* slot in hashtable */
741         u2 i;  
742
743         key  = utf_hashkey (u->text, u->blength);
744         slot = key & (class_hash.size-1);
745         c    = class_hash.ptr[slot];
746
747         /* search external hash-chain */
748         while (c) {
749                 if (c->name->blength == u->blength) {
750                         
751                         /* compare classnames */
752                         for (i=0; i<u->blength; i++) 
753                                 if (u->text[i] != c->name->text[i]) goto nomatch;
754
755                         /* class found in hashtable */                          
756                         return c;
757                         }
758                         
759                 nomatch:
760                 c = c->hashlink;
761                 }
762
763         /* class not found */
764         return NULL;
765 }
766
767
768 /************************** function: utf_strlen ******************************
769
770     determine number of unicode characters in the utf string
771
772 *******************************************************************************/
773
774 u4 utf_strlen(utf *u) 
775 {
776     char *endpos  = utf_end(u);  /* points behind utf string       */
777     char *utf_ptr = u->text;     /* current position in utf text   */
778     u4 len = 0;                  /* number of unicode characters   */
779
780     while (utf_ptr<endpos) {
781       len++;
782       /* next unicode character */
783       utf_nextu2(&utf_ptr);
784     }
785
786     if (utf_ptr!=endpos)
787         /* string ended abruptly */
788         panic("illegal utf string"); 
789
790     return len;
791 }
792
793
794
795
796
797
798
799  
800
801  
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817