* m4/classpath.m4: Renamed --with-classpath* options to
[cacao.git] / src / native / native.c
index f3ff12994111b0eae970b1c31eba996113485b5b..9a4cd343f55d984a39cd2b519d419967c23e6e34 100644 (file)
@@ -1,9 +1,7 @@
 /* src/native/native.c - table of native functions
 
-   Copyright (C) 1996-2005, 2006, 2007 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, 2007, 2008
+   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
 
    This file is part of CACAO.
 
@@ -22,8 +20,6 @@
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
 
-   $Id: native.c 7918 2007-05-20 20:42:18Z michi $
-
 */
 
 
 #include <assert.h>
 #include <ctype.h>
 
-#if !defined(WITH_STATIC_CLASSPATH)
+#if defined(ENABLE_LTDL) && defined(HAVE_LTDL_H)
 # include <ltdl.h>
 #endif
 
+#include <stdint.h>
+
 #include "vm/types.h"
 
 #include "mm/memory.h"
 #endif
 
 
-/* include table of native functions ******************************************/
-
-#if defined(WITH_STATIC_CLASSPATH)
-# include "native/nativetable.inc"
-#endif
-
-
-/* tables for methods *********************************************************/
-
-#if defined(WITH_STATIC_CLASSPATH)
-#define NATIVETABLESIZE  (sizeof(nativetable)/sizeof(struct nativeref))
-
-/* table for fast string comparison */
-static nativecompref nativecomptable[NATIVETABLESIZE];
-
-/* string comparsion table initialized */
-static bool nativecompdone = false;
-#endif
-
-
 /* global variables ***********************************************************/
 
 static avl_tree_t *tree_native_methods;
+
+#if defined(ENABLE_LTDL)
 static hashtable *hashtable_library;
+#endif
 
 
 /* prototypes *****************************************************************/
@@ -108,7 +89,9 @@ static s4 native_tree_native_methods_comparator(const void *treenode, const void
 
 bool native_init(void)
 {
-#if !defined(WITH_STATIC_CLASSPATH)
+       TRACESUBSYSTEMINITIALIZATION("native_init");
+
+#if defined(ENABLE_LTDL)
        /* initialize libltdl */
 
        if (lt_dlinit())
@@ -125,10 +108,6 @@ bool native_init(void)
 
        tree_native_methods = avl_create(&native_tree_native_methods_comparator);
 
-       /* register the intern native functions */
-
-       nativevm_init();
-
        /* everything's ok */
 
        return true;
@@ -185,7 +164,6 @@ static s4 native_tree_native_methods_comparator(const void *treenode, const void
 
 *******************************************************************************/
 
-#if !defined(WITH_STATIC_CLASSPATH)
 static utf *native_make_overloaded_function(utf *name, utf *descriptor)
 {
        char *newname;
@@ -193,12 +171,12 @@ static utf *native_make_overloaded_function(utf *name, utf *descriptor)
        char *utf_ptr;
        u2    c;
        s4    i;
-       s4    dumpsize;
        utf  *u;
+       int32_t dumpmarker;
 
        /* mark memory */
 
-       dumpsize = dump_size();
+       DMARKER;
 
        utf_ptr = descriptor->text;
        namelen = strlen(name->text) + strlen("__") + strlen("0");
@@ -290,7 +268,7 @@ static utf *native_make_overloaded_function(utf *name, utf *descriptor)
 
        /* release memory */
 
-       dump_release(dumpsize);
+       DRELEASE;
 
        return u;
 }
@@ -373,12 +351,12 @@ static utf *native_method_symbol(utf *classname, utf *methodname)
        char *utf_endptr;
        u2    c;
        u4    pos;
-       s4    dumpsize;
        utf  *u;
+       int32_t dumpmarker;
 
        /* mark memory */
 
-       dumpsize = dump_size();
+       DMARKER;
 
        /* Calculate length of native function name.  We multiply the
           class and method name length by 6 as this is the maxium
@@ -434,7 +412,7 @@ static utf *native_method_symbol(utf *classname, utf *methodname)
 
        /* release memory */
 
-       dump_release(dumpsize);
+       DRELEASE;
 
        return u;
 }
@@ -446,12 +424,13 @@ static utf *native_method_symbol(utf *classname, utf *methodname)
 
 *******************************************************************************/
 
-void native_method_register(utf *classname, JNINativeMethod *methods, s4 count)
+void native_method_register(utf *classname, const JNINativeMethod *methods,
+                                                       int32_t count)
 {
        native_methods_node_t *nmn;
        utf                   *name;
        utf                   *descriptor;
-       s4                     i;
+       int32_t                i;
 
        /* insert all methods passed */
 
@@ -496,7 +475,7 @@ static functionptr native_method_find(methodinfo *m)
 
        /* fill the temporary structure used for searching the tree */
 
-       tmpnmn.classname  = m->class->name;
+       tmpnmn.classname  = m->clazz->name;
        tmpnmn.name       = m->name;
        tmpnmn.descriptor = m->descriptor;
 
@@ -511,25 +490,190 @@ static functionptr native_method_find(methodinfo *m)
 }
 
 
+/* native_method_resolve *******************************************************
+
+   Resolves a native method, maybe from a dynamic library.
+
+   IN:
+       m ... methodinfo of the native Java method to resolve
+
+   RESULT:
+       pointer to the resolved method (symbol)
+
+*******************************************************************************/
+
+functionptr native_method_resolve(methodinfo *m)
+{
+       utf                            *name;
+       utf                            *newname;
+       functionptr                     f;
+#if defined(ENABLE_LTDL)
+       classloader_t                  *cl;
+       hashtable_library_loader_entry *le;
+       hashtable_library_name_entry   *ne;
+       u4                              key;    /* hashkey                        */
+       u4                              slot;   /* slot in hashtable              */
+#endif
+#if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
+       methodinfo                     *method_findNative;
+       java_handle_t                  *s;
+#endif
+
+       /* verbose output */
+
+       if (opt_verbosejni) {
+               printf("[Dynamic-linking native method ");
+               utf_display_printable_ascii_classname(m->clazz->name);
+               printf(".");
+               utf_display_printable_ascii(m->name);
+               printf(" ... ");
+       }
+
+       /* generate method symbol string */
+
+       name = native_method_symbol(m->clazz->name, m->name);
+
+       /* generate overloaded function (having the types in it's name)           */
+
+       newname = native_make_overloaded_function(name, m->descriptor);
+
+       /* check the library hash entries of the classloader of the
+          methods's class  */
+
+       f = NULL;
+
+#if defined(ENABLE_LTDL)
+       /* Get the classloader. */
+
+       cl = class_get_classloader(m->clazz);
+
+       /* normally addresses are aligned to 4, 8 or 16 bytes */
+
+       key  = ((u4) (ptrint) cl) >> 4;                       /* align to 16-byte */
+       slot = key & (hashtable_library->size - 1);
+       le   = hashtable_library->ptr[slot];
+
+       /* iterate through loaders in this hash slot */
+
+       while ((le != NULL) && (f == NULL)) {
+               /* iterate through names in this loader */
+
+               ne = le->namelink;
+                       
+               while ((ne != NULL) && (f == NULL)) {
+                       f = (functionptr) (ptrint) lt_dlsym(ne->handle, name->text);
+
+                       if (f == NULL)
+                               f = (functionptr) (ptrint) lt_dlsym(ne->handle, newname->text);
+
+                       ne = ne->hashlink;
+               }
+
+               le = le->hashlink;
+       }
+
+# if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
+       if (f == NULL) {
+               /* We can resolve the function directly from
+                  java.lang.ClassLoader as it's a static function. */
+               /* XXX should be done in native_init */
+
+               method_findNative =
+                       class_resolveclassmethod(class_java_lang_ClassLoader,
+                                                                        utf_findNative,
+                                                                        utf_java_lang_ClassLoader_java_lang_String__J,
+                                                                        class_java_lang_ClassLoader,
+                                                                        true);
+
+               if (method_findNative == NULL)
+                       return NULL;
+
+               /* try the normal name */
+
+               s = javastring_new(name);
+
+               f = (functionptr) (intptr_t) vm_call_method_long(method_findNative,
+                                                                                                                NULL, cl, s);
+
+               /* if not found, try the mangled name */
+
+               if (f == NULL) {
+                       s = javastring_new(newname);
+
+                       f = (functionptr) (intptr_t) vm_call_method_long(method_findNative,
+                                                                                                                        NULL, cl, s);
+               }
+       }
+# endif
+
+       if (f != NULL)
+               if (opt_verbosejni)
+                       printf("JNI ]\n");
+#endif
+
+       /* If not found, try to find the native function symbol in the
+          main program. */
+
+       if (f == NULL) {
+               f = native_method_find(m);
+
+               if (f != NULL)
+                       if (opt_verbosejni)
+                               printf("internal ]\n");
+       }
+
+#if defined(ENABLE_JVMTI)
+       /* fire Native Method Bind event */
+       if (jvmti) jvmti_NativeMethodBind(m, f, &f);
+#endif
+
+       /* no symbol found? throw exception */
+
+       if (f == NULL) {
+               if (opt_verbosejni)
+                       printf("failed ]\n");
+
+               exceptions_throw_unsatisfiedlinkerror(m->name);
+       }
+
+       return f;
+}
+
+
 /* native_library_open *********************************************************
 
    Open a native library with the given utf8 name.
 
+   IN:
+       filename ... filename of the library to open
+
+   RETURN:
+       handle of the opened library
+
 *******************************************************************************/
 
-#if !defined(WITH_STATIC_CLASSPATH)
+#if defined(ENABLE_LTDL)
 lt_dlhandle native_library_open(utf *filename)
 {
        lt_dlhandle handle;
 
+       if (opt_verbosejni) {
+               printf("[Loading native library ");
+               utf_display_printable_ascii(filename);
+               printf(" ... ");
+       }
+
        /* try to open the library */
 
        handle = lt_dlopen(filename->text);
 
        if (handle == NULL) {
+               if (opt_verbosejni)
+                       printf("failed ]\n");
+
                if (opt_verbose) {
                        log_start();
-                       log_print("native_library_load: lt_dlopen failed: ");
+                       log_print("native_library_open: lt_dlopen failed: ");
                        log_print(lt_dlerror());
                        log_finish();
                }
@@ -537,22 +681,59 @@ lt_dlhandle native_library_open(utf *filename)
                return NULL;
        }
 
+       if (opt_verbosejni)
+               printf("OK ]\n");
+
        return handle;
 }
 #endif
 
 
+/* native_library_close ********************************************************
+
+   Close the native library of the given handle.
+
+   IN:
+       handle ... handle of the open library
+
+*******************************************************************************/
+
+#if defined(ENABLE_LTDL)
+void native_library_close(lt_dlhandle handle)
+{
+       int result;
+
+       if (opt_verbosejni) {
+               printf("[Unloading native library ");
+/*             utf_display_printable_ascii(filename); */
+               printf(" ... ");
+       }
+
+       /* Close the library. */
+
+       result = lt_dlclose(handle);
+
+       if (result != 0) {
+               if (opt_verbose) {
+                       log_start();
+                       log_print("native_library_close: lt_dlclose failed: ");
+                       log_print(lt_dlerror());
+                       log_finish();
+               }
+       }
+}
+#endif
+
+
 /* native_library_add **********************************************************
 
    Adds an entry to the native library hashtable.
 
 *******************************************************************************/
 
-#if !defined(WITH_STATIC_CLASSPATH)
-void native_library_add(utf *filename, java_objectheader *loader,
-                                               lt_dlhandle handle)
+#if defined(ENABLE_LTDL)
+void native_library_add(utf *filename, classloader_t *loader, lt_dlhandle handle)
 {
-       hashtable_classloader_entry    *cle;
        hashtable_library_loader_entry *le;
        hashtable_library_name_entry   *ne; /* library name                       */
        u4   key;                           /* hashkey                            */
@@ -560,20 +741,16 @@ void native_library_add(utf *filename, java_objectheader *loader,
 
        LOCK_MONITOR_ENTER(hashtable_library->header);
 
-       /* insert loader into the classloader hashtable */
-
-       cle = loader_hashtable_classloader_add(loader);
-
        /* normally addresses are aligned to 4, 8 or 16 bytes */
 
-       key  = ((u4) (ptrint) cle) >> 4;        /* align to 16-byte boundaries    */
+       key  = ((u4) (ptrint) loader) >> 4;        /* align to 16-byte boundaries */
        slot = key & (hashtable_library->size - 1);
        le   = hashtable_library->ptr[slot];
 
        /* search external hash chain for the entry */
 
        while (le) {
-               if (le->cle == cle)
+               if (le->loader == loader)
                        break;
 
                le = le->hashlink;                  /* next element in external chain */
@@ -584,7 +761,7 @@ void native_library_add(utf *filename, java_objectheader *loader,
        if (le == NULL) {
                le = NEW(hashtable_library_loader_entry);
 
-               le->cle   = cle;
+               le->loader   = loader;
                le->namelink = NULL;
 
                /* insert entry into hashtable */
@@ -627,7 +804,7 @@ void native_library_add(utf *filename, java_objectheader *loader,
 
        LOCK_MONITOR_EXIT(hashtable_library->header);
 }
-#endif /* !defined(WITH_STATIC_CLASSPATH) */
+#endif
 
 
 /* native_library_find *********************************************************
@@ -636,33 +813,25 @@ void native_library_add(utf *filename, java_objectheader *loader,
 
 *******************************************************************************/
 
-#if !defined(WITH_STATIC_CLASSPATH)
+#if defined(ENABLE_LTDL)
 hashtable_library_name_entry *native_library_find(utf *filename,
-                                                                                                 java_objectheader *loader)
+                                                                                                 classloader_t *loader)
 {
-       hashtable_classloader_entry    *cle;
        hashtable_library_loader_entry *le;
        hashtable_library_name_entry   *ne; /* library name                       */
        u4   key;                           /* hashkey                            */
        u4   slot;                          /* slot in hashtable                  */
 
-       /* search loader in the classloader hashtable */
-
-       cle = loader_hashtable_classloader_find(loader);
-
-       if (!cle)
-               return NULL;
-
        /* normally addresses are aligned to 4, 8 or 16 bytes */
 
-       key  = ((u4) (ptrint) cle) >> 4;        /* align to 16-byte boundaries    */
+       key  = ((u4) (ptrint) loader) >> 4;        /* align to 16-byte boundaries */
        slot = key & (hashtable_library->size - 1);
        le   = hashtable_library->ptr[slot];
 
        /* search external hash chain for the entry */
 
        while (le) {
-               if (le->cle == cle)
+               if (le->loader == loader)
                        break;
 
                le = le->hashlink;                  /* next element in external chain */
@@ -688,163 +857,87 @@ hashtable_library_name_entry *native_library_find(utf *filename,
 
        return ne;
 }
-#endif /* !defined(WITH_STATIC_CLASSPATH) */
-
-
-/* native_findfunction *********************************************************
-
-   Looks up a method (must have the same class name, method name,
-   descriptor and 'static'ness) and returns a function pointer to it.
-   Returns: function pointer or NULL (if there is no such method)
-
-   Remark: For faster operation, the names/descriptors are converted
-   from C strings to Unicode the first time this function is called.
-
-*******************************************************************************/
-
-#if defined(WITH_STATIC_CLASSPATH)
-functionptr native_findfunction(utf *cname, utf *mname, utf *desc,
-                                                               bool isstatic)
-{
-       /* entry of table for fast string comparison */
-       struct nativecompref *n;
-       s4 i;
-
-       isstatic = isstatic ? true : false;
-       
-       if (!nativecompdone) {
-               for (i = 0; i < NATIVETABLESIZE; i++) {
-                       nativecomptable[i].classname  = 
-                               utf_new_char(nativetable[i].classname);
-
-                       nativecomptable[i].methodname = 
-                               utf_new_char(nativetable[i].methodname);
-
-                       nativecomptable[i].descriptor =
-                               utf_new_char(nativetable[i].descriptor);
-
-                       nativecomptable[i].isstatic   = nativetable[i].isstatic;
-                       nativecomptable[i].func       = nativetable[i].func;
-               }
-
-               nativecompdone = true;
-       }
-
-       for (i = 0; i < NATIVETABLESIZE; i++) {
-               n = &(nativecomptable[i]);
-
-               if (cname == n->classname && mname == n->methodname &&
-                   desc == n->descriptor && isstatic == n->isstatic)
-                       return n->func;
-       }
-
-       /* no function was found, throw exception */
+#endif
 
-       *exceptionptr =
-                       new_exception_utfmessage(string_java_lang_UnsatisfiedLinkError,
-                                                                        mname);
 
-       return NULL;
-}
-#endif /* defined(WITH_STATIC_CLASSPATH) */
+/* native_library_load *********************************************************
 
+   Load a native library and initialize it, if possible.
 
-/* native_resolve_function *****************************************************
+   IN:
+       name ... name of the library
+          cl ..... classloader which loads this library
 
-   Resolves a native function, maybe from a dynamic library.
+   RETURN:
+       1 ... library loaded successfully
+       0 ... error
 
 *******************************************************************************/
 
-functionptr native_resolve_function(methodinfo *m)
+int native_library_load(JNIEnv *env, utf *name, classloader_t *cl)
 {
-       utf                            *name;
-       utf                            *newname;
-       functionptr                     f;
-       hashtable_library_loader_entry *le;
-       hashtable_library_name_entry   *ne;
-       u4                              key;    /* hashkey                        */
-       u4                              slot;   /* slot in hashtable              */
-
-       /* verbose output */
-
-       if (opt_verbosejni) {
-               printf("[Dynamic-linking native method ");
-               utf_display_printable_ascii_classname(m->class->name);
-               printf(".");
-               utf_display_printable_ascii(m->name);
-               printf(" ... ");
+#if defined(ENABLE_LTDL)
+       lt_dlhandle        handle;
+# if defined(ENABLE_JNI)
+       lt_ptr             onload;
+       int32_t            version;
+# endif
+
+       if (name == NULL) {
+               exceptions_throw_nullpointerexception();
+               return 0;
        }
 
-       /* generate method symbol string */
+       /* Is the library already loaded? */
 
-       name = native_method_symbol(m->class->name, m->name);
+       if (native_library_find(name, cl) != NULL)
+               return 1;
 
-       /* generate overloaded function (having the types in it's name)           */
+       /* Open the library. */
 
-       newname = native_make_overloaded_function(name, m->descriptor);
+       handle = native_library_open(name);
 
-       /* check the library hash entries of the classloader of the
-          methods's class  */
+       if (handle == NULL)
+               return 0;
 
-       f = NULL;
+# if defined(ENABLE_JNI)
+       /* Resolve JNI_OnLoad function. */
 
-       /* normally addresses are aligned to 4, 8 or 16 bytes */
+       onload = lt_dlsym(handle, "JNI_OnLoad");
 
-       key  = ((u4) (ptrint) m->class->classloader) >> 4;    /* align to 16-byte */
-       slot = key & (hashtable_library->size - 1);
-       le   = hashtable_library->ptr[slot];
+       if (onload != NULL) {
+               JNIEXPORT int32_t (JNICALL *JNI_OnLoad) (JavaVM *, void *);
+               JavaVM *vm;
 
-       /* iterate through loaders in this hash slot */
+               JNI_OnLoad = (JNIEXPORT int32_t (JNICALL *)(JavaVM *, void *)) (ptrint) onload;
 
-       while ((le != NULL) && (f == NULL)) {
-               /* iterate through names in this loader */
+               (*env)->GetJavaVM(env, &vm);
 
-               ne = le->namelink;
-                       
-               while ((ne != NULL) && (f == NULL)) {
-                       f = (functionptr) (ptrint) lt_dlsym(ne->handle, name->text);
+               version = JNI_OnLoad(vm, NULL);
 
-                       if (f == NULL)
-                               f = (functionptr) (ptrint) lt_dlsym(ne->handle, newname->text);
+               /* If the version is not 1.2 and not 1.4 the library cannot be
+                  loaded. */
 
-                       ne = ne->hashlink;
+               if ((version != JNI_VERSION_1_2) && (version != JNI_VERSION_1_4)) {
+                       lt_dlclose(handle);
+                       return 0;
                }
-
-               le = le->hashlink;
        }
+# endif
 
-       if (f != NULL)
-               if (opt_verbosejni)
-                       printf("JNI ]\n");
+       /* Insert the library name into the library hash. */
 
-       /* If not found, try to find the native function symbol in the
-          main program. */
+       native_library_add(name, cl, handle);
 
-       if (f == NULL) {
-               f = native_method_find(m);
+       return 1;
+#else
+       vm_abort("native_library_load: not available");
 
-               if (f != NULL)
-                       if (opt_verbosejni)
-                               printf("internal ]\n");
-       }
+       /* Keep compiler happy. */
 
-#if defined(ENABLE_JVMTI)
-       /* fire Native Method Bind event */
-       if (jvmti) jvmti_NativeMethodBind(m, f, &f);
+       return 0;
 #endif
-
-       /* no symbol found? throw exception */
-
-       if (f == NULL) {
-               if (opt_verbosejni)
-                       printf("failed ]\n");
-
-               exceptions_throw_unsatisfiedlinkerror(m->name);
-       }
-
-       return f;
 }
-#endif /* !defined(WITH_STATIC_CLASSPATH) */
 
 
 /* native_new_and_init *********************************************************
@@ -854,10 +947,10 @@ functionptr native_resolve_function(methodinfo *m)
                        
 *******************************************************************************/
 
-java_objectheader *native_new_and_init(classinfo *c)
+java_handle_t *native_new_and_init(classinfo *c)
 {
-       methodinfo *m;
-       java_objectheader *o;
+       methodinfo    *m;
+       java_handle_t *o;
 
        if (c == NULL)
                vm_abort("native_new_and_init: c == NULL");
@@ -887,10 +980,10 @@ java_objectheader *native_new_and_init(classinfo *c)
 }
 
 
-java_objectheader *native_new_and_init_string(classinfo *c, java_objectheader *s)
+java_handle_t *native_new_and_init_string(classinfo *c, java_handle_t *s)
 {
-       methodinfo        *m;
-       java_objectheader *o;
+       methodinfo    *m;
+       java_handle_t *o;
 
        if (c == NULL)
                vm_abort("native_new_and_init_string: c == NULL");
@@ -904,11 +997,7 @@ java_objectheader *native_new_and_init_string(classinfo *c, java_objectheader *s
 
        /* find initializer */
 
-       m = class_resolveclassmethod(c,
-                                                                utf_init,
-                                                                utf_java_lang_String__void,
-                                                                NULL,
-                                                                true);
+       m = class_findmethod(c, utf_init, utf_java_lang_String__void);
 
        /* initializer not found */
 
@@ -923,70 +1012,6 @@ java_objectheader *native_new_and_init_string(classinfo *c, java_objectheader *s
 }
 
 
-java_objectheader *native_new_and_init_int(classinfo *c, s4 i)
-{
-       methodinfo *m;
-       java_objectheader *o;
-
-       if (c == NULL)
-               vm_abort("native_new_and_init_int: c == NULL");
-
-       /* create object */
-
-       o = builtin_new(c);
-       
-       if (o == NULL)
-               return NULL;
-
-       /* find initializer */
-
-       m = class_resolveclassmethod(c, utf_init, utf_int__void, NULL, true);
-
-       /* initializer not found  */
-
-       if (m == NULL)
-               return NULL;
-
-       /* call initializer */
-
-       (void) vm_call_method(m, o, i);
-
-       return o;
-}
-
-
-java_objectheader *native_new_and_init_throwable(classinfo *c, java_objectheader *t)
-{
-       java_objectheader *o;
-       methodinfo        *m;
-
-       if (c == NULL)
-               vm_abort("native_new_and_init_throwable: c == NULL");
-
-       /* create object */
-
-       o = builtin_new(c);
-       
-       if (o == NULL)
-               return NULL;
-
-       /* find initializer */
-
-       m = class_findmethod(c, utf_init, utf_java_lang_Throwable__void);
-                                                     
-       /* initializer not found */
-
-       if (m == NULL)
-               return NULL;
-
-       /* call initializer */
-
-       (void) vm_call_method(m, o, t);
-
-       return o;
-}
-
-
 /*
  * 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
@@ -998,4 +1023,5 @@ java_objectheader *native_new_and_init_throwable(classinfo *c, java_objectheader
  * c-basic-offset: 4
  * tab-width: 4
  * End:
+ * vim:noexpandtab:sw=4:ts=4:
  */