X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Flinker.c;h=bb2a8e13963383db1c0fd9ca036474a019f79c5c;hb=a74e124b11bdb08cd3e932f2878cc9bd13df701e;hp=2ba7652baefbbeb81a3936b1c38146c9de763cd3;hpb=96eba2648769bd09f17f81007e848bf09fd45d65;p=cacao.git diff --git a/src/vm/linker.c b/src/vm/linker.c index 2ba7652ba..bb2a8e139 100644 --- a/src/vm/linker.c +++ b/src/vm/linker.c @@ -1,9 +1,9 @@ /* src/vm/linker.c - class linker functions - Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates, - R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, - C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, - Institut f. Computersprachen - TU Wien + Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien This file is part of CACAO. @@ -19,10 +19,10 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. - Contact: cacao@complang.tuwien.ac.at + Contact: cacao@cacaojvm.org Authors: Reinhard Grafl @@ -32,20 +32,29 @@ Edwin Steiner Christian Thalinger - $Id: linker.c 2186 2005-04-02 00:43:25Z edwin $ + $Id: linker.c 4551 2006-03-03 00:00:39Z twisti $ */ +#include "config.h" + +#include + +#include "vm/types.h" + #include "mm/memory.h" #include "native/native.h" #include "vm/builtin.h" #include "vm/class.h" +#include "vm/classcache.h" #include "vm/exceptions.h" #include "vm/loader.h" #include "vm/options.h" +#include "vm/resolve.h" #include "vm/statistics.h" -#include "vm/jit/codegen.inc.h" +#include "vm/stringlocal.h" +#include "vm/access.h" /* global variables ***********************************************************/ @@ -62,7 +71,7 @@ static s4 classvalue; primitive class. CAUTION: Don't change the order of the types. This table is indexed - by the ARRAYTYPE_ constants (expcept ARRAYTYPE_OBJECT). + by the ARRAYTYPE_ constants (except ARRAYTYPE_OBJECT). *******************************************************************************/ @@ -104,6 +113,19 @@ bool linker_init(void) interfaceindex = 0; + /* link java.lang.Class as first class of the system, because we + need it's vftbl for all other classes so we can use a class as + object */ + + if (!link_class(class_java_lang_Class)) + return false; + + /* now set the header.vftbl of all classes which were created + before java.lang.Class was linked */ + + class_postset_header_vftbl(); + + /* link important system classes */ if (!link_class(class_java_lang_Object)) @@ -149,34 +171,97 @@ bool linker_init(void) return false; + /* load some other important classes */ + + if (!link_class(class_java_lang_ClassLoader)) + return false; + + if (!link_class(class_java_lang_SecurityManager)) + return false; + + if (!link_class(class_java_lang_System)) + return false; + + if (!link_class(class_java_lang_Thread)) + return false; + + if (!link_class(class_java_lang_ThreadGroup)) + return false; + + if (!link_class(class_java_lang_VMThread)) + return false; + + + /* some classes which may be used more often */ + + if (!link_class(class_java_lang_StackTraceElement)) + return false; + + if (!link_class(class_java_lang_reflect_Constructor)) + return false; + + if (!link_class(class_java_lang_reflect_Field)) + return false; + + if (!link_class(class_java_lang_reflect_Method)) + return false; + + if (!link_class(class_java_security_PrivilegedAction)) + return false; + + if (!link_class(class_java_util_Vector)) + return false; + + if (!link_class(arrayclass_java_lang_Object)) + return false; + + /* create pseudo classes used by the typechecker */ /* pseudo class for Arraystubs (extends java.lang.Object) */ - pseudo_class_Arraystub->loaded = true; - pseudo_class_Arraystub->super.cls = class_java_lang_Object; - pseudo_class_Arraystub->interfacescount = 2; - pseudo_class_Arraystub->interfaces = MNEW(classref_or_classinfo, 2); - pseudo_class_Arraystub->interfaces[0].cls = class_java_lang_Cloneable; - pseudo_class_Arraystub->interfaces[1].cls = class_java_io_Serializable; - - if (!link_class(pseudo_class_Arraystub)) + pseudo_class_Arraystub = + class_create_classinfo(utf_new_char("$ARRAYSTUB$")); + pseudo_class_Arraystub->state |= CLASS_LOADED; + pseudo_class_Arraystub->super.cls = class_java_lang_Object; + pseudo_class_Arraystub->interfacescount = 2; + pseudo_class_Arraystub->interfaces = MNEW(classref_or_classinfo, 2); + pseudo_class_Arraystub->interfaces[0].cls = class_java_lang_Cloneable; + pseudo_class_Arraystub->interfaces[1].cls = class_java_io_Serializable; + + if (!classcache_store_unique(pseudo_class_Arraystub)) { + log_text("could not cache pseudo_class_Arraystub"); + assert(0); + } + + if (!link_class(pseudo_class_Arraystub)) return false; - /* pseudo class representing the null type */ - - pseudo_class_Null->loaded = true; - pseudo_class_Null->super.cls = class_java_lang_Object; + /* pseudo class representing the null type */ + + pseudo_class_Null = class_create_classinfo(utf_new_char("$NULL$")); + pseudo_class_Null->state |= CLASS_LOADED; + pseudo_class_Null->super.cls = class_java_lang_Object; + + if (!classcache_store_unique(pseudo_class_Null)) { + log_text("could not cache pseudo_class_Null"); + assert(0); + } if (!link_class(pseudo_class_Null)) return false; - /* pseudo class representing new uninitialized objects */ + /* pseudo class representing new uninitialized objects */ - pseudo_class_New->loaded = true; - pseudo_class_New->linked = true; /* XXX is this allright? */ + pseudo_class_New = class_create_classinfo(utf_new_char("$NEW$")); + pseudo_class_New->state |= CLASS_LOADED; + pseudo_class_New->state |= CLASS_LINKED; /* XXX is this allright? */ pseudo_class_New->super.cls = class_java_lang_Object; + if (!classcache_store_unique(pseudo_class_New)) { + log_text("could not cache pseudo_class_New"); + assert(0); + } /* create classes representing primitive types */ @@ -202,39 +287,58 @@ bool linker_init(void) static bool link_primitivetype_table(void) { classinfo *c; - s4 i; + utf *u; + s4 i; for (i = 0; i < PRIMITIVETYPE_COUNT; i++) { /* skip dummies */ + if (!primitivetype_table[i].name) continue; /* create primitive class */ - c = class_new_intern(utf_new_char(primitivetype_table[i].name)); - c->classUsed = NOTUSED; /* not used initially CO-RT */ - c->impldBy = NULL; + + c = class_create_classinfo(utf_new_char(primitivetype_table[i].name)); + + c->flags = ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT; /* prevent loader from loading primitive class */ - c->loaded = true; + + c->state |= CLASS_LOADED; + + /* INFO: don't put primitive classes into the classcache */ + if (!link_class(c)) return false; primitivetype_table[i].class_primitive = c; /* create class for wrapping the primitive type */ - c = class_new_intern(utf_new_char(primitivetype_table[i].wrapname)); + + u = utf_new_char(primitivetype_table[i].wrapname); + + if (!(c = load_class_bootstrap(u))) + return false; + primitivetype_table[i].class_wrap = c; - primitivetype_table[i].class_wrap->classUsed = NOTUSED; /* not used initially CO-RT */ - primitivetype_table[i].class_wrap->impldBy = NULL; /* create the primitive array class */ + if (primitivetype_table[i].arrayname) { - c = class_new_intern(utf_new_char(primitivetype_table[i].arrayname)); + u = utf_new_char(primitivetype_table[i].arrayname); + c = class_create_classinfo(u); + c = load_newly_created_array(c, NULL); + if (c == NULL) + return false; + primitivetype_table[i].arrayclass = c; - c->loaded = true; - if (!c->linked) + + assert(c->state & CLASS_LOADED); + + if (!(c->state & CLASS_LINKED)) if (!link_class(c)) return false; + primitivetype_table[i].arrayvftbl = c->vftbl; } } @@ -254,6 +358,11 @@ classinfo *link_class(classinfo *c) { classinfo *r; + if (!c) { + exceptions_throw_nullpointerexception(); + return NULL; + } + #if defined(USE_THREADS) /* enter a monitor on the class */ @@ -261,7 +370,8 @@ classinfo *link_class(classinfo *c) #endif /* maybe the class is already linked */ - if (c->linked) { + + if (c->state & CLASS_LINKED) { #if defined(USE_THREADS) builtin_monitorexit((java_objectheader *) c); #endif @@ -269,7 +379,7 @@ classinfo *link_class(classinfo *c) return c; } -#if defined(STATISTICS) +#if defined(ENABLE_STATISTICS) /* measure time */ if (getcompilingtime) @@ -280,13 +390,15 @@ classinfo *link_class(classinfo *c) #endif /* call the internal function */ + r = link_class_intern(c); /* if return value is NULL, we had a problem and the class is not linked */ + if (!r) - c->linked = false; + c->state &= ~CLASS_LINKING; -#if defined(STATISTICS) +#if defined(ENABLE_STATISTICS) /* measure time */ if (getloadingtime) @@ -322,31 +434,49 @@ static classinfo *link_class_intern(classinfo *c) s4 vftbllength; /* vftbllength of current class */ s4 interfacetablelength; /* interface table length */ vftbl_t *v; /* vftbl of current class */ - s4 i; /* interface/method/field counter */ + s4 i,j; /* interface/method/field counter */ arraydescriptor *arraydesc; /* descriptor for array classes */ - /* maybe the class is already linked */ - if (c->linked) - return c; + /* the class is already linked */ - /* the class must be loaded */ - if (!c->loaded) - throw_cacao_exception_exit(string_java_lang_InternalError, - "Trying to link unloaded class"); + if (c->state & CLASS_LINKED) + return c; if (linkverbose) log_message_class("Linking class: ", c); - /* ok, this class is somewhat linked */ - c->linked = true; + /* the class must be loaded */ + + /* XXX should this be a specific exception? */ + assert(c->state & CLASS_LOADED); + + /* cache the self-reference of this class */ + /* we do this for cases where the defining loader of the class */ + /* has not yet been recorded as an initiating loader for the class */ + /* this is needed so subsequent code can assume that self-refs */ + /* will always resolve lazily */ + /* No need to do it for the bootloader - it is always registered */ + /* as initiating loader for the classes it loads. */ + if (c->classloader) + classcache_store(c->classloader,c,false); + + /* this class is currently linking */ + + c->state |= CLASS_LINKING; arraydesc = NULL; /* check interfaces */ for (i = 0; i < c->interfacescount; i++) { - tc = c->interfaces[i].cls; + /* resolve this super interface */ + if (!resolve_classref_or_classinfo(NULL, c->interfaces[i], resolveEager, + true, false, &tc)) + return NULL; + + c->interfaces[i].cls = tc; + /* detect circularity */ if (tc == c) { @@ -356,9 +486,7 @@ static classinfo *link_class_intern(classinfo *c) return NULL; } - if (!tc->loaded) - if (!load_class_from_classloader(tc, c->classloader)) - return NULL; + assert(tc->state & CLASS_LOADED); if (!(tc->flags & ACC_INTERFACE)) { *exceptionptr = @@ -367,19 +495,17 @@ static classinfo *link_class_intern(classinfo *c) return NULL; } - if (!tc->linked) + if (!(tc->state & CLASS_LINKED)) if (!link_class(tc)) return NULL; } /* check super class */ - super = c->super.cls; + super = NULL; - if (super == NULL) { /* class java.lang.Object */ + if (c->super.any == NULL) { /* class java.lang.Object */ c->index = 0; - c->classUsed = USED; /* Object class is always used CO-RT*/ - c->impldBy = NULL; c->instancesize = sizeof(java_objectheader); vftbllength = supervftbllength = 0; @@ -387,7 +513,15 @@ static classinfo *link_class_intern(classinfo *c) c->finalizer = NULL; } else { + /* resolve super class */ + + if (!resolve_classref_or_classinfo(NULL, c->super, resolveEager, true, false, + &super)) + return NULL; + c->super.cls = super; + /* detect circularity */ + if (super == c) { *exceptionptr = new_exception_utfmessage(string_java_lang_ClassCircularityError, @@ -395,16 +529,16 @@ static classinfo *link_class_intern(classinfo *c) return NULL; } - if (!super->loaded) - if (!load_class_from_classloader(super, c->classloader)) - return NULL; + assert(super->state & CLASS_LOADED); if (super->flags & ACC_INTERFACE) { /* java.lang.IncompatibleClassChangeError: class a has interface java.lang.Cloneable as super class */ - panic("Interface specified as super class"); + log_text("Interface specified as super class"); + assert(0); } /* Don't allow extending final classes */ + if (super->flags & ACC_FINAL) { *exceptionptr = new_exception_message(string_java_lang_VerifyError, @@ -412,11 +546,12 @@ static classinfo *link_class_intern(classinfo *c) return NULL; } - if (!super->linked) + if (!(super->state & CLASS_LINKED)) if (!link_class(super)) return NULL; /* handle array classes */ + if (c->name->text[0] == '[') if (!(arraydesc = link_array(c))) return NULL; @@ -450,6 +585,15 @@ static classinfo *link_class_intern(classinfo *c) if (tc->methods[j].flags & ACC_PRIVATE) goto notfoundvftblindex; + /* package-private methods in other packages */ + /* must not be overridden */ + /* (see Java Language Specification 8.4.8.1) */ + if ( !(tc->methods[j].flags & (ACC_PUBLIC | ACC_PROTECTED)) + && !SAME_PACKAGE(c,tc) ) + { + goto notfoundvftblindex; + } + if (tc->methods[j].flags & ACC_FINAL) { /* class a overrides final method . */ *exceptionptr = @@ -473,7 +617,10 @@ static classinfo *link_class_intern(classinfo *c) } - /* check interfaces of ABSTRACT class for unimplemented methods */ + /* Check all interfaces of an abtract class (maybe be an interface + too) for unimplemented methods. Such methods are called + miranda-methods and are marked with the ACC_MIRANDA flag. + VMClass.getDeclaredMethods does not return such methods. */ if (c->flags & ACC_ABSTRACT) { classinfo *ic; @@ -484,6 +631,8 @@ static classinfo *link_class_intern(classinfo *c) abstractmethodscount = 0; + /* check all interfaces of the abtract class */ + for (i = 0; i < c->interfacescount; i++) { ic = c->interfaces[i].cls; @@ -492,18 +641,14 @@ static classinfo *link_class_intern(classinfo *c) /* skip `' and `' */ - if (im->name == utf_clinit || im->name == utf_init) + if ((im->name == utf_clinit) || (im->name == utf_init)) continue; - tc = c; - - while (tc) { + for (tc = c; tc != NULL; tc = tc->super.cls) { for (k = 0; k < tc->methodscount; k++) { if (method_canoverwrite(im, &(tc->methods[k]))) goto noabstractmethod; } - - tc = tc->super.cls; } abstractmethodscount++; @@ -529,27 +674,27 @@ static classinfo *link_class_intern(classinfo *c) /* skip `' and `' */ - if (im->name == utf_clinit || im->name == utf_init) + if ((im->name == utf_clinit) || (im->name == utf_init)) continue; - tc = c; - - while (tc) { + for (tc = c; tc != NULL; tc = tc->super.cls) { for (k = 0; k < tc->methodscount; k++) { if (method_canoverwrite(im, &(tc->methods[k]))) goto noabstractmethod2; } - - tc = tc->super.cls; } + /* Copy the method found into the new c->methods + array and tag it as miranda-method. */ + am = &(c->methods[c->methodscount]); c->methodscount++; MCOPY(am, im, methodinfo, 1); - am->vftblindex = (vftbllength++); - am->class = c; + am->vftblindex = (vftbllength++); + am->class = c; + am->flags |= ACC_MIRANDA; noabstractmethod2: ; @@ -559,7 +704,7 @@ static classinfo *link_class_intern(classinfo *c) } -#if defined(STATISTICS) +#if defined(ENABLE_STATISTICS) if (opt_stat) count_vftbl_len += sizeof(vftbl_t) + (sizeof(methodptr) * (vftbllength - 1)); @@ -585,7 +730,7 @@ static classinfo *link_class_intern(classinfo *c) sizeof(methodptr*) * (interfacetablelength - (interfacetablelength > 0))); v = (vftbl_t *) (((methodptr *) v) + (interfacetablelength - 1) * (interfacetablelength > 1)); - c->header.vftbl = c->vftbl = v; + c->vftbl = v; v->class = c; v->vftbllength = vftbllength; v->interfacetablelength = interfacetablelength; @@ -606,27 +751,24 @@ static classinfo *link_class_intern(classinfo *c) for (i = 0; i < c->methodscount; i++) { methodinfo *m = &(c->methods[i]); - /* Methods in ABSTRACT classes from interfaces maybe already have a */ - /* stubroutine. */ + /* Methods in ABSTRACT classes from interfaces maybe already + have a stubroutine. */ if (!m->stubroutine) { - if (!(m->flags & ACC_NATIVE)) { +#if defined(ENABLE_JIT) +# if defined(ENABLE_INTRP) + if (opt_intrp) + m->stubroutine = intrp_createcompilerstub(m); + else +#endif m->stubroutine = createcompilerstub(m); - - } else { - functionptr f = native_findfunction(c->name, - m->name, - m->descriptor, - (m->flags & ACC_STATIC)); -#if defined(STATIC_CLASSPATH) - if (f) +#else + m->stubroutine = intrp_createcompilerstub(m); #endif - m->stubroutine = createnativestub(f, m); - } } if (!(m->flags & ACC_STATIC)) - v->table[m->vftblindex] = m->stubroutine; + v->table[m->vftblindex] = (methodptr) (ptrint) m->stubroutine; } /* compute instance size and offset of each field */ @@ -636,7 +778,7 @@ static classinfo *link_class_intern(classinfo *c) fieldinfo *f = &(c->fields[i]); if (!(f->flags & ACC_STATIC)) { - dsize = desc_typesize(f->descriptor); + dsize = descriptor_typesize(f->parseddesc); c->instancesize = ALIGN(c->instancesize, dsize); f->offset = c->instancesize; c->instancesize += dsize; @@ -647,7 +789,7 @@ static classinfo *link_class_intern(classinfo *c) v->interfacevftbllength = MNEW(s4, interfacetablelength); -#if defined(STATISTICS) +#if defined(ENABLE_STATISTICS) if (opt_stat) count_vftbl_len += (4 + sizeof(s4)) * v->interfacetablelength; #endif @@ -675,10 +817,30 @@ static classinfo *link_class_intern(classinfo *c) c->finalizer = fi; } + /* resolve exception class references */ + + for (i = 0; i < c->methodscount; i++) { + methodinfo *m = &(c->methods[i]); + + for (j = 0; j < m->exceptiontablelength; j++) { + if (!m->exceptiontable[j].catchtype.any) + continue; + if (!resolve_classref_or_classinfo(NULL, + m->exceptiontable[j].catchtype, + resolveEager, true, false, + &(m->exceptiontable[j].catchtype.cls))) + return NULL; + } + } + /* final tasks */ linker_compute_subclasses(c); + /* revert the linking state and class is linked */ + + c->state = (c->state & ~CLASS_LINKING) | CLASS_LINKED; + if (linkverbose) log_message_class("Linking done class: ", c); @@ -700,39 +862,43 @@ static classinfo *link_class_intern(classinfo *c) static arraydescriptor *link_array(classinfo *c) { - classinfo *comp = NULL; - s4 namelen = c->name->blength; + classinfo *comp; + s4 namelen; arraydescriptor *desc; - vftbl_t *compvftbl; + vftbl_t *compvftbl; + utf *u; + + comp = NULL; + namelen = c->name->blength; /* Check the component type */ + switch (c->name->text[1]) { case '[': /* c is an array of arrays. */ - comp = class_new(utf_new_intern(c->name->text + 1, namelen - 1)); - if (!comp) - panic("Could not find component array class."); + u = utf_new(c->name->text + 1, namelen - 1); + if (!(comp = load_class_from_classloader(u, c->classloader))) + return NULL; break; case 'L': /* c is an array of objects. */ - comp = class_new(utf_new_intern(c->name->text + 2, namelen - 3)); - if (!comp) - panic("Could not find component class."); + u = utf_new(c->name->text + 2, namelen - 3); + if (!(comp = load_class_from_classloader(u, c->classloader))) + return NULL; break; } /* If the component type has not been linked, link it now */ - if (comp && !comp->linked) { - if (!comp->loaded) - if (!load_class_from_classloader(comp, c->classloader)) - return NULL; + assert(!comp || (comp->state & CLASS_LOADED)); + + if (comp && !(comp->state & CLASS_LINKED)) if (!link_class(comp)) return NULL; - } /* Allocate the arraydescriptor */ + desc = NEW(arraydescriptor); if (comp) { @@ -742,14 +908,22 @@ static arraydescriptor *link_array(classinfo *c) desc->dataoffset = OFFSET(java_objectarray, data); compvftbl = comp->vftbl; - if (!compvftbl) - panic("Component class has no vftbl"); + + if (!compvftbl) { + log_text("Component class has no vftbl"); + assert(0); + } + desc->componentvftbl = compvftbl; if (compvftbl->arraydesc) { desc->elementvftbl = compvftbl->arraydesc->elementvftbl; - if (compvftbl->arraydesc->dimension >= 255) - panic("Creating array of dimension >255"); + + if (compvftbl->arraydesc->dimension >= 255) { + log_text("Creating array of dimension >255"); + assert(0); + } + desc->dimension = compvftbl->arraydesc->dimension + 1; desc->elementtype = compvftbl->arraydesc->elementtype; @@ -811,7 +985,8 @@ static arraydescriptor *link_array(classinfo *c) break; default: - panic("Invalid array class name"); + *exceptionptr = new_noclassdeffounderror(c->name); + return NULL; } desc->componentvftbl = NULL; @@ -852,14 +1027,9 @@ static void linker_compute_subclasses(classinfo *c) classvalue = 0; - /* this is the java.lang.Object special case */ + /* compute class values */ - if (!class_java_lang_Object) { - linker_compute_class_values(c); - - } else { - linker_compute_class_values(class_java_lang_Object); - } + linker_compute_class_values(class_java_lang_Object); #if defined(USE_THREADS) #if defined(NATIVE_THREADS) @@ -908,8 +1078,10 @@ static void linker_addinterface(classinfo *c, classinfo *ic) s4 i = ic->index; vftbl_t *v = c->vftbl; - if (i >= v->interfacetablelength) - panic ("Inernal error: interfacetable overflow"); + if (i >= v->interfacetablelength) { + log_text("Inernal error: interfacetable overflow"); + assert(0); + } if (v->interfacetable[-i]) return; @@ -923,7 +1095,7 @@ static void linker_addinterface(classinfo *c, classinfo *ic) v->interfacevftbllength[i] = ic->methodscount; v->interfacetable[-i] = MNEW(methodptr, ic->methodscount); -#if defined(STATISTICS) +#if defined(ENABLE_STATISTICS) if (opt_stat) count_vftbl_len += sizeof(methodptr) * (ic->methodscount + (ic->methodscount == 0)); @@ -981,43 +1153,6 @@ static s4 class_highestinterface(classinfo *c) } -/***************** Function: print_arraydescriptor **************************** - - Debug helper for displaying an arraydescriptor - -*******************************************************************************/ - -void print_arraydescriptor(FILE *file, arraydescriptor *desc) -{ - if (!desc) { - fprintf(file, ""); - return; - } - - fprintf(file, "{"); - if (desc->componentvftbl) { - if (desc->componentvftbl->class) - utf_fprint(file, desc->componentvftbl->class->name); - else - fprintf(file, ""); - } - else - fprintf(file, "0"); - - fprintf(file, ","); - if (desc->elementvftbl) { - if (desc->elementvftbl->class) - utf_fprint(file, desc->elementvftbl->class->name); - else - fprintf(file, ""); - } - else - fprintf(file, "0"); - fprintf(file, ",%d,%d,%d,%d}", desc->arraytype, desc->dimension, - desc->dataoffset, desc->componentsize); -} - - /* * These are local overrides for various environment variables in Emacs. * Please do not remove this and leave it at the end of the file, where @@ -1029,4 +1164,5 @@ void print_arraydescriptor(FILE *file, arraydescriptor *desc) * c-basic-offset: 4 * tab-width: 4 * End: + * vim:noexpandtab:sw=4:ts=4: */