5995c1ec9f49a3d023abd1c4c179bf1d07ce324d
[cacao.git] / src / vm / class.c
1 /* src/vm/class.c - class related functions
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: Reinhard Grafl
28
29    Changes: Mark Probst
30             Andreas Krall
31             Christian Thalinger
32
33    $Id: class.c 2153 2005-03-30 19:30:05Z twisti $
34
35 */
36
37 #include <assert.h>
38 #include <string.h>
39
40 #include "config.h"
41 #include "types.h"
42
43 #include "mm/memory.h"
44
45 #if defined(USE_THREADS)
46 # if defined(NATIVE_THREADS)
47 #  include "threads/native/threads.h"
48 # else
49 #  include "threads/green/threads.h"
50 #  include "threads/green/locks.h"
51 # endif
52 #endif
53
54 #include "toolbox/logging.h"
55 #include "vm/class.h"
56 #include "vm/options.h"
57 #include "vm/resolve.h"
58 #include "vm/statistics.h"
59 #include "vm/tables.h"
60 #include "vm/utf8.h"
61
62
63 /******************************************************************************/
64 /* DEBUG HELPERS                                                              */
65 /******************************************************************************/
66
67 #ifndef NDEBUG
68 #define CLASS_DEBUG
69 #endif
70
71 #ifdef CLASS_DEBUG
72 #define CLASS_ASSERT(cond)  assert(cond)
73 #else
74 #define CLASS_ASSERT(cond)
75 #endif
76
77
78 /* global variables ***********************************************************/
79
80 hashtable class_hash;                   /* hashtable for classes              */
81
82 list unlinkedclasses;                   /* this is only used for eager class  */
83                                         /* loading                            */
84
85
86 /* frequently used classes ****************************************************/
87
88 /* important system classes */
89
90 classinfo *class_java_lang_Object;
91 classinfo *class_java_lang_Class;
92 classinfo *class_java_lang_ClassLoader;
93 classinfo *class_java_lang_Cloneable;
94 classinfo *class_java_lang_SecurityManager;
95 classinfo *class_java_lang_String;
96 classinfo *class_java_lang_System;
97 classinfo *class_java_io_Serializable;
98
99
100 /* system exception classes required in cacao */
101
102 classinfo *class_java_lang_Throwable;
103 classinfo *class_java_lang_VMThrowable;
104 classinfo *class_java_lang_Exception;
105 classinfo *class_java_lang_Error;
106 classinfo *class_java_lang_OutOfMemoryError;
107 classinfo *class_java_lang_NoClassDefFoundError;
108
109 classinfo *class_java_lang_Void;
110 classinfo *class_java_lang_Boolean;
111 classinfo *class_java_lang_Byte;
112 classinfo *class_java_lang_Character;
113 classinfo *class_java_lang_Short;
114 classinfo *class_java_lang_Integer;
115 classinfo *class_java_lang_Long;
116 classinfo *class_java_lang_Float;
117 classinfo *class_java_lang_Double;
118
119 /* some classes which may be used more often */
120
121 classinfo *class_java_util_Vector;
122
123
124 /* pseudo classes for the typechecker */
125
126 classinfo *pseudo_class_Arraystub;
127 classinfo *pseudo_class_Null;
128 classinfo *pseudo_class_New;
129
130
131 /* class_init ******************************************************************
132
133    Initialize the class subsystem.
134
135 *******************************************************************************/
136
137 void class_init_foo(void)
138 {
139         class_java_lang_Object          = class_new_intern(utf_java_lang_Object);
140
141         class_java_lang_Class           = class_new(utf_java_lang_Class);
142         class_java_lang_ClassLoader     = class_new(utf_java_lang_ClassLoader);
143         class_java_lang_Cloneable       = class_new(utf_java_lang_Cloneable);
144         class_java_lang_SecurityManager = class_new(utf_java_lang_SecurityManager);
145         class_java_lang_String          = class_new(utf_java_lang_String);
146         class_java_lang_System          = class_new(utf_java_lang_System);
147         class_java_io_Serializable      = class_new(utf_java_io_Serializable);
148
149         class_java_lang_Throwable       = class_new(utf_java_lang_Throwable);
150         class_java_lang_VMThrowable     = class_new(utf_java_lang_VMThrowable);
151         class_java_lang_Exception       = class_new(utf_java_lang_Exception);
152         class_java_lang_Error           = class_new(utf_java_lang_Error);
153
154         class_java_lang_OutOfMemoryError =
155                 class_new(utf_java_lang_OutOfMemoryError);
156
157         class_java_lang_NoClassDefFoundError =
158                 class_new(utf_java_lang_NoClassDefFoundError);
159
160         class_java_lang_Void            = class_new(utf_java_lang_Void);
161         class_java_lang_Boolean         = class_new(utf_java_lang_Boolean);
162         class_java_lang_Byte            = class_new(utf_java_lang_Byte);
163         class_java_lang_Character       = class_new(utf_java_lang_Character);
164         class_java_lang_Short           = class_new(utf_java_lang_Short);
165         class_java_lang_Integer         = class_new(utf_java_lang_Integer);
166         class_java_lang_Long            = class_new(utf_java_lang_Long);
167         class_java_lang_Float           = class_new(utf_java_lang_Float);
168         class_java_lang_Double          = class_new(utf_java_lang_Double);
169
170         class_java_util_Vector          = class_new(utf_java_util_Vector);
171
172     pseudo_class_Arraystub = class_new_intern(utf_new_char("$ARRAYSTUB$"));
173         pseudo_class_Null      = class_new_intern(utf_new_char("$NULL$"));
174         pseudo_class_New       = class_new_intern(utf_new_char("$NEW$"));
175 }
176
177
178 /* class_new *******************************************************************
179
180    Searches for the class with the specified name in the classes
181    hashtable, if there is no such class a new classinfo structure is
182    created and inserted into the list of classes to be loaded.
183
184 *******************************************************************************/
185
186 classinfo *class_new(utf *classname)
187 {
188     classinfo *c;
189
190 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
191     tables_lock();
192 #endif
193
194     c = class_new_intern(classname);
195
196         /* we support eager class loading and linking on demand */
197
198         if (opt_eager) {
199                 classinfo *tc;
200                 classinfo *tmp;
201
202                 list_init(&unlinkedclasses, OFFSET(classinfo, listnode));
203
204                 if (!c->loaded) {
205                         if (!load_class_bootstrap(c)) {
206 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
207                                 tables_unlock();
208 #endif
209                                 return c;
210                         }
211                 }
212
213                 /* link all referenced classes */
214
215                 tc = list_first(&unlinkedclasses);
216
217                 while (tc) {
218                         /* skip the current loaded/linked class */
219                         if (tc != c) {
220                                 if (!link_class(tc)) {
221 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
222                                         tables_unlock();
223 #endif
224                                         return c;
225                                 }
226                         }
227
228                         /* we need a tmp variable here, because list_remove sets prev and
229                            next to NULL */
230                         tmp = list_next(&unlinkedclasses, tc);
231                         list_remove(&unlinkedclasses, tc);
232                         tc = tmp;
233                 }
234
235                 if (!c->linked) {
236                         if (!link_class(c)) {
237 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
238                                 tables_unlock();
239 #endif
240                                 return c;
241                         }
242                 }
243         }
244
245 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
246     tables_unlock();
247 #endif
248
249     return c;
250 }
251
252
253 classinfo *class_new_intern(utf *classname)
254 {
255         classinfo *c;     /* hashtable element */
256         u4 key;           /* hashkey computed from classname */
257         u4 slot;          /* slot in hashtable */
258         u2 i;
259
260         key  = utf_hashkey(classname->text, classname->blength);
261         slot = key & (class_hash.size - 1);
262         c    = class_hash.ptr[slot];
263
264         /* search external hash chain for the class */
265         while (c) {
266                 if (c->name->blength == classname->blength) {
267                         for (i = 0; i < classname->blength; i++)
268                                 if (classname->text[i] != c->name->text[i]) goto nomatch;
269                                                 
270                         /* class found in hashtable */
271                         return c;
272                 }
273                         
274         nomatch:
275                 c = c->hashlink; /* next element in external chain */
276         }
277
278         /* location in hashtable found, create new classinfo structure */
279
280 #if defined(STATISTICS)
281         if (opt_stat)
282                 count_class_infos += sizeof(classinfo);
283 #endif
284
285         if (initverbose) {
286                 char logtext[MAXLOGTEXT];
287                 sprintf(logtext, "Creating class: ");
288                 utf_sprint_classname(logtext + strlen(logtext), classname);
289                 log_text(logtext);
290         }
291
292         c = GCNEW(classinfo, 1); /*JOWENN: NEW*/
293         /*c=NEW(classinfo);*/
294         c->vmClass = 0;
295         c->flags = 0;
296         c->name = classname;
297         c->packagename = NULL;
298         c->cpcount = 0;
299         c->cptags = NULL;
300         c->cpinfos = NULL;
301         c->classrefs = NULL;
302         c->extclassrefs = NULL;
303         c->classrefcount = 0;
304         c->parseddescs = NULL;
305         c->parseddescsize = 0;
306         c->super = NULL;
307         c->sub = NULL;
308         c->nextsub = NULL;
309         c->interfacescount = 0;
310         c->interfaces = NULL;
311         c->fieldscount = 0;
312         c->fields = NULL;
313         c->methodscount = 0;
314         c->methods = NULL;
315         c->linked = false;
316         c->loaded = false;
317         c->index = 0;
318         c->instancesize = 0;
319         c->header.vftbl = NULL;
320         c->innerclasscount = 0;
321         c->innerclass = NULL;
322         c->vftbl = NULL;
323         c->initialized = false;
324         c->initializing = false;
325         c->classvftbl = false;
326     c->classUsed = 0;
327     c->impldBy = NULL;
328         c->classloader = NULL;
329         c->sourcefile = NULL;
330         
331         /* insert class into the hashtable */
332         c->hashlink = class_hash.ptr[slot];
333         class_hash.ptr[slot] = c;
334
335         /* update number of hashtable-entries */
336         class_hash.entries++;
337
338         if (class_hash.entries > (class_hash.size * 2)) {
339
340                 /* reorganization of hashtable, average length of 
341                    the external chains is approx. 2                */  
342
343                 u4 i;
344                 classinfo *c;
345                 hashtable newhash;  /* the new hashtable */
346
347                 /* create new hashtable, double the size */
348                 init_hashtable(&newhash, class_hash.size * 2);
349                 newhash.entries = class_hash.entries;
350
351                 /* transfer elements to new hashtable */
352                 for (i = 0; i < class_hash.size; i++) {
353                         c = (classinfo *) class_hash.ptr[i];
354                         while (c) {
355                                 classinfo *nextc = c->hashlink;
356                                 u4 slot = (utf_hashkey(c->name->text, c->name->blength)) & (newhash.size - 1);
357                                                 
358                                 c->hashlink = newhash.ptr[slot];
359                                 newhash.ptr[slot] = c;
360
361                                 c = nextc;
362                         }
363                 }
364         
365                 /* dispose old table */ 
366                 MFREE(class_hash.ptr, void*, class_hash.size);
367                 class_hash = newhash;
368         }
369
370         /* Array classes need further initialization. */
371         if (c->name->text[0] == '[') {
372                 /* Array classes are not loaded from classfiles. */
373                 c->loaded = true;
374                 class_new_array(c);
375                 c->packagename = array_packagename;
376
377         } else {
378                 /* Find the package name */
379                 /* Classes in the unnamed package keep packagename == NULL. */
380                 char *p = utf_end(c->name) - 1;
381                 char *start = c->name->text;
382                 for (;p > start; --p) {
383                         if (*p == '/') {
384                                 c->packagename = utf_new (start, p - start);
385                                 break;
386                         }
387                 }
388         }
389
390 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
391         initObjectLock(&c->header);
392 #endif
393
394         return c;
395 }
396
397
398 /* class_get *******************************************************************
399
400    Searches for the class with the specified name in the classes
401    hashtable if there is no such class NULL is returned.
402
403 *******************************************************************************/
404
405 classinfo *class_get(utf *classname)
406 {
407         classinfo *c;  /* hashtable element */ 
408         u4 key;        /* hashkey computed from classname */   
409         u4 slot;       /* slot in hashtable */
410         u2 i;  
411
412         key  = utf_hashkey(classname->text, classname->blength);
413         slot = key & (class_hash.size-1);
414         c    = class_hash.ptr[slot];
415
416         /* search external hash-chain */
417         while (c) {
418                 if (c->name->blength == classname->blength) {
419                         /* compare classnames */
420                         for (i = 0; i < classname->blength; i++) 
421                                 if (classname->text[i] != c->name->text[i])
422                                         goto nomatch;
423
424                         /* class found in hashtable */                          
425                         return c;
426                 }
427                         
428         nomatch:
429                 c = c->hashlink;
430         }
431
432         /* class not found */
433         return NULL;
434 }
435
436
437 /* class_remove ****************************************************************
438
439    Removes the class entry wth the specified name in the classes
440    hashtable, furthermore the class' resources are freed if there is
441    no such class false is returned.
442
443 *******************************************************************************/
444
445 bool class_remove(classinfo *c)
446 {
447         classinfo *tc;                      /* hashtable element                  */
448         classinfo *pc;
449         u4 key;                             /* hashkey computed from classname    */
450         u4 slot;                            /* slot in hashtable                  */
451         u2 i;  
452
453         key  = utf_hashkey(c->name->text, c->name->blength);
454         slot = key & (class_hash.size - 1);
455         tc   = class_hash.ptr[slot];
456         pc   = NULL;
457
458         /* search external hash-chain */
459         while (tc) {
460                 if (tc->name->blength == c->name->blength) {
461                         
462                         /* compare classnames */
463                         for (i = 0; i < c->name->blength; i++)
464                                 if (tc->name->text[i] != c->name->text[i])
465                                         goto nomatch;
466
467                         /* class found in hashtable */
468                         if (!pc)
469                                 class_hash.ptr[slot] = tc->hashlink;
470                         else
471                                 pc->hashlink = tc->hashlink;
472
473                         class_free(tc);
474
475                         return true;
476                 }
477                         
478         nomatch:
479                 pc = tc;
480                 tc = tc->hashlink;
481         }
482
483         /* class not found */
484         return false;
485 }
486
487
488 /* class_freepool **************************************************************
489
490         Frees all resources used by this classes Constant Pool.
491
492 *******************************************************************************/
493
494 static void class_freecpool(classinfo *c)
495 {
496         u4 idx;
497         u4 tag;
498         voidptr info;
499         
500         if (c->cptags && c->cpinfos) {
501                 for (idx = 0; idx < c->cpcount; idx++) {
502                         tag = c->cptags[idx];
503                         info = c->cpinfos[idx];
504                 
505                         if (info != NULL) {
506                                 switch (tag) {
507                                 case CONSTANT_Fieldref:
508                                 case CONSTANT_Methodref:
509                                 case CONSTANT_InterfaceMethodref:
510                                         FREE(info, constant_FMIref);
511                                         break;
512                                 case CONSTANT_Integer:
513                                         FREE(info, constant_integer);
514                                         break;
515                                 case CONSTANT_Float:
516                                         FREE(info, constant_float);
517                                         break;
518                                 case CONSTANT_Long:
519                                         FREE(info, constant_long);
520                                         break;
521                                 case CONSTANT_Double:
522                                         FREE(info, constant_double);
523                                         break;
524                                 case CONSTANT_NameAndType:
525                                         FREE(info, constant_nameandtype);
526                                         break;
527                                 }
528                         }
529                 }
530         }
531
532         if (c->cptags)
533                 MFREE(c->cptags, u1, c->cpcount);
534
535         if (c->cpinfos)
536                 MFREE(c->cpinfos, voidptr, c->cpcount);
537 }
538
539
540 /* class_free ******************************************************************
541
542    Frees all resources used by the class.
543
544 *******************************************************************************/
545
546 void class_free(classinfo *c)
547 {
548         s4 i;
549         vftbl_t *v;
550                 
551         class_freecpool(c);
552
553         if (c->interfaces)
554                 MFREE(c->interfaces, classinfo*, c->interfacescount);
555
556         if (c->fields) {
557                 for (i = 0; i < c->fieldscount; i++)
558                         field_free(&(c->fields[i]));
559 /*      MFREE(c->fields, fieldinfo, c->fieldscount); */
560         }
561         
562         if (c->methods) {
563                 for (i = 0; i < c->methodscount; i++)
564                         method_free(&(c->methods[i]));
565                 MFREE(c->methods, methodinfo, c->methodscount);
566         }
567
568         if ((v = c->vftbl) != NULL) {
569                 if (v->arraydesc)
570                         mem_free(v->arraydesc,sizeof(arraydescriptor));
571                 
572                 for (i = 0; i < v->interfacetablelength; i++) {
573                         MFREE(v->interfacetable[-i], methodptr, v->interfacevftbllength[i]);
574                 }
575                 MFREE(v->interfacevftbllength, s4, v->interfacetablelength);
576
577                 i = sizeof(vftbl_t) + sizeof(methodptr) * (v->vftbllength - 1) +
578                     sizeof(methodptr*) * (v->interfacetablelength -
579                                          (v->interfacetablelength > 0));
580                 v = (vftbl_t*) (((methodptr*) v) -
581                                                 (v->interfacetablelength - 1) * (v->interfacetablelength > 1));
582                 mem_free(v, i);
583         }
584
585         if (c->innerclass)
586                 MFREE(c->innerclass, innerclassinfo, c->innerclasscount);
587
588         /*      if (c->classvftbl)
589                 mem_free(c->header.vftbl, sizeof(vftbl) + sizeof(methodptr)*(c->vftbl->vftbllength-1)); */
590         
591 /*      GCFREE(c); */
592 }
593
594
595 /* class_array_of **************************************************************
596
597    Returns an array class with the given component class. The array
598    class is dynamically created if neccessary.
599
600 *******************************************************************************/
601
602 classinfo *class_array_of(classinfo *component)
603 {
604     s4 namelen;
605     char *namebuf;
606         classinfo *c;
607
608     /* Assemble the array class name */
609     namelen = component->name->blength;
610     
611     if (component->name->text[0] == '[') {
612         /* the component is itself an array */
613         namebuf = DMNEW(char, namelen + 1);
614         namebuf[0] = '[';
615         MCOPY(namebuf + 1, component->name->text, char, namelen);
616         namelen++;
617
618     } else {
619         /* the component is a non-array class */
620         namebuf = DMNEW(char, namelen + 3);
621         namebuf[0] = '[';
622         namebuf[1] = 'L';
623         MCOPY(namebuf + 2, component->name->text, char, namelen);
624         namebuf[2 + namelen] = ';';
625         namelen += 3;
626     }
627
628         c = class_new(utf_new(namebuf, namelen));
629
630         /* load this class and link it */
631
632         c->loaded = true;
633
634         if (!c->linked)
635                 if (!link_class(c))
636                         return NULL;
637
638     return c;
639 }
640
641
642 /* class_multiarray_of *********************************************************
643
644    Returns an array class with the given dimension and element class.
645    The array class is dynamically created if neccessary.
646
647 *******************************************************************************/
648
649 classinfo *class_multiarray_of(s4 dim, classinfo *element)
650 {
651     s4 namelen;
652     char *namebuf;
653
654         if (dim < 1)
655                 panic("Invalid array dimension requested");
656
657     /* Assemble the array class name */
658     namelen = element->name->blength;
659     
660     if (element->name->text[0] == '[') {
661         /* the element is itself an array */
662         namebuf = DMNEW(char, namelen + dim);
663         memcpy(namebuf + dim, element->name->text, namelen);
664         namelen += dim;
665     }
666     else {
667         /* the element is a non-array class */
668         namebuf = DMNEW(char, namelen + 2 + dim);
669         namebuf[dim] = 'L';
670         memcpy(namebuf + dim + 1, element->name->text, namelen);
671         namelen += (2 + dim);
672         namebuf[namelen - 1] = ';';
673     }
674         memset(namebuf, '[', dim);
675
676     return class_new(utf_new(namebuf, namelen));
677 }
678
679 /* class_lookup_classref *******************************************************
680
681    Looks up the constant_classref for a given classname in the classref
682    tables of a class.
683
684    IN:
685        cls..............the class containing the reference
686            name.............the name of the class refered to
687
688     RETURN VALUE:
689            a pointer to a constant_classref, or 
690            NULL if the reference was not found
691    
692 *******************************************************************************/
693
694 constant_classref *class_lookup_classref(classinfo *cls,utf *name)
695 {
696         constant_classref *ref;
697         extra_classref *xref;
698         int count;
699
700         CLASS_ASSERT(cls);
701         CLASS_ASSERT(name);
702         CLASS_ASSERT(!cls->classrefcount || cls->classrefs);
703         
704         /* first search the main classref table */
705         count = cls->classrefcount;
706         ref = cls->classrefs;
707         for (; count; --count, ++ref)
708                 if (ref->name == name)
709                         return ref;
710
711         /* next try the list of extra classrefs */
712         for (xref=cls->extclassrefs; xref; xref=xref->next) {
713                 if (xref->classref.name == name)
714                         return &(xref->classref);
715         }
716
717         /* not found */
718         return NULL;
719 }
720
721
722 /* class_get_classref **********************************************************
723
724    Returns the constant_classref for a given classname.
725
726    IN:
727        cls..............the class containing the reference
728            name.............the name of the class refered to
729
730    RETURN VALUE:
731        a pointer to a constant_classref (never NULL)
732
733    NOTE:
734        The given name is not checked for validity!
735    
736 *******************************************************************************/
737
738 constant_classref *class_get_classref(classinfo *cls,utf *name)
739 {
740         constant_classref *ref;
741         extra_classref *xref;
742
743         CLASS_ASSERT(cls);
744         CLASS_ASSERT(name);
745
746         ref = class_lookup_classref(cls,name);
747         if (ref)
748                 return ref;
749
750         xref = NEW(extra_classref);
751         CLASSREF_INIT(xref->classref,cls,name);
752
753         xref->next = cls->extclassrefs;
754         cls->extclassrefs = xref;
755
756         return &(xref->classref);
757 }
758
759 /* class_get_classref_multiarray_of ********************************************
760
761    Returns an array type reference with the given dimension and element class
762    reference.
763
764    IN:
765        dim..............the requested dimension
766                             dim must be in [1;255]. This is NOT checked!
767            ref..............the component class reference
768
769    RETURN VALUE:
770        a pointer to the class reference for the array type
771
772    NOTE:
773        The referer of `ref` is used as the referer for the new classref.
774
775 *******************************************************************************/
776
777 constant_classref *class_get_classref_multiarray_of(s4 dim,constant_classref *ref)
778 {
779     s4 namelen;
780     char *namebuf;
781
782         CLASS_ASSERT(ref);
783         CLASS_ASSERT(dim >= 1 && dim <= 255);
784
785     /* Assemble the array class name */
786     namelen = ref->name->blength;
787     
788     if (ref->name->text[0] == '[') {
789         /* the element is itself an array */
790         namebuf = DMNEW(char, namelen + dim);
791         memcpy(namebuf + dim, ref->name->text, namelen);
792         namelen += dim;
793     }
794     else {
795         /* the element is a non-array class */
796         namebuf = DMNEW(char, namelen + 2 + dim);
797         namebuf[dim] = 'L';
798         memcpy(namebuf + dim + 1, ref->name->text, namelen);
799         namelen += (2 + dim);
800         namebuf[namelen - 1] = ';';
801     }
802         memset(namebuf, '[', dim);
803
804     return class_get_classref(ref->referer,utf_new(namebuf, namelen));
805 }
806
807 /* class_get_classref_component_of *********************************************
808
809    Returns the component classref of a given array type reference
810
811    IN:
812        ref..............the array type reference
813
814    RETURN VALUE:
815        a reference to the component class, or
816            NULL if `ref` is not an object array type reference
817
818    NOTE:
819        The referer of `ref` is used as the referer for the new classref.
820
821 *******************************************************************************/
822
823 constant_classref *class_get_classref_component_of(constant_classref *ref)
824 {
825         s4 namelen;
826         char *name;
827         
828         CLASS_ASSERT(ref);
829
830         name = ref->name->text;
831         if (*name++ != '[')
832                 return NULL;
833         
834         namelen = ref->name->blength - 1;
835         if (*name == 'L') {
836                 name++;
837                 namelen -= 2;
838         }
839         else if (*name != '[') {
840                 return NULL;
841         }
842
843     return class_get_classref(ref->referer,utf_new(name, namelen));
844 }
845
846
847 /*
848  * These are local overrides for various environment variables in Emacs.
849  * Please do not remove this and leave it at the end of the file, where
850  * Emacs will automagically detect them.
851  * ---------------------------------------------------------------------
852  * Local variables:
853  * mode: c
854  * indent-tabs-mode: t
855  * c-basic-offset: 4
856  * tab-width: 4
857  * End:
858  */