* classcache_lookup_name, classcache_new_name: Speed up lookup in external
[cacao.git] / src / vm / classcache.c
1 /* src/vm/classcache.c - loaded class cache and loading constraints
2
3    Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
4    R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
5    C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
6    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., 59 Temple Place - Suite 330, Boston, MA
23    02111-1307, USA.
24
25    Contact: cacao@complang.tuwien.ac.at
26
27    Authors: Edwin Steiner
28
29    Changes: Christian Thalinger
30
31    $Id: classcache.c 3263 2005-09-21 20:18:03Z twisti $
32
33 */
34
35
36 #include <assert.h>
37
38 #include "mm/memory.h"
39 #include "vm/classcache.h"
40 #include "vm/exceptions.h"
41 #include "vm/stringlocal.h"
42 #include "vm/tables.h"
43 #include "vm/utf8.h"
44
45
46 /* initial number of slots in the classcache hash table */
47 #define CLASSCACHE_INIT_SIZE  2048
48
49 /*============================================================================*/
50 /* DEBUG HELPERS                                                              */
51 /*============================================================================*/
52
53 /*#define CLASSCACHE_VERBOSE*/
54
55 #ifndef NDEBUG
56 #define CLASSCACHE_DEBUG
57 #endif
58
59 #ifdef CLASSCACHE_DEBUG
60 #define CLASSCACHE_ASSERT(cond)  assert(cond)
61 #else
62 #define CLASSCACHE_ASSERT(cond)
63 #endif
64
65 /*============================================================================*/
66 /* THREAD-SAFE LOCKING                                                        */
67 /*============================================================================*/
68
69         /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
70         /* CAUTION: The static functions below are */
71         /*          NOT synchronized!              */
72         /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
73
74 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
75 #  define CLASSCACHE_LOCK()    tables_lock()
76 #  define CLASSCACHE_UNLOCK()  tables_unlock()
77 #else
78 #  define CLASSCACHE_LOCK()
79 #  define CLASSCACHE_UNLOCK()
80 #endif
81
82 /*============================================================================*/
83 /* GLOBAL VARIABLES                                                           */
84 /*============================================================================*/
85
86 hashtable classcache_hash;
87
88 /*============================================================================*/
89 /*                                                                            */
90 /*============================================================================*/
91
92 /* classcache_init *************************************************************
93  
94    Initialize the loaded class cache
95
96    Note: NOT synchronized!
97   
98 *******************************************************************************/
99
100 void
101 classcache_init(
102         )
103 {
104         init_hashtable(&classcache_hash, CLASSCACHE_INIT_SIZE);
105 }
106
107 /* classcache_new_loader_entry *************************************************
108  
109    Create a new classcache_loader_entry struct
110    (internally used helper function)
111   
112    IN:
113        loader...........the ClassLoader object
114            next.............the next classcache_loader_entry
115
116    RETURN VALUE:
117        the new classcache_loader_entry
118   
119 *******************************************************************************/
120
121 static classcache_loader_entry *
122 classcache_new_loader_entry(
123         /*@shared@*/ /*@null@*/ classloader * loader,
124         /*@only  @*/ /*@null@*/ classcache_loader_entry * next)
125 {
126         classcache_loader_entry *lden;
127
128         lden = NEW(classcache_loader_entry);
129         lden->loader = loader;
130         lden->next = next;
131
132         return lden;
133 }
134
135 /* classcache_merge_loaders ****************************************************
136  
137    Merge two lists of loaders into one
138    (internally used helper function)
139   
140    IN:
141        lista............first list (may be NULL)
142            listb............second list (may be NULL)
143
144    RETURN VALUE:
145        the merged list (may be NULL)
146
147    NOTE:
148        The lists given as arguments are destroyed!
149   
150 *******************************************************************************/
151
152 static /*@null@*/ classcache_loader_entry *
153 classcache_merge_loaders(
154         /*@null@*/ classcache_loader_entry * lista,
155         /*@null@*/ classcache_loader_entry * listb)
156 {
157         classcache_loader_entry *result;
158         classcache_loader_entry *ldenA;
159         classcache_loader_entry *ldenB;
160         classcache_loader_entry **chain;
161
162         /* XXX This is a quadratic algorithm. If this ever
163          * becomes a problem, the loader lists should be
164          * stored as sorted lists and merged in linear time. */
165
166         result = NULL;
167         chain = &result;
168
169         for (ldenA = lista; ldenA != NULL; ldenA = ldenA->next) {
170
171                 for (ldenB = listb; ldenB != NULL; ldenB = ldenB->next) {
172                         if (ldenB->loader == ldenA->loader)
173                                 goto common_element;
174                 }
175
176                 /* this loader is only in lista */
177                 *chain = ldenA;
178                 chain = &(ldenA->next);
179
180           common_element:
181                 /* XXX free the duplicated element */
182                 ;
183         }
184
185         /* concat listb to the result */
186         *chain = listb;
187
188         return result;
189 }
190
191
192 /* classcache_lookup_name ******************************************************
193  
194    Lookup a name in the first level of the cache
195    (internally used helper function)
196    
197    IN:
198        name.............the name to look up
199   
200    RETURN VALUE:
201        a pointer to the classcache_name_entry for this name, or
202        null if no entry was found.
203            
204 *******************************************************************************/
205
206 static classcache_name_entry *classcache_lookup_name(utf *name)
207 {
208         classcache_name_entry *c;           /* hash table element                 */
209         u4 key;                             /* hashkey computed from classname    */
210         u4 slot;                            /* slot in hashtable                  */
211 /*      u4 i; */
212
213         key  = utf_hashkey(name->text, (u4) name->blength);
214         slot = key & (classcache_hash.size - 1);
215         c    = classcache_hash.ptr[slot];
216
217         /* search external hash chain for the entry */
218
219         while (c) {
220                 /* entry found in hashtable */
221
222                 if (c->name == name)
223                         return c;
224
225                 c = c->hashlink;                    /* next element in external chain */
226         }
227
228         /* not found */
229
230         return NULL;
231 }
232
233
234 /* classcache_new_name *********************************************************
235  
236    Return a classcache_name_entry for the given name. The entry is created
237    if it is not already in the cache.
238    (internally used helper function)
239    
240    IN:
241        name.............the name to look up / create an entry for
242   
243    RETURN VALUE:
244        a pointer to the classcache_name_entry for this name
245            
246 *******************************************************************************/
247
248 static classcache_name_entry *classcache_new_name(utf *name)
249 {
250         classcache_name_entry *c;       /* hash table element */
251         u4 key;                                         /* hashkey computed from classname */
252         u4 slot;                                        /* slot in hashtable               */
253         u4 i;
254
255         key  = utf_hashkey(name->text, (u4) name->blength);
256         slot = key & (classcache_hash.size - 1);
257         c    = classcache_hash.ptr[slot];
258
259         /* search external hash chain for the entry */
260
261         while (c) {
262                 /* entry found in hashtable */
263
264                 if (c->name == name)
265                         return c;
266
267                 c = c->hashlink;                    /* next element in external chain */
268         }
269
270         /* location in hashtable found, create new entry */
271
272         c = NEW(classcache_name_entry);
273
274         c->name = name;
275         c->classes = NULL;
276
277         /* insert entry into hashtable */
278         c->hashlink = (classcache_name_entry *) classcache_hash.ptr[slot];
279         classcache_hash.ptr[slot] = c;
280
281         /* update number of hashtable-entries */
282         classcache_hash.entries++;
283
284         if (classcache_hash.entries > (classcache_hash.size * 2)) {
285
286                 /* reorganization of hashtable, average length of 
287                    the external chains is approx. 2                */
288
289                 classcache_name_entry *c2;
290                 hashtable newhash;              /* the new hashtable */
291
292                 /* create new hashtable, double the size */
293
294                 init_hashtable(&newhash, classcache_hash.size * 2);
295                 newhash.entries = classcache_hash.entries;
296
297                 /* transfer elements to new hashtable */
298
299                 for (i = 0; i < classcache_hash.size; i++) {
300                         c2 = (classcache_name_entry *) classcache_hash.ptr[i];
301                         while (c2) {
302                                 classcache_name_entry *nextc = c2->hashlink;
303                                 u4 newslot =
304                                         (utf_hashkey(c2->name->text, (u4) c2->name->blength)) & (newhash.size - 1);
305
306                                 c2->hashlink = (classcache_name_entry *) newhash.ptr[newslot];
307                                 newhash.ptr[newslot] = c2;
308
309                                 c2 = nextc;
310                         }
311                 }
312
313                 /* dispose old table */
314
315                 MFREE(classcache_hash.ptr, void *, classcache_hash.size);
316                 classcache_hash = newhash;
317         }
318
319         return c;
320 }
321
322
323 /* classcache_lookup ***********************************************************
324  
325    Lookup a possibly loaded class
326   
327    IN:
328        initloader.......initiating loader for resolving the class name
329        classname........class name to look up
330   
331    RETURN VALUE:
332        The return value is a pointer to the cached class object,
333        or NULL, if the class is not in the cache.
334
335    Note: synchronized with global tablelock
336    
337 *******************************************************************************/
338
339 classinfo *classcache_lookup(classloader *initloader, utf *classname)
340 {
341         classcache_name_entry *en;
342         classcache_class_entry *clsen;
343         classcache_loader_entry *lden;
344         classinfo *cls = NULL;
345
346         CLASSCACHE_LOCK();
347
348         en = classcache_lookup_name(classname);
349
350         if (en) {
351                 /* iterate over all class entries */
352
353                 for (clsen = en->classes; clsen != NULL; clsen = clsen->next) {
354                         /* check if this entry has been loaded by initloader */
355
356                         for (lden = clsen->loaders; lden != NULL; lden = lden->next) {
357                                 if (lden->loader == initloader) {
358                                         /* found the loaded class entry */
359
360                                         CLASSCACHE_ASSERT(clsen->classobj != NULL);
361                                         cls = clsen->classobj;
362                                         goto found;
363                                 }
364                         }
365                 }
366         }
367
368   found:
369         CLASSCACHE_UNLOCK();
370         return cls;
371 }
372
373
374 /* classcache_lookup_defined ***************************************************
375  
376    Lookup a class with the given name and defining loader
377   
378    IN:
379        defloader........defining loader
380        classname........class name
381   
382    RETURN VALUE:
383        The return value is a pointer to the cached class object,
384        or NULL, if the class is not in the cache.
385    
386 *******************************************************************************/
387
388 classinfo *classcache_lookup_defined(classloader *defloader, utf *classname)
389 {
390         classcache_name_entry *en;
391         classcache_class_entry *clsen;
392         classinfo *cls = NULL;
393
394         CLASSCACHE_LOCK();
395
396         en = classcache_lookup_name(classname);
397
398         if (en) {
399                 /* iterate over all class entries */
400                 for (clsen = en->classes; clsen != NULL; clsen = clsen->next) {
401                         if (!clsen->classobj)
402                                 continue;
403
404                         /* check if this entry has been defined by defloader */
405                         if (clsen->classobj->classloader == defloader) {
406                                 cls = clsen->classobj;
407                                 goto found;
408                         }
409                 }
410         }
411
412   found:
413         CLASSCACHE_UNLOCK();
414         return cls;
415 }
416
417
418 /* classcache_store ************************************************************
419    
420    Store a loaded class. If a class of the same name has already been stored
421    with the same initiating loader, then the given class CLS is freed (if
422    possible) and the previously stored class is returned.
423   
424    IN:
425        initloader.......initiating loader used to load the class
426                             (may be NULL indicating the bootstrap loader)
427        cls..............class object to cache
428            mayfree..........true if CLS may be freed in case another class is
429                             returned
430   
431    RETURN VALUE:
432        cls..............everything ok, the class was stored in the cache,
433            other classinfo..another class with the same (initloader,name) has been
434                             stored earlier. CLS has been freed and the earlier
435                                                 stored class is returned.
436        NULL.............an exception has been thrown.
437    
438    Note: synchronized with global tablelock
439    
440 *******************************************************************************/
441
442 /*@shared@*/ /*@null@*/ classinfo *
443 classcache_store(
444         /*@shared@*/ /*@null@*/ classloader * initloader,
445         /*@shared@*/ classinfo * cls,
446         bool mayfree)
447 {
448         classcache_name_entry *en;
449         classcache_class_entry *clsen;
450         classcache_loader_entry *lden;
451 #ifdef CLASSCACHE_VERBOSE
452         char logbuffer[1024];
453 #endif
454         
455         CLASSCACHE_ASSERT(cls != NULL);
456         CLASSCACHE_ASSERT(cls->loaded != 0);
457
458         CLASSCACHE_LOCK();
459
460 #ifdef CLASSCACHE_VERBOSE
461         sprintf(logbuffer,"classcache_store (%p,%d,", (void*)initloader,mayfree);
462         utf_strcat(logbuffer, cls->name);
463         strcat(logbuffer,")");
464         log_text(logbuffer);
465 #endif
466
467         en = classcache_new_name(cls->name);
468
469         CLASSCACHE_ASSERT(en != NULL);
470
471         /* iterate over all class entries */
472         for (clsen = en->classes; clsen != NULL; clsen = clsen->next) {
473
474                 /* check if this entry has already been loaded by initloader */
475                 for (lden = clsen->loaders; lden != NULL; lden = lden->next) {
476                         if (lden->loader == initloader) {
477                                 /* A class with the same (initloader,name) pair has been stored already. */
478                                 /* We free the given class and return the earlier one.                   */
479 #ifdef CLASSCACHE_VERBOSE
480                                 dolog("replacing %p with earlier loaded class %p",cls,clsen->classobj);
481 #endif
482                                 CLASSCACHE_ASSERT(clsen->classobj != NULL);
483                                 if (mayfree)
484                                         class_free(cls);
485                                 cls = clsen->classobj;
486                                 goto return_success;
487                         }
488                 }
489
490                 /* check if initloader is constrained to this entry */
491                 for (lden = clsen->constraints; lden != NULL; lden = lden->next) {
492                         if (lden->loader == initloader) {
493                                 /* we have to use this entry */
494                                 /* check if is has already been resolved to another class */
495                                 if (clsen->classobj != NULL && clsen->classobj != cls) {
496                                         /* a loading constraint is violated */
497                                         *exceptionptr = new_exception_message(string_java_lang_LinkageError,
498                                                                                                                   "loading constraint violated XXX add message");
499                                         goto return_exception;
500                                 }
501
502                                 /* record initloader as initiating loader */
503                                 clsen->loaders = classcache_new_loader_entry(initloader, clsen->loaders);
504
505                                 /* record the loaded class object */
506                                 clsen->classobj = cls;
507
508                                 /* done */
509                                 goto return_success;
510                         }
511                 }
512
513         }
514
515         /* create a new class entry for this class object with */
516         /* initiating loader initloader                        */
517
518         clsen = NEW(classcache_class_entry);
519         clsen->classobj = cls;
520         clsen->loaders = classcache_new_loader_entry(initloader, NULL);
521         clsen->constraints = NULL;
522
523         clsen->next = en->classes;
524         en->classes = clsen;
525
526   return_success:
527         CLASSCACHE_UNLOCK();
528         return cls;
529
530   return_exception:
531         CLASSCACHE_UNLOCK();
532         return NULL;                            /* exception */
533 }
534
535 /* classcache_store_unique *****************************************************
536    
537    Store a loaded class as loaded by the bootstrap loader. This is a wrapper 
538    aroung classcache_store that throws an exception if a class with the same 
539    name has already been loaded by the bootstrap loader.
540
541    This function is used to register a few special classes during startup.
542    It should not be used otherwise.
543   
544    IN:
545        cls..............class object to cache
546   
547    RETURN VALUE:
548        true.............everything ok, the class was stored.
549        false............an exception has been thrown.
550    
551    Note: synchronized with global tablelock
552    
553 *******************************************************************************/
554
555 bool 
556 classcache_store_unique(
557                 /*@shared@*/ classinfo *cls)
558 {
559         /*@shared@*/ classinfo *result;
560
561         result = classcache_store(NULL,cls,false);
562         if (result == NULL)
563                 return false;
564
565         if (result != cls) {
566                 *exceptionptr = new_internalerror("class already stored in the class cache");
567                 return false;
568         }
569
570         return true;
571 }
572
573 /* classcache_store_defined ****************************************************
574    
575    Store a loaded class after it has been defined. If the class has already
576    been defined by the same defining loader in another thread, free the given
577    class and returned the one which has been defined earlier.
578   
579    IN:
580        cls..............class object to store. classloader must be set
581                             (classloader may be NULL, for bootloader)
582   
583    RETURN VALUE:
584        cls..............everything ok, the class was stored the cache,
585            other classinfo..the class had already been defined, CLS was freed, the
586                             class which was defined earlier is returned,
587        NULL.............an exception has been thrown.
588    
589 *******************************************************************************/
590
591 /*@shared@*/ /*@null@*/ classinfo * 
592 classcache_store_defined(/*@shared@*/ classinfo *cls)
593 {
594         classcache_name_entry *en;
595         classcache_class_entry *clsen;
596 #ifdef CLASSCACHE_VERBOSE
597         char logbuffer[1024];
598 #endif
599
600         CLASSCACHE_ASSERT(cls != NULL);
601         CLASSCACHE_ASSERT(cls->loaded != 0);
602
603         CLASSCACHE_LOCK();
604
605 #ifdef CLASSCACHE_VERBOSE
606         sprintf(logbuffer,"classcache_store_defined (%p,", (void*)cls->classloader);
607         utf_strcat(logbuffer, cls->name);
608         strcat(logbuffer,")");
609         log_text(logbuffer);
610 #endif
611
612         en = classcache_new_name(cls->name);
613
614         CLASSCACHE_ASSERT(en != NULL);
615
616         /* iterate over all class entries */
617         for (clsen = en->classes; clsen != NULL; clsen = clsen->next) {
618                 
619                 /* check if this class has been defined by the same classloader */
620                 if (clsen->classobj != NULL && clsen->classobj->classloader == cls->classloader) {
621                         /* we found an earlier definition, delete the newer one */
622 #ifdef CLASSCACHE_VERBOSE
623                         dolog("replacing %p with earlier defined class %p",cls,clsen->classobj);
624 #endif
625                         /* we assert that the earlier object is not the same that we were given */
626                         CLASSCACHE_ASSERT(clsen->classobj != cls);
627                         class_free(cls);
628                         cls = clsen->classobj;
629                         goto return_success;
630                 }
631         }
632
633         /* create a new class entry for this class object */
634         /* the list of initiating loaders is empty at this point */
635
636         clsen = NEW(classcache_class_entry);
637         clsen->classobj = cls;
638         clsen->loaders = NULL;
639         clsen->constraints = NULL;
640
641         clsen->next = en->classes;
642         en->classes = clsen;
643
644 return_success:
645         CLASSCACHE_UNLOCK();
646         return cls;
647 }
648
649 /* classcache_find_loader ******************************************************
650  
651    Find the class entry loaded by or constrained to a given loader
652    (internally used helper function)
653   
654    IN:
655        entry............the classcache_name_entry
656        loader...........the loader to look for
657   
658    RETURN VALUE:
659        the classcache_class_entry for the given loader, or
660            NULL if no entry was found
661    
662 *******************************************************************************/
663
664 static /*@exposed@*/ /*@null@*/ classcache_class_entry *
665 classcache_find_loader(
666         classcache_name_entry * entry,
667         /*@shared@*/ /*@null@*/ classloader * loader)
668 {
669         classcache_class_entry *clsen;
670         classcache_loader_entry *lden;
671
672         CLASSCACHE_ASSERT(entry != NULL);
673
674         /* iterate over all class entries */
675         for (clsen = entry->classes; clsen != NULL; clsen = clsen->next) {
676
677                 /* check if this entry has already been loaded by initloader */
678                 for (lden = clsen->loaders; lden != NULL; lden = lden->next) {
679                         if (lden->loader == loader)
680                                 return clsen;   /* found */
681                 }
682
683                 /* check if loader is constrained to this entry */
684                 for (lden = clsen->constraints; lden != NULL; lden = lden->next) {
685                         if (lden->loader == loader)
686                                 return clsen;   /* found */
687                 }
688         }
689
690         /* not found */
691         return NULL;
692 }
693
694 /* classcache_free_class_entry *************************************************
695  
696    Free the memory used by a class entry
697   
698    IN:
699        clsen............the classcache_class_entry to free  
700            
701 *******************************************************************************/
702
703 static void
704 classcache_free_class_entry(
705         classcache_class_entry * clsen)
706 {
707         classcache_loader_entry *lden;
708         classcache_loader_entry *next;
709
710         CLASSCACHE_ASSERT(clsen != NULL);
711
712         for (lden = clsen->loaders; lden != NULL; lden = next) {
713                 next = lden->next;
714                 FREE(lden, classcache_loader_entry);
715         }
716         for (lden = clsen->constraints; lden != NULL; lden = next) {
717                 next = lden->next;
718                 FREE(lden, classcache_loader_entry);
719         }
720
721         FREE(clsen, classcache_class_entry);
722 }
723
724 /* classcache_remove_class_entry ***********************************************
725  
726    Remove a classcache_class_entry from the list of possible resolution of
727    a name entry
728    (internally used helper function)
729   
730    IN:
731        entry............the classcache_name_entry
732        clsen............the classcache_class_entry to remove
733   
734 *******************************************************************************/
735
736 static void
737 classcache_remove_class_entry(
738         classcache_name_entry * entry,
739         classcache_class_entry * clsen)
740 {
741         classcache_class_entry **chain;
742
743         CLASSCACHE_ASSERT(entry != NULL);
744         CLASSCACHE_ASSERT(clsen != NULL);
745
746         chain = &(entry->classes);
747         while (*chain) {
748                 if (*chain == clsen) {
749                         *chain = clsen->next;
750                         classcache_free_class_entry(clsen);
751                         return;
752                 }
753                 chain = &((*chain)->next);
754         }
755 }
756
757 /* classcache_free_name_entry **************************************************
758  
759    Free the memory used by a name entry
760   
761    IN:
762        entry............the classcache_name_entry to free  
763            
764 *******************************************************************************/
765
766 static void
767 classcache_free_name_entry(
768         classcache_name_entry * entry)
769 {
770         classcache_class_entry *clsen;
771         classcache_class_entry *next;
772
773         CLASSCACHE_ASSERT(entry != NULL);
774
775         for (clsen = entry->classes; clsen; clsen = next) {
776                 next = clsen->next;
777                 classcache_free_class_entry(clsen);
778         }
779
780         FREE(entry, classcache_name_entry);
781 }
782
783 /* classcache_free *************************************************************
784  
785    Free the memory used by the class cache
786
787    NOTE:
788        The class cache may not be used any more after this call, except
789            when it is reinitialized with classcache_init.
790   
791    Note: NOT synchronized!
792   
793 *******************************************************************************/
794
795 void
796 classcache_free(
797         )
798         /*@globals killed classcache_hash@*/
799 {
800         u4 slot;
801         classcache_name_entry *entry;
802         classcache_name_entry *next;
803
804         for (slot = 0; slot < classcache_hash.size; ++slot) {
805                 for (entry = (classcache_name_entry *) classcache_hash.ptr[slot]; entry; entry = next) {
806                         next = entry->hashlink;
807                         classcache_free_name_entry(entry);
808                 }
809         }
810
811         MFREE(classcache_hash.ptr, voidptr, classcache_hash.size);
812         classcache_hash.size = 0;
813         classcache_hash.entries = 0;
814         classcache_hash.ptr = NULL;
815 }
816
817 /* classcache_add_constraint ***************************************************
818  
819    Add a loading constraint
820   
821    IN:
822        a................first initiating loader
823        b................second initiating loader
824        classname........class name
825   
826    RETURN VALUE:
827        true.............everything ok, the constraint has been added,
828        false............an exception has been thrown.
829    
830    Note: synchronized with global tablelock
831    
832 *******************************************************************************/
833
834 bool
835 classcache_add_constraint(
836         /*@shared@*/ /*@null@*/ classloader * a,
837         /*@shared@*/ /*@null@*/ classloader * b,
838         /*@shared@*/ utf * classname)
839 {
840         classcache_name_entry *en;
841         classcache_class_entry *clsenA;
842         classcache_class_entry *clsenB;
843
844         CLASSCACHE_ASSERT(classname != NULL);
845
846 #ifdef CLASSCACHE_VERBOSE
847         fprintf(stderr, "classcache_add_constraint(%p,%p,", (void *) a, (void *) b);
848         utf_fprint_classname(stderr, classname);
849         fprintf(stderr, ")\n");
850 #endif
851
852         /* a constraint with a == b is trivially satisfied */
853         if (a == b)
854                 return true;
855
856         CLASSCACHE_LOCK();
857
858         en = classcache_new_name(classname);
859
860         CLASSCACHE_ASSERT(en != NULL);
861
862         /* find the entry loaded by / constrained to each loader */
863         clsenA = classcache_find_loader(en, a);
864         clsenB = classcache_find_loader(en, b);
865
866         if (clsenA != NULL && clsenB != NULL) {
867                 /* { both loaders have corresponding entries } */
868
869                 /* if the entries are the same, the constraint is already recorded */
870                 if (clsenA == clsenB)
871                         goto return_success;
872
873                 /* check if the entries can be merged */
874                 if (clsenA->classobj != NULL && clsenB->classobj != NULL
875                         && clsenA->classobj != clsenB->classobj) {
876                         /* no, the constraint is violated */
877                         *exceptionptr = new_exception_message(string_java_lang_LinkageError,
878                                                                                                   "loading constraint violated XXX add message");
879                         goto return_exception;
880                 }
881
882                 /* yes, merge the entries */
883                 /* clsenB will be merged into clsenA */
884                 clsenA->loaders = classcache_merge_loaders(clsenA->loaders, clsenB->loaders);
885                 clsenB->loaders = NULL;
886
887                 clsenA->constraints = classcache_merge_loaders(clsenA->constraints,
888                                                                                                            clsenB->constraints);
889                 clsenB->constraints = NULL;
890
891                 if (!clsenA->classobj)
892                         clsenA->classobj = clsenB->classobj;
893
894                 /* remove clsenB from the list of class entries */
895                 classcache_remove_class_entry(en, clsenB);
896         }
897         else {
898                 /* { at most one of the loaders has a corresponding entry } */
899
900                 /* set clsenA to the single class entry we have */
901                 if (!clsenA)
902                         clsenA = clsenB;
903
904                 if (!clsenA) {
905                         /* { no loader has a corresponding entry } */
906
907                         /* create a new class entry with the constraint (a,b,en->name) */
908                         clsenA = NEW(classcache_class_entry);
909                         clsenA->classobj = NULL;
910                         clsenA->loaders = NULL;
911                         clsenA->constraints = classcache_new_loader_entry(b, NULL);
912                         clsenA->constraints = classcache_new_loader_entry(a, clsenA->constraints);
913
914                         clsenA->next = en->classes;
915                         en->classes = clsenA;
916                 }
917                 else {
918                         /* make b the loader that has no corresponding entry */
919                         if (clsenB)
920                                 b = a;
921
922                         /* loader b must be added to entry clsenA */
923                         clsenA->constraints = classcache_new_loader_entry(b, clsenA->constraints);
924                 }
925         }
926
927   return_success:
928         CLASSCACHE_UNLOCK();
929         return true;
930
931   return_exception:
932         CLASSCACHE_UNLOCK();
933         return false;                           /* exception */
934 }
935
936 /*============================================================================*/
937 /* DEBUG DUMPS                                                                */
938 /*============================================================================*/
939
940 /* classcache_debug_dump *******************************************************
941  
942    Print the contents of the loaded class cache to a stream
943   
944    IN:
945        file.............output stream
946   
947    Note: synchronized with global tablelock
948    
949 *******************************************************************************/
950
951 void
952 classcache_debug_dump(
953         /*@shared@*/ FILE * file)
954 {
955         classcache_name_entry *c;
956         classcache_class_entry *clsen;
957         classcache_loader_entry *lden;
958         u4 slot;
959
960         CLASSCACHE_LOCK();
961
962         fprintf(file, "\n=== [loaded class cache] =====================================\n\n");
963         fprintf(file, "hash size   : %d\n", (int) classcache_hash.size);
964         fprintf(file, "hash entries: %d\n", (int) classcache_hash.entries);
965         fprintf(file, "\n");
966
967         for (slot = 0; slot < classcache_hash.size; ++slot) {
968                 c = (classcache_name_entry *) classcache_hash.ptr[slot];
969
970                 for (; c != NULL; c = c->hashlink) {
971                         utf_fprint_classname(file, c->name);
972                         fprintf(file, "\n");
973
974                         /* iterate over all class entries */
975                         for (clsen = c->classes; clsen != NULL; clsen = clsen->next) {
976                                 if (clsen->classobj) {
977                                         fprintf(file, "    loaded %p\n", (void *) clsen->classobj);
978                                 }
979                                 else {
980                                         fprintf(file, "    unresolved\n");
981                                 }
982                                 fprintf(file, "        loaders:");
983                                 for (lden = clsen->loaders; lden != NULL; lden = lden->next) {
984                                         fprintf(file, "<%p> %p", (void *) lden, (void *) lden->loader);
985                                 }
986                                 fprintf(file, "\n        constraints:");
987                                 for (lden = clsen->constraints; lden != NULL; lden = lden->next) {
988                                         fprintf(file, "<%p> %p", (void *) lden, (void *) lden->loader);
989                                 }
990                                 fprintf(file, "\n");
991                         }
992                 }
993         }
994         fprintf(file, "\n==============================================================\n\n");
995
996         CLASSCACHE_UNLOCK();
997 }
998
999 /*
1000  * These are local overrides for various environment variables in Emacs.
1001  * Please do not remove this and leave it at the end of the file, where
1002  * Emacs will automagically detect them.
1003  * ---------------------------------------------------------------------
1004  * Local variables:
1005  * mode: c
1006  * indent-tabs-mode: t
1007  * c-basic-offset: 4
1008  * tab-width: 4
1009  * End:
1010  * vim:noexpandtab:sw=4:ts=4:
1011  */