* exceptions_new_nosuchmethoderror: Added.
[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 3351 2005-10-05 11:53:28Z edwin $
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                         /* (if it is a different classinfo)                     */
623                         if (clsen->classobj != cls) {
624 #ifdef CLASSCACHE_VERBOSE
625                                 dolog("replacing %p with earlier defined class %p",cls,clsen->classobj);
626 #endif
627                                 class_free(cls);
628                                 cls = clsen->classobj;
629                         }
630                         goto return_success;
631                 }
632         }
633
634         /* create a new class entry for this class object */
635         /* the list of initiating loaders is empty at this point */
636
637         clsen = NEW(classcache_class_entry);
638         clsen->classobj = cls;
639         clsen->loaders = NULL;
640         clsen->constraints = NULL;
641
642         clsen->next = en->classes;
643         en->classes = clsen;
644
645 return_success:
646         CLASSCACHE_UNLOCK();
647         return cls;
648 }
649
650 /* classcache_find_loader ******************************************************
651  
652    Find the class entry loaded by or constrained to a given loader
653    (internally used helper function)
654   
655    IN:
656        entry............the classcache_name_entry
657        loader...........the loader to look for
658   
659    RETURN VALUE:
660        the classcache_class_entry for the given loader, or
661            NULL if no entry was found
662    
663 *******************************************************************************/
664
665 static /*@exposed@*/ /*@null@*/ classcache_class_entry *
666 classcache_find_loader(
667         classcache_name_entry * entry,
668         /*@shared@*/ /*@null@*/ classloader * loader)
669 {
670         classcache_class_entry *clsen;
671         classcache_loader_entry *lden;
672
673         CLASSCACHE_ASSERT(entry != NULL);
674
675         /* iterate over all class entries */
676         for (clsen = entry->classes; clsen != NULL; clsen = clsen->next) {
677
678                 /* check if this entry has already been loaded by initloader */
679                 for (lden = clsen->loaders; lden != NULL; lden = lden->next) {
680                         if (lden->loader == loader)
681                                 return clsen;   /* found */
682                 }
683
684                 /* check if loader is constrained to this entry */
685                 for (lden = clsen->constraints; lden != NULL; lden = lden->next) {
686                         if (lden->loader == loader)
687                                 return clsen;   /* found */
688                 }
689         }
690
691         /* not found */
692         return NULL;
693 }
694
695 /* classcache_free_class_entry *************************************************
696  
697    Free the memory used by a class entry
698   
699    IN:
700        clsen............the classcache_class_entry to free  
701            
702 *******************************************************************************/
703
704 static void
705 classcache_free_class_entry(
706         classcache_class_entry * clsen)
707 {
708         classcache_loader_entry *lden;
709         classcache_loader_entry *next;
710
711         CLASSCACHE_ASSERT(clsen != NULL);
712
713         for (lden = clsen->loaders; lden != NULL; lden = next) {
714                 next = lden->next;
715                 FREE(lden, classcache_loader_entry);
716         }
717         for (lden = clsen->constraints; lden != NULL; lden = next) {
718                 next = lden->next;
719                 FREE(lden, classcache_loader_entry);
720         }
721
722         FREE(clsen, classcache_class_entry);
723 }
724
725 /* classcache_remove_class_entry ***********************************************
726  
727    Remove a classcache_class_entry from the list of possible resolution of
728    a name entry
729    (internally used helper function)
730   
731    IN:
732        entry............the classcache_name_entry
733        clsen............the classcache_class_entry to remove
734   
735 *******************************************************************************/
736
737 static void
738 classcache_remove_class_entry(
739         classcache_name_entry * entry,
740         classcache_class_entry * clsen)
741 {
742         classcache_class_entry **chain;
743
744         CLASSCACHE_ASSERT(entry != NULL);
745         CLASSCACHE_ASSERT(clsen != NULL);
746
747         chain = &(entry->classes);
748         while (*chain) {
749                 if (*chain == clsen) {
750                         *chain = clsen->next;
751                         classcache_free_class_entry(clsen);
752                         return;
753                 }
754                 chain = &((*chain)->next);
755         }
756 }
757
758 /* classcache_free_name_entry **************************************************
759  
760    Free the memory used by a name entry
761   
762    IN:
763        entry............the classcache_name_entry to free  
764            
765 *******************************************************************************/
766
767 static void
768 classcache_free_name_entry(
769         classcache_name_entry * entry)
770 {
771         classcache_class_entry *clsen;
772         classcache_class_entry *next;
773
774         CLASSCACHE_ASSERT(entry != NULL);
775
776         for (clsen = entry->classes; clsen; clsen = next) {
777                 next = clsen->next;
778                 classcache_free_class_entry(clsen);
779         }
780
781         FREE(entry, classcache_name_entry);
782 }
783
784 /* classcache_free *************************************************************
785  
786    Free the memory used by the class cache
787
788    NOTE:
789        The class cache may not be used any more after this call, except
790            when it is reinitialized with classcache_init.
791   
792    Note: NOT synchronized!
793   
794 *******************************************************************************/
795
796 void
797 classcache_free(
798         )
799         /*@globals killed classcache_hash@*/
800 {
801         u4 slot;
802         classcache_name_entry *entry;
803         classcache_name_entry *next;
804
805         for (slot = 0; slot < classcache_hash.size; ++slot) {
806                 for (entry = (classcache_name_entry *) classcache_hash.ptr[slot]; entry; entry = next) {
807                         next = entry->hashlink;
808                         classcache_free_name_entry(entry);
809                 }
810         }
811
812         MFREE(classcache_hash.ptr, voidptr, classcache_hash.size);
813         classcache_hash.size = 0;
814         classcache_hash.entries = 0;
815         classcache_hash.ptr = NULL;
816 }
817
818 /* classcache_add_constraint ***************************************************
819  
820    Add a loading constraint
821   
822    IN:
823        a................first initiating loader
824        b................second initiating loader
825        classname........class name
826   
827    RETURN VALUE:
828        true.............everything ok, the constraint has been added,
829        false............an exception has been thrown.
830    
831    Note: synchronized with global tablelock
832    
833 *******************************************************************************/
834
835 bool
836 classcache_add_constraint(
837         /*@shared@*/ /*@null@*/ classloader * a,
838         /*@shared@*/ /*@null@*/ classloader * b,
839         /*@shared@*/ utf * classname)
840 {
841         classcache_name_entry *en;
842         classcache_class_entry *clsenA;
843         classcache_class_entry *clsenB;
844
845         CLASSCACHE_ASSERT(classname != NULL);
846
847 #ifdef CLASSCACHE_VERBOSE
848         fprintf(stderr, "classcache_add_constraint(%p,%p,", (void *) a, (void *) b);
849         utf_fprint_classname(stderr, classname);
850         fprintf(stderr, ")\n");
851 #endif
852
853         /* a constraint with a == b is trivially satisfied */
854         if (a == b)
855                 return true;
856
857         CLASSCACHE_LOCK();
858
859         en = classcache_new_name(classname);
860
861         CLASSCACHE_ASSERT(en != NULL);
862
863         /* find the entry loaded by / constrained to each loader */
864         clsenA = classcache_find_loader(en, a);
865         clsenB = classcache_find_loader(en, b);
866
867         if (clsenA != NULL && clsenB != NULL) {
868                 /* { both loaders have corresponding entries } */
869
870                 /* if the entries are the same, the constraint is already recorded */
871                 if (clsenA == clsenB)
872                         goto return_success;
873
874                 /* check if the entries can be merged */
875                 if (clsenA->classobj != NULL && clsenB->classobj != NULL
876                         && clsenA->classobj != clsenB->classobj) {
877                         /* no, the constraint is violated */
878                         *exceptionptr = new_exception_message(string_java_lang_LinkageError,
879                                                                                                   "loading constraint violated XXX add message");
880                         goto return_exception;
881                 }
882
883                 /* yes, merge the entries */
884                 /* clsenB will be merged into clsenA */
885                 clsenA->loaders = classcache_merge_loaders(clsenA->loaders, clsenB->loaders);
886                 clsenB->loaders = NULL;
887
888                 clsenA->constraints = classcache_merge_loaders(clsenA->constraints,
889                                                                                                            clsenB->constraints);
890                 clsenB->constraints = NULL;
891
892                 if (!clsenA->classobj)
893                         clsenA->classobj = clsenB->classobj;
894
895                 /* remove clsenB from the list of class entries */
896                 classcache_remove_class_entry(en, clsenB);
897         }
898         else {
899                 /* { at most one of the loaders has a corresponding entry } */
900
901                 /* set clsenA to the single class entry we have */
902                 if (!clsenA)
903                         clsenA = clsenB;
904
905                 if (!clsenA) {
906                         /* { no loader has a corresponding entry } */
907
908                         /* create a new class entry with the constraint (a,b,en->name) */
909                         clsenA = NEW(classcache_class_entry);
910                         clsenA->classobj = NULL;
911                         clsenA->loaders = NULL;
912                         clsenA->constraints = classcache_new_loader_entry(b, NULL);
913                         clsenA->constraints = classcache_new_loader_entry(a, clsenA->constraints);
914
915                         clsenA->next = en->classes;
916                         en->classes = clsenA;
917                 }
918                 else {
919                         /* make b the loader that has no corresponding entry */
920                         if (clsenB)
921                                 b = a;
922
923                         /* loader b must be added to entry clsenA */
924                         clsenA->constraints = classcache_new_loader_entry(b, clsenA->constraints);
925                 }
926         }
927
928   return_success:
929         CLASSCACHE_UNLOCK();
930         return true;
931
932   return_exception:
933         CLASSCACHE_UNLOCK();
934         return false;                           /* exception */
935 }
936
937 /*============================================================================*/
938 /* DEBUG DUMPS                                                                */
939 /*============================================================================*/
940
941 /* classcache_debug_dump *******************************************************
942  
943    Print the contents of the loaded class cache to a stream
944   
945    IN:
946        file.............output stream
947   
948    Note: synchronized with global tablelock
949    
950 *******************************************************************************/
951
952 void
953 classcache_debug_dump(
954         /*@shared@*/ FILE * file)
955 {
956         classcache_name_entry *c;
957         classcache_class_entry *clsen;
958         classcache_loader_entry *lden;
959         u4 slot;
960
961         CLASSCACHE_LOCK();
962
963         fprintf(file, "\n=== [loaded class cache] =====================================\n\n");
964         fprintf(file, "hash size   : %d\n", (int) classcache_hash.size);
965         fprintf(file, "hash entries: %d\n", (int) classcache_hash.entries);
966         fprintf(file, "\n");
967
968         for (slot = 0; slot < classcache_hash.size; ++slot) {
969                 c = (classcache_name_entry *) classcache_hash.ptr[slot];
970
971                 for (; c != NULL; c = c->hashlink) {
972                         utf_fprint_classname(file, c->name);
973                         fprintf(file, "\n");
974
975                         /* iterate over all class entries */
976                         for (clsen = c->classes; clsen != NULL; clsen = clsen->next) {
977                                 if (clsen->classobj) {
978                                         fprintf(file, "    loaded %p\n", (void *) clsen->classobj);
979                                 }
980                                 else {
981                                         fprintf(file, "    unresolved\n");
982                                 }
983                                 fprintf(file, "        loaders:");
984                                 for (lden = clsen->loaders; lden != NULL; lden = lden->next) {
985                                         fprintf(file, "<%p> %p", (void *) lden, (void *) lden->loader);
986                                 }
987                                 fprintf(file, "\n        constraints:");
988                                 for (lden = clsen->constraints; lden != NULL; lden = lden->next) {
989                                         fprintf(file, "<%p> %p", (void *) lden, (void *) lden->loader);
990                                 }
991                                 fprintf(file, "\n");
992                         }
993                 }
994         }
995         fprintf(file, "\n==============================================================\n\n");
996
997         CLASSCACHE_UNLOCK();
998 }
999
1000 /*
1001  * These are local overrides for various environment variables in Emacs.
1002  * Please do not remove this and leave it at the end of the file, where
1003  * Emacs will automagically detect them.
1004  * ---------------------------------------------------------------------
1005  * Local variables:
1006  * mode: c
1007  * indent-tabs-mode: t
1008  * c-basic-offset: 4
1009  * tab-width: 4
1010  * End:
1011  * vim:noexpandtab:sw=4:ts=4:
1012  */