1 /* src/vm/linker.c - class linker functions
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
8 This file is part of CACAO.
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.
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.
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
25 Contact: cacao@complang.tuwien.ac.at
27 Authors: Reinhard Grafl
29 Changes: Andreas Krall
35 $Id: linker.c 2978 2005-07-11 08:26:41Z twisti $
42 #include "mm/memory.h"
43 #include "native/native.h"
44 #include "vm/builtin.h"
46 #include "vm/classcache.h"
47 #include "vm/exceptions.h"
48 #include "vm/loader.h"
49 #include "vm/options.h"
50 #include "vm/resolve.h"
51 #include "vm/statistics.h"
52 #include "vm/stringlocal.h"
53 #include "vm/jit/codegen.inc.h"
56 /* global variables ***********************************************************/
58 static s4 interfaceindex; /* sequential numbering of interfaces */
62 /* primitivetype_table *********************************************************
64 Structure for primitive classes: contains the class for wrapping
65 the primitive type, the primitive class, the name of the class for
66 wrapping, the one character type signature and the name of the
69 CAUTION: Don't change the order of the types. This table is indexed
70 by the ARRAYTYPE_ constants (except ARRAYTYPE_OBJECT).
72 *******************************************************************************/
74 primitivetypeinfo primitivetype_table[PRIMITIVETYPE_COUNT] = {
75 { NULL, NULL, "java/lang/Integer", 'I', "int" , "[I", NULL, NULL },
76 { NULL, NULL, "java/lang/Long", 'J', "long" , "[J", NULL, NULL },
77 { NULL, NULL, "java/lang/Float", 'F', "float" , "[F", NULL, NULL },
78 { NULL, NULL, "java/lang/Double", 'D', "double" , "[D", NULL, NULL },
79 { NULL, NULL, NULL, 0 , NULL , NULL, NULL, NULL },
80 { NULL, NULL, "java/lang/Byte", 'B', "byte" , "[B", NULL, NULL },
81 { NULL, NULL, "java/lang/Character", 'C', "char" , "[C", NULL, NULL },
82 { NULL, NULL, "java/lang/Short", 'S', "short" , "[S", NULL, NULL },
83 { NULL, NULL, "java/lang/Boolean", 'Z', "boolean" , "[Z", NULL, NULL },
84 { NULL, NULL, NULL, 0 , NULL , NULL, NULL, NULL },
85 { NULL, NULL, "java/lang/Void", 'V', "void" , NULL, NULL, NULL }
89 /* private functions **********************************************************/
91 static bool link_primitivetype_table(void);
92 static classinfo *link_class_intern(classinfo *c);
93 static arraydescriptor *link_array(classinfo *c);
94 static void linker_compute_class_values(classinfo *c);
95 static void linker_compute_subclasses(classinfo *c);
96 static void linker_addinterface(classinfo *c, classinfo *ic);
97 static s4 class_highestinterface(classinfo *c);
100 /* linker_init *****************************************************************
102 Initializes the linker subsystem.
104 *******************************************************************************/
106 bool linker_init(void)
108 /* reset interface index */
112 /* link important system classes */
114 if (!link_class(class_java_lang_Object))
117 if (!link_class(class_java_lang_String))
120 if (!link_class(class_java_lang_Cloneable))
123 if (!link_class(class_java_io_Serializable))
127 /* link classes for wrapping primitive types */
129 if (!link_class(class_java_lang_Void))
132 if (!link_class(class_java_lang_Boolean))
135 if (!link_class(class_java_lang_Byte))
138 if (!link_class(class_java_lang_Character))
141 if (!link_class(class_java_lang_Short))
144 if (!link_class(class_java_lang_Integer))
147 if (!link_class(class_java_lang_Long))
150 if (!link_class(class_java_lang_Float))
153 if (!link_class(class_java_lang_Double))
157 /* load some other important classes */
159 if (!link_class(class_java_lang_Class))
162 if (!link_class(class_java_lang_ClassLoader))
165 if (!link_class(class_java_lang_SecurityManager))
168 if (!link_class(class_java_lang_System))
171 if (!link_class(class_java_lang_ThreadGroup))
175 /* some classes which may be used more often */
177 if (!link_class(class_java_lang_StackTraceElement))
180 if (!link_class(class_java_lang_reflect_Constructor))
183 if (!link_class(class_java_lang_reflect_Field))
186 if (!link_class(class_java_lang_reflect_Method))
189 if (!link_class(class_java_security_PrivilegedAction))
192 if (!link_class(class_java_util_Vector))
195 if (!link_class(arrayclass_java_lang_Object))
199 /* create pseudo classes used by the typechecker */
201 /* pseudo class for Arraystubs (extends java.lang.Object) */
203 pseudo_class_Arraystub =
204 class_create_classinfo(utf_new_char("$ARRAYSTUB$"));
205 pseudo_class_Arraystub->loaded = true;
206 pseudo_class_Arraystub->super.cls = class_java_lang_Object;
207 pseudo_class_Arraystub->interfacescount = 2;
208 pseudo_class_Arraystub->interfaces = MNEW(classref_or_classinfo, 2);
209 pseudo_class_Arraystub->interfaces[0].cls = class_java_lang_Cloneable;
210 pseudo_class_Arraystub->interfaces[1].cls = class_java_io_Serializable;
212 if (!classcache_store_unique(pseudo_class_Arraystub)) {
213 log_text("could not cache pseudo_class_Arraystub");
217 if (!link_class(pseudo_class_Arraystub))
220 /* pseudo class representing the null type */
222 pseudo_class_Null = class_create_classinfo(utf_new_char("$NULL$"));
223 pseudo_class_Null->loaded = true;
224 pseudo_class_Null->super.cls = class_java_lang_Object;
226 if (!classcache_store_unique(pseudo_class_Null)) {
227 log_text("could not cache pseudo_class_Null");
231 if (!link_class(pseudo_class_Null))
234 /* pseudo class representing new uninitialized objects */
236 pseudo_class_New = class_create_classinfo(utf_new_char("$NEW$"));
237 pseudo_class_New->loaded = true;
238 pseudo_class_New->linked = true; /* XXX is this allright? */
239 pseudo_class_New->super.cls = class_java_lang_Object;
241 if (!classcache_store_unique(pseudo_class_New)) {
242 log_text("could not cache pseudo_class_New");
246 /* create classes representing primitive types */
248 if (!link_primitivetype_table())
252 /* Correct vftbl-entries (retarded loading and linking of class */
253 /* java/lang/String). */
255 stringtable_update();
261 /* link_primitivetype_table ****************************************************
263 Create classes representing primitive types.
265 *******************************************************************************/
267 static bool link_primitivetype_table(void)
273 for (i = 0; i < PRIMITIVETYPE_COUNT; i++) {
276 if (!primitivetype_table[i].name)
279 /* create primitive class */
281 c = class_create_classinfo(utf_new_char(primitivetype_table[i].name));
282 c->classUsed = NOTUSED; /* not used initially CO-RT */
285 /* prevent loader from loading primitive class */
288 if (!classcache_store_unique(c)) {
289 log_text("Could not cache primitive class");
295 primitivetype_table[i].class_primitive = c;
297 /* create class for wrapping the primitive type */
299 u = utf_new_char(primitivetype_table[i].wrapname);
301 if (!(c = load_class_bootstrap(u)))
304 primitivetype_table[i].class_wrap = c;
305 primitivetype_table[i].class_wrap->classUsed = NOTUSED; /* not used initially CO-RT */
306 primitivetype_table[i].class_wrap->impldBy = NULL;
308 /* create the primitive array class */
310 if (primitivetype_table[i].arrayname) {
311 u = utf_new_char(primitivetype_table[i].arrayname);
312 c = class_create_classinfo(u);
313 c = load_newly_created_array(c, NULL);
317 primitivetype_table[i].arrayclass = c;
324 primitivetype_table[i].arrayvftbl = c->vftbl;
332 /* link_class ******************************************************************
334 Wrapper function for link_class_intern to ease monitor enter/exit
335 and exception handling.
337 *******************************************************************************/
339 classinfo *link_class(classinfo *c)
344 *exceptionptr = new_nullpointerexception();
348 #if defined(USE_THREADS)
349 /* enter a monitor on the class */
351 builtin_monitorenter((java_objectheader *) c);
354 /* maybe the class is already linked */
356 #if defined(USE_THREADS)
357 builtin_monitorexit((java_objectheader *) c);
363 #if defined(STATISTICS)
366 if (getcompilingtime)
367 compilingtime_stop();
373 /* call the internal function */
375 r = link_class_intern(c);
377 /* if return value is NULL, we had a problem and the class is not linked */
382 #if defined(STATISTICS)
388 if (getcompilingtime)
389 compilingtime_start();
392 #if defined(USE_THREADS)
393 /* leave the monitor */
395 builtin_monitorexit((java_objectheader *) c);
402 /* link_class_intern ***********************************************************
404 Tries to link a class. The function calculates the length in bytes
405 that an instance of this class requires as well as the VTBL for
406 methods and interface methods.
408 *******************************************************************************/
410 static classinfo *link_class_intern(classinfo *c)
412 classinfo *super; /* super class */
413 classinfo *tc; /* temporary class variable */
414 s4 supervftbllength; /* vftbllegnth of super class */
415 s4 vftbllength; /* vftbllength of current class */
416 s4 interfacetablelength; /* interface table length */
417 vftbl_t *v; /* vftbl of current class */
418 s4 i,j; /* interface/method/field counter */
419 arraydescriptor *arraydesc; /* descriptor for array classes */
421 /* maybe the class is already linked */
427 log_message_class("Linking class: ", c);
429 /* the class must be loaded */
432 throw_cacao_exception_exit(string_java_lang_InternalError,
433 "Trying to link unloaded class");
435 /* ok, this class is somewhat linked */
441 /* check interfaces */
443 for (i = 0; i < c->interfacescount; i++) {
444 /* resolve this super interface */
446 if (!resolve_classref_or_classinfo(NULL, c->interfaces[i], resolveEager,
450 c->interfaces[i].cls = tc;
452 /* detect circularity */
456 new_exception_utfmessage(string_java_lang_ClassCircularityError,
463 if (!(tc->flags & ACC_INTERFACE)) {
465 new_exception_message(string_java_lang_IncompatibleClassChangeError,
466 "Implementing class");
475 /* check super class */
479 if (c->super.any == NULL) { /* class java.lang.Object */
481 c->classUsed = USED; /* Object class is always used CO-RT*/
483 c->instancesize = sizeof(java_objectheader);
485 vftbllength = supervftbllength = 0;
490 /* resolve super class */
492 if (!resolve_classref_or_classinfo(NULL, c->super, resolveEager, true, false,
495 c->super.cls = super;
497 /* detect circularity */
501 new_exception_utfmessage(string_java_lang_ClassCircularityError,
506 assert(super->loaded);
508 if (super->flags & ACC_INTERFACE) {
509 /* java.lang.IncompatibleClassChangeError: class a has interface java.lang.Cloneable as super class */
510 log_text("Interface specified as super class");
514 /* Don't allow extending final classes */
516 if (super->flags & ACC_FINAL) {
518 new_exception_message(string_java_lang_VerifyError,
519 "Cannot inherit from final class");
524 if (!link_class(super))
527 /* handle array classes */
529 if (c->name->text[0] == '[')
530 if (!(arraydesc = link_array(c)))
533 if (c->flags & ACC_INTERFACE)
534 c->index = interfaceindex++;
536 c->index = super->index + 1;
538 c->instancesize = super->instancesize;
540 vftbllength = supervftbllength = super->vftbl->vftbllength;
542 c->finalizer = super->finalizer;
546 /* compute vftbl length */
548 for (i = 0; i < c->methodscount; i++) {
549 methodinfo *m = &(c->methods[i]);
551 if (!(m->flags & ACC_STATIC)) { /* is instance method */
557 for (j = 0; j < tc->methodscount; j++) {
558 if (method_canoverwrite(m, &(tc->methods[j]))) {
559 if (tc->methods[j].flags & ACC_PRIVATE)
560 goto notfoundvftblindex;
562 if (tc->methods[j].flags & ACC_FINAL) {
563 /* class a overrides final method . */
565 new_exception(string_java_lang_VerifyError);
569 m->vftblindex = tc->methods[j].vftblindex;
570 goto foundvftblindex;
578 m->vftblindex = (vftbllength++);
585 /* check interfaces of ABSTRACT class for unimplemented methods */
587 if (c->flags & ACC_ABSTRACT) {
590 s4 abstractmethodscount;
594 abstractmethodscount = 0;
596 for (i = 0; i < c->interfacescount; i++) {
597 ic = c->interfaces[i].cls;
599 for (j = 0; j < ic->methodscount; j++) {
600 im = &(ic->methods[j]);
602 /* skip `<clinit>' and `<init>' */
604 if (im->name == utf_clinit || im->name == utf_init)
610 for (k = 0; k < tc->methodscount; k++) {
611 if (method_canoverwrite(im, &(tc->methods[k])))
612 goto noabstractmethod;
618 abstractmethodscount++;
625 if (abstractmethodscount > 0) {
628 /* reallocate methods memory */
630 c->methods = MREALLOC(c->methods, methodinfo, c->methodscount,
631 c->methodscount + abstractmethodscount);
633 for (i = 0; i < c->interfacescount; i++) {
634 ic = c->interfaces[i].cls;
636 for (j = 0; j < ic->methodscount; j++) {
637 im = &(ic->methods[j]);
639 /* skip `<clinit>' and `<init>' */
641 if (im->name == utf_clinit || im->name == utf_init)
647 for (k = 0; k < tc->methodscount; k++) {
648 if (method_canoverwrite(im, &(tc->methods[k])))
649 goto noabstractmethod2;
655 am = &(c->methods[c->methodscount]);
658 MCOPY(am, im, methodinfo, 1);
660 am->vftblindex = (vftbllength++);
671 #if defined(STATISTICS)
674 sizeof(vftbl_t) + (sizeof(methodptr) * (vftbllength - 1));
677 /* compute interfacetable length */
679 interfacetablelength = 0;
682 for (i = 0; i < tc->interfacescount; i++) {
683 s4 h = class_highestinterface(tc->interfaces[i].cls) + 1;
684 if (h > interfacetablelength)
685 interfacetablelength = h;
690 /* allocate virtual function table */
692 v = (vftbl_t *) mem_alloc(sizeof(vftbl_t) +
693 sizeof(methodptr) * (vftbllength - 1) +
694 sizeof(methodptr*) * (interfacetablelength - (interfacetablelength > 0)));
695 v = (vftbl_t *) (((methodptr *) v) +
696 (interfacetablelength - 1) * (interfacetablelength > 1));
697 c->header.vftbl = c->vftbl = v;
699 v->vftbllength = vftbllength;
700 v->interfacetablelength = interfacetablelength;
701 v->arraydesc = arraydesc;
703 /* store interface index in vftbl */
705 if (c->flags & ACC_INTERFACE)
706 v->baseval = -(c->index);
708 /* copy virtual function table of super class */
710 for (i = 0; i < supervftbllength; i++)
711 v->table[i] = super->vftbl->table[i];
713 /* add method stubs into virtual function table */
715 for (i = 0; i < c->methodscount; i++) {
716 methodinfo *m = &(c->methods[i]);
718 /* Methods in ABSTRACT classes from interfaces maybe already have a */
721 if (!m->stubroutine) {
722 if (!(m->flags & ACC_NATIVE)) {
723 m->stubroutine = createcompilerstub(m);
726 functionptr f = NULL;
728 #if defined(ENABLE_STATICVM)
729 f = native_findfunction(c->name, m->name, m->descriptor,
730 (m->flags & ACC_STATIC));
735 m->stubroutine = codegen_createnativestub(f, m);
739 if (!(m->flags & ACC_STATIC))
740 v->table[m->vftblindex] = (methodptr) (ptrint) m->stubroutine;
743 /* compute instance size and offset of each field */
745 for (i = 0; i < c->fieldscount; i++) {
747 fieldinfo *f = &(c->fields[i]);
749 if (!(f->flags & ACC_STATIC)) {
750 dsize = desc_typesize(f->descriptor);
751 c->instancesize = ALIGN(c->instancesize, dsize);
752 f->offset = c->instancesize;
753 c->instancesize += dsize;
757 /* initialize interfacetable and interfacevftbllength */
759 v->interfacevftbllength = MNEW(s4, interfacetablelength);
761 #if defined(STATISTICS)
763 count_vftbl_len += (4 + sizeof(s4)) * v->interfacetablelength;
766 for (i = 0; i < interfacetablelength; i++) {
767 v->interfacevftbllength[i] = 0;
768 v->interfacetable[-i] = NULL;
773 for (tc = c; tc != NULL; tc = tc->super.cls)
774 for (i = 0; i < tc->interfacescount; i++)
775 linker_addinterface(c, tc->interfaces[i].cls);
777 /* add finalizer method (not for java.lang.Object) */
782 fi = class_findmethod(c, utf_finalize, utf_void__void);
785 if (!(fi->flags & ACC_STATIC))
789 /* resolve exception class references */
791 for (i = 0; i < c->methodscount; i++) {
792 methodinfo *m = &(c->methods[i]);
794 for (j = 0; j < m->exceptiontablelength; j++) {
795 if (!m->exceptiontable[j].catchtype.any)
797 if (!resolve_classref_or_classinfo(NULL,
798 m->exceptiontable[j].catchtype,
799 resolveEager, true, false,
800 &(m->exceptiontable[j].catchtype.cls)))
804 for (j = 0; j < m->thrownexceptionscount; j++)
805 if (!resolve_classref_or_classinfo(NULL, m->thrownexceptions[j],
806 resolveEager, true, false,
807 &(m->thrownexceptions[j].cls)))
813 linker_compute_subclasses(c);
816 log_message_class("Linking done class: ", c);
818 /* just return c to show that we didn't had a problem */
824 /* link_array ******************************************************************
826 This function is called by link_class to create the arraydescriptor
829 This function returns NULL if the array cannot be linked because
830 the component type has not been linked yet.
832 *******************************************************************************/
834 static arraydescriptor *link_array(classinfo *c)
838 arraydescriptor *desc;
843 namelen = c->name->blength;
845 /* Check the component type */
847 switch (c->name->text[1]) {
849 /* c is an array of arrays. */
850 u = utf_new_intern(c->name->text + 1, namelen - 1);
851 if (!(comp = load_class_from_classloader(u, c->classloader)))
856 /* c is an array of objects. */
857 u = utf_new_intern(c->name->text + 2, namelen - 3);
858 if (!(comp = load_class_from_classloader(u, c->classloader)))
863 /* If the component type has not been linked, link it now */
864 assert(!comp || comp->loaded);
865 if (comp && !comp->linked) {
867 if (!link_class(comp))
871 /* Allocate the arraydescriptor */
872 desc = NEW(arraydescriptor);
875 /* c is an array of references */
876 desc->arraytype = ARRAYTYPE_OBJECT;
877 desc->componentsize = sizeof(void*);
878 desc->dataoffset = OFFSET(java_objectarray, data);
880 compvftbl = comp->vftbl;
883 log_text("Component class has no vftbl");
887 desc->componentvftbl = compvftbl;
889 if (compvftbl->arraydesc) {
890 desc->elementvftbl = compvftbl->arraydesc->elementvftbl;
892 if (compvftbl->arraydesc->dimension >= 255) {
893 log_text("Creating array of dimension >255");
897 desc->dimension = compvftbl->arraydesc->dimension + 1;
898 desc->elementtype = compvftbl->arraydesc->elementtype;
901 desc->elementvftbl = compvftbl;
903 desc->elementtype = ARRAYTYPE_OBJECT;
907 /* c is an array of a primitive type */
908 switch (c->name->text[1]) {
910 desc->arraytype = ARRAYTYPE_BOOLEAN;
911 desc->dataoffset = OFFSET(java_booleanarray,data);
912 desc->componentsize = sizeof(u1);
916 desc->arraytype = ARRAYTYPE_BYTE;
917 desc->dataoffset = OFFSET(java_bytearray,data);
918 desc->componentsize = sizeof(u1);
922 desc->arraytype = ARRAYTYPE_CHAR;
923 desc->dataoffset = OFFSET(java_chararray,data);
924 desc->componentsize = sizeof(u2);
928 desc->arraytype = ARRAYTYPE_DOUBLE;
929 desc->dataoffset = OFFSET(java_doublearray,data);
930 desc->componentsize = sizeof(double);
934 desc->arraytype = ARRAYTYPE_FLOAT;
935 desc->dataoffset = OFFSET(java_floatarray,data);
936 desc->componentsize = sizeof(float);
940 desc->arraytype = ARRAYTYPE_INT;
941 desc->dataoffset = OFFSET(java_intarray,data);
942 desc->componentsize = sizeof(s4);
946 desc->arraytype = ARRAYTYPE_LONG;
947 desc->dataoffset = OFFSET(java_longarray,data);
948 desc->componentsize = sizeof(s8);
952 desc->arraytype = ARRAYTYPE_SHORT;
953 desc->dataoffset = OFFSET(java_shortarray,data);
954 desc->componentsize = sizeof(s2);
958 log_text("Invalid array class name");
962 desc->componentvftbl = NULL;
963 desc->elementvftbl = NULL;
965 desc->elementtype = desc->arraytype;
972 /* linker_compute_subclasses ***************************************************
976 *******************************************************************************/
978 static void linker_compute_subclasses(classinfo *c)
980 #if defined(USE_THREADS)
981 #if defined(NATIVE_THREADS)
988 if (!(c->flags & ACC_INTERFACE)) {
993 if (!(c->flags & ACC_INTERFACE) && (c->super.any != NULL)) {
994 c->nextsub = c->super.cls->sub;
995 c->super.cls->sub = c;
1000 /* compute class values */
1002 linker_compute_class_values(class_java_lang_Object);
1004 #if defined(USE_THREADS)
1005 #if defined(NATIVE_THREADS)
1014 /* linker_compute_class_values *************************************************
1018 *******************************************************************************/
1020 static void linker_compute_class_values(classinfo *c)
1024 c->vftbl->baseval = ++classvalue;
1029 linker_compute_class_values(subs);
1031 subs = subs->nextsub;
1034 c->vftbl->diffval = classvalue - c->vftbl->baseval;
1038 /* linker_addinterface *********************************************************
1040 Is needed by link_class for adding a VTBL to a class. All
1041 interfaces implemented by ic are added as well.
1043 *******************************************************************************/
1045 static void linker_addinterface(classinfo *c, classinfo *ic)
1049 vftbl_t *v = c->vftbl;
1051 if (i >= v->interfacetablelength) {
1052 log_text("Inernal error: interfacetable overflow");
1056 if (v->interfacetable[-i])
1059 if (ic->methodscount == 0) { /* fake entry needed for subtype test */
1060 v->interfacevftbllength[i] = 1;
1061 v->interfacetable[-i] = MNEW(methodptr, 1);
1062 v->interfacetable[-i][0] = NULL;
1065 v->interfacevftbllength[i] = ic->methodscount;
1066 v->interfacetable[-i] = MNEW(methodptr, ic->methodscount);
1068 #if defined(STATISTICS)
1070 count_vftbl_len += sizeof(methodptr) *
1071 (ic->methodscount + (ic->methodscount == 0));
1074 for (j = 0; j < ic->methodscount; j++) {
1078 for (m = 0; m < sc->methodscount; m++) {
1079 methodinfo *mi = &(sc->methods[m]);
1081 if (method_canoverwrite(mi, &(ic->methods[j]))) {
1082 v->interfacetable[-i][j] = v->table[mi->vftblindex];
1093 for (j = 0; j < ic->interfacescount; j++)
1094 linker_addinterface(c, ic->interfaces[j].cls);
1098 /* class_highestinterface ******************************************************
1100 Used by the function link_class to determine the amount of memory
1101 needed for the interface table.
1103 *******************************************************************************/
1105 static s4 class_highestinterface(classinfo *c)
1111 /* check for ACC_INTERFACE bit already done in link_class_intern */
1115 for (i = 0; i < c->interfacescount; i++) {
1116 h2 = class_highestinterface(c->interfaces[i].cls);
1127 * These are local overrides for various environment variables in Emacs.
1128 * Please do not remove this and leave it at the end of the file, where
1129 * Emacs will automagically detect them.
1130 * ---------------------------------------------------------------------
1133 * indent-tabs-mode: t