1 /* src/vm/builtin.c - functions for unsupported operations
3 Copyright (C) 1996-2005, 2006, 2007, 2008
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)
50 #include "mm/gc-common.h"
51 #include "mm/memory.h"
53 #include "native/jni.h"
54 #include "native/llni.h"
56 #include "threads/lock-common.h"
57 #include "threads/thread.h"
59 #include "toolbox/logging.h"
60 #include "toolbox/util.h"
63 #include "vm/builtin.h"
64 #include "vm/cycles-stats.h"
65 #include "vm/exceptions.h"
66 #include "vm/global.h"
67 #include "vm/initialize.h"
68 #include "vm/primitive.h"
69 #include "vm/stringlocal.h"
71 #include "vm/jit/asmpart.h"
72 #include "vm/jit/trace.h"
74 #include "vmcore/class.h"
75 #include "vmcore/linker.h"
76 #include "vmcore/loader.h"
77 #include "vmcore/options.h"
78 #include "vmcore/rt-timing.h"
80 #if defined(ENABLE_VMLOG)
81 #include <vmlog_cacao.h>
85 /* include builtin tables *****************************************************/
87 #include "vm/builtintable.inc"
90 CYCLES_STATS_DECLARE(builtin_new ,100,5)
91 CYCLES_STATS_DECLARE(builtin_overhead , 80,1)
94 /*============================================================================*/
95 /* BUILTIN TABLE MANAGEMENT FUNCTIONS */
96 /*============================================================================*/
98 /* builtintable_init ***********************************************************
100 Parse the descriptors of builtin functions and create the parsed
103 *******************************************************************************/
105 static bool builtintable_init(void)
107 descriptor_pool *descpool;
108 builtintable_entry *bte;
112 /* mark start of 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)) {
135 /* release dump area */
143 for (bte = builtintable_automatic; bte->fp != NULL; bte++) {
144 bte->descriptor = utf_new_char(bte->cdescriptor);
146 if (!descriptor_pool_add(descpool, bte->descriptor, NULL)) {
152 for (bte = builtintable_function; bte->fp != NULL; bte++) {
153 bte->classname = utf_new_char(bte->cclassname);
154 bte->name = utf_new_char(bte->cname);
155 bte->descriptor = utf_new_char(bte->cdescriptor);
157 if (!descriptor_pool_add(descpool, bte->descriptor, NULL)) {
163 /* create the class reference table */
165 (void) descriptor_pool_create_classrefs(descpool, NULL);
167 /* allocate space for the parsed descriptors */
169 descriptor_pool_alloc_parsed_descriptors(descpool);
171 /* Now parse all descriptors. NOTE: builtin-functions are treated
172 like static methods (no `this' pointer). */
174 for (bte = builtintable_internal; bte->fp != NULL; bte++) {
176 descriptor_pool_parse_method_descriptor(descpool,
178 ACC_STATIC | ACC_METHOD_BUILTIN,
181 /* generate a builtin stub if we need one */
183 if (bte->flags & BUILTINTABLE_FLAG_STUB) {
184 m = method_new_builtin(bte);
185 codegen_generate_stub_builtin(m, bte);
189 for (bte = builtintable_automatic; bte->fp != NULL; bte++) {
191 descriptor_pool_parse_method_descriptor(descpool,
193 ACC_STATIC | ACC_METHOD_BUILTIN,
196 /* no stubs should be needed for this table */
198 assert(!bte->flags & BUILTINTABLE_FLAG_STUB);
201 for (bte = builtintable_function; bte->fp != NULL; bte++) {
203 descriptor_pool_parse_method_descriptor(descpool,
205 ACC_STATIC | ACC_METHOD_BUILTIN,
208 /* generate a builtin stub if we need one */
210 if (bte->flags & BUILTINTABLE_FLAG_STUB) {
211 m = method_new_builtin(bte);
212 codegen_generate_stub_builtin(m, bte);
216 /* release dump area */
224 /* builtintable_comparator *****************************************************
226 qsort comparator for the automatic builtin table.
228 *******************************************************************************/
230 static int builtintable_comparator(const void *a, const void *b)
232 builtintable_entry *bte1;
233 builtintable_entry *bte2;
235 bte1 = (builtintable_entry *) a;
236 bte2 = (builtintable_entry *) b;
238 return (bte1->opcode < bte2->opcode) ? -1 : (bte1->opcode > bte2->opcode);
242 /* builtintable_sort_automatic *************************************************
244 Sorts the automatic builtin table.
246 *******************************************************************************/
248 static void builtintable_sort_automatic(void)
252 /* calculate table size statically (`- 1' comment see builtintable.inc) */
254 entries = sizeof(builtintable_automatic) / sizeof(builtintable_entry) - 1;
256 qsort(builtintable_automatic, entries, sizeof(builtintable_entry),
257 builtintable_comparator);
261 /* builtin_init ****************************************************************
263 Initialize the global table of builtin functions.
265 *******************************************************************************/
267 bool builtin_init(void)
269 TRACESUBSYSTEMINITIALIZATION("builtin_init");
271 /* initialize the builtin tables */
273 if (!builtintable_init())
276 /* sort builtin tables */
278 builtintable_sort_automatic();
284 /* builtintable_get_internal ***************************************************
286 Finds an entry in the builtintable for internal functions and
287 returns the a pointer to the structure.
289 *******************************************************************************/
291 builtintable_entry *builtintable_get_internal(functionptr fp)
293 builtintable_entry *bte;
295 for (bte = builtintable_internal; bte->fp != NULL; bte++) {
304 /* builtintable_get_automatic **************************************************
306 Finds an entry in the builtintable for functions which are replaced
307 automatically and returns the a pointer to the structure.
309 *******************************************************************************/
311 builtintable_entry *builtintable_get_automatic(s4 opcode)
313 builtintable_entry *first;
314 builtintable_entry *last;
315 builtintable_entry *middle;
319 /* calculate table size statically (`- 1' comment see builtintable.inc) */
321 entries = sizeof(builtintable_automatic) / sizeof(builtintable_entry) - 1;
323 first = builtintable_automatic;
324 last = builtintable_automatic + entries;
326 while (entries > 0) {
328 middle = first + half;
330 if (middle->opcode < opcode) {
338 return (first != last ? first : NULL);
342 /* builtintable_replace_function ***********************************************
346 *******************************************************************************/
348 #if defined(ENABLE_JIT)
349 bool builtintable_replace_function(void *iptr_)
352 builtintable_entry *bte;
355 iptr = (instruction *) iptr_; /* twisti will kill me ;) */
357 /* get name and descriptor of the function */
360 case ICMD_INVOKESTATIC:
361 /* The instruction MUST be resolved, otherwise we run into
362 lazy loading troubles. Anyway, we should/can only replace
363 very VM-close functions. */
365 if (INSTRUCTION_IS_UNRESOLVED(iptr))
368 mr = iptr->sx.s23.s3.fmiref;
375 /* search the function table */
377 for (bte = builtintable_function; bte->fp != NULL; bte++) {
378 if ((METHODREF_CLASSNAME(mr) == bte->classname) &&
379 (mr->name == bte->name) &&
380 (mr->descriptor == bte->descriptor)) {
382 /* set the values in the instruction */
384 iptr->opc = bte->opcode;
385 iptr->sx.s23.s3.bte = bte;
387 if (bte->flags & BUILTINTABLE_FLAG_EXCEPTION)
388 iptr->flags.bits |= INS_FLAG_CHECK;
390 iptr->flags.bits &= ~INS_FLAG_CHECK;
398 #endif /* defined(ENABLE_JIT) */
401 /*============================================================================*/
402 /* INTERNAL BUILTIN FUNCTIONS */
403 /*============================================================================*/
405 /* builtin_instanceof **********************************************************
407 Checks if an object is an instance of some given class (or subclass
408 of that class). If class is an interface, checks if the interface
412 1......o is an instance of class or implements the interface
413 0......otherwise or if o == NULL
415 NOTE: This builtin can be called from NATIVE code only.
417 *******************************************************************************/
419 bool builtin_instanceof(java_handle_t *o, classinfo *class)
426 LLNI_class_get(o, c);
428 return class_isanysubclass(c, class);
433 /* builtin_checkcast ***********************************************************
435 The same as builtin_instanceof but with the exception
436 that 1 is returned when (o == NULL).
438 NOTE: This builtin can be called from NATIVE code only.
440 *******************************************************************************/
442 bool builtin_checkcast(java_handle_t *o, classinfo *class)
449 LLNI_class_get(o, c);
451 if (class_isanysubclass(c, class))
458 /* builtin_descriptorscompatible ***********************************************
460 Checks if two array type descriptors are assignment compatible.
463 1......target = desc is possible
466 *******************************************************************************/
468 static bool builtin_descriptorscompatible(arraydescriptor *desc, arraydescriptor *target)
473 if (desc->arraytype != target->arraytype)
476 if (desc->arraytype != ARRAYTYPE_OBJECT)
479 /* {both arrays are arrays of references} */
481 if (desc->dimension == target->dimension) {
482 if (!desc->elementvftbl)
484 /* an array which contains elements of interface types is
485 allowed to be casted to Object (JOWENN)*/
487 if ((desc->elementvftbl->baseval < 0) &&
488 (target->elementvftbl->baseval == 1))
491 return class_isanysubclass(desc->elementvftbl->clazz,
492 target->elementvftbl->clazz);
495 if (desc->dimension < target->dimension)
498 /* {desc has higher dimension than target} */
500 return class_isanysubclass(pseudo_class_Arraystub,
501 target->elementvftbl->clazz);
505 /* builtin_arraycheckcast ******************************************************
507 Checks if an object is really a subtype of the requested array
508 type. The object has to be an array to begin with. For simple
509 arrays (int, short, double, etc.) the types have to match exactly.
510 For arrays of objects, the type of elements in the array has to be
511 a subtype (or the same type) of the requested element type. For
512 arrays of arrays (which in turn can again be arrays of arrays), the
513 types at the lowest level have to satisfy the corresponding sub
516 NOTE: This is a FAST builtin and can be called from JIT code only.
518 *******************************************************************************/
520 bool builtin_fast_arraycheckcast(java_object_t *o, classinfo *targetclass)
522 arraydescriptor *desc;
527 desc = o->vftbl->arraydesc;
532 return builtin_descriptorscompatible(desc, targetclass->vftbl->arraydesc);
536 /* builtin_fast_arrayinstanceof ************************************************
538 NOTE: This is a FAST builtin and can be called from JIT code only.
540 *******************************************************************************/
542 bool builtin_fast_arrayinstanceof(java_object_t *o, classinfo *targetclass)
547 return builtin_fast_arraycheckcast(o, targetclass);
551 /* builtin_arrayinstanceof *****************************************************
553 NOTE: This builtin can be called from NATIVE code only.
555 *******************************************************************************/
557 bool builtin_arrayinstanceof(java_handle_t *h, classinfo *targetclass)
563 result = builtin_fast_arrayinstanceof(LLNI_UNWRAP(h), targetclass);
571 /* builtin_throw_exception *****************************************************
573 Sets the exception pointer with the thrown exception and prints some
574 debugging information.
576 NOTE: This is a FAST builtin and can be called from JIT code,
577 or from asm_vm_call_method.
579 *******************************************************************************/
581 void *builtin_throw_exception(java_object_t *xptr)
584 /* print exception trace */
586 if (opt_TraceExceptions)
587 trace_exception_builtin(xptr);
588 #endif /* !defined(NDEBUG) */
590 /* actually set the exception */
592 exceptions_set_exception(LLNI_QUICKWRAP(xptr));
594 /* Return a NULL pointer. This is required for vm_call_method to
595 check for an exception. This is for convenience. */
601 /* builtin_retrieve_exception **************************************************
603 Gets and clears the exception pointer of the current thread.
606 the exception object, or NULL if no exception was thrown.
608 NOTE: This is a FAST builtin and can be called from JIT code,
609 or from the signal handlers.
611 *******************************************************************************/
613 java_object_t *builtin_retrieve_exception(void)
618 /* actually get and clear the exception */
620 h = exceptions_get_and_clear_exception();
627 /* builtin_canstore ************************************************************
629 Checks, if an object can be stored in an array.
633 0......otherwise (throws an ArrayStoreException)
635 NOTE: This is a SLOW builtin and can be called from JIT & NATIVE code.
637 *******************************************************************************/
639 bool builtin_canstore(java_handle_objectarray_t *oa, java_handle_t *o)
645 result = builtin_fast_canstore(LLNI_DIRECT(oa), LLNI_UNWRAP(o));
649 /* if not possible, throw an exception */
652 exceptions_throw_arraystoreexception();
658 /* builtin_fast_canstore *******************************************************
660 Checks, if an object can be stored in an array.
664 0......otherwise (no exception thrown!)
666 NOTE: This is a FAST builtin and can be called from JIT code only.
668 *******************************************************************************/
670 bool fast_subtype_check(struct _vftbl *s, struct _vftbl *t)
672 if (s->subtype_display[t->subtype_depth] == t)
674 if (t->subtype_offset != OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE]))
676 return s->subtype_overflow_length > (t->subtype_depth - DISPLAY_SIZE) && s->subtype_overflow[t->subtype_depth - DISPLAY_SIZE] == t;
679 bool builtin_fast_canstore(java_objectarray_t *oa, java_object_t *o)
681 arraydescriptor *desc;
682 arraydescriptor *valuedesc;
683 vftbl_t *componentvftbl;
692 /* The following is guaranteed (by verifier checks):
694 * *) oa->...vftbl->arraydesc != NULL
695 * *) oa->...vftbl->arraydesc->componentvftbl != NULL
696 * *) o->vftbl is not an interface vftbl
699 desc = oa->header.objheader.vftbl->arraydesc;
700 componentvftbl = desc->componentvftbl;
701 valuevftbl = o->vftbl;
702 valuedesc = valuevftbl->arraydesc;
704 if ((desc->dimension - 1) == 0) {
705 /* {oa is a one-dimensional array} */
706 /* {oa is an array of references} */
708 if (valuevftbl == componentvftbl)
711 baseval = componentvftbl->baseval;
714 /* an array of interface references */
716 result = ((valuevftbl->interfacetablelength > -baseval) &&
717 (valuevftbl->interfacetable[baseval] != NULL));
720 result = fast_subtype_check(valuevftbl, componentvftbl);
723 else if (valuedesc == NULL) {
724 /* {oa has dimension > 1} */
725 /* {componentvftbl->arraydesc != NULL} */
727 /* check if o is an array */
732 /* {o is an array} */
734 result = builtin_descriptorscompatible(valuedesc, componentvftbl->arraydesc);
743 /* This is an optimized version where a is guaranteed to be one-dimensional */
744 bool builtin_fast_canstore_onedim(java_objectarray_t *a, java_object_t *o)
746 arraydescriptor *desc;
747 vftbl_t *elementvftbl;
756 /* The following is guaranteed (by verifier checks):
758 * *) a->...vftbl->arraydesc != NULL
759 * *) a->...vftbl->arraydesc->elementvftbl != NULL
760 * *) a->...vftbl->arraydesc->dimension == 1
761 * *) o->vftbl is not an interface vftbl
764 desc = a->header.objheader.vftbl->arraydesc;
765 elementvftbl = desc->elementvftbl;
766 valuevftbl = o->vftbl;
768 /* {a is a one-dimensional array} */
770 if (valuevftbl == elementvftbl)
773 baseval = elementvftbl->baseval;
776 /* an array of interface references */
777 result = ((valuevftbl->interfacetablelength > -baseval) &&
778 (valuevftbl->interfacetable[baseval] != NULL));
781 result = fast_subtype_check(valuevftbl, elementvftbl);
788 /* This is an optimized version where a is guaranteed to be a
789 * one-dimensional array of a class type */
790 bool builtin_fast_canstore_onedim_class(java_objectarray_t *a, java_object_t *o)
792 vftbl_t *elementvftbl;
800 /* The following is guaranteed (by verifier checks):
802 * *) a->...vftbl->arraydesc != NULL
803 * *) a->...vftbl->arraydesc->elementvftbl != NULL
804 * *) a->...vftbl->arraydesc->elementvftbl is not an interface vftbl
805 * *) a->...vftbl->arraydesc->dimension == 1
806 * *) o->vftbl is not an interface vftbl
809 elementvftbl = a->header.objheader.vftbl->arraydesc->elementvftbl;
810 valuevftbl = o->vftbl;
812 /* {a is a one-dimensional array} */
814 if (valuevftbl == elementvftbl)
817 result = fast_subtype_check(valuevftbl, elementvftbl);
823 /* builtin_new *****************************************************************
825 Creates a new instance of class c on the heap.
828 pointer to the object, or NULL if no memory is available
830 NOTE: This builtin can be called from NATIVE code only.
832 *******************************************************************************/
834 java_handle_t *builtin_new(classinfo *c)
837 #if defined(ENABLE_RT_TIMING)
838 struct timespec time_start, time_end;
840 #if defined(ENABLE_CYCLES_STATS)
841 u8 cycles_start, cycles_end;
844 RT_TIMING_GET_TIME(time_start);
845 CYCLES_STATS_GET(cycles_start);
847 /* is the class loaded */
849 assert(c->state & CLASS_LOADED);
851 /* check if we can instantiate this class */
853 if (c->flags & ACC_ABSTRACT) {
854 exceptions_throw_instantiationerror(c);
858 /* is the class linked */
860 if (!(c->state & CLASS_LINKED))
864 if (!(c->state & CLASS_INITIALIZED)) {
867 log_message_class("Initialize class (from builtin_new): ", c);
870 if (!initialize_class(c))
874 o = heap_alloc(c->instancesize, c->flags & ACC_CLASS_HAS_POINTERS,
880 #if !defined(ENABLE_GC_CACAO) && defined(ENABLE_HANDLES)
881 /* XXX this is only a dirty hack to make Boehm work with handles */
883 o = LLNI_WRAP((java_object_t *) o);
886 LLNI_vftbl_direct(o) = c->vftbl;
888 #if defined(ENABLE_THREADS)
889 lock_init_object_lock(LLNI_DIRECT(o));
892 CYCLES_STATS_GET(cycles_end);
893 RT_TIMING_GET_TIME(time_end);
895 CYCLES_STATS_COUNT(builtin_new,cycles_end - cycles_start);
896 RT_TIMING_TIME_DIFF(time_start, time_end, RT_TIMING_NEW_OBJECT);
902 /* builtin_java_new ************************************************************
904 NOTE: This is a SLOW builtin and can be called from JIT code only.
906 *******************************************************************************/
908 java_handle_t *builtin_java_new(java_handle_t *clazz)
910 return builtin_new(LLNI_classinfo_unwrap(clazz));
914 /* builtin_fast_new ************************************************************
916 Creates a new instance of class c on the heap.
919 pointer to the object, or NULL if no fast return
920 is possible for any reason.
922 NOTE: This is a FAST builtin and can be called from JIT code only.
924 *******************************************************************************/
926 java_object_t *builtin_fast_new(classinfo *c)
929 #if defined(ENABLE_RT_TIMING)
930 struct timespec time_start, time_end;
932 #if defined(ENABLE_CYCLES_STATS)
933 u8 cycles_start, cycles_end;
936 RT_TIMING_GET_TIME(time_start);
937 CYCLES_STATS_GET(cycles_start);
939 /* is the class loaded */
941 assert(c->state & CLASS_LOADED);
943 /* check if we can instantiate this class */
945 if (c->flags & ACC_ABSTRACT)
948 /* is the class linked */
950 if (!(c->state & CLASS_LINKED))
953 if (!(c->state & CLASS_INITIALIZED))
956 o = heap_alloc(c->instancesize, c->flags & ACC_CLASS_HAS_POINTERS,
957 c->finalizer, false);
964 #if defined(ENABLE_THREADS)
965 lock_init_object_lock(o);
968 CYCLES_STATS_GET(cycles_end);
969 RT_TIMING_GET_TIME(time_end);
971 CYCLES_STATS_COUNT(builtin_new,cycles_end - cycles_start);
972 RT_TIMING_TIME_DIFF(time_start, time_end, RT_TIMING_NEW_OBJECT);
978 /* builtin_newarray ************************************************************
980 Creates an array with the given vftbl on the heap. This function
981 takes as class argument an array class.
984 pointer to the array or NULL if no memory is available
986 NOTE: This builtin can be called from NATIVE code only.
988 *******************************************************************************/
990 java_handle_t *builtin_newarray(int32_t size, classinfo *arrayclass)
992 arraydescriptor *desc;
997 #if defined(ENABLE_RT_TIMING)
998 struct timespec time_start, time_end;
1001 RT_TIMING_GET_TIME(time_start);
1003 desc = arrayclass->vftbl->arraydesc;
1004 dataoffset = desc->dataoffset;
1005 componentsize = desc->componentsize;
1008 exceptions_throw_negativearraysizeexception();
1012 actualsize = dataoffset + size * componentsize;
1014 /* check for overflow */
1016 if (((u4) actualsize) < ((u4) size)) {
1017 exceptions_throw_outofmemoryerror();
1021 a = heap_alloc(actualsize, (desc->arraytype == ARRAYTYPE_OBJECT), NULL, true);
1026 #if !defined(ENABLE_GC_CACAO) && defined(ENABLE_HANDLES)
1027 /* XXX this is only a dirty hack to make Boehm work with handles */
1029 a = LLNI_WRAP((java_object_t *) a);
1032 LLNI_vftbl_direct(a) = arrayclass->vftbl;
1034 #if defined(ENABLE_THREADS)
1035 lock_init_object_lock(LLNI_DIRECT(a));
1038 LLNI_array_size(a) = size;
1040 RT_TIMING_GET_TIME(time_end);
1041 RT_TIMING_TIME_DIFF(time_start, time_end, RT_TIMING_NEW_ARRAY);
1047 /* builtin_java_newarray *******************************************************
1049 NOTE: This is a SLOW builtin and can be called from JIT code only.
1051 *******************************************************************************/
1053 java_handle_t *builtin_java_newarray(int32_t size, java_handle_t *arrayclazz)
1055 return builtin_newarray(size, LLNI_classinfo_unwrap(arrayclazz));
1059 /* builtin_anewarray ***********************************************************
1061 Creates an array of references to the given class type on the heap.
1064 pointer to the array or NULL if no memory is
1067 NOTE: This builtin can be called from NATIVE code only.
1069 *******************************************************************************/
1071 java_handle_objectarray_t *builtin_anewarray(int32_t size, classinfo *componentclass)
1073 classinfo *arrayclass;
1075 /* is class loaded */
1077 assert(componentclass->state & CLASS_LOADED);
1079 /* is class linked */
1081 if (!(componentclass->state & CLASS_LINKED))
1082 if (!link_class(componentclass))
1085 arrayclass = class_array_of(componentclass, true);
1090 return (java_handle_objectarray_t *) builtin_newarray(size, arrayclass);
1094 /* builtin_newarray_type ****************************************************
1096 Creates an array of [type]s on the heap.
1099 pointer to the array or NULL if no memory is available
1101 NOTE: This is a SLOW builtin and can be called from JIT & NATIVE code.
1103 *******************************************************************************/
1105 #define BUILTIN_NEWARRAY_TYPE(type, arraytype) \
1106 java_handle_##type##array_t *builtin_newarray_##type(int32_t size) \
1108 return (java_handle_##type##array_t *) \
1109 builtin_newarray(size, primitivetype_table[arraytype].arrayclass); \
1112 BUILTIN_NEWARRAY_TYPE(boolean, ARRAYTYPE_BOOLEAN)
1113 BUILTIN_NEWARRAY_TYPE(byte, ARRAYTYPE_BYTE)
1114 BUILTIN_NEWARRAY_TYPE(char, ARRAYTYPE_CHAR)
1115 BUILTIN_NEWARRAY_TYPE(short, ARRAYTYPE_SHORT)
1116 BUILTIN_NEWARRAY_TYPE(int, ARRAYTYPE_INT)
1117 BUILTIN_NEWARRAY_TYPE(long, ARRAYTYPE_LONG)
1118 BUILTIN_NEWARRAY_TYPE(float, ARRAYTYPE_FLOAT)
1119 BUILTIN_NEWARRAY_TYPE(double, ARRAYTYPE_DOUBLE)
1122 /* builtin_multianewarray_intern ***********************************************
1124 Creates a multi-dimensional array on the heap. The dimensions are
1125 passed in an array of longs.
1128 n.............number of dimensions to create
1129 arrayclass....the array class
1130 dims..........array containing the size of each dimension to create
1133 pointer to the array or NULL if no memory is available
1135 ******************************************************************************/
1137 static java_handle_t *builtin_multianewarray_intern(int n,
1138 classinfo *arrayclass,
1143 classinfo *componentclass;
1146 /* create this dimension */
1148 size = (s4) dims[0];
1149 a = builtin_newarray(size, arrayclass);
1154 /* if this is the last dimension return */
1159 /* get the class of the components to create */
1161 componentclass = arrayclass->vftbl->arraydesc->componentvftbl->clazz;
1163 /* The verifier guarantees that the dimension count is in the range. */
1165 /* create the component arrays */
1167 for (i = 0; i < size; i++) {
1169 #if defined(__MIPS__) && (SIZEOF_VOID_P == 4)
1170 /* we save an s4 to a s8 slot, 8-byte aligned */
1172 builtin_multianewarray_intern(n, componentclass, dims + 2);
1174 builtin_multianewarray_intern(n, componentclass, dims + 1);
1180 array_objectarray_element_set((java_handle_objectarray_t *) a, i, ea);
1187 /* builtin_multianewarray ******************************************************
1189 Wrapper for builtin_multianewarray_intern which checks all
1190 dimensions before we start allocating.
1192 NOTE: This is a SLOW builtin and can be called from JIT code only.
1194 ******************************************************************************/
1196 java_handle_objectarray_t *builtin_multianewarray(int n,
1197 java_handle_t *arrayclazz,
1204 /* check all dimensions before doing anything */
1206 for (i = 0; i < n; i++) {
1207 #if defined(__MIPS__) && (SIZEOF_VOID_P == 4)
1208 /* we save an s4 to a s8 slot, 8-byte aligned */
1209 size = (s4) dims[i * 2];
1211 size = (s4) dims[i];
1215 exceptions_throw_negativearraysizeexception();
1220 c = LLNI_classinfo_unwrap(arrayclazz);
1222 /* now call the real function */
1224 return (java_handle_objectarray_t *)
1225 builtin_multianewarray_intern(n, c, dims);
1229 /* builtin_verbosecall_enter ***************************************************
1231 Print method call with arguments for -verbose:call.
1233 XXX: Remove mew once all archs use the new tracer!
1235 *******************************************************************************/
1237 #if !defined(NDEBUG)
1238 #ifdef TRACE_ARGS_NUM
1239 void builtin_verbosecall_enter(s8 a0, s8 a1,
1240 # if TRACE_ARGS_NUM >= 4
1243 # if TRACE_ARGS_NUM >= 6
1246 # if TRACE_ARGS_NUM == 8
1251 log_text("builtin_verbosecall_enter: Do not call me anymore!");
1254 #endif /* !defined(NDEBUG) */
1257 /* builtin_verbosecall_exit ****************************************************
1259 Print method exit for -verbose:call.
1261 XXX: Remove mew once all archs use the new tracer!
1263 *******************************************************************************/
1265 #if !defined(NDEBUG)
1266 void builtin_verbosecall_exit(s8 l, double d, float f, methodinfo *m)
1268 log_text("builtin_verbosecall_exit: Do not call me anymore!");
1270 #endif /* !defined(NDEBUG) */
1273 /*============================================================================*/
1274 /* MISCELLANEOUS MATHEMATICAL HELPER FUNCTIONS */
1275 /*============================================================================*/
1277 /*********** Functions for integer divisions *****************************
1279 On some systems (eg. DEC ALPHA), integer division is not supported by the
1280 CPU. These helper functions implement the missing functionality.
1282 ******************************************************************************/
1284 #if !SUPPORT_DIVISION || defined(DISABLE_GC)
1285 s4 builtin_idiv(s4 a, s4 b)
1294 s4 builtin_irem(s4 a, s4 b)
1302 #endif /* !SUPPORT_DIVISION || defined(DISABLE_GC) */
1305 /* functions for long arithmetics **********************************************
1307 On systems where 64 bit Integers are not supported by the CPU,
1308 these functions are needed.
1310 ******************************************************************************/
1312 #if !(SUPPORT_LONG && SUPPORT_LONG_ADD)
1313 s8 builtin_ladd(s8 a, s8 b)
1326 s8 builtin_lsub(s8 a, s8 b)
1339 s8 builtin_lneg(s8 a)
1351 #endif /* !(SUPPORT_LONG && SUPPORT_LONG_ADD) */
1354 #if !(SUPPORT_LONG && SUPPORT_LONG_MUL)
1355 s8 builtin_lmul(s8 a, s8 b)
1367 #endif /* !(SUPPORT_LONG && SUPPORT_LONG_MUL) */
1370 #if !(SUPPORT_DIVISION && SUPPORT_LONG && SUPPORT_LONG_DIV) || defined (DISABLE_GC)
1371 s8 builtin_ldiv(s8 a, s8 b)
1384 s8 builtin_lrem(s8 a, s8 b)
1396 #endif /* !(SUPPORT_DIVISION && SUPPORT_LONG && SUPPORT_LONG_DIV) */
1399 #if !(SUPPORT_LONG && SUPPORT_LONG_SHIFT)
1400 s8 builtin_lshl(s8 a, s4 b)
1413 s8 builtin_lshr(s8 a, s4 b)
1426 s8 builtin_lushr(s8 a, s4 b)
1431 c = ((u8) a) >> (b & 63);
1438 #endif /* !(SUPPORT_LONG && SUPPORT_LONG_SHIFT) */
1441 #if !(SUPPORT_LONG && SUPPORT_LONG_LOGICAL)
1442 s8 builtin_land(s8 a, s8 b)
1455 s8 builtin_lor(s8 a, s8 b)
1468 s8 builtin_lxor(s8 a, s8 b)
1480 #endif /* !(SUPPORT_LONG && SUPPORT_LONG_LOGICAL) */
1483 #if !(SUPPORT_LONG && SUPPORT_LONG_CMP)
1484 s4 builtin_lcmp(s8 a, s8 b)
1498 #endif /* !(SUPPORT_LONG && SUPPORT_LONG_CMP) */
1501 /* functions for unsupported floating instructions ****************************/
1503 /* used to convert FLT_xxx defines into float values */
1505 static inline float intBitsToFloat(s4 i)
1514 /* used to convert DBL_xxx defines into double values */
1516 static inline float longBitsToDouble(s8 l)
1526 float builtin_fadd(float a, float b)
1528 if (isnanf(a)) return intBitsToFloat(FLT_NAN);
1529 if (isnanf(b)) return intBitsToFloat(FLT_NAN);
1540 if (copysignf(1.0, a) == copysignf(1.0, b))
1543 return intBitsToFloat(FLT_NAN);
1549 float builtin_fsub(float a, float b)
1551 return builtin_fadd(a, builtin_fneg(b));
1555 float builtin_fmul(float a, float b)
1557 if (isnanf(a)) return intBitsToFloat(FLT_NAN);
1558 if (isnanf(b)) return intBitsToFloat(FLT_NAN);
1560 if (finitef(b)) return a * b;
1562 if (a == 0) return intBitsToFloat(FLT_NAN);
1563 else return copysignf(b, copysignf(1.0, b)*a);
1568 if (b == 0) return intBitsToFloat(FLT_NAN);
1569 else return copysignf(a, copysignf(1.0, a)*b);
1572 return copysignf(a, copysignf(1.0, a)*copysignf(1.0, b));
1578 /* builtin_ddiv ****************************************************************
1580 Implementation as described in VM Spec.
1582 *******************************************************************************/
1584 float builtin_fdiv(float a, float b)
1588 /* If neither value1' nor value2' is NaN, the sign of the result */
1589 /* is positive if both values have the same sign, negative if the */
1590 /* values have different signs. */
1596 /* If either value1' or value2' is NaN, the result is NaN. */
1598 return intBitsToFloat(FLT_NAN);
1601 /* Division of a finite value by an infinity results in a */
1602 /* signed zero, with the sign-producing rule just given. */
1604 /* is sign equal? */
1606 if (copysignf(1.0, a) == copysignf(1.0, b))
1615 /* If either value1' or value2' is NaN, the result is NaN. */
1617 return intBitsToFloat(FLT_NAN);
1619 } else if (finitef(b)) {
1620 /* Division of an infinity by a finite value results in a signed */
1621 /* infinity, with the sign-producing rule just given. */
1623 /* is sign equal? */
1625 if (copysignf(1.0, a) == copysignf(1.0, b))
1626 return intBitsToFloat(FLT_POSINF);
1628 return intBitsToFloat(FLT_NEGINF);
1631 /* Division of an infinity by an infinity results in NaN. */
1633 return intBitsToFloat(FLT_NAN);
1639 float builtin_fneg(float a)
1641 if (isnanf(a)) return a;
1643 if (finitef(a)) return -a;
1644 else return copysignf(a, -copysignf(1.0, a));
1647 #endif /* !SUPPORT_FLOAT */
1650 #if !SUPPORT_FLOAT || !SUPPORT_FLOAT_CMP || defined(ENABLE_INTRP)
1651 s4 builtin_fcmpl(float a, float b)
1659 if (!finitef(a) || !finitef(b)) {
1660 a = finitef(a) ? 0 : copysignf(1.0, a);
1661 b = finitef(b) ? 0 : copysignf(1.0, b);
1674 s4 builtin_fcmpg(float a, float b)
1676 if (isnanf(a)) return 1;
1677 if (isnanf(b)) return 1;
1678 if (!finitef(a) || !finitef(b)) {
1679 a = finitef(a) ? 0 : copysignf(1.0, a);
1680 b = finitef(b) ? 0 : copysignf(1.0, b);
1682 if (a > b) return 1;
1683 if (a == b) return 0;
1686 #endif /* !SUPPORT_FLOAT || !SUPPORT_FLOAT_CMP || defined(ENABLE_INTRP) */
1689 float builtin_frem(float a, float b)
1695 /* functions for unsupported double instructions ******************************/
1698 double builtin_dadd(double a, double b)
1700 if (isnan(a)) return longBitsToDouble(DBL_NAN);
1701 if (isnan(b)) return longBitsToDouble(DBL_NAN);
1703 if (finite(b)) return a + b;
1707 if (finite(b)) return a;
1709 if (copysign(1.0, a)==copysign(1.0, b)) return a;
1710 else return longBitsToDouble(DBL_NAN);
1716 double builtin_dsub(double a, double b)
1718 return builtin_dadd(a, builtin_dneg(b));
1722 double builtin_dmul(double a, double b)
1724 if (isnan(a)) return longBitsToDouble(DBL_NAN);
1725 if (isnan(b)) return longBitsToDouble(DBL_NAN);
1727 if (finite(b)) return a * b;
1729 if (a == 0) return longBitsToDouble(DBL_NAN);
1730 else return copysign(b, copysign(1.0, b) * a);
1735 if (b == 0) return longBitsToDouble(DBL_NAN);
1736 else return copysign(a, copysign(1.0, a) * b);
1739 return copysign(a, copysign(1.0, a) * copysign(1.0, b));
1745 /* builtin_ddiv ****************************************************************
1747 Implementation as described in VM Spec.
1749 *******************************************************************************/
1751 double builtin_ddiv(double a, double b)
1755 /* If neither value1' nor value2' is NaN, the sign of the result */
1756 /* is positive if both values have the same sign, negative if the */
1757 /* values have different signs. */
1763 /* If either value1' or value2' is NaN, the result is NaN. */
1765 return longBitsToDouble(DBL_NAN);
1768 /* Division of a finite value by an infinity results in a */
1769 /* signed zero, with the sign-producing rule just given. */
1771 /* is sign equal? */
1773 if (copysign(1.0, a) == copysign(1.0, b))
1782 /* If either value1' or value2' is NaN, the result is NaN. */
1784 return longBitsToDouble(DBL_NAN);
1786 } else if (finite(b)) {
1787 /* Division of an infinity by a finite value results in a signed */
1788 /* infinity, with the sign-producing rule just given. */
1790 /* is sign equal? */
1792 if (copysign(1.0, a) == copysign(1.0, b))
1793 return longBitsToDouble(DBL_POSINF);
1795 return longBitsToDouble(DBL_NEGINF);
1798 /* Division of an infinity by an infinity results in NaN. */
1800 return longBitsToDouble(DBL_NAN);
1806 /* builtin_dneg ****************************************************************
1808 Implemented as described in VM Spec.
1810 *******************************************************************************/
1812 double builtin_dneg(double a)
1815 /* If the operand is NaN, the result is NaN (recall that NaN has no */
1822 /* If the operand is a zero, the result is the zero of opposite */
1828 /* If the operand is an infinity, the result is the infinity of */
1829 /* opposite sign. */
1831 return copysign(a, -copysign(1.0, a));
1835 #endif /* !SUPPORT_DOUBLE */
1838 #if !SUPPORT_DOUBLE || !SUPPORT_DOUBLE_CMP || defined(ENABLE_INTRP)
1839 s4 builtin_dcmpl(double a, double b)
1847 if (!finite(a) || !finite(b)) {
1848 a = finite(a) ? 0 : copysign(1.0, a);
1849 b = finite(b) ? 0 : copysign(1.0, b);
1862 s4 builtin_dcmpg(double a, double b)
1870 if (!finite(a) || !finite(b)) {
1871 a = finite(a) ? 0 : copysign(1.0, a);
1872 b = finite(b) ? 0 : copysign(1.0, b);
1883 #endif /* !SUPPORT_DOUBLE || !SUPPORT_DOUBLE_CMP || defined(ENABLE_INTRP) */
1886 double builtin_drem(double a, double b)
1892 /* conversion operations ******************************************************/
1895 s8 builtin_i2l(s4 i)
1907 s4 builtin_l2i(s8 l)
1918 #if !(SUPPORT_FLOAT && SUPPORT_I2F)
1919 float builtin_i2f(s4 a)
1921 float f = (float) a;
1924 #endif /* !(SUPPORT_FLOAT && SUPPORT_I2F) */
1927 #if !(SUPPORT_DOUBLE && SUPPORT_I2D)
1928 double builtin_i2d(s4 a)
1930 double d = (double) a;
1933 #endif /* !(SUPPORT_DOUBLE && SUPPORT_I2D) */
1936 #if !(SUPPORT_LONG && SUPPORT_FLOAT && SUPPORT_L2F)
1937 float builtin_l2f(s8 a)
1940 float f = (float) a;
1946 #endif /* !(SUPPORT_LONG && SUPPORT_FLOAT && SUPPORT_L2F) */
1949 #if !(SUPPORT_LONG && SUPPORT_DOUBLE && SUPPORT_L2D)
1950 double builtin_l2d(s8 a)
1953 double d = (double) a;
1959 #endif /* !(SUPPORT_LONG && SUPPORT_DOUBLE && SUPPORT_L2D) */
1962 #if !(SUPPORT_FLOAT && SUPPORT_F2I) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
1963 s4 builtin_f2i(float a)
1967 i = builtin_d2i((double) a);
1978 if (a < (-2147483648))
1979 return (-2147483648);
1982 f = copysignf((float) 1.0, a);
1985 return (-2147483648); */
1987 #endif /* !(SUPPORT_FLOAT && SUPPORT_F2I) || defined(ENABLE_INTRP) || defined(DISABLE_GC) */
1990 #if !(SUPPORT_FLOAT && SUPPORT_LONG && SUPPORT_F2L) || defined(DISABLE_GC)
1991 s8 builtin_f2l(float a)
1995 l = builtin_d2l((double) a);
2002 if (a > 9223372036854775807L)
2003 return 9223372036854775807L;
2004 if (a < (-9223372036854775808L))
2005 return (-9223372036854775808L);
2010 f = copysignf((float) 1.0, a);
2012 return 9223372036854775807L;
2013 return (-9223372036854775808L); */
2015 #endif /* !(SUPPORT_FLOAT && SUPPORT_LONG && SUPPORT_F2L) */
2018 #if !(SUPPORT_DOUBLE && SUPPORT_D2I) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
2019 s4 builtin_d2i(double a)
2024 if (a >= 2147483647)
2026 if (a <= (-2147483647-1))
2027 return (-2147483647-1);
2032 d = copysign(1.0, a);
2035 return (-2147483647-1);
2037 #endif /* !(SUPPORT_DOUBLE && SUPPORT_D2I) || defined(ENABLE_INTRP) || defined(DISABLE_GC) */
2040 #if !(SUPPORT_DOUBLE && SUPPORT_LONG && SUPPORT_D2L) || defined(DISABLE_GC)
2041 s8 builtin_d2l(double a)
2046 if (a >= 9223372036854775807LL)
2047 return 9223372036854775807LL;
2048 if (a <= (-9223372036854775807LL-1))
2049 return (-9223372036854775807LL-1);
2054 d = copysign(1.0, a);
2056 return 9223372036854775807LL;
2057 return (-9223372036854775807LL-1);
2059 #endif /* !(SUPPORT_DOUBLE && SUPPORT_LONG && SUPPORT_D2L) */
2062 #if !(SUPPORT_FLOAT && SUPPORT_DOUBLE)
2063 double builtin_f2d(float a)
2065 if (finitef(a)) return (double) a;
2068 return longBitsToDouble(DBL_NAN);
2070 return copysign(longBitsToDouble(DBL_POSINF), (double) copysignf(1.0, a) );
2074 float builtin_d2f(double a)
2080 return intBitsToFloat(FLT_NAN);
2082 return copysignf(intBitsToFloat(FLT_POSINF), (float) copysign(1.0, a));
2085 #endif /* !(SUPPORT_FLOAT && SUPPORT_DOUBLE) */
2088 /*============================================================================*/
2089 /* AUTOMATICALLY REPLACED FUNCTIONS */
2090 /*============================================================================*/
2092 /* builtin_arraycopy ***********************************************************
2094 Builtin for java.lang.System.arraycopy.
2096 NOTE: This is a SLOW builtin and can be called from JIT & NATIVE code.
2098 *******************************************************************************/
2100 void builtin_arraycopy(java_handle_t *src, s4 srcStart,
2101 java_handle_t *dest, s4 destStart, s4 len)
2103 arraydescriptor *sdesc;
2104 arraydescriptor *ddesc;
2107 if ((src == NULL) || (dest == NULL)) {
2108 exceptions_throw_nullpointerexception();
2112 sdesc = LLNI_vftbl_direct(src)->arraydesc;
2113 ddesc = LLNI_vftbl_direct(dest)->arraydesc;
2115 if (!sdesc || !ddesc || (sdesc->arraytype != ddesc->arraytype)) {
2116 exceptions_throw_arraystoreexception();
2120 /* we try to throw exception with the same message as SUN does */
2122 if ((len < 0) || (srcStart < 0) || (destStart < 0) ||
2123 (srcStart + len < 0) || (srcStart + len > LLNI_array_size(src)) ||
2124 (destStart + len < 0) || (destStart + len > LLNI_array_size(dest))) {
2125 exceptions_throw_arrayindexoutofboundsexception();
2129 if (sdesc->componentvftbl == ddesc->componentvftbl) {
2130 /* We copy primitive values or references of exactly the same type */
2132 s4 dataoffset = sdesc->dataoffset;
2133 s4 componentsize = sdesc->componentsize;
2135 LLNI_CRITICAL_START;
2137 MMOVE(((u1 *) LLNI_DIRECT(dest)) + dataoffset + componentsize * destStart,
2138 ((u1 *) LLNI_DIRECT(src)) + dataoffset + componentsize * srcStart,
2139 u1, (size_t) len * componentsize);
2144 /* We copy references of different type */
2146 java_handle_objectarray_t *oas = (java_handle_objectarray_t *) src;
2147 java_handle_objectarray_t *oad = (java_handle_objectarray_t *) dest;
2149 if (destStart <= srcStart) {
2150 for (i = 0; i < len; i++) {
2153 o = array_objectarray_element_get(oas, srcStart + i);
2155 if (!builtin_canstore(oad, o))
2158 array_objectarray_element_set(oad, destStart + i, o);
2162 /* XXX this does not completely obey the specification!
2163 If an exception is thrown only the elements above the
2164 current index have been copied. The specification
2165 requires that only the elements *below* the current
2166 index have been copied before the throw. */
2168 for (i = len - 1; i >= 0; i--) {
2171 o = array_objectarray_element_get(oas, srcStart + i);
2173 if (!builtin_canstore(oad, o))
2176 array_objectarray_element_set(oad, destStart + i, o);
2183 /* builtin_nanotime ************************************************************
2185 Return the current time in nanoseconds.
2187 *******************************************************************************/
2189 s8 builtin_nanotime(void)
2194 if (gettimeofday(&tv, NULL) == -1)
2195 vm_abort("gettimeofday failed: %s", strerror(errno));
2197 usecs = (s8) tv.tv_sec * (1000 * 1000) + (s8) tv.tv_usec;
2199 return usecs * 1000;
2203 /* builtin_currenttimemillis ***************************************************
2205 Return the current time in milliseconds.
2207 *******************************************************************************/
2209 s8 builtin_currenttimemillis(void)
2213 msecs = builtin_nanotime() / 1000 / 1000;
2219 /* builtin_clone ***************************************************************
2221 Function for cloning objects or arrays.
2223 NOTE: This is a SLOW builtin and can be called from JIT & NATIVE code.
2225 *******************************************************************************/
2227 java_handle_t *builtin_clone(void *env, java_handle_t *o)
2229 arraydescriptor *ad;
2232 java_handle_t *co; /* cloned object header */
2234 /* get the array descriptor */
2236 ad = LLNI_vftbl_direct(o)->arraydesc;
2238 /* we are cloning an array */
2241 size = ad->dataoffset + ad->componentsize * LLNI_array_size(o);
2243 co = heap_alloc(size, (ad->arraytype == ARRAYTYPE_OBJECT), NULL, true);
2248 #if !defined(ENABLE_GC_CACAO) && defined(ENABLE_HANDLES)
2249 /* XXX this is only a dirty hack to make Boehm work with handles */
2251 co = LLNI_WRAP((java_object_t *) co);
2254 LLNI_CRITICAL_START;
2256 MCOPY(LLNI_DIRECT(co), LLNI_DIRECT(o), u1, size);
2258 #if defined(ENABLE_GC_CACAO)
2259 heap_init_objectheader(LLNI_DIRECT(co), size);
2262 #if defined(ENABLE_THREADS)
2263 lock_init_object_lock(LLNI_DIRECT(co));
2271 /* we are cloning a non-array */
2273 if (!builtin_instanceof(o, class_java_lang_Cloneable)) {
2274 exceptions_throw_clonenotsupportedexception();
2278 /* get the class of the object */
2280 LLNI_class_get(o, c);
2282 /* create new object */
2284 co = builtin_new(c);
2289 LLNI_CRITICAL_START;
2291 MCOPY(LLNI_DIRECT(co), LLNI_DIRECT(o), u1, c->instancesize);
2293 #if defined(ENABLE_GC_CACAO)
2294 heap_init_objectheader(LLNI_DIRECT(co), c->instancesize);
2297 #if defined(ENABLE_THREADS)
2298 lock_init_object_lock(LLNI_DIRECT(co));
2307 #if defined(ENABLE_CYCLES_STATS)
2308 void builtin_print_cycles_stats(FILE *file)
2310 fprintf(file,"builtin cylce count statistics:\n");
2312 CYCLES_STATS_PRINT_OVERHEAD(builtin_overhead,file);
2313 CYCLES_STATS_PRINT(builtin_new ,file);
2317 #endif /* defined(ENABLE_CYCLES_STATS) */
2320 #if defined(ENABLE_VMLOG)
2322 #include <vmlog_cacao.c>
2327 * These are local overrides for various environment variables in Emacs.
2328 * Please do not remove this and leave it at the end of the file, where
2329 * Emacs will automagically detect them.
2330 * ---------------------------------------------------------------------
2333 * indent-tabs-mode: t
2337 * vim:noexpandtab:sw=4:ts=4: