1 /* src/vm/jit/builtin.cpp - functions for unsupported operations
3 Copyright (C) 1996-2005, 2006, 2007, 2008, 2010
4 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
6 This file is part of CACAO.
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2, or (at
11 your option) any later version.
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Contains C functions for JavaVM Instructions that cannot be
24 translated to machine language directly. Consequently, the
25 generated machine code for these instructions contains function
26 calls instead of machine instructions, using the C calling
45 #include "fdlibm/fdlibm.h"
46 #if defined(__CYGWIN__) && defined(Bias)
51 #include "mm/memory.hpp"
53 #include "native/llni.h"
55 #include "threads/lock.hpp"
56 #include "threads/mutex.hpp"
57 #include "threads/thread.hpp"
59 #include "toolbox/logging.hpp"
60 #include "toolbox/util.h"
62 #include "vm/array.hpp"
63 #include "vm/jit/builtin.hpp"
64 #include "vm/class.hpp"
65 #include "vm/cycles-stats.h"
66 #include "vm/exceptions.hpp"
67 #include "vm/global.h"
68 #include "vm/globals.hpp"
69 #include "vm/initialize.hpp"
70 #include "vm/linker.hpp"
71 #include "vm/loader.hpp"
72 #include "vm/options.h"
73 #include "vm/primitive.hpp"
74 #include "vm/rt-timing.h"
75 #include "vm/string.hpp"
77 #include "vm/jit/asmpart.h"
78 #include "vm/jit/emit-common.hpp"
79 #include "vm/jit/stubs.hpp"
80 #include "vm/jit/trace.hpp"
82 #if defined(ENABLE_VMLOG)
83 #include <vmlog_cacao.h>
87 /* include builtin tables *****************************************************/
89 #include "vm/jit/builtintable.inc"
92 CYCLES_STATS_DECLARE(builtin_new ,100,5)
93 CYCLES_STATS_DECLARE(builtin_overhead , 80,1)
96 /*============================================================================*/
97 /* BUILTIN TABLE MANAGEMENT FUNCTIONS */
98 /*============================================================================*/
100 /* builtintable_init ***********************************************************
102 Parse the descriptors of builtin functions and create the parsed
105 *******************************************************************************/
107 static bool builtintable_init(void)
109 descriptor_pool *descpool;
110 builtintable_entry *bte;
113 // Create new dump memory area.
116 /* create a new descriptor pool */
118 descpool = descriptor_pool_new(class_java_lang_Object);
120 /* add some entries we need */
122 if (!descriptor_pool_add_class(descpool, utf_java_lang_Object))
125 if (!descriptor_pool_add_class(descpool, utf_java_lang_Class))
128 /* first add all descriptors to the pool */
130 for (bte = builtintable_internal; bte->fp != NULL; bte++) {
131 bte->name = utf_new_char(bte->cname);
132 bte->descriptor = utf_new_char(bte->cdescriptor);
134 if (!descriptor_pool_add(descpool, bte->descriptor, NULL))
138 for (bte = builtintable_automatic; bte->fp != NULL; bte++) {
139 bte->descriptor = utf_new_char(bte->cdescriptor);
141 if (!descriptor_pool_add(descpool, bte->descriptor, NULL))
145 for (bte = builtintable_function; bte->fp != NULL; bte++) {
146 bte->classname = utf_new_char(bte->cclassname);
147 bte->name = utf_new_char(bte->cname);
148 bte->descriptor = utf_new_char(bte->cdescriptor);
150 if (!descriptor_pool_add(descpool, bte->descriptor, NULL))
154 /* create the class reference table */
156 (void) descriptor_pool_create_classrefs(descpool, NULL);
158 /* allocate space for the parsed descriptors */
160 descriptor_pool_alloc_parsed_descriptors(descpool);
162 /* Now parse all descriptors. NOTE: builtin-functions are treated
163 like static methods (no `this' pointer). */
165 for (bte = builtintable_internal; bte->fp != NULL; bte++) {
167 descriptor_pool_parse_method_descriptor(descpool,
169 ACC_STATIC | ACC_METHOD_BUILTIN,
172 /* generate a builtin stub if we need one */
174 if (bte->flags & BUILTINTABLE_FLAG_STUB) {
175 m = method_new_builtin(bte);
176 BuiltinStub::generate(m, bte);
180 for (bte = builtintable_automatic; bte->fp != NULL; bte++) {
182 descriptor_pool_parse_method_descriptor(descpool,
184 ACC_STATIC | ACC_METHOD_BUILTIN,
187 /* no stubs should be needed for this table */
189 assert(!bte->flags & BUILTINTABLE_FLAG_STUB);
192 for (bte = builtintable_function; bte->fp != NULL; bte++) {
194 descriptor_pool_parse_method_descriptor(descpool,
196 ACC_STATIC | ACC_METHOD_BUILTIN,
199 /* generate a builtin stub if we need one */
201 if (bte->flags & BUILTINTABLE_FLAG_STUB) {
202 m = method_new_builtin(bte);
203 BuiltinStub::generate(m, bte);
211 /* builtintable_comparator *****************************************************
213 qsort comparator for the automatic builtin table.
215 *******************************************************************************/
217 static int builtintable_comparator(const void *a, const void *b)
219 builtintable_entry *bte1;
220 builtintable_entry *bte2;
222 bte1 = (builtintable_entry *) a;
223 bte2 = (builtintable_entry *) b;
225 return (bte1->opcode < bte2->opcode) ? -1 : (bte1->opcode > bte2->opcode);
229 /* builtintable_sort_automatic *************************************************
231 Sorts the automatic builtin table.
233 *******************************************************************************/
235 static void builtintable_sort_automatic(void)
239 /* calculate table size statically (`- 1' comment see builtintable.inc) */
241 entries = sizeof(builtintable_automatic) / sizeof(builtintable_entry) - 1;
243 qsort(builtintable_automatic, entries, sizeof(builtintable_entry),
244 builtintable_comparator);
248 /* builtin_init ****************************************************************
250 Initialize the global table of builtin functions.
252 *******************************************************************************/
254 bool builtin_init(void)
256 TRACESUBSYSTEMINITIALIZATION("builtin_init");
258 /* initialize the builtin tables */
260 if (!builtintable_init())
263 /* sort builtin tables */
265 builtintable_sort_automatic();
271 /* builtintable_get_internal ***************************************************
273 Finds an entry in the builtintable for internal functions and
274 returns the a pointer to the structure.
276 *******************************************************************************/
278 builtintable_entry *builtintable_get_internal(functionptr fp)
280 builtintable_entry *bte;
282 for (bte = builtintable_internal; bte->fp != NULL; bte++) {
291 /* builtintable_get_automatic **************************************************
293 Finds an entry in the builtintable for functions which are replaced
294 automatically and returns the a pointer to the structure.
296 *******************************************************************************/
298 builtintable_entry *builtintable_get_automatic(s4 opcode)
300 builtintable_entry *first;
301 builtintable_entry *last;
302 builtintable_entry *middle;
306 /* calculate table size statically (`- 1' comment see builtintable.inc) */
308 entries = sizeof(builtintable_automatic) / sizeof(builtintable_entry) - 1;
310 first = builtintable_automatic;
311 last = builtintable_automatic + entries;
313 while (entries > 0) {
315 middle = first + half;
317 if (middle->opcode < opcode) {
325 return (first != last ? first : NULL);
329 /* builtintable_replace_function ***********************************************
333 *******************************************************************************/
335 #if defined(ENABLE_JIT)
336 bool builtintable_replace_function(void *iptr_)
339 builtintable_entry *bte;
342 iptr = (instruction *) iptr_; /* twisti will kill me ;) */
344 /* get name and descriptor of the function */
347 case ICMD_INVOKESTATIC:
348 /* The instruction MUST be resolved, otherwise we run into
349 lazy loading troubles. Anyway, we should/can only replace
350 very VM-close functions. */
352 if (INSTRUCTION_IS_UNRESOLVED(iptr))
355 mr = iptr->sx.s23.s3.fmiref;
362 /* search the function table */
364 for (bte = builtintable_function; bte->fp != NULL; bte++) {
365 if ((METHODREF_CLASSNAME(mr) == bte->classname) &&
366 (mr->name == bte->name) &&
367 (mr->descriptor == bte->descriptor)) {
369 /* set the values in the instruction */
371 iptr->opc = bte->opcode;
372 iptr->sx.s23.s3.bte = bte;
374 if (bte->flags & BUILTINTABLE_FLAG_EXCEPTION)
375 iptr->flags.bits |= INS_FLAG_CHECK;
377 iptr->flags.bits &= ~INS_FLAG_CHECK;
385 #endif /* defined(ENABLE_JIT) */
388 /*============================================================================*/
389 /* INTERNAL BUILTIN FUNCTIONS */
390 /*============================================================================*/
392 /* builtin_instanceof **********************************************************
394 Checks if an object is an instance of some given class (or subclass
395 of that class). If class is an interface, checks if the interface
399 1......o is an instance of class or implements the interface
400 0......otherwise or if o == NULL
402 NOTE: This builtin can be called from NATIVE code only.
404 *******************************************************************************/
406 bool builtin_instanceof(java_handle_t *o, classinfo *c)
413 LLNI_class_get(o, oc);
415 return class_isanysubclass(oc, c);
420 /* builtin_checkcast ***********************************************************
422 The same as builtin_instanceof but with the exception
423 that 1 is returned when (o == NULL).
425 NOTE: This builtin can be called from NATIVE code only.
427 *******************************************************************************/
429 bool builtin_checkcast(java_handle_t *o, classinfo *c)
436 LLNI_class_get(o, oc);
438 if (class_isanysubclass(oc, c))
445 /* builtin_arraycheckcast ******************************************************
447 Checks if an object is really a subtype of the requested array
448 type. The object has to be an array to begin with. For simple
449 arrays (int, short, double, etc.) the types have to match exactly.
450 For arrays of objects, the type of elements in the array has to be
451 a subtype (or the same type) of the requested element type. For
452 arrays of arrays (which in turn can again be arrays of arrays), the
453 types at the lowest level have to satisfy the corresponding sub
456 NOTE: This is a FAST builtin and can be called from JIT code only.
458 *******************************************************************************/
460 bool builtin_fast_arraycheckcast(java_object_t *o, classinfo *targetclass)
462 arraydescriptor *desc;
467 desc = o->vftbl->arraydesc;
472 return class_is_arraycompatible(desc, targetclass->vftbl->arraydesc);
476 /* builtin_fast_arrayinstanceof ************************************************
478 NOTE: This is a FAST builtin and can be called from JIT code only.
480 *******************************************************************************/
482 bool builtin_fast_arrayinstanceof(java_object_t *o, classinfo *targetclass)
487 return builtin_fast_arraycheckcast(o, targetclass);
491 /* builtin_arrayinstanceof *****************************************************
493 NOTE: This builtin can be called from NATIVE code only.
495 *******************************************************************************/
497 bool builtin_arrayinstanceof(java_handle_t *h, classinfo *targetclass)
503 result = builtin_fast_arrayinstanceof(LLNI_UNWRAP(h), targetclass);
511 /* builtin_throw_exception *****************************************************
513 Sets the exception pointer with the thrown exception and prints some
514 debugging information.
516 NOTE: This is a FAST builtin and can be called from JIT code,
517 or from asm_vm_call_method.
519 *******************************************************************************/
521 void *builtin_throw_exception(java_object_t *xptr)
524 /* print exception trace */
526 if (opt_TraceExceptions)
527 trace_exception_builtin(xptr);
528 #endif /* !defined(NDEBUG) */
530 /* actually set the exception */
532 exceptions_set_exception(LLNI_QUICKWRAP(xptr));
534 /* Return a NULL pointer. This is required for vm_call_method to
535 check for an exception. This is for convenience. */
541 /* builtin_retrieve_exception **************************************************
543 Gets and clears the exception pointer of the current thread.
546 the exception object, or NULL if no exception was thrown.
548 NOTE: This is a FAST builtin and can be called from JIT code,
549 or from the signal handlers.
551 *******************************************************************************/
553 java_object_t *builtin_retrieve_exception(void)
558 /* actually get and clear the exception */
560 h = exceptions_get_and_clear_exception();
567 /* builtin_canstore ************************************************************
569 Checks, if an object can be stored in an array.
573 0......otherwise (throws an ArrayStoreException)
575 NOTE: This is a SLOW builtin and can be called from JIT & NATIVE code.
577 *******************************************************************************/
579 bool builtin_canstore(java_handle_objectarray_t *oa, java_handle_t *o)
585 result = builtin_fast_canstore((java_objectarray_t*) LLNI_DIRECT(oa), LLNI_UNWRAP(o));
589 /* if not possible, throw an exception */
592 exceptions_throw_arraystoreexception();
598 /* fast_subtype_check **********************************************************
600 Checks if s is a subtype of t, using both the restricted subtype relation
601 and the overflow array (see Cliff Click and John Rose: Fast subtype checking
605 1......s is a subtype of t.
608 *******************************************************************************/
610 bool fast_subtype_check(struct _vftbl *s, struct _vftbl *t)
612 if (s->subtype_display[t->subtype_depth] == t)
614 if (t->subtype_offset != OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE]))
616 return s->subtype_depth >= t->subtype_depth && s->subtype_overflow[t->subtype_depth - DISPLAY_SIZE] == t;
620 /* builtin_fast_canstore *******************************************************
622 Checks, if an object can be stored in an array.
626 0......otherwise (no exception thrown!)
628 NOTE: This is a FAST builtin and can be called from JIT code only.
630 *******************************************************************************/
632 bool builtin_fast_canstore(java_objectarray_t *oa, java_object_t *o)
634 arraydescriptor *desc;
635 arraydescriptor *valuedesc;
636 vftbl_t *componentvftbl;
644 /* The following is guaranteed (by verifier checks):
646 * *) oa->...vftbl->arraydesc != NULL
647 * *) oa->...vftbl->arraydesc->componentvftbl != NULL
648 * *) o->vftbl is not an interface vftbl
651 desc = oa->header.objheader.vftbl->arraydesc;
652 componentvftbl = desc->componentvftbl;
653 valuevftbl = o->vftbl;
654 valuedesc = valuevftbl->arraydesc;
656 if ((desc->dimension - 1) == 0) {
657 /* {oa is a one-dimensional array} */
658 /* {oa is an array of references} */
660 if (valuevftbl == componentvftbl)
663 LOCK_CLASSRENUMBER_LOCK;
665 baseval = componentvftbl->baseval;
668 /* an array of interface references */
670 result = ((valuevftbl->interfacetablelength > -baseval) &&
671 (valuevftbl->interfacetable[baseval] != NULL));
675 result = fast_subtype_check(valuevftbl, componentvftbl);
677 uint32_t diffval = valuevftbl->baseval - componentvftbl->baseval;
678 result = diffval <= (uint32_t) componentvftbl->diffval;
682 UNLOCK_CLASSRENUMBER_LOCK;
684 else if (valuedesc == NULL) {
685 /* {oa has dimension > 1} */
686 /* {componentvftbl->arraydesc != NULL} */
688 /* check if o is an array */
693 /* {o is an array} */
695 result = class_is_arraycompatible(valuedesc, componentvftbl->arraydesc);
704 /* This is an optimized version where a is guaranteed to be one-dimensional */
705 bool builtin_fast_canstore_onedim(java_objectarray_t *a, java_object_t *o)
707 arraydescriptor *desc;
708 vftbl_t *elementvftbl;
716 /* The following is guaranteed (by verifier checks):
718 * *) a->...vftbl->arraydesc != NULL
719 * *) a->...vftbl->arraydesc->elementvftbl != NULL
720 * *) a->...vftbl->arraydesc->dimension == 1
721 * *) o->vftbl is not an interface vftbl
724 desc = a->header.objheader.vftbl->arraydesc;
725 elementvftbl = desc->elementvftbl;
726 valuevftbl = o->vftbl;
728 /* {a is a one-dimensional array} */
730 if (valuevftbl == elementvftbl)
733 LOCK_CLASSRENUMBER_LOCK;
735 baseval = elementvftbl->baseval;
738 /* an array of interface references */
739 result = ((valuevftbl->interfacetablelength > -baseval) &&
740 (valuevftbl->interfacetable[baseval] != NULL));
744 result = fast_subtype_check(valuevftbl, elementvftbl);
746 uint32_t diffval = valuevftbl->baseval - elementvftbl->baseval;
747 result = diffval <= (uint32_t) elementvftbl->diffval;
751 UNLOCK_CLASSRENUMBER_LOCK;
757 /* This is an optimized version where a is guaranteed to be a
758 * one-dimensional array of a class type */
759 bool builtin_fast_canstore_onedim_class(java_objectarray_t *a, java_object_t *o)
761 vftbl_t *elementvftbl;
768 /* The following is guaranteed (by verifier checks):
770 * *) a->...vftbl->arraydesc != NULL
771 * *) a->...vftbl->arraydesc->elementvftbl != NULL
772 * *) a->...vftbl->arraydesc->elementvftbl is not an interface vftbl
773 * *) a->...vftbl->arraydesc->dimension == 1
774 * *) o->vftbl is not an interface vftbl
777 elementvftbl = a->header.objheader.vftbl->arraydesc->elementvftbl;
778 valuevftbl = o->vftbl;
780 /* {a is a one-dimensional array} */
782 if (valuevftbl == elementvftbl)
785 LOCK_CLASSRENUMBER_LOCK;
788 result = fast_subtype_check(valuevftbl, elementvftbl);
790 uint32_t diffval = valuevftbl->baseval - elementvftbl->baseval;
791 result = diffval <= (uint32_t) elementvftbl->diffval;
794 UNLOCK_CLASSRENUMBER_LOCK;
800 /* builtin_new *****************************************************************
802 Creates a new instance of class c on the heap.
805 pointer to the object, or NULL if no memory is available
807 NOTE: This builtin can be called from NATIVE code only.
809 *******************************************************************************/
811 java_handle_t *builtin_new(classinfo *c)
814 #if defined(ENABLE_RT_TIMING)
815 struct timespec time_start, time_end;
817 #if defined(ENABLE_CYCLES_STATS)
818 u8 cycles_start, cycles_end;
821 RT_TIMING_GET_TIME(time_start);
822 CYCLES_STATS_GET(cycles_start);
824 /* is the class loaded */
826 assert(c->state & CLASS_LOADED);
828 /* check if we can instantiate this class */
830 if (c->flags & ACC_ABSTRACT) {
831 exceptions_throw_instantiationerror(c);
835 /* is the class linked */
837 if (!(c->state & CLASS_LINKED))
841 if (!(c->state & CLASS_INITIALIZED)) {
844 log_message_class("Initialize class (from builtin_new): ", c);
847 if (!initialize_class(c))
851 o = (java_handle_t*) heap_alloc(c->instancesize, c->flags & ACC_CLASS_HAS_POINTERS,
857 #if !defined(ENABLE_GC_CACAO) && defined(ENABLE_HANDLES)
858 /* XXX this is only a dirty hack to make Boehm work with handles */
860 o = LLNI_WRAP((java_object_t *) o);
863 LLNI_vftbl_direct(o) = c->vftbl;
865 #if defined(ENABLE_THREADS)
866 Lockword(LLNI_DIRECT(o)->lockword).init();
869 CYCLES_STATS_GET(cycles_end);
870 RT_TIMING_GET_TIME(time_end);
872 CYCLES_STATS_COUNT(builtin_new,cycles_end - cycles_start);
873 RT_TIMING_TIME_DIFF(time_start, time_end, RT_TIMING_NEW_OBJECT);
878 #if defined(ENABLE_ESCAPE_REASON)
879 java_handle_t *builtin_escape_reason_new(classinfo *c) {
880 print_escape_reasons();
881 return builtin_java_new(c);
885 #if defined(ENABLE_TLH)
886 java_handle_t *builtin_tlh_new(classinfo *c)
889 # if defined(ENABLE_RT_TIMING)
890 struct timespec time_start, time_end;
892 # if defined(ENABLE_CYCLES_STATS)
893 u8 cycles_start, cycles_end;
896 RT_TIMING_GET_TIME(time_start);
897 CYCLES_STATS_GET(cycles_start);
899 /* is the class loaded */
901 assert(c->state & CLASS_LOADED);
903 /* check if we can instantiate this class */
905 if (c->flags & ACC_ABSTRACT) {
906 exceptions_throw_instantiationerror(c);
910 /* is the class linked */
912 if (!(c->state & CLASS_LINKED))
916 if (!(c->state & CLASS_INITIALIZED)) {
917 # if !defined(NDEBUG)
919 log_message_class("Initialize class (from builtin_new): ", c);
922 if (!initialize_class(c))
927 o = tlh_alloc(&(THREADOBJECT->tlh), c->instancesize);
932 o = (java_handle_t*) heap_alloc(c->instancesize, c->flags & ACC_CLASS_HAS_POINTERS,
939 # if !defined(ENABLE_GC_CACAO) && defined(ENABLE_HANDLES)
940 /* XXX this is only a dirty hack to make Boehm work with handles */
942 o = LLNI_WRAP((java_object_t *) o);
945 LLNI_vftbl_direct(o) = c->vftbl;
947 # if defined(ENABLE_THREADS)
948 Lockword(LLNI_DIRECT(o)->lockword).init();
951 CYCLES_STATS_GET(cycles_end);
952 RT_TIMING_GET_TIME(time_end);
955 CYCLES_STATS_COUNT(builtin_new,cycles_end - cycles_start);
956 RT_TIMING_TIME_DIFF(time_start, time_end, RT_TIMING_NEW_OBJECT);
964 /* builtin_java_new ************************************************************
966 NOTE: This is a SLOW builtin and can be called from JIT code only.
968 *******************************************************************************/
970 java_handle_t *builtin_java_new(java_handle_t *clazz)
972 return builtin_new(LLNI_classinfo_unwrap(clazz));
976 /* builtin_fast_new ************************************************************
978 Creates a new instance of class c on the heap.
981 pointer to the object, or NULL if no fast return
982 is possible for any reason.
984 NOTE: This is a FAST builtin and can be called from JIT code only.
986 *******************************************************************************/
988 java_object_t *builtin_fast_new(classinfo *c)
991 #if defined(ENABLE_RT_TIMING)
992 struct timespec time_start, time_end;
994 #if defined(ENABLE_CYCLES_STATS)
995 u8 cycles_start, cycles_end;
998 RT_TIMING_GET_TIME(time_start);
999 CYCLES_STATS_GET(cycles_start);
1001 /* is the class loaded */
1003 assert(c->state & CLASS_LOADED);
1005 /* check if we can instantiate this class */
1007 if (c->flags & ACC_ABSTRACT)
1010 /* is the class linked */
1012 if (!(c->state & CLASS_LINKED))
1015 if (!(c->state & CLASS_INITIALIZED))
1018 o = (java_handle_t*) heap_alloc(c->instancesize, c->flags & ACC_CLASS_HAS_POINTERS,
1019 c->finalizer, false);
1024 o->vftbl = c->vftbl;
1026 #if defined(ENABLE_THREADS)
1027 Lockword(LLNI_DIRECT(o)->lockword).init();
1030 CYCLES_STATS_GET(cycles_end);
1031 RT_TIMING_GET_TIME(time_end);
1033 CYCLES_STATS_COUNT(builtin_new,cycles_end - cycles_start);
1034 RT_TIMING_TIME_DIFF(time_start, time_end, RT_TIMING_NEW_OBJECT);
1040 /* builtin_java_newarray *******************************************************
1042 Creates an array with the given vftbl on the heap. This function
1043 takes as class argument an array class.
1046 pointer to the array or NULL if no memory is available
1048 NOTE: This is a SLOW builtin and can be called from JIT code only.
1050 *******************************************************************************/
1052 java_handle_array_t *builtin_java_newarray(int32_t size, java_handle_t *arrayclazz)
1054 #if defined(ENABLE_RT_TIMING)
1055 struct timespec time_start, time_end;
1058 RT_TIMING_GET_TIME(time_start);
1060 classinfo* arrayclass = LLNI_classinfo_unwrap(arrayclazz);
1062 // Allocate a new array with given size and class on the heap
1063 Array a(size, arrayclass);
1065 RT_TIMING_GET_TIME(time_end);
1066 RT_TIMING_TIME_DIFF(time_start, time_end, RT_TIMING_NEW_ARRAY);
1068 return a.get_handle();
1072 /* builtin_newarray_type ****************************************************
1074 Creates an array of [type]s on the heap.
1077 pointer to the array or NULL if no memory is available
1079 NOTE: This is a SLOW builtin and can be called from JIT & NATIVE code.
1081 *******************************************************************************/
1083 #define BUILTIN_NEWARRAY_TYPE(type, name) \
1084 java_handle_##type##array_t *builtin_newarray_##type(int32_t size) \
1086 name##Array a(size); \
1087 return a.get_handle(); \
1090 BUILTIN_NEWARRAY_TYPE(boolean, Boolean)
1091 BUILTIN_NEWARRAY_TYPE(byte, Byte)
1092 BUILTIN_NEWARRAY_TYPE(char, Char)
1093 BUILTIN_NEWARRAY_TYPE(short, Short)
1094 BUILTIN_NEWARRAY_TYPE(int, Int)
1095 BUILTIN_NEWARRAY_TYPE(long, Long)
1096 BUILTIN_NEWARRAY_TYPE(float, Float)
1097 BUILTIN_NEWARRAY_TYPE(double, Double)
1100 /* builtin_multianewarray_intern ***********************************************
1102 Creates a multi-dimensional array on the heap. The dimensions are
1103 passed in an array of longs.
1106 n.............number of dimensions to create
1107 arrayclass....the array class
1108 dims..........array containing the size of each dimension to create
1111 pointer to the array or NULL if no memory is available
1113 ******************************************************************************/
1115 static java_handle_array_t *builtin_multianewarray_intern(int n,
1116 classinfo *arrayclass,
1121 /* create this dimension */
1123 int32_t size = (int32_t) dims[0];
1124 Array a(size, arrayclass);
1129 /* if this is the last dimension return */
1132 return a.get_handle();
1134 /* get the class of the components to create */
1136 classinfo* componentclass = arrayclass->vftbl->arraydesc->componentvftbl->clazz;
1138 /* The verifier guarantees that the dimension count is in the range. */
1140 /* create the component arrays */
1142 ObjectArray oa(a.get_handle());
1144 for (i = 0; i < size; i++) {
1145 java_handle_array_t *ea =
1146 #if defined(__MIPS__) && (SIZEOF_VOID_P == 4)
1147 /* we save an s4 to a s8 slot, 8-byte aligned */
1149 builtin_multianewarray_intern(n, componentclass, dims + 2);
1151 builtin_multianewarray_intern(n, componentclass, dims + 1);
1157 oa.set_element(i, (java_handle_t*) ea);
1160 return a.get_handle();
1164 /* builtin_multianewarray ******************************************************
1166 Wrapper for builtin_multianewarray_intern which checks all
1167 dimensions before we start allocating.
1169 NOTE: This is a SLOW builtin and can be called from JIT code only.
1171 ******************************************************************************/
1173 java_handle_objectarray_t *builtin_multianewarray(int n,
1174 java_handle_t *arrayclazz,
1181 /* check all dimensions before doing anything */
1183 for (i = 0; i < n; i++) {
1184 #if defined(__MIPS__) && (SIZEOF_VOID_P == 4)
1185 /* we save an s4 to a s8 slot, 8-byte aligned */
1186 size = (s4) dims[i * 2];
1188 size = (s4) dims[i];
1192 exceptions_throw_negativearraysizeexception();
1197 c = LLNI_classinfo_unwrap(arrayclazz);
1199 /* now call the real function */
1201 return (java_handle_objectarray_t *)
1202 builtin_multianewarray_intern(n, c, dims);
1206 /* builtin_verbosecall_enter ***************************************************
1208 Print method call with arguments for -verbose:call.
1210 XXX: Remove mew once all archs use the new tracer!
1212 *******************************************************************************/
1214 #if !defined(NDEBUG)
1215 #ifdef TRACE_ARGS_NUM
1216 void builtin_verbosecall_enter(s8 a0, s8 a1,
1217 # if TRACE_ARGS_NUM >= 4
1220 # if TRACE_ARGS_NUM >= 6
1223 # if TRACE_ARGS_NUM == 8
1228 log_text("builtin_verbosecall_enter: Do not call me anymore!");
1231 #endif /* !defined(NDEBUG) */
1234 /* builtin_verbosecall_exit ****************************************************
1236 Print method exit for -verbose:call.
1238 XXX: Remove mew once all archs use the new tracer!
1240 *******************************************************************************/
1242 #if !defined(NDEBUG)
1243 void builtin_verbosecall_exit(s8 l, double d, float f, methodinfo *m)
1245 log_text("builtin_verbosecall_exit: Do not call me anymore!");
1247 #endif /* !defined(NDEBUG) */
1250 /*============================================================================*/
1251 /* MISCELLANEOUS MATHEMATICAL HELPER FUNCTIONS */
1252 /*============================================================================*/
1254 /*********** Functions for integer divisions *****************************
1256 On some systems (eg. DEC ALPHA), integer division is not supported by the
1257 CPU. These helper functions implement the missing functionality.
1259 ******************************************************************************/
1261 #if !SUPPORT_DIVISION || defined(DISABLE_GC)
1262 s4 builtin_idiv(s4 a, s4 b)
1271 s4 builtin_irem(s4 a, s4 b)
1279 #endif /* !SUPPORT_DIVISION || defined(DISABLE_GC) */
1282 /* functions for long arithmetics **********************************************
1284 On systems where 64 bit Integers are not supported by the CPU,
1285 these functions are needed.
1287 ******************************************************************************/
1289 #if !(SUPPORT_LONG && SUPPORT_LONG_ADD)
1290 s8 builtin_ladd(s8 a, s8 b)
1299 s8 builtin_lsub(s8 a, s8 b)
1308 s8 builtin_lneg(s8 a)
1316 #endif /* !(SUPPORT_LONG && SUPPORT_LONG_ADD) */
1319 #if !(SUPPORT_LONG && SUPPORT_LONG_MUL)
1320 s8 builtin_lmul(s8 a, s8 b)
1328 #endif /* !(SUPPORT_LONG && SUPPORT_LONG_MUL) */
1331 #if !(SUPPORT_DIVISION && SUPPORT_LONG && SUPPORT_LONG_DIV) || defined (DISABLE_GC)
1332 s8 builtin_ldiv(s8 a, s8 b)
1341 s8 builtin_lrem(s8 a, s8 b)
1349 #endif /* !(SUPPORT_DIVISION && SUPPORT_LONG && SUPPORT_LONG_DIV) */
1352 #if !(SUPPORT_LONG && SUPPORT_LONG_SHIFT)
1353 s8 builtin_lshl(s8 a, s4 b)
1362 s8 builtin_lshr(s8 a, s4 b)
1371 s8 builtin_lushr(s8 a, s4 b)
1375 c = ((u8) a) >> (b & 63);
1379 #endif /* !(SUPPORT_LONG && SUPPORT_LONG_SHIFT) */
1382 #if !(SUPPORT_LONG && SUPPORT_LONG_LOGICAL)
1383 s8 builtin_land(s8 a, s8 b)
1392 s8 builtin_lor(s8 a, s8 b)
1401 s8 builtin_lxor(s8 a, s8 b)
1409 #endif /* !(SUPPORT_LONG && SUPPORT_LONG_LOGICAL) */
1412 s4 builtin_lcmp(s8 a, s8 b)
1424 /* functions for unsupported floating instructions ****************************/
1426 /* used to convert FLT_xxx defines into float values */
1428 static inline float intBitsToFloat(s4 i)
1437 /* used to convert DBL_xxx defines into double values */
1439 static inline float longBitsToDouble(s8 l)
1449 float builtin_fadd(float a, float b)
1451 if (isnanf(a)) return intBitsToFloat(FLT_NAN);
1452 if (isnanf(b)) return intBitsToFloat(FLT_NAN);
1463 if (copysignf(1.0, a) == copysignf(1.0, b))
1466 return intBitsToFloat(FLT_NAN);
1472 float builtin_fsub(float a, float b)
1474 return builtin_fadd(a, builtin_fneg(b));
1478 float builtin_fmul(float a, float b)
1480 if (isnanf(a)) return intBitsToFloat(FLT_NAN);
1481 if (isnanf(b)) return intBitsToFloat(FLT_NAN);
1483 if (finitef(b)) return a * b;
1485 if (a == 0) return intBitsToFloat(FLT_NAN);
1486 else return copysignf(b, copysignf(1.0, b)*a);
1491 if (b == 0) return intBitsToFloat(FLT_NAN);
1492 else return copysignf(a, copysignf(1.0, a)*b);
1495 return copysignf(a, copysignf(1.0, a)*copysignf(1.0, b));
1501 /* builtin_ddiv ****************************************************************
1503 Implementation as described in VM Spec.
1505 *******************************************************************************/
1507 float builtin_fdiv(float a, float b)
1511 /* If neither value1' nor value2' is NaN, the sign of the result */
1512 /* is positive if both values have the same sign, negative if the */
1513 /* values have different signs. */
1519 /* If either value1' or value2' is NaN, the result is NaN. */
1521 return intBitsToFloat(FLT_NAN);
1524 /* Division of a finite value by an infinity results in a */
1525 /* signed zero, with the sign-producing rule just given. */
1527 /* is sign equal? */
1529 if (copysignf(1.0, a) == copysignf(1.0, b))
1538 /* If either value1' or value2' is NaN, the result is NaN. */
1540 return intBitsToFloat(FLT_NAN);
1542 } else if (finitef(b)) {
1543 /* Division of an infinity by a finite value results in a signed */
1544 /* infinity, with the sign-producing rule just given. */
1546 /* is sign equal? */
1548 if (copysignf(1.0, a) == copysignf(1.0, b))
1549 return intBitsToFloat(FLT_POSINF);
1551 return intBitsToFloat(FLT_NEGINF);
1554 /* Division of an infinity by an infinity results in NaN. */
1556 return intBitsToFloat(FLT_NAN);
1562 float builtin_fneg(float a)
1564 if (isnanf(a)) return a;
1566 if (finitef(a)) return -a;
1567 else return copysignf(a, -copysignf(1.0, a));
1570 #endif /* !SUPPORT_FLOAT */
1573 #if !SUPPORT_FLOAT || !SUPPORT_FLOAT_CMP || defined(ENABLE_INTRP)
1574 s4 builtin_fcmpl(float a, float b)
1582 if (!finitef(a) || !finitef(b)) {
1583 a = finitef(a) ? 0 : copysignf(1.0, a);
1584 b = finitef(b) ? 0 : copysignf(1.0, b);
1597 s4 builtin_fcmpg(float a, float b)
1599 if (isnanf(a)) return 1;
1600 if (isnanf(b)) return 1;
1601 if (!finitef(a) || !finitef(b)) {
1602 a = finitef(a) ? 0 : copysignf(1.0, a);
1603 b = finitef(b) ? 0 : copysignf(1.0, b);
1605 if (a > b) return 1;
1606 if (a == b) return 0;
1609 #endif /* !SUPPORT_FLOAT || !SUPPORT_FLOAT_CMP || defined(ENABLE_INTRP) */
1612 float builtin_frem(float a, float b)
1618 /* functions for unsupported double instructions ******************************/
1621 double builtin_dadd(double a, double b)
1623 if (isnan(a)) return longBitsToDouble(DBL_NAN);
1624 if (isnan(b)) return longBitsToDouble(DBL_NAN);
1626 if (finite(b)) return a + b;
1630 if (finite(b)) return a;
1632 if (copysign(1.0, a)==copysign(1.0, b)) return a;
1633 else return longBitsToDouble(DBL_NAN);
1639 double builtin_dsub(double a, double b)
1641 return builtin_dadd(a, builtin_dneg(b));
1645 double builtin_dmul(double a, double b)
1647 if (isnan(a)) return longBitsToDouble(DBL_NAN);
1648 if (isnan(b)) return longBitsToDouble(DBL_NAN);
1650 if (finite(b)) return a * b;
1652 if (a == 0) return longBitsToDouble(DBL_NAN);
1653 else return copysign(b, copysign(1.0, b) * a);
1658 if (b == 0) return longBitsToDouble(DBL_NAN);
1659 else return copysign(a, copysign(1.0, a) * b);
1662 return copysign(a, copysign(1.0, a) * copysign(1.0, b));
1668 /* builtin_ddiv ****************************************************************
1670 Implementation as described in VM Spec.
1672 *******************************************************************************/
1674 double builtin_ddiv(double a, double b)
1678 /* If neither value1' nor value2' is NaN, the sign of the result */
1679 /* is positive if both values have the same sign, negative if the */
1680 /* values have different signs. */
1686 /* If either value1' or value2' is NaN, the result is NaN. */
1688 return longBitsToDouble(DBL_NAN);
1691 /* Division of a finite value by an infinity results in a */
1692 /* signed zero, with the sign-producing rule just given. */
1694 /* is sign equal? */
1696 if (copysign(1.0, a) == copysign(1.0, b))
1705 /* If either value1' or value2' is NaN, the result is NaN. */
1707 return longBitsToDouble(DBL_NAN);
1709 } else if (finite(b)) {
1710 /* Division of an infinity by a finite value results in a signed */
1711 /* infinity, with the sign-producing rule just given. */
1713 /* is sign equal? */
1715 if (copysign(1.0, a) == copysign(1.0, b))
1716 return longBitsToDouble(DBL_POSINF);
1718 return longBitsToDouble(DBL_NEGINF);
1721 /* Division of an infinity by an infinity results in NaN. */
1723 return longBitsToDouble(DBL_NAN);
1729 /* builtin_dneg ****************************************************************
1731 Implemented as described in VM Spec.
1733 *******************************************************************************/
1735 double builtin_dneg(double a)
1738 /* If the operand is NaN, the result is NaN (recall that NaN has no */
1745 /* If the operand is a zero, the result is the zero of opposite */
1751 /* If the operand is an infinity, the result is the infinity of */
1752 /* opposite sign. */
1754 return copysign(a, -copysign(1.0, a));
1758 #endif /* !SUPPORT_DOUBLE */
1761 #if !SUPPORT_DOUBLE || !SUPPORT_DOUBLE_CMP || defined(ENABLE_INTRP)
1762 s4 builtin_dcmpl(double a, double b)
1770 if (!finite(a) || !finite(b)) {
1771 a = finite(a) ? 0 : copysign(1.0, a);
1772 b = finite(b) ? 0 : copysign(1.0, b);
1785 s4 builtin_dcmpg(double a, double b)
1793 if (!finite(a) || !finite(b)) {
1794 a = finite(a) ? 0 : copysign(1.0, a);
1795 b = finite(b) ? 0 : copysign(1.0, b);
1806 #endif /* !SUPPORT_DOUBLE || !SUPPORT_DOUBLE_CMP || defined(ENABLE_INTRP) */
1809 double builtin_drem(double a, double b)
1815 /* conversion operations ******************************************************/
1817 #if !(SUPPORT_FLOAT && SUPPORT_I2F)
1818 float builtin_i2f(s4 a)
1820 float f = (float) a;
1823 #endif /* !(SUPPORT_FLOAT && SUPPORT_I2F) */
1826 #if !(SUPPORT_DOUBLE && SUPPORT_I2D)
1827 double builtin_i2d(s4 a)
1829 double d = (double) a;
1832 #endif /* !(SUPPORT_DOUBLE && SUPPORT_I2D) */
1835 #if !(SUPPORT_LONG && SUPPORT_FLOAT && SUPPORT_L2F)
1836 float builtin_l2f(s8 a)
1838 float f = (float) a;
1841 #endif /* !(SUPPORT_LONG && SUPPORT_FLOAT && SUPPORT_L2F) */
1844 #if !(SUPPORT_LONG && SUPPORT_DOUBLE && SUPPORT_L2D)
1845 double builtin_l2d(s8 a)
1847 double d = (double) a;
1850 #endif /* !(SUPPORT_LONG && SUPPORT_DOUBLE && SUPPORT_L2D) */
1853 #if !(SUPPORT_FLOAT && SUPPORT_F2I) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
1854 s4 builtin_f2i(float a)
1858 i = builtin_d2i((double) a);
1869 if (a < (-2147483648))
1870 return (-2147483648);
1873 f = copysignf((float) 1.0, a);
1876 return (-2147483648); */
1878 #endif /* !(SUPPORT_FLOAT && SUPPORT_F2I) || defined(ENABLE_INTRP) || defined(DISABLE_GC) */
1881 #if !(SUPPORT_FLOAT && SUPPORT_LONG && SUPPORT_F2L) || defined(DISABLE_GC)
1882 s8 builtin_f2l(float a)
1886 l = builtin_d2l((double) a);
1893 if (a > 9223372036854775807L)
1894 return 9223372036854775807L;
1895 if (a < (-9223372036854775808L))
1896 return (-9223372036854775808L);
1901 f = copysignf((float) 1.0, a);
1903 return 9223372036854775807L;
1904 return (-9223372036854775808L); */
1906 #endif /* !(SUPPORT_FLOAT && SUPPORT_LONG && SUPPORT_F2L) */
1909 #if !(SUPPORT_DOUBLE && SUPPORT_D2I) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
1910 s4 builtin_d2i(double a)
1915 if (a >= 2147483647)
1917 if (a <= (-2147483647-1))
1918 return (-2147483647-1);
1923 d = copysign(1.0, a);
1926 return (-2147483647-1);
1928 #endif /* !(SUPPORT_DOUBLE && SUPPORT_D2I) || defined(ENABLE_INTRP) || defined(DISABLE_GC) */
1931 #if !(SUPPORT_DOUBLE && SUPPORT_LONG && SUPPORT_D2L) || defined(DISABLE_GC)
1932 s8 builtin_d2l(double a)
1937 if (a >= 9223372036854775807LL)
1938 return 9223372036854775807LL;
1939 if (a <= (-9223372036854775807LL-1))
1940 return (-9223372036854775807LL-1);
1945 d = copysign(1.0, a);
1947 return 9223372036854775807LL;
1948 return (-9223372036854775807LL-1);
1950 #endif /* !(SUPPORT_DOUBLE && SUPPORT_LONG && SUPPORT_D2L) */
1953 #if !(SUPPORT_FLOAT && SUPPORT_DOUBLE)
1954 double builtin_f2d(float a)
1956 if (finitef(a)) return (double) a;
1959 return longBitsToDouble(DBL_NAN);
1961 return copysign(longBitsToDouble(DBL_POSINF), (double) copysignf(1.0, a) );
1965 float builtin_d2f(double a)
1971 return intBitsToFloat(FLT_NAN);
1973 return copysignf(intBitsToFloat(FLT_POSINF), (float) copysign(1.0, a));
1976 #endif /* !(SUPPORT_FLOAT && SUPPORT_DOUBLE) */
1979 /*============================================================================*/
1980 /* AUTOMATICALLY REPLACED FUNCTIONS */
1981 /*============================================================================*/
1983 /* builtin_arraycopy ***********************************************************
1985 Builtin for java.lang.System.arraycopy.
1987 NOTE: This is a SLOW builtin and can be called from JIT & NATIVE code.
1989 *******************************************************************************/
1991 void builtin_arraycopy(java_handle_t *src, s4 srcStart,
1992 java_handle_t *dest, s4 destStart, s4 len)
1994 arraydescriptor *sdesc;
1995 arraydescriptor *ddesc;
1998 if ((src == NULL) || (dest == NULL)) {
1999 exceptions_throw_nullpointerexception();
2006 sdesc = LLNI_vftbl_direct(src)->arraydesc;
2007 ddesc = LLNI_vftbl_direct(dest)->arraydesc;
2009 if (!sdesc || !ddesc || (sdesc->arraytype != ddesc->arraytype)) {
2010 exceptions_throw_arraystoreexception();
2014 // Check if offsets and length are positive.
2015 if ((srcStart < 0) || (destStart < 0) || (len < 0)) {
2016 exceptions_throw_arrayindexoutofboundsexception();
2020 // Check if ranges are valid.
2021 if ((((uint32_t) srcStart + (uint32_t) len) > (uint32_t) sa.get_length()) ||
2022 (((uint32_t) destStart + (uint32_t) len) > (uint32_t) da.get_length())) {
2023 exceptions_throw_arrayindexoutofboundsexception();
2032 if (sdesc->componentvftbl == ddesc->componentvftbl) {
2033 /* We copy primitive values or references of exactly the same type */
2035 s4 dataoffset = sdesc->dataoffset;
2036 s4 componentsize = sdesc->componentsize;
2038 LLNI_CRITICAL_START;
2040 MMOVE(((u1 *) LLNI_DIRECT(dest)) + dataoffset + componentsize * destStart,
2041 ((u1 *) LLNI_DIRECT(src)) + dataoffset + componentsize * srcStart,
2042 u1, (size_t) len * componentsize);
2047 /* We copy references of different type */
2049 ObjectArray oas((java_handle_objectarray_t*) src);
2050 ObjectArray oad((java_handle_objectarray_t*) dest);
2052 if (destStart <= srcStart) {
2053 for (i = 0; i < len; i++) {
2054 java_handle_t* o = oas.get_element(srcStart + i);
2056 if (!builtin_canstore(oad.get_handle(), o))
2059 oad.set_element(destStart + i, o);
2063 /* XXX this does not completely obey the specification!
2064 If an exception is thrown only the elements above the
2065 current index have been copied. The specification
2066 requires that only the elements *below* the current
2067 index have been copied before the throw. */
2069 for (i = len - 1; i >= 0; i--) {
2070 java_handle_t* o = oas.get_element(srcStart + i);
2072 if (!builtin_canstore(oad.get_handle(), o))
2075 oad.set_element(destStart + i, o);
2082 /* builtin_nanotime ************************************************************
2084 Return the current time in nanoseconds.
2086 *******************************************************************************/
2088 s8 builtin_nanotime(void)
2093 if (gettimeofday(&tv, NULL) == -1)
2094 vm_abort("gettimeofday failed: %s", strerror(errno));
2096 usecs = (s8) tv.tv_sec * (1000 * 1000) + (s8) tv.tv_usec;
2098 return usecs * 1000;
2102 /* builtin_currenttimemillis ***************************************************
2104 Return the current time in milliseconds.
2106 *******************************************************************************/
2108 s8 builtin_currenttimemillis(void)
2112 msecs = builtin_nanotime() / 1000 / 1000;
2118 /* builtin_clone ***************************************************************
2120 Function for cloning objects or arrays.
2122 NOTE: This is a SLOW builtin and can be called from JIT & NATIVE code.
2124 *******************************************************************************/
2126 java_handle_t *builtin_clone(void *env, java_handle_t *o)
2128 arraydescriptor *ad;
2131 java_handle_t *co; /* cloned object header */
2133 /* get the array descriptor */
2135 ad = LLNI_vftbl_direct(o)->arraydesc;
2137 /* we are cloning an array */
2142 size = ad->dataoffset + ad->componentsize * a.get_length();
2144 co = (java_handle_t*) heap_alloc(size, (ad->arraytype == ARRAYTYPE_OBJECT), NULL, true);
2149 #if !defined(ENABLE_GC_CACAO) && defined(ENABLE_HANDLES)
2150 /* XXX this is only a dirty hack to make Boehm work with handles */
2152 co = LLNI_WRAP((java_object_t *) co);
2155 LLNI_CRITICAL_START;
2157 MCOPY(LLNI_DIRECT(co), LLNI_DIRECT(o), u1, size);
2159 #if defined(ENABLE_GC_CACAO)
2160 heap_init_objectheader(LLNI_DIRECT(co), size);
2163 #if defined(ENABLE_THREADS)
2164 Lockword(LLNI_DIRECT(co)->lockword).init();
2172 /* we are cloning a non-array */
2174 if (!builtin_instanceof(o, class_java_lang_Cloneable)) {
2175 exceptions_throw_clonenotsupportedexception();
2179 /* get the class of the object */
2181 LLNI_class_get(o, c);
2183 /* create new object */
2185 co = builtin_new(c);
2190 LLNI_CRITICAL_START;
2192 MCOPY(LLNI_DIRECT(co), LLNI_DIRECT(o), u1, c->instancesize);
2194 #if defined(ENABLE_GC_CACAO)
2195 heap_init_objectheader(LLNI_DIRECT(co), c->instancesize);
2198 #if defined(ENABLE_THREADS)
2199 Lockword(LLNI_DIRECT(co)->lockword).init();
2208 #if defined(ENABLE_CYCLES_STATS)
2209 void builtin_print_cycles_stats(FILE *file)
2211 fprintf(file,"builtin cylce count statistics:\n");
2213 CYCLES_STATS_PRINT_OVERHEAD(builtin_overhead,file);
2214 CYCLES_STATS_PRINT(builtin_new ,file);
2218 #endif /* defined(ENABLE_CYCLES_STATS) */
2221 #if defined(ENABLE_VMLOG)
2223 #include <vmlog_cacao.c>
2228 * These are local overrides for various environment variables in Emacs.
2229 * Please do not remove this and leave it at the end of the file, where
2230 * Emacs will automagically detect them.
2231 * ---------------------------------------------------------------------
2234 * indent-tabs-mode: t
2238 * vim:noexpandtab:sw=4:ts=4: