* merged default branch into jitcache-arm-x86 branch
[cacao.git] / src / vm / jit / builtin.cpp
1 /* src/vm/jit/builtin.cpp - functions for unsupported operations
2
3    Copyright (C) 1996-2005, 2006, 2007, 2008
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5
6    This file is part of CACAO.
7
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.
12
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.
17
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
21    02110-1301, USA.
22
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
27    convention.
28
29 */
30
31
32 #include "config.h"
33
34 #include <assert.h>
35 #include <errno.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sys/time.h>
39
40 #include "vm/types.h"
41
42 #include "arch.h"
43 #include "md-abi.h"
44
45 #include "fdlibm/fdlibm.h"
46 #if defined(__CYGWIN__) && defined(Bias)
47 # undef Bias
48 #endif
49
50 #include "mm/gc.hpp"
51 #include "mm/memory.h"
52
53 #include "native/llni.h"
54
55 #include "threads/lock.hpp"
56 #include "threads/mutex.hpp"
57 #include "threads/thread.hpp"
58
59 #include "toolbox/logging.h"
60 #include "toolbox/util.h"
61
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.h"
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"
76
77 #include "vm/jit/asmpart.h"
78 #include "vm/jit/stubs.hpp"
79 #include "vm/jit/trace.hpp"
80
81 #if defined(ENABLE_VMLOG)
82 #include <vmlog_cacao.h>
83 #endif
84
85
86 /* include builtin tables *****************************************************/
87
88 #include "vm/jit/builtintable.inc"
89
90
91 CYCLES_STATS_DECLARE(builtin_new         ,100,5)
92 CYCLES_STATS_DECLARE(builtin_overhead    , 80,1)
93
94
95 /*============================================================================*/
96 /* BUILTIN TABLE MANAGEMENT FUNCTIONS                                         */
97 /*============================================================================*/
98
99 /* builtintable_init ***********************************************************
100
101    Parse the descriptors of builtin functions and create the parsed
102    descriptors.
103
104 *******************************************************************************/
105
106 static bool builtintable_init(void)
107 {
108         descriptor_pool    *descpool;
109         builtintable_entry *bte;
110         methodinfo         *m;
111
112         // Create new dump memory area.
113         DumpMemoryArea dma;
114
115         /* create a new descriptor pool */
116
117         descpool = descriptor_pool_new(class_java_lang_Object);
118
119         /* add some entries we need */
120
121         if (!descriptor_pool_add_class(descpool, utf_java_lang_Object))
122                 return false;
123
124         if (!descriptor_pool_add_class(descpool, utf_java_lang_Class))
125                 return false;
126
127         /* first add all descriptors to the pool */
128
129         for (bte = builtintable_internal; bte->fp != NULL; bte++) {
130                 bte->name       = utf_new_char(bte->cname);
131                 bte->descriptor = utf_new_char(bte->cdescriptor);
132
133                 if (!descriptor_pool_add(descpool, bte->descriptor, NULL))
134                         return false;
135         }
136
137         for (bte = builtintable_automatic; bte->fp != NULL; bte++) {
138                 bte->descriptor = utf_new_char(bte->cdescriptor);
139
140                 if (!descriptor_pool_add(descpool, bte->descriptor, NULL))
141                         return false;
142         }
143
144         for (bte = builtintable_function; bte->fp != NULL; bte++) {
145                 bte->classname  = utf_new_char(bte->cclassname);
146                 bte->name       = utf_new_char(bte->cname);
147                 bte->descriptor = utf_new_char(bte->cdescriptor);
148
149                 if (!descriptor_pool_add(descpool, bte->descriptor, NULL))
150                         return false;
151         }
152
153         /* create the class reference table */
154
155         (void) descriptor_pool_create_classrefs(descpool, NULL);
156
157         /* allocate space for the parsed descriptors */
158
159         descriptor_pool_alloc_parsed_descriptors(descpool);
160
161         /* Now parse all descriptors.  NOTE: builtin-functions are treated
162            like static methods (no `this' pointer). */
163
164         for (bte = builtintable_internal; bte->fp != NULL; bte++) {
165                 bte->md =
166                         descriptor_pool_parse_method_descriptor(descpool,
167                                                                                                         bte->descriptor,
168                                                                                                         ACC_STATIC | ACC_METHOD_BUILTIN,
169                                                                                                         NULL);
170
171                 /* generate a builtin stub if we need one */
172
173                 if (bte->flags & BUILTINTABLE_FLAG_STUB) {
174                         m = method_new_builtin(bte);
175                         BuiltinStub::generate(m, bte);
176                 }
177         }
178
179         for (bte = builtintable_automatic; bte->fp != NULL; bte++) {
180                 bte->md =
181                         descriptor_pool_parse_method_descriptor(descpool,
182                                                                                                         bte->descriptor,
183                                                                                                         ACC_STATIC | ACC_METHOD_BUILTIN,
184                                                                                                         NULL);
185
186                 /* no stubs should be needed for this table */
187
188                 assert(!bte->flags & BUILTINTABLE_FLAG_STUB);
189         }
190
191         for (bte = builtintable_function; bte->fp != NULL; bte++) {
192                 bte->md =
193                         descriptor_pool_parse_method_descriptor(descpool,
194                                                                                                         bte->descriptor,
195                                                                                                         ACC_STATIC | ACC_METHOD_BUILTIN,
196                                                                                                         NULL);
197
198                 /* generate a builtin stub if we need one */
199
200                 if (bte->flags & BUILTINTABLE_FLAG_STUB) {
201                         m = method_new_builtin(bte);
202                         BuiltinStub::generate(m, bte);
203                 }
204         }
205
206         return true;
207 }
208
209
210 /* builtintable_comparator *****************************************************
211
212    qsort comparator for the automatic builtin table.
213
214 *******************************************************************************/
215
216 static int builtintable_comparator(const void *a, const void *b)
217 {
218         builtintable_entry *bte1;
219         builtintable_entry *bte2;
220
221         bte1 = (builtintable_entry *) a;
222         bte2 = (builtintable_entry *) b;
223
224         return (bte1->opcode < bte2->opcode) ? -1 : (bte1->opcode > bte2->opcode);
225 }
226
227
228 /* builtintable_sort_automatic *************************************************
229
230    Sorts the automatic builtin table.
231
232 *******************************************************************************/
233
234 static void builtintable_sort_automatic(void)
235 {
236         s4 entries;
237
238         /* calculate table size statically (`- 1' comment see builtintable.inc) */
239
240         entries = sizeof(builtintable_automatic) / sizeof(builtintable_entry) - 1;
241
242         qsort(builtintable_automatic, entries, sizeof(builtintable_entry),
243                   builtintable_comparator);
244 }
245
246
247 /* builtin_init ****************************************************************
248
249    Initialize the global table of builtin functions.
250
251 *******************************************************************************/
252
253 bool builtin_init(void)
254 {
255         TRACESUBSYSTEMINITIALIZATION("builtin_init");
256
257         /* initialize the builtin tables */
258
259         if (!builtintable_init())
260                 return false;
261
262         /* sort builtin tables */
263
264         builtintable_sort_automatic();
265
266         return true;
267 }
268
269
270 /* builtintable_get_by_key *****************************************************
271
272    Returns a key for the given builtintable_entry object which is suitable
273    for retrieving the instance again by calling builtintable_get_by_key.
274
275    The key can be regarded fixed between multiple runs of the JVM.
276
277 *******************************************************************************/
278
279 s4 builtintable_get_key(builtintable_entry *bte)
280 {
281         s4 entries;
282 /*
283         int i;
284         entries = sizeof(builtintable_internal) / sizeof(builtintable_entry) - 1;
285         for (i = 0; i < entries; i++)
286                 if (&builtintable_internal[i] == bte)
287                         return i + 1;
288
289         entries = sizeof(builtintable_automatic) / sizeof(builtintable_entry) - 1;
290         for (i = 0; i < entries; i++)
291                 if (&builtintable_automatic[i] == bte)
292                         return -i;
293
294         entries = sizeof(builtintable_function) / sizeof(builtintable_entry) - 1;
295         for (i = 0; i < entries; i++)
296                 if (&builtintable_function[i] == bte)
297                         return -1000 - i;
298 */
299
300         entries = sizeof(builtintable_internal) / sizeof(builtintable_entry) - 1;
301         if (&builtintable_internal[0] <= bte
302                 && &builtintable_internal[entries - 1] >= bte)
303         {
304                 return (s4) (bte - &builtintable_internal[0]) + 1;
305         }
306
307         entries = sizeof(builtintable_automatic) / sizeof(builtintable_entry) - 1;
308         if (&builtintable_automatic[0] <= bte
309                 && &builtintable_automatic[entries - 1] >= bte)
310         {
311                 return -(s4) (bte - &builtintable_automatic[0]);
312         }
313
314         entries = sizeof(builtintable_function) / sizeof(builtintable_entry) - 1;
315         if (&builtintable_function[0] <= bte
316                 && &builtintable_function[entries - 1] >= bte)
317         {
318                 return -1000 - (s4) (bte - &builtintable_function[0]);
319         }
320
321         /* builtintable_entry is not in our tables. */
322         assert (0);
323
324         return 0;
325 }
326
327 /* builtintable_get_by_key *****************************************************
328
329    Retrieves an entry in the internal and automatic builtin functions tables
330    using a key that was retrived previously with builtintable_get_key()
331
332 *******************************************************************************/
333
334 builtintable_entry *builtintable_get_by_key(s4 key)
335 {
336         /* If key is positive it is the index into builtintable_internal. If it is
337          * negative it is the index into builtintable_automatic. If it is <= -1000
338      * it is the index into builtintable_function.
339      */
340         return (key > 0)
341                 ? &builtintable_internal[key - 1]
342                 : (key > -1000 ? &builtintable_automatic[-key] : &builtintable_function[-(1000 + key)]);
343 }
344
345 /* builtintable_get_internal ***************************************************
346
347    Finds an entry in the builtintable for internal functions and
348    returns the a pointer to the structure.
349
350 *******************************************************************************/
351
352 builtintable_entry *builtintable_get_internal(functionptr fp)
353 {
354         builtintable_entry *bte;
355
356         for (bte = builtintable_internal; bte->fp != NULL; bte++) {
357                 if (bte->fp == fp)
358                         return bte;
359         }
360
361         return NULL;
362 }
363
364
365 /* builtintable_get_automatic **************************************************
366
367    Finds an entry in the builtintable for functions which are replaced
368    automatically and returns the a pointer to the structure.
369
370 *******************************************************************************/
371
372 builtintable_entry *builtintable_get_automatic(s4 opcode)
373 {
374         builtintable_entry *first;
375         builtintable_entry *last;
376         builtintable_entry *middle;
377         s4                  half;
378         s4                  entries;
379
380         /* calculate table size statically (`- 1' comment see builtintable.inc) */
381
382         entries = sizeof(builtintable_automatic) / sizeof(builtintable_entry) - 1;
383
384         first = builtintable_automatic;
385         last = builtintable_automatic + entries;
386
387         while (entries > 0) {
388                 half = entries / 2;
389                 middle = first + half;
390
391                 if (middle->opcode < opcode) {
392                         first = middle + 1;
393                         entries -= half + 1;
394                 }
395                 else
396                         entries = half;
397         }
398
399         return (first != last ? first : NULL);
400 }
401
402
403 /* builtintable_replace_function ***********************************************
404
405    XXX
406
407 *******************************************************************************/
408
409 #if defined(ENABLE_JIT)
410 bool builtintable_replace_function(void *iptr_)
411 {
412         constant_FMIref    *mr;
413         builtintable_entry *bte;
414         instruction        *iptr;
415
416         iptr = (instruction *) iptr_; /* twisti will kill me ;) */
417
418         /* get name and descriptor of the function */
419
420         switch (iptr->opc) {
421         case ICMD_INVOKESTATIC:
422                 /* The instruction MUST be resolved, otherwise we run into
423                    lazy loading troubles.  Anyway, we should/can only replace
424                    very VM-close functions. */
425
426                 if (INSTRUCTION_IS_UNRESOLVED(iptr))
427                         return false;
428
429                 mr = iptr->sx.s23.s3.fmiref;
430                 break;  
431
432         default:
433                 return false;
434         }
435
436         /* search the function table */
437
438         for (bte = builtintable_function; bte->fp != NULL; bte++) {
439                 if ((METHODREF_CLASSNAME(mr) == bte->classname) &&
440                         (mr->name                == bte->name) &&
441                         (mr->descriptor          == bte->descriptor)) {
442
443                         /* set the values in the instruction */
444
445                         iptr->opc           = bte->opcode;
446                         iptr->sx.s23.s3.bte = bte;
447
448                         if (bte->flags & BUILTINTABLE_FLAG_EXCEPTION)
449                                 iptr->flags.bits |= INS_FLAG_CHECK;
450                         else
451                                 iptr->flags.bits &= ~INS_FLAG_CHECK;
452
453                         return true;
454                 }
455         }
456
457         return false;
458 }
459 #endif /* defined(ENABLE_JIT) */
460
461
462 /*============================================================================*/
463 /* INTERNAL BUILTIN FUNCTIONS                                                 */
464 /*============================================================================*/
465
466 /* builtin_instanceof **********************************************************
467
468    Checks if an object is an instance of some given class (or subclass
469    of that class). If class is an interface, checks if the interface
470    is implemented.
471
472    RETURN VALUE:
473      1......o is an instance of class or implements the interface
474      0......otherwise or if o == NULL
475
476    NOTE: This builtin can be called from NATIVE code only.
477
478 *******************************************************************************/
479
480 bool builtin_instanceof(java_handle_t *o, classinfo *c)
481 {
482         classinfo *oc;
483
484         if (o == NULL)
485                 return 0;
486
487         LLNI_class_get(o, oc);
488
489         return class_isanysubclass(oc, c);
490 }
491
492
493
494 /* builtin_checkcast ***********************************************************
495
496    The same as builtin_instanceof but with the exception
497    that 1 is returned when (o == NULL).
498
499    NOTE: This builtin can be called from NATIVE code only.
500
501 *******************************************************************************/
502
503 bool builtin_checkcast(java_handle_t *o, classinfo *c)
504 {
505         classinfo *oc;
506
507         if (o == NULL)
508                 return 1;
509
510         LLNI_class_get(o, oc);
511
512         if (class_isanysubclass(oc, c))
513                 return 1;
514
515         return 0;
516 }
517
518
519 /* builtin_descriptorscompatible ***********************************************
520
521    Checks if two array type descriptors are assignment compatible.
522
523    RETURN VALUE:
524       1......target = desc is possible
525       0......otherwise
526                         
527 *******************************************************************************/
528
529 static bool builtin_descriptorscompatible(arraydescriptor *desc, arraydescriptor *target)
530 {
531         if (desc == target)
532                 return 1;
533
534         if (desc->arraytype != target->arraytype)
535                 return 0;
536
537         if (desc->arraytype != ARRAYTYPE_OBJECT)
538                 return 1;
539         
540         /* {both arrays are arrays of references} */
541
542         if (desc->dimension == target->dimension) {
543                 if (!desc->elementvftbl)
544                         return 0;
545                 /* an array which contains elements of interface types is
546            allowed to be casted to Object (JOWENN)*/
547
548                 if ((desc->elementvftbl->baseval < 0) &&
549                         (target->elementvftbl->baseval == 1))
550                         return 1;
551
552                 return class_isanysubclass(desc->elementvftbl->clazz,
553                                                                    target->elementvftbl->clazz);
554         }
555
556         if (desc->dimension < target->dimension)
557                 return 0;
558
559         /* {desc has higher dimension than target} */
560
561         return class_isanysubclass(pseudo_class_Arraystub,
562                                                            target->elementvftbl->clazz);
563 }
564
565
566 /* builtin_arraycheckcast ******************************************************
567
568    Checks if an object is really a subtype of the requested array
569    type.  The object has to be an array to begin with. For simple
570    arrays (int, short, double, etc.) the types have to match exactly.
571    For arrays of objects, the type of elements in the array has to be
572    a subtype (or the same type) of the requested element type. For
573    arrays of arrays (which in turn can again be arrays of arrays), the
574    types at the lowest level have to satisfy the corresponding sub
575    class relation.
576
577    NOTE: This is a FAST builtin and can be called from JIT code only.
578
579 *******************************************************************************/
580
581 bool builtin_fast_arraycheckcast(java_object_t *o, classinfo *targetclass)
582 {
583         arraydescriptor *desc;
584
585         if (o == NULL)
586                 return 1;
587
588         desc = o->vftbl->arraydesc;
589
590         if (desc == NULL)
591                 return 0;
592  
593         return builtin_descriptorscompatible(desc, targetclass->vftbl->arraydesc);
594 }
595
596
597 /* builtin_fast_arrayinstanceof ************************************************
598
599    NOTE: This is a FAST builtin and can be called from JIT code only.
600
601 *******************************************************************************/
602
603 bool builtin_fast_arrayinstanceof(java_object_t *o, classinfo *targetclass)
604 {
605         if (o == NULL)
606                 return 0;
607
608         return builtin_fast_arraycheckcast(o, targetclass);
609 }
610
611
612 /* builtin_arrayinstanceof *****************************************************
613
614    NOTE: This builtin can be called from NATIVE code only.
615
616 *******************************************************************************/
617
618 bool builtin_arrayinstanceof(java_handle_t *h, classinfo *targetclass)
619 {
620         bool result;
621
622         LLNI_CRITICAL_START;
623
624         result = builtin_fast_arrayinstanceof(LLNI_UNWRAP(h), targetclass);
625
626         LLNI_CRITICAL_END;
627
628         return result;
629 }
630
631
632 /* builtin_throw_exception *****************************************************
633
634    Sets the exception pointer with the thrown exception and prints some
635    debugging information.
636    
637    NOTE: This is a FAST builtin and can be called from JIT code,
638    or from asm_vm_call_method.
639
640 *******************************************************************************/
641
642 void *builtin_throw_exception(java_object_t *xptr)
643 {
644 #if !defined(NDEBUG)
645         /* print exception trace */
646
647         if (opt_TraceExceptions)
648                 trace_exception_builtin(xptr);
649 #endif /* !defined(NDEBUG) */
650
651         /* actually set the exception */
652
653         exceptions_set_exception(LLNI_QUICKWRAP(xptr));
654
655         /* Return a NULL pointer.  This is required for vm_call_method to
656            check for an exception.  This is for convenience. */
657
658         return NULL;
659 }
660
661
662 /* builtin_retrieve_exception **************************************************
663
664    Gets and clears the exception pointer of the current thread.
665
666    RETURN VALUE:
667       the exception object, or NULL if no exception was thrown.
668
669    NOTE: This is a FAST builtin and can be called from JIT code,
670    or from the signal handlers.
671
672 *******************************************************************************/
673
674 java_object_t *builtin_retrieve_exception(void)
675 {
676         java_handle_t *h;
677         java_object_t *o;
678
679         /* actually get and clear the exception */
680
681         h = exceptions_get_and_clear_exception();
682         o = LLNI_UNWRAP(h);
683
684         return o;
685 }
686
687
688 /* builtin_canstore ************************************************************
689
690    Checks, if an object can be stored in an array.
691
692    RETURN VALUE:
693       1......possible
694       0......otherwise (throws an ArrayStoreException)
695
696    NOTE: This is a SLOW builtin and can be called from JIT & NATIVE code.
697
698 *******************************************************************************/
699
700 bool builtin_canstore(java_handle_objectarray_t *oa, java_handle_t *o)
701 {
702         bool result;
703
704         LLNI_CRITICAL_START;
705
706         result = builtin_fast_canstore(LLNI_DIRECT(oa), LLNI_UNWRAP(o));
707
708         LLNI_CRITICAL_END;
709
710         /* if not possible, throw an exception */
711
712         if (result == 0)
713                 exceptions_throw_arraystoreexception();
714
715         return result;
716 }
717
718
719 /* builtin_fast_canstore *******************************************************
720
721    Checks, if an object can be stored in an array.
722
723    RETURN VALUE:
724       1......possible
725       0......otherwise (no exception thrown!)
726
727    NOTE: This is a FAST builtin and can be called from JIT code only.
728
729 *******************************************************************************/
730
731 bool builtin_fast_canstore(java_objectarray_t *oa, java_object_t *o)
732 {
733         arraydescriptor *desc;
734         arraydescriptor *valuedesc;
735         vftbl_t         *componentvftbl;
736         vftbl_t         *valuevftbl;
737         int32_t          baseval;
738         uint32_t         diffval;
739         bool             result;
740
741         if (o == NULL)
742                 return 1;
743
744         /* The following is guaranteed (by verifier checks):
745          *
746          *     *) oa->...vftbl->arraydesc != NULL
747          *     *) oa->...vftbl->arraydesc->componentvftbl != NULL
748          *     *) o->vftbl is not an interface vftbl
749          */
750
751         desc           = oa->header.objheader.vftbl->arraydesc;
752         componentvftbl = desc->componentvftbl;
753         valuevftbl     = o->vftbl;
754         valuedesc      = valuevftbl->arraydesc;
755
756         if ((desc->dimension - 1) == 0) {
757                 /* {oa is a one-dimensional array} */
758                 /* {oa is an array of references} */
759                 
760                 if (valuevftbl == componentvftbl)
761                         return 1;
762
763                 linker_classrenumber_mutex->lock();
764
765                 baseval = componentvftbl->baseval;
766
767                 if (baseval <= 0) {
768                         /* an array of interface references */
769
770                         result = ((valuevftbl->interfacetablelength > -baseval) &&
771                                           (valuevftbl->interfacetable[baseval] != NULL));
772                 }
773                 else {
774                         diffval = valuevftbl->baseval - componentvftbl->baseval;
775                         result  = diffval <= (uint32_t) componentvftbl->diffval;
776                 }
777
778                 linker_classrenumber_mutex->unlock();
779         }
780         else if (valuedesc == NULL) {
781                 /* {oa has dimension > 1} */
782                 /* {componentvftbl->arraydesc != NULL} */
783
784                 /* check if o is an array */
785
786                 return 0;
787         }
788         else {
789                 /* {o is an array} */
790
791                 result = builtin_descriptorscompatible(valuedesc, componentvftbl->arraydesc);
792         }
793
794         /* return result */
795
796         return result;
797 }
798
799
800 /* This is an optimized version where a is guaranteed to be one-dimensional */
801 bool builtin_fast_canstore_onedim(java_objectarray_t *a, java_object_t *o)
802 {
803         arraydescriptor *desc;
804         vftbl_t         *elementvftbl;
805         vftbl_t         *valuevftbl;
806         int32_t          baseval;
807         uint32_t         diffval;
808         bool             result;
809         
810         if (o == NULL)
811                 return 1;
812
813         /* The following is guaranteed (by verifier checks):
814          *
815          *     *) a->...vftbl->arraydesc != NULL
816          *     *) a->...vftbl->arraydesc->elementvftbl != NULL
817          *     *) a->...vftbl->arraydesc->dimension == 1
818          *     *) o->vftbl is not an interface vftbl
819          */
820
821         desc = a->header.objheader.vftbl->arraydesc;
822     elementvftbl = desc->elementvftbl;
823         valuevftbl = o->vftbl;
824
825         /* {a is a one-dimensional array} */
826         
827         if (valuevftbl == elementvftbl)
828                 return 1;
829
830         linker_classrenumber_mutex->lock();
831
832         baseval = elementvftbl->baseval;
833
834         if (baseval <= 0) {
835                 /* an array of interface references */
836                 result = ((valuevftbl->interfacetablelength > -baseval) &&
837                                   (valuevftbl->interfacetable[baseval] != NULL));
838         }
839         else {
840                 diffval = valuevftbl->baseval - elementvftbl->baseval;
841                 result  = diffval <= (uint32_t) elementvftbl->diffval;
842         }
843
844         linker_classrenumber_mutex->unlock();
845
846         return result;
847 }
848
849
850 /* This is an optimized version where a is guaranteed to be a
851  * one-dimensional array of a class type */
852 bool builtin_fast_canstore_onedim_class(java_objectarray_t *a, java_object_t *o)
853 {
854         vftbl_t  *elementvftbl;
855         vftbl_t  *valuevftbl;
856         uint32_t  diffval;
857         bool      result;
858         
859         if (o == NULL)
860                 return 1;
861
862         /* The following is guaranteed (by verifier checks):
863          *
864          *     *) a->...vftbl->arraydesc != NULL
865          *     *) a->...vftbl->arraydesc->elementvftbl != NULL
866          *     *) a->...vftbl->arraydesc->elementvftbl is not an interface vftbl
867          *     *) a->...vftbl->arraydesc->dimension == 1
868          *     *) o->vftbl is not an interface vftbl
869          */
870
871     elementvftbl = a->header.objheader.vftbl->arraydesc->elementvftbl;
872         valuevftbl = o->vftbl;
873
874         /* {a is a one-dimensional array} */
875         
876         if (valuevftbl == elementvftbl)
877                 return 1;
878
879         linker_classrenumber_mutex->lock();
880
881         diffval = valuevftbl->baseval - elementvftbl->baseval;
882         result  = diffval <= (uint32_t) elementvftbl->diffval;
883
884         linker_classrenumber_mutex->unlock();
885
886         return result;
887 }
888
889
890 /* builtin_new *****************************************************************
891
892    Creates a new instance of class c on the heap.
893
894    RETURN VALUE:
895       pointer to the object, or NULL if no memory is available
896
897    NOTE: This builtin can be called from NATIVE code only.
898
899 *******************************************************************************/
900
901 java_handle_t *builtin_new(classinfo *c)
902 {
903         java_handle_t *o;
904 #if defined(ENABLE_RT_TIMING)
905         struct timespec time_start, time_end;
906 #endif
907 #if defined(ENABLE_CYCLES_STATS)
908         u8 cycles_start, cycles_end;
909 #endif
910
911         RT_TIMING_GET_TIME(time_start);
912         CYCLES_STATS_GET(cycles_start);
913
914         /* is the class loaded */
915
916         assert(c->state & CLASS_LOADED);
917
918         /* check if we can instantiate this class */
919
920         if (c->flags & ACC_ABSTRACT) {
921                 exceptions_throw_instantiationerror(c);
922                 return NULL;
923         }
924
925         /* is the class linked */
926
927         if (!(c->state & CLASS_LINKED))
928                 if (!link_class(c))
929                         return NULL;
930
931         if (!(c->state & CLASS_INITIALIZED)) {
932 #if !defined(NDEBUG)
933                 if (initverbose)
934                         log_message_class("Initialize class (from builtin_new): ", c);
935 #endif
936
937                 if (!initialize_class(c))
938                         return NULL;
939         }
940
941         o = (java_handle_t*) heap_alloc(c->instancesize, c->flags & ACC_CLASS_HAS_POINTERS,
942                                                                         c->finalizer, true);
943
944         if (!o)
945                 return NULL;
946
947 #if !defined(ENABLE_GC_CACAO) && defined(ENABLE_HANDLES)
948         /* XXX this is only a dirty hack to make Boehm work with handles */
949
950         o = LLNI_WRAP((java_object_t *) o);
951 #endif
952
953         LLNI_vftbl_direct(o) = c->vftbl;
954
955 #if defined(ENABLE_THREADS)
956         LLNI_DIRECT(o)->lockword.init();
957 #endif
958
959         CYCLES_STATS_GET(cycles_end);
960         RT_TIMING_GET_TIME(time_end);
961
962         CYCLES_STATS_COUNT(builtin_new,cycles_end - cycles_start);
963         RT_TIMING_TIME_DIFF(time_start, time_end, RT_TIMING_NEW_OBJECT);
964
965         return o;
966 }
967
968 #if defined(ENABLE_ESCAPE_REASON)
969 java_handle_t *builtin_escape_reason_new(classinfo *c) {
970         print_escape_reasons();
971         return builtin_java_new(c);
972 }
973 #endif
974
975 #if defined(ENABLE_TLH)
976 java_handle_t *builtin_tlh_new(classinfo *c)
977 {
978         java_handle_t *o;
979 # if defined(ENABLE_RT_TIMING)
980         struct timespec time_start, time_end;
981 # endif
982 # if defined(ENABLE_CYCLES_STATS)
983         u8 cycles_start, cycles_end;
984 # endif
985
986         RT_TIMING_GET_TIME(time_start);
987         CYCLES_STATS_GET(cycles_start);
988
989         /* is the class loaded */
990
991         assert(c->state & CLASS_LOADED);
992
993         /* check if we can instantiate this class */
994
995         if (c->flags & ACC_ABSTRACT) {
996                 exceptions_throw_instantiationerror(c);
997                 return NULL;
998         }
999
1000         /* is the class linked */
1001
1002         if (!(c->state & CLASS_LINKED))
1003                 if (!link_class(c))
1004                         return NULL;
1005
1006         if (!(c->state & CLASS_INITIALIZED)) {
1007 # if !defined(NDEBUG)
1008                 if (initverbose)
1009                         log_message_class("Initialize class (from builtin_new): ", c);
1010 # endif
1011
1012                 if (!initialize_class(c))
1013                         return NULL;
1014         }
1015
1016         /*
1017         o = tlh_alloc(&(THREADOBJECT->tlh), c->instancesize);
1018         */
1019         o = NULL;
1020
1021         if (o == NULL) {
1022                 o = (java_handle_t*) heap_alloc(c->instancesize, c->flags & ACC_CLASS_HAS_POINTERS,
1023                                                                                 c->finalizer, true);
1024         }
1025
1026         if (!o)
1027                 return NULL;
1028
1029 # if !defined(ENABLE_GC_CACAO) && defined(ENABLE_HANDLES)
1030         /* XXX this is only a dirty hack to make Boehm work with handles */
1031
1032         o = LLNI_WRAP((java_object_t *) o);
1033 # endif
1034
1035         LLNI_vftbl_direct(o) = c->vftbl;
1036
1037 # if defined(ENABLE_THREADS)
1038         LLNI_DIRECT(o)->lockword.init();
1039 # endif
1040
1041         CYCLES_STATS_GET(cycles_end);
1042         RT_TIMING_GET_TIME(time_end);
1043
1044 /*
1045         CYCLES_STATS_COUNT(builtin_new,cycles_end - cycles_start);
1046         RT_TIMING_TIME_DIFF(time_start, time_end, RT_TIMING_NEW_OBJECT);
1047 */
1048
1049         return o;
1050 }
1051 #endif
1052
1053
1054 /* builtin_java_new ************************************************************
1055
1056    NOTE: This is a SLOW builtin and can be called from JIT code only.
1057
1058 *******************************************************************************/
1059
1060 java_handle_t *builtin_java_new(java_handle_t *clazz)
1061 {
1062         return builtin_new(LLNI_classinfo_unwrap(clazz));
1063 }
1064
1065
1066 /* builtin_fast_new ************************************************************
1067
1068    Creates a new instance of class c on the heap.
1069
1070    RETURN VALUE:
1071       pointer to the object, or NULL if no fast return
1072       is possible for any reason.
1073
1074    NOTE: This is a FAST builtin and can be called from JIT code only.
1075
1076 *******************************************************************************/
1077
1078 java_object_t *builtin_fast_new(classinfo *c)
1079 {
1080         java_object_t *o;
1081 #if defined(ENABLE_RT_TIMING)
1082         struct timespec time_start, time_end;
1083 #endif
1084 #if defined(ENABLE_CYCLES_STATS)
1085         u8 cycles_start, cycles_end;
1086 #endif
1087
1088         RT_TIMING_GET_TIME(time_start);
1089         CYCLES_STATS_GET(cycles_start);
1090
1091         /* is the class loaded */
1092
1093         assert(c->state & CLASS_LOADED);
1094
1095         /* check if we can instantiate this class */
1096
1097         if (c->flags & ACC_ABSTRACT)
1098                 return NULL;
1099
1100         /* is the class linked */
1101
1102         if (!(c->state & CLASS_LINKED))
1103                 return NULL;
1104
1105         if (!(c->state & CLASS_INITIALIZED))
1106                 return NULL;
1107
1108         o = (java_handle_t*) heap_alloc(c->instancesize, c->flags & ACC_CLASS_HAS_POINTERS,
1109                                                                         c->finalizer, false);
1110
1111         if (!o)
1112                 return NULL;
1113
1114         o->vftbl = c->vftbl;
1115
1116 #if defined(ENABLE_THREADS)
1117         LLNI_DIRECT(o)->lockword.init();
1118 #endif
1119
1120         CYCLES_STATS_GET(cycles_end);
1121         RT_TIMING_GET_TIME(time_end);
1122
1123         CYCLES_STATS_COUNT(builtin_new,cycles_end - cycles_start);
1124         RT_TIMING_TIME_DIFF(time_start, time_end, RT_TIMING_NEW_OBJECT);
1125
1126         return o;
1127 }
1128
1129
1130 /* builtin_newarray ************************************************************
1131
1132    Creates an array with the given vftbl on the heap. This function
1133    takes as class argument an array class.
1134
1135    RETURN VALUE:
1136       pointer to the array or NULL if no memory is available
1137
1138    NOTE: This builtin can be called from NATIVE code only.
1139
1140 *******************************************************************************/
1141
1142 java_handle_t *builtin_newarray(int32_t size, classinfo *arrayclass)
1143 {
1144         arraydescriptor *desc;
1145         s4               dataoffset;
1146         s4               componentsize;
1147         s4               actualsize;
1148         java_handle_t   *a;
1149 #if defined(ENABLE_RT_TIMING)
1150         struct timespec time_start, time_end;
1151 #endif
1152
1153         RT_TIMING_GET_TIME(time_start);
1154
1155         desc          = arrayclass->vftbl->arraydesc;
1156         dataoffset    = desc->dataoffset;
1157         componentsize = desc->componentsize;
1158
1159         if (size < 0) {
1160                 exceptions_throw_negativearraysizeexception();
1161                 return NULL;
1162         }
1163
1164         actualsize = dataoffset + size * componentsize;
1165
1166         /* check for overflow */
1167
1168         if (((u4) actualsize) < ((u4) size)) {
1169                 exceptions_throw_outofmemoryerror();
1170                 return NULL;
1171         }
1172
1173         a = (java_handle_t*) heap_alloc(actualsize, (desc->arraytype == ARRAYTYPE_OBJECT), NULL, true);
1174
1175         if (a == NULL)
1176                 return NULL;
1177
1178 #if !defined(ENABLE_GC_CACAO) && defined(ENABLE_HANDLES)
1179         /* XXX this is only a dirty hack to make Boehm work with handles */
1180
1181         a = LLNI_WRAP((java_object_t *) a);
1182 #endif
1183
1184         LLNI_vftbl_direct(a) = arrayclass->vftbl;
1185
1186 #if defined(ENABLE_THREADS)
1187         LLNI_DIRECT(a)->lockword.init();
1188 #endif
1189
1190         LLNI_array_size(a) = size;
1191
1192         RT_TIMING_GET_TIME(time_end);
1193         RT_TIMING_TIME_DIFF(time_start, time_end, RT_TIMING_NEW_ARRAY);
1194
1195         return a;
1196 }
1197
1198
1199 /* builtin_java_newarray *******************************************************
1200
1201    NOTE: This is a SLOW builtin and can be called from JIT code only.
1202
1203 *******************************************************************************/
1204
1205 java_handle_t *builtin_java_newarray(int32_t size, java_handle_t *arrayclazz)
1206 {
1207         return builtin_newarray(size, LLNI_classinfo_unwrap(arrayclazz));
1208 }
1209
1210
1211 /* builtin_anewarray ***********************************************************
1212
1213    Creates an array of references to the given class type on the heap.
1214
1215    RETURN VALUE:
1216       pointer to the array or NULL if no memory is
1217       available
1218
1219    NOTE: This builtin can be called from NATIVE code only.
1220
1221 *******************************************************************************/
1222
1223 java_handle_objectarray_t *builtin_anewarray(int32_t size, classinfo *componentclass)
1224 {
1225         classinfo *arrayclass;
1226         
1227         /* is class loaded */
1228
1229         assert(componentclass->state & CLASS_LOADED);
1230
1231         /* is class linked */
1232
1233         if (!(componentclass->state & CLASS_LINKED))
1234                 if (!link_class(componentclass))
1235                         return NULL;
1236
1237         arrayclass = class_array_of(componentclass, true);
1238
1239         if (!arrayclass)
1240                 return NULL;
1241
1242         return (java_handle_objectarray_t *) builtin_newarray(size, arrayclass);
1243 }
1244
1245
1246 /* builtin_newarray_type ****************************************************
1247
1248    Creates an array of [type]s on the heap.
1249         
1250    RETURN VALUE:
1251       pointer to the array or NULL if no memory is available
1252
1253    NOTE: This is a SLOW builtin and can be called from JIT & NATIVE code.
1254
1255 *******************************************************************************/
1256
1257 #define BUILTIN_NEWARRAY_TYPE(type, arraytype)                             \
1258 java_handle_##type##array_t *builtin_newarray_##type(int32_t size)              \
1259 {                                                                          \
1260         return (java_handle_##type##array_t *)                                 \
1261                 builtin_newarray(size, primitivetype_table[arraytype].arrayclass); \
1262 }
1263
1264 BUILTIN_NEWARRAY_TYPE(boolean, ARRAYTYPE_BOOLEAN)
1265 BUILTIN_NEWARRAY_TYPE(byte,    ARRAYTYPE_BYTE)
1266 BUILTIN_NEWARRAY_TYPE(char,    ARRAYTYPE_CHAR)
1267 BUILTIN_NEWARRAY_TYPE(short,   ARRAYTYPE_SHORT)
1268 BUILTIN_NEWARRAY_TYPE(int,     ARRAYTYPE_INT)
1269 BUILTIN_NEWARRAY_TYPE(long,    ARRAYTYPE_LONG)
1270 BUILTIN_NEWARRAY_TYPE(float,   ARRAYTYPE_FLOAT)
1271 BUILTIN_NEWARRAY_TYPE(double,  ARRAYTYPE_DOUBLE)
1272
1273
1274 /* builtin_multianewarray_intern ***********************************************
1275
1276    Creates a multi-dimensional array on the heap. The dimensions are
1277    passed in an array of longs.
1278
1279    ARGUMENTS:
1280       n.............number of dimensions to create
1281       arrayclass....the array class
1282       dims..........array containing the size of each dimension to create
1283
1284    RETURN VALUE:
1285       pointer to the array or NULL if no memory is available
1286
1287 ******************************************************************************/
1288
1289 static java_handle_t *builtin_multianewarray_intern(int n,
1290                                                                                                         classinfo *arrayclass,
1291                                                                                                         long *dims)
1292 {
1293         s4             size;
1294         java_handle_t *a;
1295         classinfo     *componentclass;
1296         s4             i;
1297
1298         /* create this dimension */
1299
1300         size = (s4) dims[0];
1301         a = builtin_newarray(size, arrayclass);
1302
1303         if (!a)
1304                 return NULL;
1305
1306         /* if this is the last dimension return */
1307
1308         if (!--n)
1309                 return a;
1310
1311         /* get the class of the components to create */
1312
1313         componentclass = arrayclass->vftbl->arraydesc->componentvftbl->clazz;
1314
1315         /* The verifier guarantees that the dimension count is in the range. */
1316
1317         /* create the component arrays */
1318
1319         for (i = 0; i < size; i++) {
1320                 java_handle_t *ea =
1321 #if defined(__MIPS__) && (SIZEOF_VOID_P == 4)
1322                         /* we save an s4 to a s8 slot, 8-byte aligned */
1323
1324                         builtin_multianewarray_intern(n, componentclass, dims + 2);
1325 #else
1326                         builtin_multianewarray_intern(n, componentclass, dims + 1);
1327 #endif
1328
1329                 if (!ea)
1330                         return NULL;
1331
1332                 array_objectarray_element_set((java_handle_objectarray_t *) a, i, ea);
1333         }
1334
1335         return a;
1336 }
1337
1338
1339 /* builtin_multianewarray ******************************************************
1340
1341    Wrapper for builtin_multianewarray_intern which checks all
1342    dimensions before we start allocating.
1343
1344    NOTE: This is a SLOW builtin and can be called from JIT code only.
1345
1346 ******************************************************************************/
1347
1348 java_handle_objectarray_t *builtin_multianewarray(int n,
1349                                                                                                   java_handle_t *arrayclazz,
1350                                                                                                   long *dims)
1351 {
1352         classinfo *c;
1353         s4         i;
1354         s4         size;
1355
1356         /* check all dimensions before doing anything */
1357
1358         for (i = 0; i < n; i++) {
1359 #if defined(__MIPS__) && (SIZEOF_VOID_P == 4)
1360                 /* we save an s4 to a s8 slot, 8-byte aligned */
1361                 size = (s4) dims[i * 2];
1362 #else
1363                 size = (s4) dims[i];
1364 #endif
1365
1366                 if (size < 0) {
1367                         exceptions_throw_negativearraysizeexception();
1368                         return NULL;
1369                 }
1370         }
1371
1372         c = LLNI_classinfo_unwrap(arrayclazz);
1373
1374         /* now call the real function */
1375
1376         return (java_handle_objectarray_t *)
1377                 builtin_multianewarray_intern(n, c, dims);
1378 }
1379
1380
1381 /* builtin_verbosecall_enter ***************************************************
1382
1383    Print method call with arguments for -verbose:call.
1384
1385    XXX: Remove mew once all archs use the new tracer!
1386
1387 *******************************************************************************/
1388
1389 #if !defined(NDEBUG)
1390 #ifdef TRACE_ARGS_NUM
1391 void builtin_verbosecall_enter(s8 a0, s8 a1,
1392 # if TRACE_ARGS_NUM >= 4
1393                                                            s8 a2, s8 a3,
1394 # endif
1395 # if TRACE_ARGS_NUM >= 6
1396                                                            s8 a4, s8 a5,
1397 # endif
1398 # if TRACE_ARGS_NUM == 8
1399                                                            s8 a6, s8 a7,
1400 # endif
1401                                                            methodinfo *m)
1402 {
1403         log_text("builtin_verbosecall_enter: Do not call me anymore!");
1404 }
1405 #endif
1406 #endif /* !defined(NDEBUG) */
1407
1408
1409 /* builtin_verbosecall_exit ****************************************************
1410
1411    Print method exit for -verbose:call.
1412
1413    XXX: Remove mew once all archs use the new tracer!
1414
1415 *******************************************************************************/
1416
1417 #if !defined(NDEBUG)
1418 void builtin_verbosecall_exit(s8 l, double d, float f, methodinfo *m)
1419 {
1420         log_text("builtin_verbosecall_exit: Do not call me anymore!");
1421 }
1422 #endif /* !defined(NDEBUG) */
1423
1424
1425 /*============================================================================*/
1426 /* MISCELLANEOUS MATHEMATICAL HELPER FUNCTIONS                                */
1427 /*============================================================================*/
1428
1429 /*********** Functions for integer divisions *****************************
1430  
1431         On some systems (eg. DEC ALPHA), integer division is not supported by the
1432         CPU. These helper functions implement the missing functionality.
1433
1434 ******************************************************************************/
1435
1436 #if !SUPPORT_DIVISION || defined(DISABLE_GC)
1437 s4 builtin_idiv(s4 a, s4 b)
1438 {
1439         s4 c;
1440
1441         c = a / b;
1442
1443         return c;
1444 }
1445
1446 s4 builtin_irem(s4 a, s4 b)
1447 {
1448         s4 c;
1449
1450         c = a % b;
1451
1452         return c;
1453 }
1454 #endif /* !SUPPORT_DIVISION || defined(DISABLE_GC) */
1455
1456
1457 /* functions for long arithmetics **********************************************
1458
1459    On systems where 64 bit Integers are not supported by the CPU,
1460    these functions are needed.
1461
1462 ******************************************************************************/
1463
1464 #if !(SUPPORT_LONG && SUPPORT_LONG_ADD)
1465 s8 builtin_ladd(s8 a, s8 b)
1466 {
1467         s8 c;
1468
1469         c = a + b; 
1470
1471         return c;
1472 }
1473
1474 s8 builtin_lsub(s8 a, s8 b)
1475 {
1476         s8 c;
1477
1478         c = a - b; 
1479
1480         return c;
1481 }
1482
1483 s8 builtin_lneg(s8 a)
1484 {
1485         s8 c;
1486
1487         c = -a;
1488
1489         return c;
1490 }
1491 #endif /* !(SUPPORT_LONG && SUPPORT_LONG_ADD) */
1492
1493
1494 #if !(SUPPORT_LONG && SUPPORT_LONG_MUL)
1495 s8 builtin_lmul(s8 a, s8 b)
1496 {
1497         s8 c;
1498
1499         c = a * b; 
1500
1501         return c;
1502 }
1503 #endif /* !(SUPPORT_LONG && SUPPORT_LONG_MUL) */
1504
1505
1506 #if !(SUPPORT_DIVISION && SUPPORT_LONG && SUPPORT_LONG_DIV) || defined (DISABLE_GC)
1507 s8 builtin_ldiv(s8 a, s8 b)
1508 {
1509         s8 c;
1510
1511         c = a / b; 
1512
1513         return c;
1514 }
1515
1516 s8 builtin_lrem(s8 a, s8 b)
1517 {
1518         s8 c;
1519
1520         c = a % b; 
1521
1522         return c;
1523 }
1524 #endif /* !(SUPPORT_DIVISION && SUPPORT_LONG && SUPPORT_LONG_DIV) */
1525
1526
1527 #if !(SUPPORT_LONG && SUPPORT_LONG_SHIFT)
1528 s8 builtin_lshl(s8 a, s4 b)
1529 {
1530         s8 c;
1531
1532         c = a << (b & 63);
1533
1534         return c;
1535 }
1536
1537 s8 builtin_lshr(s8 a, s4 b)
1538 {
1539         s8 c;
1540
1541         c = a >> (b & 63);
1542
1543         return c;
1544 }
1545
1546 s8 builtin_lushr(s8 a, s4 b)
1547 {
1548         s8 c;
1549
1550         c = ((u8) a) >> (b & 63);
1551
1552         return c;
1553 }
1554 #endif /* !(SUPPORT_LONG && SUPPORT_LONG_SHIFT) */
1555
1556
1557 #if !(SUPPORT_LONG && SUPPORT_LONG_LOGICAL)
1558 s8 builtin_land(s8 a, s8 b)
1559 {
1560         s8 c;
1561
1562         c = a & b; 
1563
1564         return c;
1565 }
1566
1567 s8 builtin_lor(s8 a, s8 b)
1568 {
1569         s8 c;
1570
1571         c = a | b; 
1572
1573         return c;
1574 }
1575
1576 s8 builtin_lxor(s8 a, s8 b) 
1577 {
1578         s8 c;
1579
1580         c = a ^ b; 
1581
1582         return c;
1583 }
1584 #endif /* !(SUPPORT_LONG && SUPPORT_LONG_LOGICAL) */
1585
1586
1587 #if !(SUPPORT_LONG && SUPPORT_LONG_CMP)
1588 s4 builtin_lcmp(s8 a, s8 b)
1589
1590         if (a < b)
1591                 return -1;
1592
1593         if (a > b)
1594                 return 1;
1595
1596         return 0;
1597 }
1598 #endif /* !(SUPPORT_LONG && SUPPORT_LONG_CMP) */
1599
1600
1601 /* functions for unsupported floating instructions ****************************/
1602
1603 /* used to convert FLT_xxx defines into float values */
1604
1605 static inline float intBitsToFloat(s4 i)
1606 {
1607         imm_union imb;
1608
1609         imb.i = i;
1610         return imb.f;
1611 }
1612
1613
1614 /* used to convert DBL_xxx defines into double values */
1615
1616 static inline float longBitsToDouble(s8 l)
1617 {
1618         imm_union imb;
1619
1620         imb.l = l;
1621         return imb.d;
1622 }
1623
1624
1625 #if !SUPPORT_FLOAT
1626 float builtin_fadd(float a, float b)
1627 {
1628         if (isnanf(a)) return intBitsToFloat(FLT_NAN);
1629         if (isnanf(b)) return intBitsToFloat(FLT_NAN);
1630         if (finitef(a)) {
1631                 if (finitef(b))
1632                         return a + b;
1633                 else
1634                         return b;
1635         }
1636         else {
1637                 if (finitef(b))
1638                         return a;
1639                 else {
1640                         if (copysignf(1.0, a) == copysignf(1.0, b))
1641                                 return a;
1642                         else
1643                                 return intBitsToFloat(FLT_NAN);
1644                 }
1645         }
1646 }
1647
1648
1649 float builtin_fsub(float a, float b)
1650 {
1651         return builtin_fadd(a, builtin_fneg(b));
1652 }
1653
1654
1655 float builtin_fmul(float a, float b)
1656 {
1657         if (isnanf(a)) return intBitsToFloat(FLT_NAN);
1658         if (isnanf(b)) return intBitsToFloat(FLT_NAN);
1659         if (finitef(a)) {
1660                 if (finitef(b)) return a * b;
1661                 else {
1662                         if (a == 0) return intBitsToFloat(FLT_NAN);
1663                         else return copysignf(b, copysignf(1.0, b)*a);
1664                 }
1665         }
1666         else {
1667                 if (finitef(b)) {
1668                         if (b == 0) return intBitsToFloat(FLT_NAN);
1669                         else return copysignf(a, copysignf(1.0, a)*b);
1670                 }
1671                 else {
1672                         return copysignf(a, copysignf(1.0, a)*copysignf(1.0, b));
1673                 }
1674         }
1675 }
1676
1677
1678 /* builtin_ddiv ****************************************************************
1679
1680    Implementation as described in VM Spec.
1681
1682 *******************************************************************************/
1683
1684 float builtin_fdiv(float a, float b)
1685 {
1686         if (finitef(a)) {
1687                 if (finitef(b)) {
1688                         /* If neither value1' nor value2' is NaN, the sign of the result */
1689                         /* is positive if both values have the same sign, negative if the */
1690                         /* values have different signs. */
1691
1692                         return a / b;
1693
1694                 } else {
1695                         if (isnanf(b)) {
1696                                 /* If either value1' or value2' is NaN, the result is NaN. */
1697
1698                                 return intBitsToFloat(FLT_NAN);
1699
1700                         } else {
1701                                 /* Division of a finite value by an infinity results in a */
1702                                 /* signed zero, with the sign-producing rule just given. */
1703
1704                                 /* is sign equal? */
1705
1706                                 if (copysignf(1.0, a) == copysignf(1.0, b))
1707                                         return 0.0;
1708                                 else
1709                                         return -0.0;
1710                         }
1711                 }
1712
1713         } else {
1714                 if (isnanf(a)) {
1715                         /* If either value1' or value2' is NaN, the result is NaN. */
1716
1717                         return intBitsToFloat(FLT_NAN);
1718
1719                 } else if (finitef(b)) {
1720                         /* Division of an infinity by a finite value results in a signed */
1721                         /* infinity, with the sign-producing rule just given. */
1722
1723                         /* is sign equal? */
1724
1725                         if (copysignf(1.0, a) == copysignf(1.0, b))
1726                                 return intBitsToFloat(FLT_POSINF);
1727                         else
1728                                 return intBitsToFloat(FLT_NEGINF);
1729
1730                 } else {
1731                         /* Division of an infinity by an infinity results in NaN. */
1732
1733                         return intBitsToFloat(FLT_NAN);
1734                 }
1735         }
1736 }
1737
1738
1739 float builtin_fneg(float a)
1740 {
1741         if (isnanf(a)) return a;
1742         else {
1743                 if (finitef(a)) return -a;
1744                 else return copysignf(a, -copysignf(1.0, a));
1745         }
1746 }
1747 #endif /* !SUPPORT_FLOAT */
1748
1749
1750 #if !SUPPORT_FLOAT || !SUPPORT_FLOAT_CMP || defined(ENABLE_INTRP)
1751 s4 builtin_fcmpl(float a, float b)
1752 {
1753         if (isnanf(a))
1754                 return -1;
1755
1756         if (isnanf(b))
1757                 return -1;
1758
1759         if (!finitef(a) || !finitef(b)) {
1760                 a = finitef(a) ? 0 : copysignf(1.0,     a);
1761                 b = finitef(b) ? 0 : copysignf(1.0, b);
1762         }
1763
1764         if (a > b)
1765                 return 1;
1766
1767         if (a == b)
1768                 return 0;
1769
1770         return -1;
1771 }
1772
1773
1774 s4 builtin_fcmpg(float a, float b)
1775 {
1776         if (isnanf(a)) return 1;
1777         if (isnanf(b)) return 1;
1778         if (!finitef(a) || !finitef(b)) {
1779                 a = finitef(a) ? 0 : copysignf(1.0, a);
1780                 b = finitef(b) ? 0 : copysignf(1.0, b);
1781         }
1782         if (a > b) return 1;
1783         if (a == b) return 0;
1784         return -1;
1785 }
1786 #endif /* !SUPPORT_FLOAT || !SUPPORT_FLOAT_CMP || defined(ENABLE_INTRP) */
1787
1788
1789 float builtin_frem(float a, float b)
1790 {
1791         return fmodf(a, b);
1792 }
1793
1794
1795 /* functions for unsupported double instructions ******************************/
1796
1797 #if !SUPPORT_DOUBLE
1798 double builtin_dadd(double a, double b)
1799 {
1800         if (isnan(a)) return longBitsToDouble(DBL_NAN);
1801         if (isnan(b)) return longBitsToDouble(DBL_NAN);
1802         if (finite(a)) {
1803                 if (finite(b)) return a + b;
1804                 else return b;
1805         }
1806         else {
1807                 if (finite(b)) return a;
1808                 else {
1809                         if (copysign(1.0, a)==copysign(1.0, b)) return a;
1810                         else return longBitsToDouble(DBL_NAN);
1811                 }
1812         }
1813 }
1814
1815
1816 double builtin_dsub(double a, double b)
1817 {
1818         return builtin_dadd(a, builtin_dneg(b));
1819 }
1820
1821
1822 double builtin_dmul(double a, double b)
1823 {
1824         if (isnan(a)) return longBitsToDouble(DBL_NAN);
1825         if (isnan(b)) return longBitsToDouble(DBL_NAN);
1826         if (finite(a)) {
1827                 if (finite(b)) return a * b;
1828                 else {
1829                         if (a == 0) return longBitsToDouble(DBL_NAN);
1830                         else return copysign(b, copysign(1.0, b) * a);
1831                 }
1832         }
1833         else {
1834                 if (finite(b)) {
1835                         if (b == 0) return longBitsToDouble(DBL_NAN);
1836                         else return copysign(a, copysign(1.0, a) * b);
1837                 }
1838                 else {
1839                         return copysign(a, copysign(1.0, a) * copysign(1.0, b));
1840                 }
1841         }
1842 }
1843
1844
1845 /* builtin_ddiv ****************************************************************
1846
1847    Implementation as described in VM Spec.
1848
1849 *******************************************************************************/
1850
1851 double builtin_ddiv(double a, double b)
1852 {
1853         if (finite(a)) {
1854                 if (finite(b)) {
1855                         /* If neither value1' nor value2' is NaN, the sign of the result */
1856                         /* is positive if both values have the same sign, negative if the */
1857                         /* values have different signs. */
1858
1859                         return a / b;
1860
1861                 } else {
1862                         if (isnan(b)) {
1863                                 /* If either value1' or value2' is NaN, the result is NaN. */
1864
1865                                 return longBitsToDouble(DBL_NAN);
1866
1867                         } else {
1868                                 /* Division of a finite value by an infinity results in a */
1869                                 /* signed zero, with the sign-producing rule just given. */
1870
1871                                 /* is sign equal? */
1872
1873                                 if (copysign(1.0, a) == copysign(1.0, b))
1874                                         return 0.0;
1875                                 else
1876                                         return -0.0;
1877                         }
1878                 }
1879
1880         } else {
1881                 if (isnan(a)) {
1882                         /* If either value1' or value2' is NaN, the result is NaN. */
1883
1884                         return longBitsToDouble(DBL_NAN);
1885
1886                 } else if (finite(b)) {
1887                         /* Division of an infinity by a finite value results in a signed */
1888                         /* infinity, with the sign-producing rule just given. */
1889
1890                         /* is sign equal? */
1891
1892                         if (copysign(1.0, a) == copysign(1.0, b))
1893                                 return longBitsToDouble(DBL_POSINF);
1894                         else
1895                                 return longBitsToDouble(DBL_NEGINF);
1896
1897                 } else {
1898                         /* Division of an infinity by an infinity results in NaN. */
1899
1900                         return longBitsToDouble(DBL_NAN);
1901                 }
1902         }
1903 }
1904
1905
1906 /* builtin_dneg ****************************************************************
1907
1908    Implemented as described in VM Spec.
1909
1910 *******************************************************************************/
1911
1912 double builtin_dneg(double a)
1913 {
1914         if (isnan(a)) {
1915                 /* If the operand is NaN, the result is NaN (recall that NaN has no */
1916                 /* sign). */
1917
1918                 return a;
1919
1920         } else {
1921                 if (finite(a)) {
1922                         /* If the operand is a zero, the result is the zero of opposite */
1923                         /* sign. */
1924
1925                         return -a;
1926
1927                 } else {
1928                         /* If the operand is an infinity, the result is the infinity of */
1929                         /* opposite sign. */
1930
1931                         return copysign(a, -copysign(1.0, a));
1932                 }
1933         }
1934 }
1935 #endif /* !SUPPORT_DOUBLE */
1936
1937
1938 #if !SUPPORT_DOUBLE || !SUPPORT_DOUBLE_CMP || defined(ENABLE_INTRP)
1939 s4 builtin_dcmpl(double a, double b)
1940 {
1941         if (isnan(a))
1942                 return -1;
1943
1944         if (isnan(b))
1945                 return -1;
1946
1947         if (!finite(a) || !finite(b)) {
1948                 a = finite(a) ? 0 : copysign(1.0, a);
1949                 b = finite(b) ? 0 : copysign(1.0, b);
1950         }
1951
1952         if (a > b)
1953                 return 1;
1954
1955         if (a == b)
1956                 return 0;
1957
1958         return -1;
1959 }
1960
1961
1962 s4 builtin_dcmpg(double a, double b)
1963 {
1964         if (isnan(a))
1965                 return 1;
1966
1967         if (isnan(b))
1968                 return 1;
1969
1970         if (!finite(a) || !finite(b)) {
1971                 a = finite(a) ? 0 : copysign(1.0, a);
1972                 b = finite(b) ? 0 : copysign(1.0, b);
1973         }
1974
1975         if (a > b)
1976                 return 1;
1977
1978         if (a == b)
1979                 return 0;
1980
1981         return -1;
1982 }
1983 #endif /* !SUPPORT_DOUBLE || !SUPPORT_DOUBLE_CMP || defined(ENABLE_INTRP) */
1984
1985
1986 double builtin_drem(double a, double b)
1987 {
1988         return fmod(a, b);
1989 }
1990
1991
1992 /* conversion operations ******************************************************/
1993
1994 #if !(SUPPORT_FLOAT && SUPPORT_I2F)
1995 float builtin_i2f(s4 a)
1996 {
1997         float f = (float) a;
1998         return f;
1999 }
2000 #endif /* !(SUPPORT_FLOAT && SUPPORT_I2F) */
2001
2002
2003 #if !(SUPPORT_DOUBLE && SUPPORT_I2D)
2004 double builtin_i2d(s4 a)
2005 {
2006         double d = (double) a;
2007         return d;
2008 }
2009 #endif /* !(SUPPORT_DOUBLE && SUPPORT_I2D) */
2010
2011
2012 #if !(SUPPORT_LONG && SUPPORT_FLOAT && SUPPORT_L2F)
2013 float builtin_l2f(s8 a)
2014 {
2015         float f = (float) a;
2016         return f;
2017 }
2018 #endif /* !(SUPPORT_LONG && SUPPORT_FLOAT && SUPPORT_L2F) */
2019
2020
2021 #if !(SUPPORT_LONG && SUPPORT_DOUBLE && SUPPORT_L2D)
2022 double builtin_l2d(s8 a)
2023 {
2024         double d = (double) a;
2025         return d;
2026 }
2027 #endif /* !(SUPPORT_LONG && SUPPORT_DOUBLE && SUPPORT_L2D) */
2028
2029
2030 #if !(SUPPORT_FLOAT && SUPPORT_F2I) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
2031 s4 builtin_f2i(float a) 
2032 {
2033         s4 i;
2034
2035         i = builtin_d2i((double) a);
2036
2037         return i;
2038
2039         /*      float f;
2040         
2041                 if (isnanf(a))
2042                 return 0;
2043                 if (finitef(a)) {
2044                 if (a > 2147483647)
2045                 return 2147483647;
2046                 if (a < (-2147483648))
2047                 return (-2147483648);
2048                 return (s4) a;
2049                 }
2050                 f = copysignf((float) 1.0, a);
2051                 if (f > 0)
2052                 return 2147483647;
2053                 return (-2147483648); */
2054 }
2055 #endif /* !(SUPPORT_FLOAT && SUPPORT_F2I) || defined(ENABLE_INTRP) || defined(DISABLE_GC) */
2056
2057
2058 #if !(SUPPORT_FLOAT && SUPPORT_LONG && SUPPORT_F2L) || defined(DISABLE_GC)
2059 s8 builtin_f2l(float a)
2060 {
2061         s8 l;
2062
2063         l = builtin_d2l((double) a);
2064
2065         return l;
2066
2067         /*      float f;
2068         
2069                 if (finitef(a)) {
2070                 if (a > 9223372036854775807L)
2071                 return 9223372036854775807L;
2072                 if (a < (-9223372036854775808L))
2073                 return (-9223372036854775808L);
2074                 return (s8) a;
2075                 }
2076                 if (isnanf(a))
2077                 return 0;
2078                 f = copysignf((float) 1.0, a);
2079                 if (f > 0)
2080                 return 9223372036854775807L;
2081                 return (-9223372036854775808L); */
2082 }
2083 #endif /* !(SUPPORT_FLOAT && SUPPORT_LONG && SUPPORT_F2L) */
2084
2085
2086 #if !(SUPPORT_DOUBLE && SUPPORT_D2I) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
2087 s4 builtin_d2i(double a) 
2088
2089         double d;
2090         
2091         if (finite(a)) {
2092                 if (a >= 2147483647)
2093                         return 2147483647;
2094                 if (a <= (-2147483647-1))
2095                         return (-2147483647-1);
2096                 return (s4) a;
2097         }
2098         if (isnan(a))
2099                 return 0;
2100         d = copysign(1.0, a);
2101         if (d > 0)
2102                 return 2147483647;
2103         return (-2147483647-1);
2104 }
2105 #endif /* !(SUPPORT_DOUBLE && SUPPORT_D2I) || defined(ENABLE_INTRP) || defined(DISABLE_GC) */
2106
2107
2108 #if !(SUPPORT_DOUBLE && SUPPORT_LONG && SUPPORT_D2L) || defined(DISABLE_GC)
2109 s8 builtin_d2l(double a)
2110 {
2111         double d;
2112         
2113         if (finite(a)) {
2114                 if (a >= 9223372036854775807LL)
2115                         return 9223372036854775807LL;
2116                 if (a <= (-9223372036854775807LL-1))
2117                         return (-9223372036854775807LL-1);
2118                 return (s8) a;
2119         }
2120         if (isnan(a))
2121                 return 0;
2122         d = copysign(1.0, a);
2123         if (d > 0)
2124                 return 9223372036854775807LL;
2125         return (-9223372036854775807LL-1);
2126 }
2127 #endif /* !(SUPPORT_DOUBLE && SUPPORT_LONG && SUPPORT_D2L) */
2128
2129
2130 #if !(SUPPORT_FLOAT && SUPPORT_DOUBLE)
2131 double builtin_f2d(float a)
2132 {
2133         if (finitef(a)) return (double) a;
2134         else {
2135                 if (isnanf(a))
2136                         return longBitsToDouble(DBL_NAN);
2137                 else
2138                         return copysign(longBitsToDouble(DBL_POSINF), (double) copysignf(1.0, a) );
2139         }
2140 }
2141
2142 float builtin_d2f(double a)
2143 {
2144         if (finite(a))
2145                 return (float) a;
2146         else {
2147                 if (isnan(a))
2148                         return intBitsToFloat(FLT_NAN);
2149                 else
2150                         return copysignf(intBitsToFloat(FLT_POSINF), (float) copysign(1.0, a));
2151         }
2152 }
2153 #endif /* !(SUPPORT_FLOAT && SUPPORT_DOUBLE) */
2154
2155
2156 /*============================================================================*/
2157 /* AUTOMATICALLY REPLACED FUNCTIONS                                           */
2158 /*============================================================================*/
2159
2160 /* builtin_arraycopy ***********************************************************
2161
2162    Builtin for java.lang.System.arraycopy.
2163
2164    NOTE: This is a SLOW builtin and can be called from JIT & NATIVE code.
2165
2166 *******************************************************************************/
2167
2168 void builtin_arraycopy(java_handle_t *src, s4 srcStart,
2169                                            java_handle_t *dest, s4 destStart, s4 len)
2170 {
2171         arraydescriptor *sdesc;
2172         arraydescriptor *ddesc;
2173         s4               i;
2174
2175         if ((src == NULL) || (dest == NULL)) {
2176                 exceptions_throw_nullpointerexception();
2177                 return;
2178         }
2179
2180         sdesc = LLNI_vftbl_direct(src)->arraydesc;
2181         ddesc = LLNI_vftbl_direct(dest)->arraydesc;
2182
2183         if (!sdesc || !ddesc || (sdesc->arraytype != ddesc->arraytype)) {
2184                 exceptions_throw_arraystoreexception();
2185                 return;
2186         }
2187
2188         // Check if offsets and length are positive.
2189         if ((srcStart < 0) || (destStart < 0) || (len < 0)) {
2190                 exceptions_throw_arrayindexoutofboundsexception();
2191                 return;
2192         }
2193
2194         // Check if ranges are valid.
2195         if ((((uint32_t) srcStart  + (uint32_t) len) > (uint32_t) LLNI_array_size(src)) ||
2196                 (((uint32_t) destStart + (uint32_t) len) > (uint32_t) LLNI_array_size(dest))) {
2197                 exceptions_throw_arrayindexoutofboundsexception();
2198                 return;
2199         }
2200
2201         // Special case.
2202         if (len == 0) {
2203                 return;
2204         }
2205
2206         if (sdesc->componentvftbl == ddesc->componentvftbl) {
2207                 /* We copy primitive values or references of exactly the same type */
2208
2209                 s4 dataoffset = sdesc->dataoffset;
2210                 s4 componentsize = sdesc->componentsize;
2211
2212                 LLNI_CRITICAL_START;
2213
2214                 MMOVE(((u1 *) LLNI_DIRECT(dest)) + dataoffset + componentsize * destStart,
2215                           ((u1 *) LLNI_DIRECT(src))  + dataoffset + componentsize * srcStart,
2216                           u1, (size_t) len * componentsize);
2217
2218                 LLNI_CRITICAL_END;
2219         }
2220         else {
2221                 /* We copy references of different type */
2222
2223                 java_handle_objectarray_t *oas = (java_handle_objectarray_t *) src;
2224                 java_handle_objectarray_t *oad = (java_handle_objectarray_t *) dest;
2225  
2226                 if (destStart <= srcStart) {
2227                         for (i = 0; i < len; i++) {
2228                                 java_handle_t *o;
2229
2230                                 o = array_objectarray_element_get(oas, srcStart + i);
2231
2232                                 if (!builtin_canstore(oad, o))
2233                                         return;
2234
2235                                 array_objectarray_element_set(oad, destStart + i, o);
2236                         }
2237                 }
2238                 else {
2239                         /* XXX this does not completely obey the specification!
2240                            If an exception is thrown only the elements above the
2241                            current index have been copied. The specification
2242                            requires that only the elements *below* the current
2243                            index have been copied before the throw. */
2244
2245                         for (i = len - 1; i >= 0; i--) {
2246                                 java_handle_t *o;
2247
2248                                 o = array_objectarray_element_get(oas, srcStart + i);
2249
2250                                 if (!builtin_canstore(oad, o))
2251                                         return;
2252
2253                                 array_objectarray_element_set(oad, destStart + i, o);
2254                         }
2255                 }
2256         }
2257 }
2258
2259
2260 /* builtin_nanotime ************************************************************
2261
2262    Return the current time in nanoseconds.
2263
2264 *******************************************************************************/
2265
2266 s8 builtin_nanotime(void)
2267 {
2268         struct timeval tv;
2269         s8             usecs;
2270
2271         if (gettimeofday(&tv, NULL) == -1)
2272                 vm_abort("gettimeofday failed: %s", strerror(errno));
2273
2274         usecs = (s8) tv.tv_sec * (1000 * 1000) + (s8) tv.tv_usec;
2275
2276         return usecs * 1000;
2277 }
2278
2279
2280 /* builtin_currenttimemillis ***************************************************
2281
2282    Return the current time in milliseconds.
2283
2284 *******************************************************************************/
2285
2286 s8 builtin_currenttimemillis(void)
2287 {
2288         s8 msecs;
2289
2290         msecs = builtin_nanotime() / 1000 / 1000;
2291
2292         return msecs;
2293 }
2294
2295
2296 /* builtin_clone ***************************************************************
2297
2298    Function for cloning objects or arrays.
2299
2300    NOTE: This is a SLOW builtin and can be called from JIT & NATIVE code.
2301
2302 *******************************************************************************/
2303
2304 java_handle_t *builtin_clone(void *env, java_handle_t *o)
2305 {
2306         arraydescriptor *ad;
2307         u4               size;
2308         classinfo       *c;
2309         java_handle_t   *co;                /* cloned object header               */
2310
2311         /* get the array descriptor */
2312
2313         ad = LLNI_vftbl_direct(o)->arraydesc;
2314
2315         /* we are cloning an array */
2316
2317         if (ad != NULL) {
2318                 size = ad->dataoffset + ad->componentsize * LLNI_array_size(o);
2319         
2320                 co = (java_handle_t*) heap_alloc(size, (ad->arraytype == ARRAYTYPE_OBJECT), NULL, true);
2321
2322                 if (co == NULL)
2323                         return NULL;
2324
2325 #if !defined(ENABLE_GC_CACAO) && defined(ENABLE_HANDLES)
2326                 /* XXX this is only a dirty hack to make Boehm work with handles */
2327
2328                 co = LLNI_WRAP((java_object_t *) co);
2329 #endif
2330
2331                 LLNI_CRITICAL_START;
2332
2333                 MCOPY(LLNI_DIRECT(co), LLNI_DIRECT(o), u1, size);
2334
2335 #if defined(ENABLE_GC_CACAO)
2336                 heap_init_objectheader(LLNI_DIRECT(co), size);
2337 #endif
2338
2339 #if defined(ENABLE_THREADS)
2340                 LLNI_DIRECT(co)->lockword.init();
2341 #endif
2342
2343                 LLNI_CRITICAL_END;
2344
2345                 return co;
2346         }
2347     
2348     /* we are cloning a non-array */
2349
2350     if (!builtin_instanceof(o, class_java_lang_Cloneable)) {
2351         exceptions_throw_clonenotsupportedexception();
2352         return NULL;
2353     }
2354
2355         /* get the class of the object */
2356
2357         LLNI_class_get(o, c);
2358
2359         /* create new object */
2360
2361     co = builtin_new(c);
2362
2363     if (co == NULL)
2364         return NULL;
2365
2366         LLNI_CRITICAL_START;
2367
2368         MCOPY(LLNI_DIRECT(co), LLNI_DIRECT(o), u1, c->instancesize);
2369
2370 #if defined(ENABLE_GC_CACAO)
2371         heap_init_objectheader(LLNI_DIRECT(co), c->instancesize);
2372 #endif
2373
2374 #if defined(ENABLE_THREADS)
2375         LLNI_DIRECT(co)->lockword.init();
2376 #endif
2377
2378         LLNI_CRITICAL_END;
2379
2380     return co;
2381 }
2382
2383
2384 #if defined(ENABLE_CYCLES_STATS)
2385 void builtin_print_cycles_stats(FILE *file)
2386 {
2387         fprintf(file,"builtin cylce count statistics:\n");
2388
2389         CYCLES_STATS_PRINT_OVERHEAD(builtin_overhead,file);
2390         CYCLES_STATS_PRINT(builtin_new         ,file);
2391
2392         fprintf(file,"\n");
2393 }
2394 #endif /* defined(ENABLE_CYCLES_STATS) */
2395
2396
2397 #if defined(ENABLE_VMLOG)
2398 #define NDEBUG
2399 #include <vmlog_cacao.c>
2400 #endif
2401
2402
2403 /*
2404  * These are local overrides for various environment variables in Emacs.
2405  * Please do not remove this and leave it at the end of the file, where
2406  * Emacs will automagically detect them.
2407  * ---------------------------------------------------------------------
2408  * Local variables:
2409  * mode: c++
2410  * indent-tabs-mode: t
2411  * c-basic-offset: 4
2412  * tab-width: 4
2413  * End:
2414  * vim:noexpandtab:sw=4:ts=4:
2415  */