* src/native/native.c (native_library_open): New function.
[cacao.git] / src / native / native.c
1 /* src/native/native.c - table of native functions
2
3    Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
4    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6    J. Wenninger, 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., 51 Franklin Street, Fifth Floor, Boston, MA
23    02110-1301, USA.
24
25    $Id: native.c 7911 2007-05-16 09:01:10Z twisti $
26
27 */
28
29
30 #include "config.h"
31
32 #include <assert.h>
33 #include <ctype.h>
34
35 #if !defined(WITH_STATIC_CLASSPATH)
36 # include <ltdl.h>
37 #endif
38
39 #include "vm/types.h"
40
41 #include "mm/memory.h"
42
43 #include "native/jni.h"
44 #include "native/native.h"
45
46 #include "native/vm/nativevm.h"
47
48 #include "threads/lock-common.h"
49
50 #include "toolbox/avl.h"
51 #include "toolbox/hashtable.h"
52 #include "toolbox/logging.h"
53
54 #include "vm/builtin.h"
55 #include "vm/exceptions.h"
56 #include "vm/global.h"
57 #include "vm/stringlocal.h"
58 #include "vm/vm.h"
59
60 #include "vm/jit/asmpart.h"
61 #include "vm/jit/jit.h"
62
63 #include "vmcore/loader.h"
64 #include "vmcore/options.h"
65 #include "vm/resolve.h"
66
67 #if defined(ENABLE_JVMTI)
68 #include "native/jvmti/cacaodbg.h"
69 #endif
70
71
72 /* include table of native functions ******************************************/
73
74 #if defined(WITH_STATIC_CLASSPATH)
75 # include "native/nativetable.inc"
76 #endif
77
78
79 /* tables for methods *********************************************************/
80
81 #if defined(WITH_STATIC_CLASSPATH)
82 #define NATIVETABLESIZE  (sizeof(nativetable)/sizeof(struct nativeref))
83
84 /* table for fast string comparison */
85 static nativecompref nativecomptable[NATIVETABLESIZE];
86
87 /* string comparsion table initialized */
88 static bool nativecompdone = false;
89 #endif
90
91
92 /* global variables ***********************************************************/
93
94 static avl_tree_t *tree_native_methods;
95 static hashtable *hashtable_library;
96
97
98 /* prototypes *****************************************************************/
99
100 static s4 native_tree_native_methods_comparator(const void *treenode, const void *node);
101
102
103 /* native_init *****************************************************************
104
105    Initializes the native subsystem.
106
107 *******************************************************************************/
108
109 bool native_init(void)
110 {
111 #if !defined(WITH_STATIC_CLASSPATH)
112         /* initialize libltdl */
113
114         if (lt_dlinit())
115                 vm_abort("native_init: lt_dlinit failed: %s\n", lt_dlerror());
116
117         /* initialize library hashtable, 10 entries should be enough */
118
119         hashtable_library = NEW(hashtable);
120
121         hashtable_create(hashtable_library, 10);
122 #endif
123
124         /* initialize the native methods table */
125
126         tree_native_methods = avl_create(&native_tree_native_methods_comparator);
127
128         /* register the intern native functions */
129
130         nativevm_init();
131
132         /* everything's ok */
133
134         return true;
135 }
136
137
138 /* native_tree_native_methods_comparator ***************************************
139
140    Comparison function for AVL tree of native methods.
141
142    IN:
143        treenode....node in the tree
144            node........node to compare with tree-node
145
146    RETURN VALUE:
147        -1, 0, +1
148
149 *******************************************************************************/
150
151 static s4 native_tree_native_methods_comparator(const void *treenode, const void *node)
152 {
153         const native_methods_node_t *treenmn;
154         const native_methods_node_t *nmn;
155
156         treenmn = treenode;
157         nmn     = node;
158
159         /* compare for avl_find if we have found an entry */
160
161         if (treenmn->name == nmn->name)
162                 return 0;
163
164         /* these are for walking the tree */
165
166         if (treenmn->name < nmn->name)
167                 return -1;
168         else
169                 return 1;
170 }
171
172
173 /* native_make_overloaded_function *********************************************
174
175    XXX
176
177 *******************************************************************************/
178
179 #if !defined(WITH_STATIC_CLASSPATH)
180 static utf *native_make_overloaded_function(utf *name, utf *descriptor)
181 {
182         char *newname;
183         s4    namelen;
184         char *utf_ptr;
185         u2    c;
186         s4    i;
187         s4    dumpsize;
188         utf  *u;
189
190         /* mark memory */
191
192         dumpsize = dump_size();
193
194         utf_ptr = descriptor->text;
195         namelen = strlen(name->text) + strlen("__") + strlen("0");
196
197         /* calculate additional length */
198
199         while ((c = utf_nextu2(&utf_ptr)) != ')') {
200                 switch (c) {
201                 case 'Z':
202                 case 'B':
203                 case 'C':
204                 case 'S':
205                 case 'I':
206                 case 'J':
207                 case 'F':
208                 case 'D':
209                         namelen++;
210                         break;
211                 case '[':
212                         namelen += 2;
213                         break;
214                 case 'L':
215                         namelen++;
216                         while (utf_nextu2(&utf_ptr) != ';')
217                                 namelen++;
218                         namelen += 2;
219                         break;
220                 case '(':
221                         break;
222                 default:
223                         assert(0);
224                 }
225         }
226
227         /* reallocate memory */
228
229         i = strlen(name->text);
230
231         newname = DMNEW(char, namelen);
232         MCOPY(newname, name->text, char, i);
233
234         utf_ptr = descriptor->text;
235
236         newname[i++] = '_';
237         newname[i++] = '_';
238
239         while ((c = utf_nextu2(&utf_ptr)) != ')') {
240                 switch (c) {
241                 case 'Z':
242                 case 'B':
243                 case 'C':
244                 case 'S':
245                 case 'J':
246                 case 'I':
247                 case 'F':
248                 case 'D':
249                         newname[i++] = c;
250                         break;
251                 case '[':
252                         newname[i++] = '_';
253                         newname[i++] = '3';
254                         break;
255                 case 'L':
256                         newname[i++] = 'L';
257                         while ((c = utf_nextu2(&utf_ptr)) != ';')
258                                 if (((c >= 'a') && (c <= 'z')) ||
259                                         ((c >= 'A') && (c <= 'Z')) ||
260                                         ((c >= '0') && (c <= '9')))
261                                         newname[i++] = c;
262                                 else
263                                         newname[i++] = '_';
264                         newname[i++] = '_';
265                         newname[i++] = '2';
266                         break;
267                 case '(':
268                         break;
269                 default:
270                         assert(0);
271                 }
272         }
273
274         /* close string */
275
276         newname[i] = '\0';
277
278         /* make a utf-string */
279
280         u = utf_new_char(newname);
281
282         /* release memory */
283
284         dump_release(dumpsize);
285
286         return u;
287 }
288
289
290 /* native_insert_char **********************************************************
291
292    Inserts the passed UTF character into the native method name.  If
293    necessary it is escaped properly.
294
295 *******************************************************************************/
296
297 static s4 native_insert_char(char *name, u4 pos, u2 c)
298 {
299         s4 val;
300         s4 i;
301
302         switch (c) {
303         case '/':
304         case '.':
305                 /* replace '/' or '.' with '_' */
306                 name[pos] = '_';
307                 break;
308
309         case '_':
310                 /* escape sequence for '_' is '_1' */
311                 name[pos]   = '_';
312                 name[++pos] = '1';
313                 break;
314
315         case ';':
316                 /* escape sequence for ';' is '_2' */
317                 name[pos]   = '_';
318                 name[++pos] = '2';
319                 break;
320
321         case '[':
322                 /* escape sequence for '[' is '_1' */
323                 name[pos]   = '_';
324                 name[++pos] = '3';
325                 break;
326
327         default:
328                 if (isalnum(c))
329                         name[pos] = c;
330                 else {
331                         /* unicode character */
332                         name[pos]   = '_';
333                         name[++pos] = '0';
334
335                         for (i = 0; i < 4; ++i) {
336                                 val = c & 0x0f;
337                                 name[pos + 4 - i] = (val > 10) ? ('a' + val - 10) : ('0' + val);
338                                 c >>= 4;
339                         }
340
341                         pos += 4;
342                 }
343                 break;
344         }
345
346         /* return the new buffer index */
347
348         return pos;
349 }
350
351
352 /* native_method_symbol ********************************************************
353
354    Generate a method-symbol string out of the class name and the
355    method name.
356
357 *******************************************************************************/
358
359 static utf *native_method_symbol(utf *classname, utf *methodname)
360 {
361         char *name;
362         s4    namelen;
363         char *utf_ptr;
364         char *utf_endptr;
365         u2    c;
366         u4    pos;
367         s4    dumpsize;
368         utf  *u;
369
370         /* mark memory */
371
372         dumpsize = dump_size();
373
374         /* Calculate length of native function name.  We multiply the
375            class and method name length by 6 as this is the maxium
376            escape-sequence that can be generated (unicode). */
377
378         namelen =
379                 strlen("Java_") +
380                 utf_get_number_of_u2s(classname) * 6 +
381                 strlen("_") +
382                 utf_get_number_of_u2s(methodname) * 6 +
383                 strlen("0");
384
385         /* allocate memory */
386
387         name = DMNEW(char, namelen);
388
389         /* generate name of native functions */
390
391         strcpy(name, "Java_");
392         pos = strlen("Java_");
393
394         utf_ptr    = classname->text;
395         utf_endptr = UTF_END(classname);
396
397         for (; utf_ptr < utf_endptr; utf_ptr++, pos++) {
398                 c   = *utf_ptr;
399                 pos = native_insert_char(name, pos, c);
400         }
401
402         /* seperator between class and method */
403
404         name[pos++] = '_';
405
406         utf_ptr    = methodname->text;
407         utf_endptr = UTF_END(methodname);
408
409         for (; utf_ptr < utf_endptr; utf_ptr++, pos++) {
410                 c   = *utf_ptr;
411                 pos = native_insert_char(name, pos, c);
412         }
413
414         /* close string */
415
416         name[pos] = '\0';
417
418         /* check for an buffer overflow */
419
420         assert(pos <= namelen);
421
422         /* make a utf-string */
423
424         u = utf_new_char(name);
425
426         /* release memory */
427
428         dump_release(dumpsize);
429
430         return u;
431 }
432
433
434 /* native_method_register ******************************************************
435
436    Register a native method in the native method table.
437
438 *******************************************************************************/
439
440 void native_method_register(utf *classname, JNINativeMethod *methods, s4 count)
441 {
442         native_methods_node_t *nmn;
443         utf                   *methodname;
444         utf                   *name;
445         s4                     i;
446
447         /* insert all methods passed */
448
449         for (i = 0; i < count; i++) {
450                 if (opt_verbosejni) {
451                         printf("[Registering JNI native method ");
452                         utf_display_printable_ascii_classname(classname);
453                         printf(".%s]\n", methods[i].name);
454                 }
455
456                 /* generate the method-symbol string */
457
458                 methodname = utf_new_char(methods[i].name);
459                 name       = native_method_symbol(classname, methodname);
460
461                 /* allocate a new tree node */
462
463                 nmn = NEW(native_methods_node_t);
464
465                 nmn->name   = name;
466                 nmn->method = (functionptr) (ptrint) methods[i].fnPtr;
467
468                 /* insert the method into the tree */
469
470                 avl_insert(tree_native_methods, nmn);
471         }
472 }
473
474
475 /* native_method_find **********************************************************
476
477    Find a native method in the native method table.
478
479 *******************************************************************************/
480
481 static functionptr native_method_find(utf *name)
482 {
483         native_methods_node_t  tmpnmn;
484         native_methods_node_t *nmn;
485
486         tmpnmn.name = name;
487
488         nmn = avl_find(tree_native_methods, &tmpnmn);
489
490         if (nmn == NULL)
491                 return NULL;
492
493         return nmn->method;
494 }
495
496
497 /* native_library_open *********************************************************
498
499    Open a native library with the given utf8 name.
500
501 *******************************************************************************/
502
503 #if !defined(WITH_STATIC_CLASSPATH)
504 lt_dlhandle native_library_open(utf *filename)
505 {
506         lt_dlhandle handle;
507
508         /* try to open the library */
509
510         handle = lt_dlopen(filename->text);
511
512         if (handle == NULL) {
513                 if (opt_verbose) {
514                         log_start();
515                         log_print("native_library_load: lt_dlopen failed: ");
516                         log_print(lt_dlerror());
517                         log_finish();
518                 }
519
520                 return NULL;
521         }
522
523         return handle;
524 }
525 #endif
526
527
528 /* native_library_add **********************************************************
529
530    Adds an entry to the native library hashtable.
531
532 *******************************************************************************/
533
534 #if !defined(WITH_STATIC_CLASSPATH)
535 void native_library_add(utf *filename, java_objectheader *loader,
536                                                 lt_dlhandle handle)
537 {
538         hashtable_library_loader_entry *le;
539         hashtable_library_name_entry   *ne; /* library name                       */
540         u4   key;                           /* hashkey                            */
541         u4   slot;                          /* slot in hashtable                  */
542
543         LOCK_MONITOR_ENTER(hashtable_library->header);
544
545         /* normally addresses are aligned to 4, 8 or 16 bytes */
546
547         key  = ((u4) (ptrint) loader) >> 4;        /* align to 16-byte boundaries */
548         slot = key & (hashtable_library->size - 1);
549         le   = hashtable_library->ptr[slot];
550
551         /* search external hash chain for the entry */
552
553         while (le) {
554                 if (le->loader == loader)
555                         break;
556
557                 le = le->hashlink;                  /* next element in external chain */
558         }
559
560         /* no loader found? create a new entry */
561
562         if (le == NULL) {
563                 le = NEW(hashtable_library_loader_entry);
564
565                 le->loader   = loader;
566                 le->namelink = NULL;
567
568                 /* insert entry into hashtable */
569
570                 le->hashlink =
571                         (hashtable_library_loader_entry *) hashtable_library->ptr[slot];
572                 hashtable_library->ptr[slot] = le;
573
574                 /* update number of hashtable-entries */
575
576                 hashtable_library->entries++;
577         }
578
579
580         /* search for library name */
581
582         ne = le->namelink;
583
584         while (ne) {
585                 if (ne->name == filename) {
586                         LOCK_MONITOR_EXIT(hashtable_library->header);
587
588                         return;
589                 }
590
591                 ne = ne->hashlink;                  /* next element in external chain */
592         }
593
594         /* not found? add the library name to the classloader */
595
596         ne = NEW(hashtable_library_name_entry);
597
598         ne->name   = filename;
599         ne->handle = handle;
600
601         /* insert entry into external chain */
602
603         ne->hashlink = le->namelink;
604         le->namelink = ne;
605
606         LOCK_MONITOR_EXIT(hashtable_library->header);
607 }
608 #endif /* !defined(WITH_STATIC_CLASSPATH) */
609
610
611 /* native_library_find *********************************************************
612
613    Find an entry in the native library hashtable.
614
615 *******************************************************************************/
616
617 #if !defined(WITH_STATIC_CLASSPATH)
618 hashtable_library_name_entry *native_library_find(utf *filename,
619                                                                                                   java_objectheader *loader)
620 {
621         hashtable_library_loader_entry *le;
622         hashtable_library_name_entry   *ne; /* library name                       */
623         u4   key;                           /* hashkey                            */
624         u4   slot;                          /* slot in hashtable                  */
625
626         /* normally addresses are aligned to 4, 8 or 16 bytes */
627
628         key  = ((u4) (ptrint) loader) >> 4;        /* align to 16-byte boundaries */
629         slot = key & (hashtable_library->size - 1);
630         le   = hashtable_library->ptr[slot];
631
632         /* search external hash chain for the entry */
633
634         while (le) {
635                 if (le->loader == loader)
636                         break;
637
638                 le = le->hashlink;                  /* next element in external chain */
639         }
640
641         /* no loader found? return NULL */
642
643         if (le == NULL)
644                 return NULL;
645
646         /* search for library name */
647
648         ne = le->namelink;
649
650         while (ne) {
651                 if (ne->name == filename)
652                         return ne;
653
654                 ne = ne->hashlink;                  /* next element in external chain */
655         }
656
657         /* return entry, if no entry was found, ne is NULL */
658
659         return ne;
660 }
661 #endif /* !defined(WITH_STATIC_CLASSPATH) */
662
663
664 /* native_findfunction *********************************************************
665
666    Looks up a method (must have the same class name, method name,
667    descriptor and 'static'ness) and returns a function pointer to it.
668    Returns: function pointer or NULL (if there is no such method)
669
670    Remark: For faster operation, the names/descriptors are converted
671    from C strings to Unicode the first time this function is called.
672
673 *******************************************************************************/
674
675 #if defined(WITH_STATIC_CLASSPATH)
676 functionptr native_findfunction(utf *cname, utf *mname, utf *desc,
677                                                                 bool isstatic)
678 {
679         /* entry of table for fast string comparison */
680         struct nativecompref *n;
681         s4 i;
682
683         isstatic = isstatic ? true : false;
684         
685         if (!nativecompdone) {
686                 for (i = 0; i < NATIVETABLESIZE; i++) {
687                         nativecomptable[i].classname  = 
688                                 utf_new_char(nativetable[i].classname);
689
690                         nativecomptable[i].methodname = 
691                                 utf_new_char(nativetable[i].methodname);
692
693                         nativecomptable[i].descriptor =
694                                 utf_new_char(nativetable[i].descriptor);
695
696                         nativecomptable[i].isstatic   = nativetable[i].isstatic;
697                         nativecomptable[i].func       = nativetable[i].func;
698                 }
699
700                 nativecompdone = true;
701         }
702
703         for (i = 0; i < NATIVETABLESIZE; i++) {
704                 n = &(nativecomptable[i]);
705
706                 if (cname == n->classname && mname == n->methodname &&
707                     desc == n->descriptor && isstatic == n->isstatic)
708                         return n->func;
709         }
710
711         /* no function was found, throw exception */
712
713         *exceptionptr =
714                         new_exception_utfmessage(string_java_lang_UnsatisfiedLinkError,
715                                                                          mname);
716
717         return NULL;
718 }
719 #endif /* defined(WITH_STATIC_CLASSPATH) */
720
721
722 /* native_resolve_function *****************************************************
723
724    Resolves a native function, maybe from a dynamic library.
725
726 *******************************************************************************/
727
728 functionptr native_resolve_function(methodinfo *m)
729 {
730         utf                            *name;
731         utf                            *newname;
732         functionptr                     f;
733         hashtable_library_loader_entry *le;
734         hashtable_library_name_entry   *ne;
735         u4                              key;    /* hashkey                        */
736         u4                              slot;   /* slot in hashtable              */
737
738         /* verbose output */
739
740         if (opt_verbosejni) {
741                 printf("[Dynamic-linking native method ");
742                 utf_display_printable_ascii_classname(m->class->name);
743                 printf(".");
744                 utf_display_printable_ascii(m->name);
745                 printf(" ... ");
746         }
747
748         /* generate method symbol string */
749
750         name = native_method_symbol(m->class->name, m->name);
751
752         /* generate overloaded function (having the types in it's name)           */
753
754         newname = native_make_overloaded_function(name, m->descriptor);
755
756         /* check the library hash entries of the classloader of the
757            methods's class  */
758
759         f = NULL;
760
761         /* normally addresses are aligned to 4, 8 or 16 bytes */
762
763         key  = ((u4) (ptrint) m->class->classloader) >> 4;    /* align to 16-byte */
764         slot = key & (hashtable_library->size - 1);
765         le   = hashtable_library->ptr[slot];
766
767         /* iterate through loaders in this hash slot */
768
769         while ((le != NULL) && (f == NULL)) {
770                 /* iterate through names in this loader */
771
772                 ne = le->namelink;
773                         
774                 while ((ne != NULL) && (f == NULL)) {
775                         f = (functionptr) (ptrint) lt_dlsym(ne->handle, name->text);
776
777                         if (f == NULL)
778                                 f = (functionptr) (ptrint) lt_dlsym(ne->handle, newname->text);
779
780                         ne = ne->hashlink;
781                 }
782
783                 le = le->hashlink;
784         }
785
786         if (f != NULL)
787                 if (opt_verbosejni)
788                         printf("JNI ]\n");
789
790         /* If not found, try to find the native function symbol in the
791            main program. */
792
793         if (f == NULL) {
794                 f = native_method_find(name);
795
796                 if (f == NULL)
797                         f = native_method_find(newname);
798
799                 if (f != NULL)
800                         if (opt_verbosejni)
801                                 printf("internal ]\n");
802         }
803
804 #if defined(ENABLE_JVMTI)
805         /* fire Native Method Bind event */
806         if (jvmti) jvmti_NativeMethodBind(m, f, &f);
807 #endif
808
809         /* no symbol found? throw exception */
810
811         if (f == NULL) {
812                 if (opt_verbosejni)
813                         printf("failed ]\n");
814
815                 exceptions_throw_unsatisfiedlinkerror(m->name);
816         }
817
818         return f;
819 }
820 #endif /* !defined(WITH_STATIC_CLASSPATH) */
821
822
823 /* native_new_and_init *********************************************************
824
825    Creates a new object on the heap and calls the initializer.
826    Returns the object pointer or NULL if memory is exhausted.
827                         
828 *******************************************************************************/
829
830 java_objectheader *native_new_and_init(classinfo *c)
831 {
832         methodinfo *m;
833         java_objectheader *o;
834
835         if (c == NULL)
836                 vm_abort("native_new_and_init: c == NULL");
837
838         /* create object */
839
840         o = builtin_new(c);
841         
842         if (o == NULL)
843                 return NULL;
844
845         /* try to find the initializer */
846
847         m = class_findmethod(c, utf_init, utf_void__void);
848                                                       
849         /* ATTENTION: returning the object here is ok, since the class may
850        not have an initializer */
851
852         if (m == NULL)
853                 return o;
854
855         /* call initializer */
856
857         (void) vm_call_method(m, o);
858
859         return o;
860 }
861
862
863 java_objectheader *native_new_and_init_string(classinfo *c, java_objectheader *s)
864 {
865         methodinfo        *m;
866         java_objectheader *o;
867
868         if (c == NULL)
869                 vm_abort("native_new_and_init_string: c == NULL");
870
871         /* create object */
872
873         o = builtin_new(c);
874
875         if (o == NULL)
876                 return NULL;
877
878         /* find initializer */
879
880         m = class_resolveclassmethod(c,
881                                                                  utf_init,
882                                                                  utf_java_lang_String__void,
883                                                                  NULL,
884                                                                  true);
885
886         /* initializer not found */
887
888         if (m == NULL)
889                 return NULL;
890
891         /* call initializer */
892
893         (void) vm_call_method(m, o, s);
894
895         return o;
896 }
897
898
899 java_objectheader *native_new_and_init_int(classinfo *c, s4 i)
900 {
901         methodinfo *m;
902         java_objectheader *o;
903
904         if (c == NULL)
905                 vm_abort("native_new_and_init_int: c == NULL");
906
907         /* create object */
908
909         o = builtin_new(c);
910         
911         if (o == NULL)
912                 return NULL;
913
914         /* find initializer */
915
916         m = class_resolveclassmethod(c, utf_init, utf_int__void, NULL, true);
917
918         /* initializer not found  */
919
920         if (m == NULL)
921                 return NULL;
922
923         /* call initializer */
924
925         (void) vm_call_method(m, o, i);
926
927         return o;
928 }
929
930
931 java_objectheader *native_new_and_init_throwable(classinfo *c, java_objectheader *t)
932 {
933         java_objectheader *o;
934         methodinfo        *m;
935
936         if (c == NULL)
937                 vm_abort("native_new_and_init_throwable: c == NULL");
938
939         /* create object */
940
941         o = builtin_new(c);
942         
943         if (o == NULL)
944                 return NULL;
945
946         /* find initializer */
947
948         m = class_findmethod(c, utf_init, utf_java_lang_Throwable__void);
949                                                       
950         /* initializer not found */
951
952         if (m == NULL)
953                 return NULL;
954
955         /* call initializer */
956
957         (void) vm_call_method(m, o, t);
958
959         return o;
960 }
961
962
963 /*
964  * These are local overrides for various environment variables in Emacs.
965  * Please do not remove this and leave it at the end of the file, where
966  * Emacs will automagically detect them.
967  * ---------------------------------------------------------------------
968  * Local variables:
969  * mode: c
970  * indent-tabs-mode: t
971  * c-basic-offset: 4
972  * tab-width: 4
973  * End:
974  */