Merged new changes from default (manually: src/vm/jit/i386/codegen.c).
[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 fast_subtype_check(struct _vftbl *s, struct _vftbl *t)
732 {
733         if (s->subtype_display[t->subtype_depth] == t)
734                 return true;
735         if (t->subtype_offset != OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE]))
736                 return false;
737         return s->subtype_depth >= t->subtype_depth && s->subtype_overflow[t->subtype_depth - DISPLAY_SIZE] == t;
738 }
739
740 bool builtin_fast_canstore(java_objectarray_t *oa, java_object_t *o)
741 {
742         arraydescriptor *desc;
743         arraydescriptor *valuedesc;
744         vftbl_t         *componentvftbl;
745         vftbl_t         *valuevftbl;
746         int32_t          baseval;
747         uint32_t         diffval;
748         bool             result;
749
750         if (o == NULL)
751                 return 1;
752
753         /* The following is guaranteed (by verifier checks):
754          *
755          *     *) oa->...vftbl->arraydesc != NULL
756          *     *) oa->...vftbl->arraydesc->componentvftbl != NULL
757          *     *) o->vftbl is not an interface vftbl
758          */
759
760         desc           = oa->header.objheader.vftbl->arraydesc;
761         componentvftbl = desc->componentvftbl;
762         valuevftbl     = o->vftbl;
763         valuedesc      = valuevftbl->arraydesc;
764
765         if ((desc->dimension - 1) == 0) {
766                 /* {oa is a one-dimensional array} */
767                 /* {oa is an array of references} */
768                 
769                 if (valuevftbl == componentvftbl)
770                         return 1;
771
772                 baseval = componentvftbl->baseval;
773
774                 if (baseval <= 0) {
775                         /* an array of interface references */
776
777                         result = ((valuevftbl->interfacetablelength > -baseval) &&
778                                           (valuevftbl->interfacetable[baseval] != NULL));
779                 }
780                 else {
781                         result = fast_subtype_check(valuevftbl, componentvftbl);
782                 }
783         }
784         else if (valuedesc == NULL) {
785                 /* {oa has dimension > 1} */
786                 /* {componentvftbl->arraydesc != NULL} */
787
788                 /* check if o is an array */
789
790                 return 0;
791         }
792         else {
793                 /* {o is an array} */
794
795                 result = builtin_descriptorscompatible(valuedesc, componentvftbl->arraydesc);
796         }
797
798         /* return result */
799
800         return result;
801 }
802
803
804 /* This is an optimized version where a is guaranteed to be one-dimensional */
805 bool builtin_fast_canstore_onedim(java_objectarray_t *a, java_object_t *o)
806 {
807         arraydescriptor *desc;
808         vftbl_t         *elementvftbl;
809         vftbl_t         *valuevftbl;
810         int32_t          baseval;
811         uint32_t         diffval;
812         bool             result;
813         
814         if (o == NULL)
815                 return 1;
816
817         /* The following is guaranteed (by verifier checks):
818          *
819          *     *) a->...vftbl->arraydesc != NULL
820          *     *) a->...vftbl->arraydesc->elementvftbl != NULL
821          *     *) a->...vftbl->arraydesc->dimension == 1
822          *     *) o->vftbl is not an interface vftbl
823          */
824
825         desc = a->header.objheader.vftbl->arraydesc;
826     elementvftbl = desc->elementvftbl;
827         valuevftbl = o->vftbl;
828
829         /* {a is a one-dimensional array} */
830         
831         if (valuevftbl == elementvftbl)
832                 return 1;
833
834         baseval = elementvftbl->baseval;
835
836         if (baseval <= 0) {
837                 /* an array of interface references */
838                 result = ((valuevftbl->interfacetablelength > -baseval) &&
839                                   (valuevftbl->interfacetable[baseval] != NULL));
840         }
841         else {
842                 result = fast_subtype_check(valuevftbl, elementvftbl);
843         }
844
845         return result;
846 }
847
848
849 /* This is an optimized version where a is guaranteed to be a
850  * one-dimensional array of a class type */
851 bool builtin_fast_canstore_onedim_class(java_objectarray_t *a, java_object_t *o)
852 {
853         vftbl_t  *elementvftbl;
854         vftbl_t  *valuevftbl;
855         uint32_t  diffval;
856         bool      result;
857         
858         if (o == NULL)
859                 return 1;
860
861         /* The following is guaranteed (by verifier checks):
862          *
863          *     *) a->...vftbl->arraydesc != NULL
864          *     *) a->...vftbl->arraydesc->elementvftbl != NULL
865          *     *) a->...vftbl->arraydesc->elementvftbl is not an interface vftbl
866          *     *) a->...vftbl->arraydesc->dimension == 1
867          *     *) o->vftbl is not an interface vftbl
868          */
869
870     elementvftbl = a->header.objheader.vftbl->arraydesc->elementvftbl;
871         valuevftbl = o->vftbl;
872
873         /* {a is a one-dimensional array} */
874         
875         if (valuevftbl == elementvftbl)
876                 return 1;
877
878         result = fast_subtype_check(valuevftbl, elementvftbl);
879
880         return result;
881 }
882
883
884 /* builtin_new *****************************************************************
885
886    Creates a new instance of class c on the heap.
887
888    RETURN VALUE:
889       pointer to the object, or NULL if no memory is available
890
891    NOTE: This builtin can be called from NATIVE code only.
892
893 *******************************************************************************/
894
895 java_handle_t *builtin_new(classinfo *c)
896 {
897         java_handle_t *o;
898 #if defined(ENABLE_RT_TIMING)
899         struct timespec time_start, time_end;
900 #endif
901 #if defined(ENABLE_CYCLES_STATS)
902         u8 cycles_start, cycles_end;
903 #endif
904
905         RT_TIMING_GET_TIME(time_start);
906         CYCLES_STATS_GET(cycles_start);
907
908         /* is the class loaded */
909
910         assert(c->state & CLASS_LOADED);
911
912         /* check if we can instantiate this class */
913
914         if (c->flags & ACC_ABSTRACT) {
915                 exceptions_throw_instantiationerror(c);
916                 return NULL;
917         }
918
919         /* is the class linked */
920
921         if (!(c->state & CLASS_LINKED))
922                 if (!link_class(c))
923                         return NULL;
924
925         if (!(c->state & CLASS_INITIALIZED)) {
926 #if !defined(NDEBUG)
927                 if (initverbose)
928                         log_message_class("Initialize class (from builtin_new): ", c);
929 #endif
930
931                 if (!initialize_class(c))
932                         return NULL;
933         }
934
935         o = (java_handle_t*) heap_alloc(c->instancesize, c->flags & ACC_CLASS_HAS_POINTERS,
936                                                                         c->finalizer, true);
937
938         if (!o)
939                 return NULL;
940
941 #if !defined(ENABLE_GC_CACAO) && defined(ENABLE_HANDLES)
942         /* XXX this is only a dirty hack to make Boehm work with handles */
943
944         o = LLNI_WRAP((java_object_t *) o);
945 #endif
946
947         LLNI_vftbl_direct(o) = c->vftbl;
948
949 #if defined(ENABLE_THREADS)
950         LLNI_DIRECT(o)->lockword.init();
951 #endif
952
953         CYCLES_STATS_GET(cycles_end);
954         RT_TIMING_GET_TIME(time_end);
955
956         CYCLES_STATS_COUNT(builtin_new,cycles_end - cycles_start);
957         RT_TIMING_TIME_DIFF(time_start, time_end, RT_TIMING_NEW_OBJECT);
958
959         return o;
960 }
961
962 #if defined(ENABLE_ESCAPE_REASON)
963 java_handle_t *builtin_escape_reason_new(classinfo *c) {
964         print_escape_reasons();
965         return builtin_java_new(c);
966 }
967 #endif
968
969 #if defined(ENABLE_TLH)
970 java_handle_t *builtin_tlh_new(classinfo *c)
971 {
972         java_handle_t *o;
973 # if defined(ENABLE_RT_TIMING)
974         struct timespec time_start, time_end;
975 # endif
976 # if defined(ENABLE_CYCLES_STATS)
977         u8 cycles_start, cycles_end;
978 # endif
979
980         RT_TIMING_GET_TIME(time_start);
981         CYCLES_STATS_GET(cycles_start);
982
983         /* is the class loaded */
984
985         assert(c->state & CLASS_LOADED);
986
987         /* check if we can instantiate this class */
988
989         if (c->flags & ACC_ABSTRACT) {
990                 exceptions_throw_instantiationerror(c);
991                 return NULL;
992         }
993
994         /* is the class linked */
995
996         if (!(c->state & CLASS_LINKED))
997                 if (!link_class(c))
998                         return NULL;
999
1000         if (!(c->state & CLASS_INITIALIZED)) {
1001 # if !defined(NDEBUG)
1002                 if (initverbose)
1003                         log_message_class("Initialize class (from builtin_new): ", c);
1004 # endif
1005
1006                 if (!initialize_class(c))
1007                         return NULL;
1008         }
1009
1010         /*
1011         o = tlh_alloc(&(THREADOBJECT->tlh), c->instancesize);
1012         */
1013         o = NULL;
1014
1015         if (o == NULL) {
1016                 o = (java_handle_t*) heap_alloc(c->instancesize, c->flags & ACC_CLASS_HAS_POINTERS,
1017                                                                                 c->finalizer, true);
1018         }
1019
1020         if (!o)
1021                 return NULL;
1022
1023 # if !defined(ENABLE_GC_CACAO) && defined(ENABLE_HANDLES)
1024         /* XXX this is only a dirty hack to make Boehm work with handles */
1025
1026         o = LLNI_WRAP((java_object_t *) o);
1027 # endif
1028
1029         LLNI_vftbl_direct(o) = c->vftbl;
1030
1031 # if defined(ENABLE_THREADS)
1032         LLNI_DIRECT(o)->lockword.init();
1033 # endif
1034
1035         CYCLES_STATS_GET(cycles_end);
1036         RT_TIMING_GET_TIME(time_end);
1037
1038 /*
1039         CYCLES_STATS_COUNT(builtin_new,cycles_end - cycles_start);
1040         RT_TIMING_TIME_DIFF(time_start, time_end, RT_TIMING_NEW_OBJECT);
1041 */
1042
1043         return o;
1044 }
1045 #endif
1046
1047
1048 /* builtin_java_new ************************************************************
1049
1050    NOTE: This is a SLOW builtin and can be called from JIT code only.
1051
1052 *******************************************************************************/
1053
1054 java_handle_t *builtin_java_new(java_handle_t *clazz)
1055 {
1056         return builtin_new(LLNI_classinfo_unwrap(clazz));
1057 }
1058
1059
1060 /* builtin_fast_new ************************************************************
1061
1062    Creates a new instance of class c on the heap.
1063
1064    RETURN VALUE:
1065       pointer to the object, or NULL if no fast return
1066       is possible for any reason.
1067
1068    NOTE: This is a FAST builtin and can be called from JIT code only.
1069
1070 *******************************************************************************/
1071
1072 java_object_t *builtin_fast_new(classinfo *c)
1073 {
1074         java_object_t *o;
1075 #if defined(ENABLE_RT_TIMING)
1076         struct timespec time_start, time_end;
1077 #endif
1078 #if defined(ENABLE_CYCLES_STATS)
1079         u8 cycles_start, cycles_end;
1080 #endif
1081
1082         RT_TIMING_GET_TIME(time_start);
1083         CYCLES_STATS_GET(cycles_start);
1084
1085         /* is the class loaded */
1086
1087         assert(c->state & CLASS_LOADED);
1088
1089         /* check if we can instantiate this class */
1090
1091         if (c->flags & ACC_ABSTRACT)
1092                 return NULL;
1093
1094         /* is the class linked */
1095
1096         if (!(c->state & CLASS_LINKED))
1097                 return NULL;
1098
1099         if (!(c->state & CLASS_INITIALIZED))
1100                 return NULL;
1101
1102         o = (java_handle_t*) heap_alloc(c->instancesize, c->flags & ACC_CLASS_HAS_POINTERS,
1103                                                                         c->finalizer, false);
1104
1105         if (!o)
1106                 return NULL;
1107
1108         o->vftbl = c->vftbl;
1109
1110 #if defined(ENABLE_THREADS)
1111         LLNI_DIRECT(o)->lockword.init();
1112 #endif
1113
1114         CYCLES_STATS_GET(cycles_end);
1115         RT_TIMING_GET_TIME(time_end);
1116
1117         CYCLES_STATS_COUNT(builtin_new,cycles_end - cycles_start);
1118         RT_TIMING_TIME_DIFF(time_start, time_end, RT_TIMING_NEW_OBJECT);
1119
1120         return o;
1121 }
1122
1123
1124 /* builtin_newarray ************************************************************
1125
1126    Creates an array with the given vftbl on the heap. This function
1127    takes as class argument an array class.
1128
1129    RETURN VALUE:
1130       pointer to the array or NULL if no memory is available
1131
1132    NOTE: This builtin can be called from NATIVE code only.
1133
1134 *******************************************************************************/
1135
1136 java_handle_t *builtin_newarray(int32_t size, classinfo *arrayclass)
1137 {
1138         arraydescriptor *desc;
1139         s4               dataoffset;
1140         s4               componentsize;
1141         s4               actualsize;
1142         java_handle_t   *a;
1143 #if defined(ENABLE_RT_TIMING)
1144         struct timespec time_start, time_end;
1145 #endif
1146
1147         RT_TIMING_GET_TIME(time_start);
1148
1149         desc          = arrayclass->vftbl->arraydesc;
1150         dataoffset    = desc->dataoffset;
1151         componentsize = desc->componentsize;
1152
1153         if (size < 0) {
1154                 exceptions_throw_negativearraysizeexception();
1155                 return NULL;
1156         }
1157
1158         actualsize = dataoffset + size * componentsize;
1159
1160         /* check for overflow */
1161
1162         if (((u4) actualsize) < ((u4) size)) {
1163                 exceptions_throw_outofmemoryerror();
1164                 return NULL;
1165         }
1166
1167         a = (java_handle_t*) heap_alloc(actualsize, (desc->arraytype == ARRAYTYPE_OBJECT), NULL, true);
1168
1169         if (a == NULL)
1170                 return NULL;
1171
1172 #if !defined(ENABLE_GC_CACAO) && defined(ENABLE_HANDLES)
1173         /* XXX this is only a dirty hack to make Boehm work with handles */
1174
1175         a = LLNI_WRAP((java_object_t *) a);
1176 #endif
1177
1178         LLNI_vftbl_direct(a) = arrayclass->vftbl;
1179
1180 #if defined(ENABLE_THREADS)
1181         LLNI_DIRECT(a)->lockword.init();
1182 #endif
1183
1184         LLNI_array_size(a) = size;
1185
1186         RT_TIMING_GET_TIME(time_end);
1187         RT_TIMING_TIME_DIFF(time_start, time_end, RT_TIMING_NEW_ARRAY);
1188
1189         return a;
1190 }
1191
1192
1193 /* builtin_java_newarray *******************************************************
1194
1195    NOTE: This is a SLOW builtin and can be called from JIT code only.
1196
1197 *******************************************************************************/
1198
1199 java_handle_t *builtin_java_newarray(int32_t size, java_handle_t *arrayclazz)
1200 {
1201         return builtin_newarray(size, LLNI_classinfo_unwrap(arrayclazz));
1202 }
1203
1204
1205 /* builtin_anewarray ***********************************************************
1206
1207    Creates an array of references to the given class type on the heap.
1208
1209    RETURN VALUE:
1210       pointer to the array or NULL if no memory is
1211       available
1212
1213    NOTE: This builtin can be called from NATIVE code only.
1214
1215 *******************************************************************************/
1216
1217 java_handle_objectarray_t *builtin_anewarray(int32_t size, classinfo *componentclass)
1218 {
1219         classinfo *arrayclass;
1220         
1221         /* is class loaded */
1222
1223         assert(componentclass->state & CLASS_LOADED);
1224
1225         /* is class linked */
1226
1227         if (!(componentclass->state & CLASS_LINKED))
1228                 if (!link_class(componentclass))
1229                         return NULL;
1230
1231         arrayclass = class_array_of(componentclass, true);
1232
1233         if (!arrayclass)
1234                 return NULL;
1235
1236         return (java_handle_objectarray_t *) builtin_newarray(size, arrayclass);
1237 }
1238
1239
1240 /* builtin_newarray_type ****************************************************
1241
1242    Creates an array of [type]s on the heap.
1243         
1244    RETURN VALUE:
1245       pointer to the array or NULL if no memory is available
1246
1247    NOTE: This is a SLOW builtin and can be called from JIT & NATIVE code.
1248
1249 *******************************************************************************/
1250
1251 #define BUILTIN_NEWARRAY_TYPE(type, arraytype)                             \
1252 java_handle_##type##array_t *builtin_newarray_##type(int32_t size)              \
1253 {                                                                          \
1254         return (java_handle_##type##array_t *)                                 \
1255                 builtin_newarray(size, primitivetype_table[arraytype].arrayclass); \
1256 }
1257
1258 BUILTIN_NEWARRAY_TYPE(boolean, ARRAYTYPE_BOOLEAN)
1259 BUILTIN_NEWARRAY_TYPE(byte,    ARRAYTYPE_BYTE)
1260 BUILTIN_NEWARRAY_TYPE(char,    ARRAYTYPE_CHAR)
1261 BUILTIN_NEWARRAY_TYPE(short,   ARRAYTYPE_SHORT)
1262 BUILTIN_NEWARRAY_TYPE(int,     ARRAYTYPE_INT)
1263 BUILTIN_NEWARRAY_TYPE(long,    ARRAYTYPE_LONG)
1264 BUILTIN_NEWARRAY_TYPE(float,   ARRAYTYPE_FLOAT)
1265 BUILTIN_NEWARRAY_TYPE(double,  ARRAYTYPE_DOUBLE)
1266
1267
1268 /* builtin_multianewarray_intern ***********************************************
1269
1270    Creates a multi-dimensional array on the heap. The dimensions are
1271    passed in an array of longs.
1272
1273    ARGUMENTS:
1274       n.............number of dimensions to create
1275       arrayclass....the array class
1276       dims..........array containing the size of each dimension to create
1277
1278    RETURN VALUE:
1279       pointer to the array or NULL if no memory is available
1280
1281 ******************************************************************************/
1282
1283 static java_handle_t *builtin_multianewarray_intern(int n,
1284                                                                                                         classinfo *arrayclass,
1285                                                                                                         long *dims)
1286 {
1287         s4             size;
1288         java_handle_t *a;
1289         classinfo     *componentclass;
1290         s4             i;
1291
1292         /* create this dimension */
1293
1294         size = (s4) dims[0];
1295         a = builtin_newarray(size, arrayclass);
1296
1297         if (!a)
1298                 return NULL;
1299
1300         /* if this is the last dimension return */
1301
1302         if (!--n)
1303                 return a;
1304
1305         /* get the class of the components to create */
1306
1307         componentclass = arrayclass->vftbl->arraydesc->componentvftbl->clazz;
1308
1309         /* The verifier guarantees that the dimension count is in the range. */
1310
1311         /* create the component arrays */
1312
1313         for (i = 0; i < size; i++) {
1314                 java_handle_t *ea =
1315 #if defined(__MIPS__) && (SIZEOF_VOID_P == 4)
1316                         /* we save an s4 to a s8 slot, 8-byte aligned */
1317
1318                         builtin_multianewarray_intern(n, componentclass, dims + 2);
1319 #else
1320                         builtin_multianewarray_intern(n, componentclass, dims + 1);
1321 #endif
1322
1323                 if (!ea)
1324                         return NULL;
1325
1326                 array_objectarray_element_set((java_handle_objectarray_t *) a, i, ea);
1327         }
1328
1329         return a;
1330 }
1331
1332
1333 /* builtin_multianewarray ******************************************************
1334
1335    Wrapper for builtin_multianewarray_intern which checks all
1336    dimensions before we start allocating.
1337
1338    NOTE: This is a SLOW builtin and can be called from JIT code only.
1339
1340 ******************************************************************************/
1341
1342 java_handle_objectarray_t *builtin_multianewarray(int n,
1343                                                                                                   java_handle_t *arrayclazz,
1344                                                                                                   long *dims)
1345 {
1346         classinfo *c;
1347         s4         i;
1348         s4         size;
1349
1350         /* check all dimensions before doing anything */
1351
1352         for (i = 0; i < n; i++) {
1353 #if defined(__MIPS__) && (SIZEOF_VOID_P == 4)
1354                 /* we save an s4 to a s8 slot, 8-byte aligned */
1355                 size = (s4) dims[i * 2];
1356 #else
1357                 size = (s4) dims[i];
1358 #endif
1359
1360                 if (size < 0) {
1361                         exceptions_throw_negativearraysizeexception();
1362                         return NULL;
1363                 }
1364         }
1365
1366         c = LLNI_classinfo_unwrap(arrayclazz);
1367
1368         /* now call the real function */
1369
1370         return (java_handle_objectarray_t *)
1371                 builtin_multianewarray_intern(n, c, dims);
1372 }
1373
1374
1375 /* builtin_verbosecall_enter ***************************************************
1376
1377    Print method call with arguments for -verbose:call.
1378
1379    XXX: Remove mew once all archs use the new tracer!
1380
1381 *******************************************************************************/
1382
1383 #if !defined(NDEBUG)
1384 #ifdef TRACE_ARGS_NUM
1385 void builtin_verbosecall_enter(s8 a0, s8 a1,
1386 # if TRACE_ARGS_NUM >= 4
1387                                                            s8 a2, s8 a3,
1388 # endif
1389 # if TRACE_ARGS_NUM >= 6
1390                                                            s8 a4, s8 a5,
1391 # endif
1392 # if TRACE_ARGS_NUM == 8
1393                                                            s8 a6, s8 a7,
1394 # endif
1395                                                            methodinfo *m)
1396 {
1397         log_text("builtin_verbosecall_enter: Do not call me anymore!");
1398 }
1399 #endif
1400 #endif /* !defined(NDEBUG) */
1401
1402
1403 /* builtin_verbosecall_exit ****************************************************
1404
1405    Print method exit for -verbose:call.
1406
1407    XXX: Remove mew once all archs use the new tracer!
1408
1409 *******************************************************************************/
1410
1411 #if !defined(NDEBUG)
1412 void builtin_verbosecall_exit(s8 l, double d, float f, methodinfo *m)
1413 {
1414         log_text("builtin_verbosecall_exit: Do not call me anymore!");
1415 }
1416 #endif /* !defined(NDEBUG) */
1417
1418
1419 /*============================================================================*/
1420 /* MISCELLANEOUS MATHEMATICAL HELPER FUNCTIONS                                */
1421 /*============================================================================*/
1422
1423 /*********** Functions for integer divisions *****************************
1424  
1425         On some systems (eg. DEC ALPHA), integer division is not supported by the
1426         CPU. These helper functions implement the missing functionality.
1427
1428 ******************************************************************************/
1429
1430 #if !SUPPORT_DIVISION || defined(DISABLE_GC)
1431 s4 builtin_idiv(s4 a, s4 b)
1432 {
1433         s4 c;
1434
1435         c = a / b;
1436
1437         return c;
1438 }
1439
1440 s4 builtin_irem(s4 a, s4 b)
1441 {
1442         s4 c;
1443
1444         c = a % b;
1445
1446         return c;
1447 }
1448 #endif /* !SUPPORT_DIVISION || defined(DISABLE_GC) */
1449
1450
1451 /* functions for long arithmetics **********************************************
1452
1453    On systems where 64 bit Integers are not supported by the CPU,
1454    these functions are needed.
1455
1456 ******************************************************************************/
1457
1458 #if !(SUPPORT_LONG && SUPPORT_LONG_ADD)
1459 s8 builtin_ladd(s8 a, s8 b)
1460 {
1461         s8 c;
1462
1463         c = a + b; 
1464
1465         return c;
1466 }
1467
1468 s8 builtin_lsub(s8 a, s8 b)
1469 {
1470         s8 c;
1471
1472         c = a - b; 
1473
1474         return c;
1475 }
1476
1477 s8 builtin_lneg(s8 a)
1478 {
1479         s8 c;
1480
1481         c = -a;
1482
1483         return c;
1484 }
1485 #endif /* !(SUPPORT_LONG && SUPPORT_LONG_ADD) */
1486
1487
1488 #if !(SUPPORT_LONG && SUPPORT_LONG_MUL)
1489 s8 builtin_lmul(s8 a, s8 b)
1490 {
1491         s8 c;
1492
1493         c = a * b; 
1494
1495         return c;
1496 }
1497 #endif /* !(SUPPORT_LONG && SUPPORT_LONG_MUL) */
1498
1499
1500 #if !(SUPPORT_DIVISION && SUPPORT_LONG && SUPPORT_LONG_DIV) || defined (DISABLE_GC)
1501 s8 builtin_ldiv(s8 a, s8 b)
1502 {
1503         s8 c;
1504
1505         c = a / b; 
1506
1507         return c;
1508 }
1509
1510 s8 builtin_lrem(s8 a, s8 b)
1511 {
1512         s8 c;
1513
1514         c = a % b; 
1515
1516         return c;
1517 }
1518 #endif /* !(SUPPORT_DIVISION && SUPPORT_LONG && SUPPORT_LONG_DIV) */
1519
1520
1521 #if !(SUPPORT_LONG && SUPPORT_LONG_SHIFT)
1522 s8 builtin_lshl(s8 a, s4 b)
1523 {
1524         s8 c;
1525
1526         c = a << (b & 63);
1527
1528         return c;
1529 }
1530
1531 s8 builtin_lshr(s8 a, s4 b)
1532 {
1533         s8 c;
1534
1535         c = a >> (b & 63);
1536
1537         return c;
1538 }
1539
1540 s8 builtin_lushr(s8 a, s4 b)
1541 {
1542         s8 c;
1543
1544         c = ((u8) a) >> (b & 63);
1545
1546         return c;
1547 }
1548 #endif /* !(SUPPORT_LONG && SUPPORT_LONG_SHIFT) */
1549
1550
1551 #if !(SUPPORT_LONG && SUPPORT_LONG_LOGICAL)
1552 s8 builtin_land(s8 a, s8 b)
1553 {
1554         s8 c;
1555
1556         c = a & b; 
1557
1558         return c;
1559 }
1560
1561 s8 builtin_lor(s8 a, s8 b)
1562 {
1563         s8 c;
1564
1565         c = a | b; 
1566
1567         return c;
1568 }
1569
1570 s8 builtin_lxor(s8 a, s8 b) 
1571 {
1572         s8 c;
1573
1574         c = a ^ b; 
1575
1576         return c;
1577 }
1578 #endif /* !(SUPPORT_LONG && SUPPORT_LONG_LOGICAL) */
1579
1580
1581 #if !(SUPPORT_LONG && SUPPORT_LONG_CMP)
1582 s4 builtin_lcmp(s8 a, s8 b)
1583
1584         if (a < b)
1585                 return -1;
1586
1587         if (a > b)
1588                 return 1;
1589
1590         return 0;
1591 }
1592 #endif /* !(SUPPORT_LONG && SUPPORT_LONG_CMP) */
1593
1594
1595 /* functions for unsupported floating instructions ****************************/
1596
1597 /* used to convert FLT_xxx defines into float values */
1598
1599 static inline float intBitsToFloat(s4 i)
1600 {
1601         imm_union imb;
1602
1603         imb.i = i;
1604         return imb.f;
1605 }
1606
1607
1608 /* used to convert DBL_xxx defines into double values */
1609
1610 static inline float longBitsToDouble(s8 l)
1611 {
1612         imm_union imb;
1613
1614         imb.l = l;
1615         return imb.d;
1616 }
1617
1618
1619 #if !SUPPORT_FLOAT
1620 float builtin_fadd(float a, float b)
1621 {
1622         if (isnanf(a)) return intBitsToFloat(FLT_NAN);
1623         if (isnanf(b)) return intBitsToFloat(FLT_NAN);
1624         if (finitef(a)) {
1625                 if (finitef(b))
1626                         return a + b;
1627                 else
1628                         return b;
1629         }
1630         else {
1631                 if (finitef(b))
1632                         return a;
1633                 else {
1634                         if (copysignf(1.0, a) == copysignf(1.0, b))
1635                                 return a;
1636                         else
1637                                 return intBitsToFloat(FLT_NAN);
1638                 }
1639         }
1640 }
1641
1642
1643 float builtin_fsub(float a, float b)
1644 {
1645         return builtin_fadd(a, builtin_fneg(b));
1646 }
1647
1648
1649 float builtin_fmul(float a, float b)
1650 {
1651         if (isnanf(a)) return intBitsToFloat(FLT_NAN);
1652         if (isnanf(b)) return intBitsToFloat(FLT_NAN);
1653         if (finitef(a)) {
1654                 if (finitef(b)) return a * b;
1655                 else {
1656                         if (a == 0) return intBitsToFloat(FLT_NAN);
1657                         else return copysignf(b, copysignf(1.0, b)*a);
1658                 }
1659         }
1660         else {
1661                 if (finitef(b)) {
1662                         if (b == 0) return intBitsToFloat(FLT_NAN);
1663                         else return copysignf(a, copysignf(1.0, a)*b);
1664                 }
1665                 else {
1666                         return copysignf(a, copysignf(1.0, a)*copysignf(1.0, b));
1667                 }
1668         }
1669 }
1670
1671
1672 /* builtin_ddiv ****************************************************************
1673
1674    Implementation as described in VM Spec.
1675
1676 *******************************************************************************/
1677
1678 float builtin_fdiv(float a, float b)
1679 {
1680         if (finitef(a)) {
1681                 if (finitef(b)) {
1682                         /* If neither value1' nor value2' is NaN, the sign of the result */
1683                         /* is positive if both values have the same sign, negative if the */
1684                         /* values have different signs. */
1685
1686                         return a / b;
1687
1688                 } else {
1689                         if (isnanf(b)) {
1690                                 /* If either value1' or value2' is NaN, the result is NaN. */
1691
1692                                 return intBitsToFloat(FLT_NAN);
1693
1694                         } else {
1695                                 /* Division of a finite value by an infinity results in a */
1696                                 /* signed zero, with the sign-producing rule just given. */
1697
1698                                 /* is sign equal? */
1699
1700                                 if (copysignf(1.0, a) == copysignf(1.0, b))
1701                                         return 0.0;
1702                                 else
1703                                         return -0.0;
1704                         }
1705                 }
1706
1707         } else {
1708                 if (isnanf(a)) {
1709                         /* If either value1' or value2' is NaN, the result is NaN. */
1710
1711                         return intBitsToFloat(FLT_NAN);
1712
1713                 } else if (finitef(b)) {
1714                         /* Division of an infinity by a finite value results in a signed */
1715                         /* infinity, with the sign-producing rule just given. */
1716
1717                         /* is sign equal? */
1718
1719                         if (copysignf(1.0, a) == copysignf(1.0, b))
1720                                 return intBitsToFloat(FLT_POSINF);
1721                         else
1722                                 return intBitsToFloat(FLT_NEGINF);
1723
1724                 } else {
1725                         /* Division of an infinity by an infinity results in NaN. */
1726
1727                         return intBitsToFloat(FLT_NAN);
1728                 }
1729         }
1730 }
1731
1732
1733 float builtin_fneg(float a)
1734 {
1735         if (isnanf(a)) return a;
1736         else {
1737                 if (finitef(a)) return -a;
1738                 else return copysignf(a, -copysignf(1.0, a));
1739         }
1740 }
1741 #endif /* !SUPPORT_FLOAT */
1742
1743
1744 #if !SUPPORT_FLOAT || !SUPPORT_FLOAT_CMP || defined(ENABLE_INTRP)
1745 s4 builtin_fcmpl(float a, float b)
1746 {
1747         if (isnanf(a))
1748                 return -1;
1749
1750         if (isnanf(b))
1751                 return -1;
1752
1753         if (!finitef(a) || !finitef(b)) {
1754                 a = finitef(a) ? 0 : copysignf(1.0,     a);
1755                 b = finitef(b) ? 0 : copysignf(1.0, b);
1756         }
1757
1758         if (a > b)
1759                 return 1;
1760
1761         if (a == b)
1762                 return 0;
1763
1764         return -1;
1765 }
1766
1767
1768 s4 builtin_fcmpg(float a, float b)
1769 {
1770         if (isnanf(a)) return 1;
1771         if (isnanf(b)) return 1;
1772         if (!finitef(a) || !finitef(b)) {
1773                 a = finitef(a) ? 0 : copysignf(1.0, a);
1774                 b = finitef(b) ? 0 : copysignf(1.0, b);
1775         }
1776         if (a > b) return 1;
1777         if (a == b) return 0;
1778         return -1;
1779 }
1780 #endif /* !SUPPORT_FLOAT || !SUPPORT_FLOAT_CMP || defined(ENABLE_INTRP) */
1781
1782
1783 float builtin_frem(float a, float b)
1784 {
1785         return fmodf(a, b);
1786 }
1787
1788
1789 /* functions for unsupported double instructions ******************************/
1790
1791 #if !SUPPORT_DOUBLE
1792 double builtin_dadd(double a, double b)
1793 {
1794         if (isnan(a)) return longBitsToDouble(DBL_NAN);
1795         if (isnan(b)) return longBitsToDouble(DBL_NAN);
1796         if (finite(a)) {
1797                 if (finite(b)) return a + b;
1798                 else return b;
1799         }
1800         else {
1801                 if (finite(b)) return a;
1802                 else {
1803                         if (copysign(1.0, a)==copysign(1.0, b)) return a;
1804                         else return longBitsToDouble(DBL_NAN);
1805                 }
1806         }
1807 }
1808
1809
1810 double builtin_dsub(double a, double b)
1811 {
1812         return builtin_dadd(a, builtin_dneg(b));
1813 }
1814
1815
1816 double builtin_dmul(double a, double b)
1817 {
1818         if (isnan(a)) return longBitsToDouble(DBL_NAN);
1819         if (isnan(b)) return longBitsToDouble(DBL_NAN);
1820         if (finite(a)) {
1821                 if (finite(b)) return a * b;
1822                 else {
1823                         if (a == 0) return longBitsToDouble(DBL_NAN);
1824                         else return copysign(b, copysign(1.0, b) * a);
1825                 }
1826         }
1827         else {
1828                 if (finite(b)) {
1829                         if (b == 0) return longBitsToDouble(DBL_NAN);
1830                         else return copysign(a, copysign(1.0, a) * b);
1831                 }
1832                 else {
1833                         return copysign(a, copysign(1.0, a) * copysign(1.0, b));
1834                 }
1835         }
1836 }
1837
1838
1839 /* builtin_ddiv ****************************************************************
1840
1841    Implementation as described in VM Spec.
1842
1843 *******************************************************************************/
1844
1845 double builtin_ddiv(double a, double b)
1846 {
1847         if (finite(a)) {
1848                 if (finite(b)) {
1849                         /* If neither value1' nor value2' is NaN, the sign of the result */
1850                         /* is positive if both values have the same sign, negative if the */
1851                         /* values have different signs. */
1852
1853                         return a / b;
1854
1855                 } else {
1856                         if (isnan(b)) {
1857                                 /* If either value1' or value2' is NaN, the result is NaN. */
1858
1859                                 return longBitsToDouble(DBL_NAN);
1860
1861                         } else {
1862                                 /* Division of a finite value by an infinity results in a */
1863                                 /* signed zero, with the sign-producing rule just given. */
1864
1865                                 /* is sign equal? */
1866
1867                                 if (copysign(1.0, a) == copysign(1.0, b))
1868                                         return 0.0;
1869                                 else
1870                                         return -0.0;
1871                         }
1872                 }
1873
1874         } else {
1875                 if (isnan(a)) {
1876                         /* If either value1' or value2' is NaN, the result is NaN. */
1877
1878                         return longBitsToDouble(DBL_NAN);
1879
1880                 } else if (finite(b)) {
1881                         /* Division of an infinity by a finite value results in a signed */
1882                         /* infinity, with the sign-producing rule just given. */
1883
1884                         /* is sign equal? */
1885
1886                         if (copysign(1.0, a) == copysign(1.0, b))
1887                                 return longBitsToDouble(DBL_POSINF);
1888                         else
1889                                 return longBitsToDouble(DBL_NEGINF);
1890
1891                 } else {
1892                         /* Division of an infinity by an infinity results in NaN. */
1893
1894                         return longBitsToDouble(DBL_NAN);
1895                 }
1896         }
1897 }
1898
1899
1900 /* builtin_dneg ****************************************************************
1901
1902    Implemented as described in VM Spec.
1903
1904 *******************************************************************************/
1905
1906 double builtin_dneg(double a)
1907 {
1908         if (isnan(a)) {
1909                 /* If the operand is NaN, the result is NaN (recall that NaN has no */
1910                 /* sign). */
1911
1912                 return a;
1913
1914         } else {
1915                 if (finite(a)) {
1916                         /* If the operand is a zero, the result is the zero of opposite */
1917                         /* sign. */
1918
1919                         return -a;
1920
1921                 } else {
1922                         /* If the operand is an infinity, the result is the infinity of */
1923                         /* opposite sign. */
1924
1925                         return copysign(a, -copysign(1.0, a));
1926                 }
1927         }
1928 }
1929 #endif /* !SUPPORT_DOUBLE */
1930
1931
1932 #if !SUPPORT_DOUBLE || !SUPPORT_DOUBLE_CMP || defined(ENABLE_INTRP)
1933 s4 builtin_dcmpl(double a, double b)
1934 {
1935         if (isnan(a))
1936                 return -1;
1937
1938         if (isnan(b))
1939                 return -1;
1940
1941         if (!finite(a) || !finite(b)) {
1942                 a = finite(a) ? 0 : copysign(1.0, a);
1943                 b = finite(b) ? 0 : copysign(1.0, b);
1944         }
1945
1946         if (a > b)
1947                 return 1;
1948
1949         if (a == b)
1950                 return 0;
1951
1952         return -1;
1953 }
1954
1955
1956 s4 builtin_dcmpg(double a, double b)
1957 {
1958         if (isnan(a))
1959                 return 1;
1960
1961         if (isnan(b))
1962                 return 1;
1963
1964         if (!finite(a) || !finite(b)) {
1965                 a = finite(a) ? 0 : copysign(1.0, a);
1966                 b = finite(b) ? 0 : copysign(1.0, b);
1967         }
1968
1969         if (a > b)
1970                 return 1;
1971
1972         if (a == b)
1973                 return 0;
1974
1975         return -1;
1976 }
1977 #endif /* !SUPPORT_DOUBLE || !SUPPORT_DOUBLE_CMP || defined(ENABLE_INTRP) */
1978
1979
1980 double builtin_drem(double a, double b)
1981 {
1982         return fmod(a, b);
1983 }
1984
1985
1986 /* conversion operations ******************************************************/
1987
1988 #if !(SUPPORT_FLOAT && SUPPORT_I2F)
1989 float builtin_i2f(s4 a)
1990 {
1991         float f = (float) a;
1992         return f;
1993 }
1994 #endif /* !(SUPPORT_FLOAT && SUPPORT_I2F) */
1995
1996
1997 #if !(SUPPORT_DOUBLE && SUPPORT_I2D)
1998 double builtin_i2d(s4 a)
1999 {
2000         double d = (double) a;
2001         return d;
2002 }
2003 #endif /* !(SUPPORT_DOUBLE && SUPPORT_I2D) */
2004
2005
2006 #if !(SUPPORT_LONG && SUPPORT_FLOAT && SUPPORT_L2F)
2007 float builtin_l2f(s8 a)
2008 {
2009         float f = (float) a;
2010         return f;
2011 }
2012 #endif /* !(SUPPORT_LONG && SUPPORT_FLOAT && SUPPORT_L2F) */
2013
2014
2015 #if !(SUPPORT_LONG && SUPPORT_DOUBLE && SUPPORT_L2D)
2016 double builtin_l2d(s8 a)
2017 {
2018         double d = (double) a;
2019         return d;
2020 }
2021 #endif /* !(SUPPORT_LONG && SUPPORT_DOUBLE && SUPPORT_L2D) */
2022
2023
2024 #if !(SUPPORT_FLOAT && SUPPORT_F2I) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
2025 s4 builtin_f2i(float a) 
2026 {
2027         s4 i;
2028
2029         i = builtin_d2i((double) a);
2030
2031         return i;
2032
2033         /*      float f;
2034         
2035                 if (isnanf(a))
2036                 return 0;
2037                 if (finitef(a)) {
2038                 if (a > 2147483647)
2039                 return 2147483647;
2040                 if (a < (-2147483648))
2041                 return (-2147483648);
2042                 return (s4) a;
2043                 }
2044                 f = copysignf((float) 1.0, a);
2045                 if (f > 0)
2046                 return 2147483647;
2047                 return (-2147483648); */
2048 }
2049 #endif /* !(SUPPORT_FLOAT && SUPPORT_F2I) || defined(ENABLE_INTRP) || defined(DISABLE_GC) */
2050
2051
2052 #if !(SUPPORT_FLOAT && SUPPORT_LONG && SUPPORT_F2L) || defined(DISABLE_GC)
2053 s8 builtin_f2l(float a)
2054 {
2055         s8 l;
2056
2057         l = builtin_d2l((double) a);
2058
2059         return l;
2060
2061         /*      float f;
2062         
2063                 if (finitef(a)) {
2064                 if (a > 9223372036854775807L)
2065                 return 9223372036854775807L;
2066                 if (a < (-9223372036854775808L))
2067                 return (-9223372036854775808L);
2068                 return (s8) a;
2069                 }
2070                 if (isnanf(a))
2071                 return 0;
2072                 f = copysignf((float) 1.0, a);
2073                 if (f > 0)
2074                 return 9223372036854775807L;
2075                 return (-9223372036854775808L); */
2076 }
2077 #endif /* !(SUPPORT_FLOAT && SUPPORT_LONG && SUPPORT_F2L) */
2078
2079
2080 #if !(SUPPORT_DOUBLE && SUPPORT_D2I) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
2081 s4 builtin_d2i(double a) 
2082
2083         double d;
2084         
2085         if (finite(a)) {
2086                 if (a >= 2147483647)
2087                         return 2147483647;
2088                 if (a <= (-2147483647-1))
2089                         return (-2147483647-1);
2090                 return (s4) a;
2091         }
2092         if (isnan(a))
2093                 return 0;
2094         d = copysign(1.0, a);
2095         if (d > 0)
2096                 return 2147483647;
2097         return (-2147483647-1);
2098 }
2099 #endif /* !(SUPPORT_DOUBLE && SUPPORT_D2I) || defined(ENABLE_INTRP) || defined(DISABLE_GC) */
2100
2101
2102 #if !(SUPPORT_DOUBLE && SUPPORT_LONG && SUPPORT_D2L) || defined(DISABLE_GC)
2103 s8 builtin_d2l(double a)
2104 {
2105         double d;
2106         
2107         if (finite(a)) {
2108                 if (a >= 9223372036854775807LL)
2109                         return 9223372036854775807LL;
2110                 if (a <= (-9223372036854775807LL-1))
2111                         return (-9223372036854775807LL-1);
2112                 return (s8) a;
2113         }
2114         if (isnan(a))
2115                 return 0;
2116         d = copysign(1.0, a);
2117         if (d > 0)
2118                 return 9223372036854775807LL;
2119         return (-9223372036854775807LL-1);
2120 }
2121 #endif /* !(SUPPORT_DOUBLE && SUPPORT_LONG && SUPPORT_D2L) */
2122
2123
2124 #if !(SUPPORT_FLOAT && SUPPORT_DOUBLE)
2125 double builtin_f2d(float a)
2126 {
2127         if (finitef(a)) return (double) a;
2128         else {
2129                 if (isnanf(a))
2130                         return longBitsToDouble(DBL_NAN);
2131                 else
2132                         return copysign(longBitsToDouble(DBL_POSINF), (double) copysignf(1.0, a) );
2133         }
2134 }
2135
2136 float builtin_d2f(double a)
2137 {
2138         if (finite(a))
2139                 return (float) a;
2140         else {
2141                 if (isnan(a))
2142                         return intBitsToFloat(FLT_NAN);
2143                 else
2144                         return copysignf(intBitsToFloat(FLT_POSINF), (float) copysign(1.0, a));
2145         }
2146 }
2147 #endif /* !(SUPPORT_FLOAT && SUPPORT_DOUBLE) */
2148
2149
2150 /*============================================================================*/
2151 /* AUTOMATICALLY REPLACED FUNCTIONS                                           */
2152 /*============================================================================*/
2153
2154 /* builtin_arraycopy ***********************************************************
2155
2156    Builtin for java.lang.System.arraycopy.
2157
2158    NOTE: This is a SLOW builtin and can be called from JIT & NATIVE code.
2159
2160 *******************************************************************************/
2161
2162 void builtin_arraycopy(java_handle_t *src, s4 srcStart,
2163                                            java_handle_t *dest, s4 destStart, s4 len)
2164 {
2165         arraydescriptor *sdesc;
2166         arraydescriptor *ddesc;
2167         s4               i;
2168
2169         if ((src == NULL) || (dest == NULL)) {
2170                 exceptions_throw_nullpointerexception();
2171                 return;
2172         }
2173
2174         sdesc = LLNI_vftbl_direct(src)->arraydesc;
2175         ddesc = LLNI_vftbl_direct(dest)->arraydesc;
2176
2177         if (!sdesc || !ddesc || (sdesc->arraytype != ddesc->arraytype)) {
2178                 exceptions_throw_arraystoreexception();
2179                 return;
2180         }
2181
2182         // Check if offsets and length are positive.
2183         if ((srcStart < 0) || (destStart < 0) || (len < 0)) {
2184                 exceptions_throw_arrayindexoutofboundsexception();
2185                 return;
2186         }
2187
2188         // Check if ranges are valid.
2189         if ((((uint32_t) srcStart  + (uint32_t) len) > (uint32_t) LLNI_array_size(src)) ||
2190                 (((uint32_t) destStart + (uint32_t) len) > (uint32_t) LLNI_array_size(dest))) {
2191                 exceptions_throw_arrayindexoutofboundsexception();
2192                 return;
2193         }
2194
2195         // Special case.
2196         if (len == 0) {
2197                 return;
2198         }
2199
2200         if (sdesc->componentvftbl == ddesc->componentvftbl) {
2201                 /* We copy primitive values or references of exactly the same type */
2202
2203                 s4 dataoffset = sdesc->dataoffset;
2204                 s4 componentsize = sdesc->componentsize;
2205
2206                 LLNI_CRITICAL_START;
2207
2208                 MMOVE(((u1 *) LLNI_DIRECT(dest)) + dataoffset + componentsize * destStart,
2209                           ((u1 *) LLNI_DIRECT(src))  + dataoffset + componentsize * srcStart,
2210                           u1, (size_t) len * componentsize);
2211
2212                 LLNI_CRITICAL_END;
2213         }
2214         else {
2215                 /* We copy references of different type */
2216
2217                 java_handle_objectarray_t *oas = (java_handle_objectarray_t *) src;
2218                 java_handle_objectarray_t *oad = (java_handle_objectarray_t *) dest;
2219  
2220                 if (destStart <= srcStart) {
2221                         for (i = 0; i < len; i++) {
2222                                 java_handle_t *o;
2223
2224                                 o = array_objectarray_element_get(oas, srcStart + i);
2225
2226                                 if (!builtin_canstore(oad, o))
2227                                         return;
2228
2229                                 array_objectarray_element_set(oad, destStart + i, o);
2230                         }
2231                 }
2232                 else {
2233                         /* XXX this does not completely obey the specification!
2234                            If an exception is thrown only the elements above the
2235                            current index have been copied. The specification
2236                            requires that only the elements *below* the current
2237                            index have been copied before the throw. */
2238
2239                         for (i = len - 1; i >= 0; i--) {
2240                                 java_handle_t *o;
2241
2242                                 o = array_objectarray_element_get(oas, srcStart + i);
2243
2244                                 if (!builtin_canstore(oad, o))
2245                                         return;
2246
2247                                 array_objectarray_element_set(oad, destStart + i, o);
2248                         }
2249                 }
2250         }
2251 }
2252
2253
2254 /* builtin_nanotime ************************************************************
2255
2256    Return the current time in nanoseconds.
2257
2258 *******************************************************************************/
2259
2260 s8 builtin_nanotime(void)
2261 {
2262         struct timeval tv;
2263         s8             usecs;
2264
2265         if (gettimeofday(&tv, NULL) == -1)
2266                 vm_abort("gettimeofday failed: %s", strerror(errno));
2267
2268         usecs = (s8) tv.tv_sec * (1000 * 1000) + (s8) tv.tv_usec;
2269
2270         return usecs * 1000;
2271 }
2272
2273
2274 /* builtin_currenttimemillis ***************************************************
2275
2276    Return the current time in milliseconds.
2277
2278 *******************************************************************************/
2279
2280 s8 builtin_currenttimemillis(void)
2281 {
2282         s8 msecs;
2283
2284         msecs = builtin_nanotime() / 1000 / 1000;
2285
2286         return msecs;
2287 }
2288
2289
2290 /* builtin_clone ***************************************************************
2291
2292    Function for cloning objects or arrays.
2293
2294    NOTE: This is a SLOW builtin and can be called from JIT & NATIVE code.
2295
2296 *******************************************************************************/
2297
2298 java_handle_t *builtin_clone(void *env, java_handle_t *o)
2299 {
2300         arraydescriptor *ad;
2301         u4               size;
2302         classinfo       *c;
2303         java_handle_t   *co;                /* cloned object header               */
2304
2305         /* get the array descriptor */
2306
2307         ad = LLNI_vftbl_direct(o)->arraydesc;
2308
2309         /* we are cloning an array */
2310
2311         if (ad != NULL) {
2312                 size = ad->dataoffset + ad->componentsize * LLNI_array_size(o);
2313         
2314                 co = (java_handle_t*) heap_alloc(size, (ad->arraytype == ARRAYTYPE_OBJECT), NULL, true);
2315
2316                 if (co == NULL)
2317                         return NULL;
2318
2319 #if !defined(ENABLE_GC_CACAO) && defined(ENABLE_HANDLES)
2320                 /* XXX this is only a dirty hack to make Boehm work with handles */
2321
2322                 co = LLNI_WRAP((java_object_t *) co);
2323 #endif
2324
2325                 LLNI_CRITICAL_START;
2326
2327                 MCOPY(LLNI_DIRECT(co), LLNI_DIRECT(o), u1, size);
2328
2329 #if defined(ENABLE_GC_CACAO)
2330                 heap_init_objectheader(LLNI_DIRECT(co), size);
2331 #endif
2332
2333 #if defined(ENABLE_THREADS)
2334                 LLNI_DIRECT(co)->lockword.init();
2335 #endif
2336
2337                 LLNI_CRITICAL_END;
2338
2339                 return co;
2340         }
2341     
2342     /* we are cloning a non-array */
2343
2344     if (!builtin_instanceof(o, class_java_lang_Cloneable)) {
2345         exceptions_throw_clonenotsupportedexception();
2346         return NULL;
2347     }
2348
2349         /* get the class of the object */
2350
2351         LLNI_class_get(o, c);
2352
2353         /* create new object */
2354
2355     co = builtin_new(c);
2356
2357     if (co == NULL)
2358         return NULL;
2359
2360         LLNI_CRITICAL_START;
2361
2362         MCOPY(LLNI_DIRECT(co), LLNI_DIRECT(o), u1, c->instancesize);
2363
2364 #if defined(ENABLE_GC_CACAO)
2365         heap_init_objectheader(LLNI_DIRECT(co), c->instancesize);
2366 #endif
2367
2368 #if defined(ENABLE_THREADS)
2369         LLNI_DIRECT(co)->lockword.init();
2370 #endif
2371
2372         LLNI_CRITICAL_END;
2373
2374     return co;
2375 }
2376
2377
2378 #if defined(ENABLE_CYCLES_STATS)
2379 void builtin_print_cycles_stats(FILE *file)
2380 {
2381         fprintf(file,"builtin cylce count statistics:\n");
2382
2383         CYCLES_STATS_PRINT_OVERHEAD(builtin_overhead,file);
2384         CYCLES_STATS_PRINT(builtin_new         ,file);
2385
2386         fprintf(file,"\n");
2387 }
2388 #endif /* defined(ENABLE_CYCLES_STATS) */
2389
2390
2391 #if defined(ENABLE_VMLOG)
2392 #define NDEBUG
2393 #include <vmlog_cacao.c>
2394 #endif
2395
2396
2397 /*
2398  * These are local overrides for various environment variables in Emacs.
2399  * Please do not remove this and leave it at the end of the file, where
2400  * Emacs will automagically detect them.
2401  * ---------------------------------------------------------------------
2402  * Local variables:
2403  * mode: c++
2404  * indent-tabs-mode: t
2405  * c-basic-offset: 4
2406  * tab-width: 4
2407  * End:
2408  * vim:noexpandtab:sw=4:ts=4:
2409  */