/* src/vm/builtin.c - functions for unsupported operations Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien This file is part of CACAO. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Contains C functions for JavaVM Instructions that cannot be translated to machine language directly. Consequently, the generated machine code for these instructions contains function calls instead of machine instructions, using the C calling convention. $Id: builtin.c 8321 2007-08-16 11:37:25Z michi $ */ #include "config.h" #include #include #include #include #include #include "vm/types.h" #include "arch.h" #include "md-abi.h" #include "fdlibm/fdlibm.h" #if defined(__CYGWIN__) && defined(Bias) # undef Bias #endif #include "mm/gc-common.h" #include "mm/memory.h" #include "native/jni.h" #include "native/llni.h" #include "native/include/java_lang_String.h" #include "native/include/java_lang_Throwable.h" #include "threads/lock-common.h" #include "toolbox/logging.h" #include "toolbox/util.h" #include "vm/builtin.h" #include "vm/cycles-stats.h" #include "vm/exceptions.h" #include "vm/global.h" #include "vm/initialize.h" #include "vm/primitive.h" #include "vm/stringlocal.h" #include "vm/jit/asmpart.h" #include "vmcore/class.h" #include "vmcore/linker.h" #include "vmcore/loader.h" #include "vmcore/options.h" #include "vmcore/rt-timing.h" #if defined(ENABLE_VMLOG) #include #endif #if defined(ENABLE_DEBUG_FILTER) # include "vm/jit/show.h" #endif /* include builtin tables *****************************************************/ #include "vm/builtintable.inc" CYCLES_STATS_DECLARE(builtin_new ,100,5) CYCLES_STATS_DECLARE(builtin_overhead , 80,1) /* builtintable_init *********************************************************** Parse the descriptors of builtin functions and create the parsed descriptors. *******************************************************************************/ static bool builtintable_init(void) { descriptor_pool *descpool; s4 dumpsize; builtintable_entry *bte; /* mark start of dump memory area */ dumpsize = dump_size(); /* create a new descriptor pool */ descpool = descriptor_pool_new(class_java_lang_Object); /* add some entries we need */ if (!descriptor_pool_add_class(descpool, utf_java_lang_Object)) return false; if (!descriptor_pool_add_class(descpool, utf_java_lang_Class)) return false; /* first add all descriptors to the pool */ for (bte = builtintable_internal; bte->fp != NULL; bte++) { /* create a utf8 string from descriptor */ bte->descriptor = utf_new_char(bte->cdescriptor); if (!descriptor_pool_add(descpool, bte->descriptor, NULL)) { /* release dump area */ dump_release(dumpsize); return false; } } for (bte = builtintable_automatic; bte->fp != NULL; bte++) { bte->descriptor = utf_new_char(bte->cdescriptor); if (!descriptor_pool_add(descpool, bte->descriptor, NULL)) { dump_release(dumpsize); return false; } } for (bte = builtintable_function; bte->fp != NULL; bte++) { bte->classname = utf_new_char(bte->cclassname); bte->name = utf_new_char(bte->cname); bte->descriptor = utf_new_char(bte->cdescriptor); if (!descriptor_pool_add(descpool, bte->descriptor, NULL)) { dump_release(dumpsize); return false; } } /* create the class reference table */ (void) descriptor_pool_create_classrefs(descpool, NULL); /* allocate space for the parsed descriptors */ descriptor_pool_alloc_parsed_descriptors(descpool); /* Now parse all descriptors. NOTE: builtin-functions are treated like static methods (no `this' pointer). */ for (bte = builtintable_internal; bte->fp != NULL; bte++) { bte->md = descriptor_pool_parse_method_descriptor(descpool, bte->descriptor, ACC_STATIC | ACC_METHOD_BUILTIN, NULL); /* generate a builtin stub if we need one */ if (bte->flags & BUILTINTABLE_FLAG_STUB) codegen_generate_stub_builtin(bte); } for (bte = builtintable_automatic; bte->fp != NULL; bte++) { bte->md = descriptor_pool_parse_method_descriptor(descpool, bte->descriptor, ACC_STATIC | ACC_METHOD_BUILTIN, NULL); } for (bte = builtintable_function; bte->fp != NULL; bte++) { bte->md = descriptor_pool_parse_method_descriptor(descpool, bte->descriptor, ACC_STATIC | ACC_METHOD_BUILTIN, NULL); } /* release dump area */ dump_release(dumpsize); return true; } /* builtintable_comparator ***************************************************** qsort comparator for the automatic builtin table. *******************************************************************************/ static int builtintable_comparator(const void *a, const void *b) { builtintable_entry *bte1; builtintable_entry *bte2; bte1 = (builtintable_entry *) a; bte2 = (builtintable_entry *) b; return (bte1->opcode < bte2->opcode) ? -1 : (bte1->opcode > bte2->opcode); } /* builtintable_sort_automatic ************************************************* Sorts the automatic builtin table. *******************************************************************************/ static void builtintable_sort_automatic(void) { s4 entries; /* calculate table size statically (`- 1' comment see builtintable.inc) */ entries = sizeof(builtintable_automatic) / sizeof(builtintable_entry) - 1; qsort(builtintable_automatic, entries, sizeof(builtintable_entry), builtintable_comparator); } /* builtin_init **************************************************************** Initialize the global table of builtin functions. *******************************************************************************/ bool builtin_init(void) { /* initialize the builtin tables */ if (!builtintable_init()) return false; /* sort builtin tables */ builtintable_sort_automatic(); return true; } /* builtintable_get_internal *************************************************** Finds an entry in the builtintable for internal functions and returns the a pointer to the structure. *******************************************************************************/ builtintable_entry *builtintable_get_internal(functionptr fp) { builtintable_entry *bte; for (bte = builtintable_internal; bte->fp != NULL; bte++) { if (bte->fp == fp) return bte; } return NULL; } /* builtintable_get_automatic ************************************************** Finds an entry in the builtintable for functions which are replaced automatically and returns the a pointer to the structure. *******************************************************************************/ builtintable_entry *builtintable_get_automatic(s4 opcode) { builtintable_entry *first; builtintable_entry *last; builtintable_entry *middle; s4 half; s4 entries; /* calculate table size statically (`- 1' comment see builtintable.inc) */ entries = sizeof(builtintable_automatic) / sizeof(builtintable_entry) - 1; first = builtintable_automatic; last = builtintable_automatic + entries; while (entries > 0) { half = entries / 2; middle = first + half; if (middle->opcode < opcode) { first = middle + 1; entries -= half + 1; } else entries = half; } return (first != last ? first : NULL); } /* builtintable_replace_function *********************************************** XXX *******************************************************************************/ #if defined(ENABLE_JIT) bool builtintable_replace_function(void *iptr_) { constant_FMIref *mr; builtintable_entry *bte; instruction *iptr; iptr = (instruction *) iptr_; /* twisti will kill me ;) */ /* get name and descriptor of the function */ switch (iptr->opc) { case ICMD_INVOKESTATIC: /* The instruction MUST be resolved, otherwise we run into lazy loading troubles. Anyway, we should/can only replace very VM-close functions. */ if (INSTRUCTION_IS_UNRESOLVED(iptr)) return false; mr = iptr->sx.s23.s3.fmiref; break; default: return false; } /* search the function table */ for (bte = builtintable_function; bte->fp != NULL; bte++) { if ((METHODREF_CLASSNAME(mr) == bte->classname) && (mr->name == bte->name) && (mr->descriptor == bte->descriptor)) { /* set the values in the instruction */ iptr->opc = bte->opcode; iptr->sx.s23.s3.bte = bte; if (bte->flags & BUILTINTABLE_FLAG_EXCEPTION) iptr->flags.bits |= INS_FLAG_CHECK; else iptr->flags.bits &= ~INS_FLAG_CHECK; return true; } } return false; } #endif /* defined(ENABLE_JIT) */ /***************************************************************************** TYPE CHECKS *****************************************************************************/ /* builtin_instanceof ********************************************************** Checks if an object is an instance of some given class (or subclass of that class). If class is an interface, checks if the interface is implemented. Return value: 1 ... o is an instance of class or implements the interface 0 ... otherwise or if o == NULL *******************************************************************************/ s4 builtin_instanceof(java_handle_t *o, classinfo *class) { if (o == NULL) return 0; return class_isanysubclass(o->vftbl->class, class); } /* builtin_checkcast *********************************************************** The same as builtin_instanceof except that 1 is returned when o == NULL. *******************************************************************************/ s4 builtin_checkcast(java_handle_t *o, classinfo *class) { if (o == NULL) return 1; if (class_isanysubclass(o->vftbl->class, class)) return 1; return 0; } /* builtin_descriptorscompatible *********************************************** Checks if two array type descriptors are assignment compatible Return value: 1 ... target = desc is possible 0 ... otherwise *******************************************************************************/ static s4 builtin_descriptorscompatible(arraydescriptor *desc, arraydescriptor *target) { if (desc == target) return 1; if (desc->arraytype != target->arraytype) return 0; if (desc->arraytype != ARRAYTYPE_OBJECT) return 1; /* {both arrays are arrays of references} */ if (desc->dimension == target->dimension) { /* an array which contains elements of interface types is allowed to be casted to Object (JOWENN)*/ if ((desc->elementvftbl->baseval < 0) && (target->elementvftbl->baseval == 1)) return 1; return class_isanysubclass(desc->elementvftbl->class, target->elementvftbl->class); } if (desc->dimension < target->dimension) return 0; /* {desc has higher dimension than target} */ return class_isanysubclass(pseudo_class_Arraystub, target->elementvftbl->class); } /* builtin_arraycheckcast ****************************************************** Checks if an object is really a subtype of the requested array type. The object has to be an array to begin with. For simple arrays (int, short, double, etc.) the types have to match exactly. For arrays of objects, the type of elements in the array has to be a subtype (or the same type) of the requested element type. For arrays of arrays (which in turn can again be arrays of arrays), the types at the lowest level have to satisfy the corresponding sub class relation. *******************************************************************************/ s4 builtin_arraycheckcast(java_handle_t *o, classinfo *targetclass) { arraydescriptor *desc; if (o == NULL) return 1; desc = o->vftbl->arraydesc; if (desc == NULL) return 0; return builtin_descriptorscompatible(desc, targetclass->vftbl->arraydesc); } s4 builtin_arrayinstanceof(java_handle_t *o, classinfo *targetclass) { if (o == NULL) return 0; return builtin_arraycheckcast(o, targetclass); } /* builtin_throw_exception ***************************************************** Sets the exceptionptr with the thrown exception and prints some debugging information. Called from asm_vm_call_method. *******************************************************************************/ void *builtin_throw_exception(java_handle_t *xptr) { #if !defined(NDEBUG) java_lang_Throwable *t; java_lang_String *s; char *logtext; s4 logtextlen; s4 dumpsize; if (opt_verbose) { t = (java_lang_Throwable *) xptr; /* get detail message */ if (t) LLNI_field_get_ref(t, detailMessage, s); /* calculate message length */ logtextlen = strlen("Builtin exception thrown: ") + strlen("0"); if (t) { logtextlen += utf_bytes(xptr->vftbl->class->name); if (s) { logtextlen += strlen(": ") + u2_utflength(LLNI_field_direct(s, value)->data + LLNI_field_direct(s, offset), LLNI_field_direct(s,count)); } } else { logtextlen += strlen("(nil)"); } /* allocate memory */ dumpsize = dump_size(); logtext = DMNEW(char, logtextlen); strcpy(logtext, "Builtin exception thrown: "); if (t) { utf_cat_classname(logtext, xptr->vftbl->class->name); if (s) { char *buf; buf = javastring_tochar((java_handle_t *) s); strcat(logtext, ": "); strcat(logtext, buf); MFREE(buf, char, strlen(buf) + 1); } } else { strcat(logtext, "(nil)"); } log_text(logtext); /* release memory */ dump_release(dumpsize); } #endif /* !defined(NDEBUG) */ /* actually set the exception */ exceptions_set_exception(xptr); /* Return a NULL pointer. This is required for vm_call_method to check for an exception. This is for convenience. */ return NULL; } /* builtin_canstore ************************************************************ Checks, if an object can be stored in an array. Return value: 1 ... possible 0 ... otherwise (throws an ArrayStoreException) *******************************************************************************/ s4 builtin_canstore(java_handle_objectarray_t *oa, java_handle_t *o) { arraydescriptor *desc; arraydescriptor *valuedesc; vftbl_t *componentvftbl; vftbl_t *valuevftbl; int32_t baseval; uint32_t diffval; int result; if (o == NULL) return 1; /* The following is guaranteed (by verifier checks): * * *) oa->...vftbl->arraydesc != NULL * *) oa->...vftbl->arraydesc->componentvftbl != NULL * *) o->vftbl is not an interface vftbl */ desc = oa->header.objheader.vftbl->arraydesc; componentvftbl = desc->componentvftbl; valuevftbl = o->vftbl; valuedesc = valuevftbl->arraydesc; if ((desc->dimension - 1) == 0) { /* {oa is a one-dimensional array} */ /* {oa is an array of references} */ if (valuevftbl == componentvftbl) return 1; LOCK_MONITOR_ENTER(linker_classrenumber_lock); baseval = componentvftbl->baseval; if (baseval <= 0) { /* an array of interface references */ result = ((valuevftbl->interfacetablelength > -baseval) && (valuevftbl->interfacetable[baseval] != NULL)); } else { diffval = valuevftbl->baseval - componentvftbl->baseval; result = diffval <= (uint32_t) componentvftbl->diffval; } LOCK_MONITOR_EXIT(linker_classrenumber_lock); } else if (valuedesc == NULL) { /* {oa has dimension > 1} */ /* {componentvftbl->arraydesc != NULL} */ /* check if o is an array */ return 0; } else { /* {o is an array} */ result = builtin_descriptorscompatible(valuedesc, componentvftbl->arraydesc); } /* if not possible, throw an exception */ if (result == 0) exceptions_throw_arraystoreexception(); /* return result */ return result; } /* This is an optimized version where a is guaranteed to be one-dimensional */ s4 builtin_canstore_onedim (java_handle_objectarray_t *a, java_handle_t *o) { arraydescriptor *desc; vftbl_t *elementvftbl; vftbl_t *valuevftbl; int32_t baseval; uint32_t diffval; int result; if (o == NULL) return 1; /* The following is guaranteed (by verifier checks): * * *) a->...vftbl->arraydesc != NULL * *) a->...vftbl->arraydesc->elementvftbl != NULL * *) a->...vftbl->arraydesc->dimension == 1 * *) o->vftbl is not an interface vftbl */ desc = a->header.objheader.vftbl->arraydesc; elementvftbl = desc->elementvftbl; valuevftbl = o->vftbl; /* {a is a one-dimensional array} */ if (valuevftbl == elementvftbl) return 1; LOCK_MONITOR_ENTER(linker_classrenumber_lock); baseval = elementvftbl->baseval; if (baseval <= 0) { /* an array of interface references */ result = ((valuevftbl->interfacetablelength > -baseval) && (valuevftbl->interfacetable[baseval] != NULL)); } else { diffval = valuevftbl->baseval - elementvftbl->baseval; result = diffval <= (uint32_t) elementvftbl->diffval; } LOCK_MONITOR_EXIT(linker_classrenumber_lock); return result; } /* This is an optimized version where a is guaranteed to be a * one-dimensional array of a class type */ s4 builtin_canstore_onedim_class(java_handle_objectarray_t *a, java_handle_t *o) { vftbl_t *elementvftbl; vftbl_t *valuevftbl; uint32_t diffval; int result; if (o == NULL) return 1; /* The following is guaranteed (by verifier checks): * * *) a->...vftbl->arraydesc != NULL * *) a->...vftbl->arraydesc->elementvftbl != NULL * *) a->...vftbl->arraydesc->elementvftbl is not an interface vftbl * *) a->...vftbl->arraydesc->dimension == 1 * *) o->vftbl is not an interface vftbl */ elementvftbl = a->header.objheader.vftbl->arraydesc->elementvftbl; valuevftbl = o->vftbl; /* {a is a one-dimensional array} */ if (valuevftbl == elementvftbl) return 1; LOCK_MONITOR_ENTER(linker_classrenumber_lock); diffval = valuevftbl->baseval - elementvftbl->baseval; result = diffval <= (uint32_t) elementvftbl->diffval; LOCK_MONITOR_EXIT(linker_classrenumber_lock); return result; } /* builtin_new ***************************************************************** Creates a new instance of class c on the heap. Return value: pointer to the object or NULL if no memory is available *******************************************************************************/ java_handle_t *builtin_new(classinfo *c) { java_object_t *o; #if defined(ENABLE_RT_TIMING) struct timespec time_start, time_end; #endif #if defined(ENABLE_CYCLES_STATS) u8 cycles_start, cycles_end; #endif RT_TIMING_GET_TIME(time_start); CYCLES_STATS_GET(cycles_start); /* is the class loaded */ assert(c->state & CLASS_LOADED); /* check if we can instantiate this class */ if (c->flags & ACC_ABSTRACT) { exceptions_throw_instantiationerror(c); return NULL; } /* is the class linked */ if (!(c->state & CLASS_LINKED)) if (!link_class(c)) return NULL; if (!(c->state & CLASS_INITIALIZED)) { #if !defined(NDEBUG) if (initverbose) log_message_class("Initialize class (from builtin_new): ", c); #endif if (!initialize_class(c)) return NULL; } o = heap_alloc(c->instancesize, c->flags & ACC_CLASS_HAS_POINTERS, c->finalizer, true); if (!o) return NULL; o->vftbl = c->vftbl; #if defined(ENABLE_THREADS) lock_init_object_lock(o); #endif CYCLES_STATS_GET(cycles_end); RT_TIMING_GET_TIME(time_end); CYCLES_STATS_COUNT(builtin_new,cycles_end - cycles_start); RT_TIMING_TIME_DIFF(time_start, time_end, RT_TIMING_NEW_OBJECT); return o; } /* builtin_fast_new ************************************************************ Creates a new instance of class c on the heap. Return value: pointer to the object or NULL if no fast return is possible for any reason. *******************************************************************************/ java_objectheader *builtin_fast_new(classinfo *c) { java_objectheader *o; #if defined(ENABLE_RT_TIMING) struct timespec time_start, time_end; #endif #if defined(ENABLE_CYCLES_STATS) u8 cycles_start, cycles_end; #endif RT_TIMING_GET_TIME(time_start); CYCLES_STATS_GET(cycles_start); /* is the class loaded */ assert(c->state & CLASS_LOADED); /* check if we can instantiate this class */ if (c->flags & ACC_ABSTRACT) return NULL; /* is the class linked */ if (!(c->state & CLASS_LINKED)) return NULL; if (!(c->state & CLASS_INITIALIZED)) return NULL; o = heap_alloc(c->instancesize, c->flags & ACC_CLASS_HAS_POINTERS, c->finalizer, false); if (!o) return NULL; o->vftbl = c->vftbl; #if defined(ENABLE_THREADS) lock_init_object_lock(o); #endif CYCLES_STATS_GET(cycles_end); RT_TIMING_GET_TIME(time_end); CYCLES_STATS_COUNT(builtin_new,cycles_end - cycles_start); RT_TIMING_TIME_DIFF(time_start, time_end, RT_TIMING_NEW_OBJECT); return o; } /* builtin_newarray ************************************************************ Creates an array with the given vftbl on the heap. This function takes as class argument an array class. Return value: pointer to the array or NULL if no memory is available *******************************************************************************/ java_handle_t *builtin_newarray(s4 size, classinfo *arrayclass) { arraydescriptor *desc; s4 dataoffset; s4 componentsize; s4 actualsize; java_array_t *a; #if defined(ENABLE_RT_TIMING) struct timespec time_start, time_end; #endif RT_TIMING_GET_TIME(time_start); desc = arrayclass->vftbl->arraydesc; dataoffset = desc->dataoffset; componentsize = desc->componentsize; if (size < 0) { exceptions_throw_negativearraysizeexception(); return NULL; } actualsize = dataoffset + size * componentsize; /* check for overflow */ if (((u4) actualsize) < ((u4) size)) { exceptions_throw_outofmemoryerror(); return NULL; } a = heap_alloc(actualsize, (desc->arraytype == ARRAYTYPE_OBJECT), NULL, true); if (a == NULL) return NULL; a->objheader.vftbl = arrayclass->vftbl; #if defined(ENABLE_THREADS) lock_init_object_lock(&a->objheader); #endif LLNI_array_size(a) = size; RT_TIMING_GET_TIME(time_end); RT_TIMING_TIME_DIFF(time_start, time_end, RT_TIMING_NEW_ARRAY); return a; } /* builtin_anewarray *********************************************************** Creates an array of references to the given class type on the heap. Return value: pointer to the array or NULL if no memory is available *******************************************************************************/ java_handle_objectarray_t *builtin_anewarray(s4 size, classinfo *componentclass) { classinfo *arrayclass; /* is class loaded */ assert(componentclass->state & CLASS_LOADED); /* is class linked */ if (!(componentclass->state & CLASS_LINKED)) if (!link_class(componentclass)) return NULL; arrayclass = class_array_of(componentclass, true); if (!arrayclass) return NULL; return (java_handle_objectarray_t *) builtin_newarray(size, arrayclass); } /* builtin_newarray_boolean **************************************************** Creates an array of bytes on the heap. The array is designated as an array of booleans (important for casts) Return value: pointer to the array or NULL if no memory is available *******************************************************************************/ java_handle_booleanarray_t *builtin_newarray_boolean(s4 size) { return (java_handle_booleanarray_t *) builtin_newarray(size, primitivetype_table[ARRAYTYPE_BOOLEAN].arrayclass); } /* builtin_newarray_byte ******************************************************* Creates an array of 8 bit Integers on the heap. Return value: pointer to the array or NULL if no memory is available *******************************************************************************/ java_handle_bytearray_t *builtin_newarray_byte(s4 size) { return (java_handle_bytearray_t *) builtin_newarray(size, primitivetype_table[ARRAYTYPE_BYTE].arrayclass); } /* builtin_newarray_char ******************************************************* Creates an array of characters on the heap. Return value: pointer to the array or NULL if no memory is available *******************************************************************************/ java_handle_chararray_t *builtin_newarray_char(s4 size) { return (java_handle_chararray_t *) builtin_newarray(size, primitivetype_table[ARRAYTYPE_CHAR].arrayclass); } /* builtin_newarray_short ****************************************************** Creates an array of 16 bit Integers on the heap. Return value: pointer to the array or NULL if no memory is available *******************************************************************************/ java_handle_shortarray_t *builtin_newarray_short(s4 size) { return (java_handle_shortarray_t *) builtin_newarray(size, primitivetype_table[ARRAYTYPE_SHORT].arrayclass); } /* builtin_newarray_int ******************************************************** Creates an array of 32 bit Integers on the heap. Return value: pointer to the array or NULL if no memory is available *******************************************************************************/ java_handle_intarray_t *builtin_newarray_int(s4 size) { return (java_handle_intarray_t *) builtin_newarray(size, primitivetype_table[ARRAYTYPE_INT].arrayclass); } /* builtin_newarray_long ******************************************************* Creates an array of 64 bit Integers on the heap. Return value: pointer to the array or NULL if no memory is available *******************************************************************************/ java_handle_longarray_t *builtin_newarray_long(s4 size) { return (java_handle_longarray_t *) builtin_newarray(size, primitivetype_table[ARRAYTYPE_LONG].arrayclass); } /* builtin_newarray_float ****************************************************** Creates an array of 32 bit IEEE floats on the heap. Return value: pointer to the array or NULL if no memory is available *******************************************************************************/ java_handle_floatarray_t *builtin_newarray_float(s4 size) { return (java_handle_floatarray_t *) builtin_newarray(size, primitivetype_table[ARRAYTYPE_FLOAT].arrayclass); } /* builtin_newarray_double ***************************************************** Creates an array of 64 bit IEEE floats on the heap. Return value: pointer to the array or NULL if no memory is available *******************************************************************************/ java_handle_doublearray_t *builtin_newarray_double(s4 size) { return (java_handle_doublearray_t *) builtin_newarray(size, primitivetype_table[ARRAYTYPE_DOUBLE].arrayclass); } /* builtin_multianewarray_intern *********************************************** Creates a multi-dimensional array on the heap. The dimensions are passed in an array of longs. Arguments: n.............number of dimensions to create arrayclass....the array class dims..........array containing the size of each dimension to create Return value: pointer to the array or NULL if no memory is available ******************************************************************************/ static java_handle_t *builtin_multianewarray_intern(int n, classinfo *arrayclass, long *dims) { s4 size; java_handle_t *a; classinfo *componentclass; s4 i; /* create this dimension */ size = (s4) dims[0]; a = builtin_newarray(size, arrayclass); if (!a) return NULL; /* if this is the last dimension return */ if (!--n) return a; /* get the class of the components to create */ componentclass = arrayclass->vftbl->arraydesc->componentvftbl->class; /* The verifier guarantees that the dimension count is in the range. */ /* create the component arrays */ for (i = 0; i < size; i++) { java_handle_t *ea = #if defined(__MIPS__) && (SIZEOF_VOID_P == 4) /* we save an s4 to a s8 slot, 8-byte aligned */ builtin_multianewarray_intern(n, componentclass, dims + 2); #else builtin_multianewarray_intern(n, componentclass, dims + 1); #endif if (!ea) return NULL; ((java_handle_objectarray_t *) a)->data[i] = (java_object_t *) ea; } return a; } /* builtin_multianewarray ****************************************************** Wrapper for builtin_multianewarray_intern which checks all dimensions before we start allocating. ******************************************************************************/ java_handle_objectarray_t *builtin_multianewarray(int n, classinfo *arrayclass, long *dims) { s4 i; s4 size; /* check all dimensions before doing anything */ for (i = 0; i < n; i++) { #if defined(__MIPS__) && (SIZEOF_VOID_P == 4) /* we save an s4 to a s8 slot, 8-byte aligned */ size = (s4) dims[i * 2]; #else size = (s4) dims[i]; #endif if (size < 0) { exceptions_throw_negativearraysizeexception(); return NULL; } } /* now call the real function */ return builtin_multianewarray_intern(n, arrayclass, dims); } /***************************************************************************** METHOD LOGGING Various functions for printing a message at method entry or exit (for debugging) *****************************************************************************/ #if !defined(NDEBUG) static s4 methodindent = 0; static u4 callcount = 0; java_handle_t *builtin_trace_exception(java_handle_t *xptr, methodinfo *m, void *pos, s4 indent) { char *logtext; s4 logtextlen; s4 dumpsize; codeinfo *code; #if defined(ENABLE_DEBUG_FILTER) if (! show_filters_test_verbosecall_exit(m)) return xptr; #endif #if defined(ENABLE_VMLOG) return xptr; #endif if (opt_verbosecall && indent) methodindent--; /* calculate message length */ if (xptr) { logtextlen = strlen("Exception ") + utf_bytes(xptr->vftbl->class->name); } else { logtextlen = strlen("Some Throwable"); } logtextlen += strlen(" thrown in "); if (m) { logtextlen += utf_bytes(m->class->name) + strlen(".") + utf_bytes(m->name) + utf_bytes(m->descriptor) + strlen("(NOSYNC,NATIVE"); #if SIZEOF_VOID_P == 8 logtextlen += strlen(")(0x123456789abcdef0) at position 0x123456789abcdef0 ("); #else logtextlen += strlen(")(0x12345678) at position 0x12345678 ("); #endif if (m->class->sourcefile == NULL) logtextlen += strlen(""); else logtextlen += utf_bytes(m->class->sourcefile); logtextlen += strlen(":65536)"); } else { logtextlen += strlen("call_java_method"); } logtextlen += strlen("0"); /* allocate memory */ dumpsize = dump_size(); logtext = DMNEW(char, logtextlen); if (xptr) { strcpy(logtext, "Exception "); utf_cat_classname(logtext, xptr->vftbl->class->name); } else { strcpy(logtext, "Some Throwable"); } strcat(logtext, " thrown in "); if (m) { utf_cat_classname(logtext, m->class->name); strcat(logtext, "."); utf_cat(logtext, m->name); utf_cat(logtext, m->descriptor); if (m->flags & ACC_SYNCHRONIZED) strcat(logtext, "(SYNC"); else strcat(logtext, "(NOSYNC"); if (m->flags & ACC_NATIVE) { strcat(logtext, ",NATIVE"); code = m->code; #if SIZEOF_VOID_P == 8 sprintf(logtext + strlen(logtext), ")(0x%016lx) at position 0x%016lx", (ptrint) code->entrypoint, (ptrint) pos); #else sprintf(logtext + strlen(logtext), ")(0x%08x) at position 0x%08x", (ptrint) code->entrypoint, (ptrint) pos); #endif } else { /* XXX preliminary: This should get the actual codeinfo */ /* in which the exception happened. */ code = m->code; #if SIZEOF_VOID_P == 8 sprintf(logtext + strlen(logtext), ")(0x%016lx) at position 0x%016lx (", (ptrint) code->entrypoint, (ptrint) pos); #else sprintf(logtext + strlen(logtext), ")(0x%08x) at position 0x%08x (", (ptrint) code->entrypoint, (ptrint) pos); #endif if (m->class->sourcefile == NULL) strcat(logtext, ""); else utf_cat(logtext, m->class->sourcefile); sprintf(logtext + strlen(logtext), ":%d)", 0); } } else strcat(logtext, "call_java_method"); log_text(logtext); /* release memory */ dump_release(dumpsize); return xptr; } #endif /* !defined(NDEBUG) */ /* builtin_print_argument ****************************************************** Prints arguments and return values for the call trace. *******************************************************************************/ #if !defined(NDEBUG) static char *builtin_print_argument(char *logtext, s4 *logtextlen, typedesc *paramtype, s8 value) { imm_union imu; java_handle_t *o; classinfo *c; utf *u; u4 len; switch (paramtype->type) { case TYPE_INT: imu.i = (s4) value; sprintf(logtext + strlen(logtext), "%d (0x%08x)", imu.i, imu.i); break; case TYPE_LNG: imu.l = value; #if SIZEOF_VOID_P == 4 sprintf(logtext + strlen(logtext), "%lld (0x%016llx)", imu.l, imu.l); #else sprintf(logtext + strlen(logtext), "%ld (0x%016lx)", imu.l, imu.l); #endif break; case TYPE_FLT: #if defined(__S390__) imu.l = value; /* The below won't work on S390 */ #else imu.i = (s4) value; #endif sprintf(logtext + strlen(logtext), "%g (0x%08x)", imu.f, imu.i); break; case TYPE_DBL: imu.l = value; #if SIZEOF_VOID_P == 4 sprintf(logtext + strlen(logtext), "%g (0x%016llx)", imu.d, imu.l); #else sprintf(logtext + strlen(logtext), "%g (0x%016lx)", imu.d, imu.l); #endif break; case TYPE_ADR: #if SIZEOF_VOID_P == 4 sprintf(logtext + strlen(logtext), "0x%08x", (ptrint) value); #else sprintf(logtext + strlen(logtext), "0x%016lx", (ptrint) value); #endif /* cast to java.lang.Object */ o = (java_handle_t *) (ptrint) value; /* check return argument for java.lang.Class or java.lang.String */ if (o != NULL) { if (o->vftbl->class == class_java_lang_String) { /* get java.lang.String object and the length of the string */ u = javastring_toutf(o, false); len = strlen(" (String = \"") + utf_bytes(u) + strlen("\")"); /* realloc memory for string length */ logtext = DMREALLOC(logtext, char, *logtextlen, *logtextlen + len); *logtextlen += len; /* convert to utf8 string and strcat it to the logtext */ strcat(logtext, " (String = \""); utf_cat(logtext, u); strcat(logtext, "\")"); } else { if (o->vftbl->class == class_java_lang_Class) { /* if the object returned is a java.lang.Class cast it to classinfo structure and get the name of the class */ c = (classinfo *) o; u = c->name; } else { /* if the object returned is not a java.lang.String or a java.lang.Class just print the name of the class */ u = o->vftbl->class->name; } len = strlen(" (Class = \"") + utf_bytes(u) + strlen("\")"); /* realloc memory for string length */ logtext = DMREALLOC(logtext, char, *logtextlen, *logtextlen + len); *logtextlen += len; /* strcat to the logtext */ strcat(logtext, " (Class = \""); utf_cat_classname(logtext, u); strcat(logtext, "\")"); } } } return logtext; } #endif /* !defined(NDEBUG) */ /* builtin_verbosecall_enter *************************************************** Print method call with arguments for -verbose:call. *******************************************************************************/ #if !defined(NDEBUG) #ifdef TRACE_ARGS_NUM void builtin_verbosecall_enter(s8 a0, s8 a1, # if TRACE_ARGS_NUM >= 4 s8 a2, s8 a3, # endif # if TRACE_ARGS_NUM >= 6 s8 a4, s8 a5, # endif # if TRACE_ARGS_NUM == 8 s8 a6, s8 a7, # endif methodinfo *m) { methoddesc *md; char *logtext; s4 logtextlen; s4 dumpsize; s4 i; s4 pos; #if defined(ENABLE_DEBUG_FILTER) if (! show_filters_test_verbosecall_enter(m)) return; #endif #if defined(ENABLE_VMLOG) vmlog_cacao_enter_method(m); return; #endif md = m->parseddesc; /* calculate message length */ logtextlen = strlen("4294967295 ") + strlen("-2147483647-") + /* INT_MAX should be sufficient */ methodindent + strlen("called: ") + utf_bytes(m->class->name) + strlen(".") + utf_bytes(m->name) + utf_bytes(m->descriptor); /* Actually it's not possible to have all flags printed, but: safety first! */ logtextlen += strlen(" PUBLIC") + strlen(" PRIVATE") + strlen(" PROTECTED") + strlen(" STATIC") + strlen(" FINAL") + strlen(" SYNCHRONIZED") + strlen(" VOLATILE") + strlen(" TRANSIENT") + strlen(" NATIVE") + strlen(" INTERFACE") + strlen(" ABSTRACT"); /* add maximal argument length */ logtextlen += strlen("(") + strlen("-9223372036854775808 (0x123456789abcdef0), ") * TRACE_ARGS_NUM + strlen("...(255)") + strlen(")"); /* allocate memory */ dumpsize = dump_size(); logtext = DMNEW(char, logtextlen); callcount++; sprintf(logtext, "%10d ", callcount); sprintf(logtext + strlen(logtext), "-%d-", methodindent); pos = strlen(logtext); for (i = 0; i < methodindent; i++) logtext[pos++] = '\t'; strcpy(logtext + pos, "called: "); utf_cat_classname(logtext, m->class->name); strcat(logtext, "."); utf_cat(logtext, m->name); utf_cat(logtext, m->descriptor); if (m->flags & ACC_PUBLIC) strcat(logtext, " PUBLIC"); if (m->flags & ACC_PRIVATE) strcat(logtext, " PRIVATE"); if (m->flags & ACC_PROTECTED) strcat(logtext, " PROTECTED"); if (m->flags & ACC_STATIC) strcat(logtext, " STATIC"); if (m->flags & ACC_FINAL) strcat(logtext, " FINAL"); if (m->flags & ACC_SYNCHRONIZED) strcat(logtext, " SYNCHRONIZED"); if (m->flags & ACC_VOLATILE) strcat(logtext, " VOLATILE"); if (m->flags & ACC_TRANSIENT) strcat(logtext, " TRANSIENT"); if (m->flags & ACC_NATIVE) strcat(logtext, " NATIVE"); if (m->flags & ACC_INTERFACE) strcat(logtext, " INTERFACE"); if (m->flags & ACC_ABSTRACT) strcat(logtext, " ABSTRACT"); strcat(logtext, "("); if (md->paramcount >= 1) { logtext = builtin_print_argument(logtext, &logtextlen, &md->paramtypes[0], a0); } if (md->paramcount >= 2) { strcat(logtext, ", "); logtext = builtin_print_argument(logtext, &logtextlen, &md->paramtypes[1], a1); } #if TRACE_ARGS_NUM >= 4 if (md->paramcount >= 3) { strcat(logtext, ", "); logtext = builtin_print_argument(logtext, &logtextlen, &md->paramtypes[2], a2); } if (md->paramcount >= 4) { strcat(logtext, ", "); logtext = builtin_print_argument(logtext, &logtextlen, &md->paramtypes[3], a3); } #endif #if TRACE_ARGS_NUM >= 6 if (md->paramcount >= 5) { strcat(logtext, ", "); logtext = builtin_print_argument(logtext, &logtextlen, &md->paramtypes[4], a4); } if (md->paramcount >= 6) { strcat(logtext, ", "); logtext = builtin_print_argument(logtext, &logtextlen, &md->paramtypes[5], a5); } #endif #if TRACE_ARGS_NUM == 8 if (md->paramcount >= 7) { strcat(logtext, ", "); logtext = builtin_print_argument(logtext, &logtextlen, &md->paramtypes[6], a6); } if (md->paramcount >= 8) { strcat(logtext, ", "); logtext = builtin_print_argument(logtext, &logtextlen, &md->paramtypes[7], a7); } #endif if (md->paramcount > 8) { sprintf(logtext + strlen(logtext), ", ...(%d)", md->paramcount - TRACE_ARGS_NUM); } strcat(logtext, ")"); log_text(logtext); /* release memory */ dump_release(dumpsize); methodindent++; } #endif #endif /* !defined(NDEBUG) */ /* builtin_verbosecall_exit **************************************************** Print method exit for -verbose:call. *******************************************************************************/ #if !defined(NDEBUG) void builtin_verbosecall_exit(s8 l, double d, float f, methodinfo *m) { methoddesc *md; char *logtext; s4 logtextlen; s4 dumpsize; s4 i; s4 pos; imm_union val; #if defined(ENABLE_DEBUG_FILTER) if (! show_filters_test_verbosecall_exit(m)) return; #endif #if defined(ENABLE_VMLOG) vmlog_cacao_leave_method(m); return; #endif md = m->parseddesc; /* calculate message length */ logtextlen = strlen("4294967295 ") + strlen("-2147483647-") + /* INT_MAX should be sufficient */ methodindent + strlen("finished: ") + utf_bytes(m->class->name) + strlen(".") + utf_bytes(m->name) + utf_bytes(m->descriptor) + strlen(" SYNCHRONIZED") + strlen("(") + strlen(")"); /* add maximal argument length */ logtextlen += strlen("->0.4872328470301428 (0x0123456789abcdef)"); /* allocate memory */ dumpsize = dump_size(); logtext = DMNEW(char, logtextlen); /* outdent the log message */ if (methodindent) methodindent--; else log_text("WARNING: unmatched methodindent--"); /* generate the message */ sprintf(logtext, " "); sprintf(logtext + strlen(logtext), "-%d-", methodindent); pos = strlen(logtext); for (i = 0; i < methodindent; i++) logtext[pos++] = '\t'; strcpy(logtext + pos, "finished: "); utf_cat_classname(logtext, m->class->name); strcat(logtext, "."); utf_cat(logtext, m->name); utf_cat(logtext, m->descriptor); if (!IS_VOID_TYPE(md->returntype.type)) { strcat(logtext, "->"); switch (md->returntype.type) { case TYPE_INT: case TYPE_LNG: case TYPE_ADR: val.l = l; break; case TYPE_FLT: val.f = f; break; case TYPE_DBL: val.d = d; break; } logtext = builtin_print_argument(logtext, &logtextlen, &md->returntype, val.l); } log_text(logtext); /* release memory */ dump_release(dumpsize); } #endif /* !defined(NDEBUG) */ #if defined(ENABLE_CYCLES_STATS) void builtin_print_cycles_stats(FILE *file) { fprintf(file,"builtin cylce count statistics:\n"); CYCLES_STATS_PRINT_OVERHEAD(builtin_overhead,file); CYCLES_STATS_PRINT(builtin_new ,file); fprintf(file,"\n"); } #endif /* defined(ENABLE_CYCLES_STATS) */ /***************************************************************************** MISCELLANEOUS HELPER FUNCTIONS *****************************************************************************/ /*********** Functions for integer divisions ***************************** On some systems (eg. DEC ALPHA), integer division is not supported by the CPU. These helper functions implement the missing functionality. ******************************************************************************/ #if !SUPPORT_DIVISION || defined(DISABLE_GC) s4 builtin_idiv(s4 a, s4 b) { s4 c; c = a / b; return c; } s4 builtin_irem(s4 a, s4 b) { s4 c; c = a % b; return c; } #endif /* !SUPPORT_DIVISION || defined(DISABLE_GC) */ /* functions for long arithmetics ********************************************** On systems where 64 bit Integers are not supported by the CPU, these functions are needed. ******************************************************************************/ #if !(SUPPORT_LONG && SUPPORT_LONG_ADD) s8 builtin_ladd(s8 a, s8 b) { s8 c; #if U8_AVAILABLE c = a + b; #else c = builtin_i2l(0); #endif return c; } s8 builtin_lsub(s8 a, s8 b) { s8 c; #if U8_AVAILABLE c = a - b; #else c = builtin_i2l(0); #endif return c; } s8 builtin_lneg(s8 a) { s8 c; #if U8_AVAILABLE c = -a; #else c = builtin_i2l(0); #endif return c; } #endif /* !(SUPPORT_LONG && SUPPORT_LONG_ADD) */ #if !(SUPPORT_LONG && SUPPORT_LONG_MUL) s8 builtin_lmul(s8 a, s8 b) { s8 c; #if U8_AVAILABLE c = a * b; #else c = builtin_i2l(0); #endif return c; } #endif /* !(SUPPORT_LONG && SUPPORT_LONG_MUL) */ #if !(SUPPORT_DIVISION && SUPPORT_LONG && SUPPORT_LONG_DIV) || defined (DISABLE_GC) s8 builtin_ldiv(s8 a, s8 b) { s8 c; #if U8_AVAILABLE c = a / b; #else c = builtin_i2l(0); #endif return c; } s8 builtin_lrem(s8 a, s8 b) { s8 c; #if U8_AVAILABLE c = a % b; #else c = builtin_i2l(0); #endif return c; } #endif /* !(SUPPORT_DIVISION && SUPPORT_LONG && SUPPORT_LONG_DIV) */ #if !(SUPPORT_LONG && SUPPORT_LONG_SHIFT) s8 builtin_lshl(s8 a, s4 b) { s8 c; #if U8_AVAILABLE c = a << (b & 63); #else c = builtin_i2l(0); #endif return c; } s8 builtin_lshr(s8 a, s4 b) { s8 c; #if U8_AVAILABLE c = a >> (b & 63); #else c = builtin_i2l(0); #endif return c; } s8 builtin_lushr(s8 a, s4 b) { s8 c; #if U8_AVAILABLE c = ((u8) a) >> (b & 63); #else c = builtin_i2l(0); #endif return c; } #endif /* !(SUPPORT_LONG && SUPPORT_LONG_SHIFT) */ #if !(SUPPORT_LONG && SUPPORT_LONG_LOGICAL) s8 builtin_land(s8 a, s8 b) { s8 c; #if U8_AVAILABLE c = a & b; #else c = builtin_i2l(0); #endif return c; } s8 builtin_lor(s8 a, s8 b) { s8 c; #if U8_AVAILABLE c = a | b; #else c = builtin_i2l(0); #endif return c; } s8 builtin_lxor(s8 a, s8 b) { s8 c; #if U8_AVAILABLE c = a ^ b; #else c = builtin_i2l(0); #endif return c; } #endif /* !(SUPPORT_LONG && SUPPORT_LONG_LOGICAL) */ #if !(SUPPORT_LONG && SUPPORT_LONG_CMP) s4 builtin_lcmp(s8 a, s8 b) { #if U8_AVAILABLE if (a < b) return -1; if (a > b) return 1; return 0; #else return 0; #endif } #endif /* !(SUPPORT_LONG && SUPPORT_LONG_CMP) */ /* functions for unsupported floating instructions ****************************/ /* used to convert FLT_xxx defines into float values */ static inline float intBitsToFloat(s4 i) { imm_union imb; imb.i = i; return imb.f; } /* used to convert DBL_xxx defines into double values */ static inline float longBitsToDouble(s8 l) { imm_union imb; imb.l = l; return imb.d; } #if !SUPPORT_FLOAT float builtin_fadd(float a, float b) { if (isnanf(a)) return intBitsToFloat(FLT_NAN); if (isnanf(b)) return intBitsToFloat(FLT_NAN); if (finitef(a)) { if (finitef(b)) return a + b; else return b; } else { if (finitef(b)) return a; else { if (copysignf(1.0, a) == copysignf(1.0, b)) return a; else return intBitsToFloat(FLT_NAN); } } } float builtin_fsub(float a, float b) { return builtin_fadd(a, builtin_fneg(b)); } float builtin_fmul(float a, float b) { if (isnanf(a)) return intBitsToFloat(FLT_NAN); if (isnanf(b)) return intBitsToFloat(FLT_NAN); if (finitef(a)) { if (finitef(b)) return a * b; else { if (a == 0) return intBitsToFloat(FLT_NAN); else return copysignf(b, copysignf(1.0, b)*a); } } else { if (finitef(b)) { if (b == 0) return intBitsToFloat(FLT_NAN); else return copysignf(a, copysignf(1.0, a)*b); } else { return copysignf(a, copysignf(1.0, a)*copysignf(1.0, b)); } } } /* builtin_ddiv **************************************************************** Implementation as described in VM Spec. *******************************************************************************/ float builtin_fdiv(float a, float b) { if (finitef(a)) { if (finitef(b)) { /* If neither value1' nor value2' is NaN, the sign of the result */ /* is positive if both values have the same sign, negative if the */ /* values have different signs. */ return a / b; } else { if (isnanf(b)) { /* If either value1' or value2' is NaN, the result is NaN. */ return intBitsToFloat(FLT_NAN); } else { /* Division of a finite value by an infinity results in a */ /* signed zero, with the sign-producing rule just given. */ /* is sign equal? */ if (copysignf(1.0, a) == copysignf(1.0, b)) return 0.0; else return -0.0; } } } else { if (isnanf(a)) { /* If either value1' or value2' is NaN, the result is NaN. */ return intBitsToFloat(FLT_NAN); } else if (finitef(b)) { /* Division of an infinity by a finite value results in a signed */ /* infinity, with the sign-producing rule just given. */ /* is sign equal? */ if (copysignf(1.0, a) == copysignf(1.0, b)) return intBitsToFloat(FLT_POSINF); else return intBitsToFloat(FLT_NEGINF); } else { /* Division of an infinity by an infinity results in NaN. */ return intBitsToFloat(FLT_NAN); } } } float builtin_fneg(float a) { if (isnanf(a)) return a; else { if (finitef(a)) return -a; else return copysignf(a, -copysignf(1.0, a)); } } #endif /* !SUPPORT_FLOAT */ #if !SUPPORT_FLOAT || !SUPPORT_FLOAT_CMP || defined(ENABLE_INTRP) s4 builtin_fcmpl(float a, float b) { if (isnanf(a)) return -1; if (isnanf(b)) return -1; if (!finitef(a) || !finitef(b)) { a = finitef(a) ? 0 : copysignf(1.0, a); b = finitef(b) ? 0 : copysignf(1.0, b); } if (a > b) return 1; if (a == b) return 0; return -1; } s4 builtin_fcmpg(float a, float b) { if (isnanf(a)) return 1; if (isnanf(b)) return 1; if (!finitef(a) || !finitef(b)) { a = finitef(a) ? 0 : copysignf(1.0, a); b = finitef(b) ? 0 : copysignf(1.0, b); } if (a > b) return 1; if (a == b) return 0; return -1; } #endif /* !SUPPORT_FLOAT || !SUPPORT_FLOAT_CMP || defined(ENABLE_INTRP) */ float builtin_frem(float a, float b) { return fmodf(a, b); } /* functions for unsupported double instructions ******************************/ #if !SUPPORT_DOUBLE double builtin_dadd(double a, double b) { if (isnan(a)) return longBitsToDouble(DBL_NAN); if (isnan(b)) return longBitsToDouble(DBL_NAN); if (finite(a)) { if (finite(b)) return a + b; else return b; } else { if (finite(b)) return a; else { if (copysign(1.0, a)==copysign(1.0, b)) return a; else return longBitsToDouble(DBL_NAN); } } } double builtin_dsub(double a, double b) { return builtin_dadd(a, builtin_dneg(b)); } double builtin_dmul(double a, double b) { if (isnan(a)) return longBitsToDouble(DBL_NAN); if (isnan(b)) return longBitsToDouble(DBL_NAN); if (finite(a)) { if (finite(b)) return a * b; else { if (a == 0) return longBitsToDouble(DBL_NAN); else return copysign(b, copysign(1.0, b) * a); } } else { if (finite(b)) { if (b == 0) return longBitsToDouble(DBL_NAN); else return copysign(a, copysign(1.0, a) * b); } else { return copysign(a, copysign(1.0, a) * copysign(1.0, b)); } } } /* builtin_ddiv **************************************************************** Implementation as described in VM Spec. *******************************************************************************/ double builtin_ddiv(double a, double b) { if (finite(a)) { if (finite(b)) { /* If neither value1' nor value2' is NaN, the sign of the result */ /* is positive if both values have the same sign, negative if the */ /* values have different signs. */ return a / b; } else { if (isnan(b)) { /* If either value1' or value2' is NaN, the result is NaN. */ return longBitsToDouble(DBL_NAN); } else { /* Division of a finite value by an infinity results in a */ /* signed zero, with the sign-producing rule just given. */ /* is sign equal? */ if (copysign(1.0, a) == copysign(1.0, b)) return 0.0; else return -0.0; } } } else { if (isnan(a)) { /* If either value1' or value2' is NaN, the result is NaN. */ return longBitsToDouble(DBL_NAN); } else if (finite(b)) { /* Division of an infinity by a finite value results in a signed */ /* infinity, with the sign-producing rule just given. */ /* is sign equal? */ if (copysign(1.0, a) == copysign(1.0, b)) return longBitsToDouble(DBL_POSINF); else return longBitsToDouble(DBL_NEGINF); } else { /* Division of an infinity by an infinity results in NaN. */ return longBitsToDouble(DBL_NAN); } } } /* builtin_dneg **************************************************************** Implemented as described in VM Spec. *******************************************************************************/ double builtin_dneg(double a) { if (isnan(a)) { /* If the operand is NaN, the result is NaN (recall that NaN has no */ /* sign). */ return a; } else { if (finite(a)) { /* If the operand is a zero, the result is the zero of opposite */ /* sign. */ return -a; } else { /* If the operand is an infinity, the result is the infinity of */ /* opposite sign. */ return copysign(a, -copysign(1.0, a)); } } } #endif /* !SUPPORT_DOUBLE */ #if !SUPPORT_DOUBLE || !SUPPORT_DOUBLE_CMP || defined(ENABLE_INTRP) s4 builtin_dcmpl(double a, double b) { if (isnan(a)) return -1; if (isnan(b)) return -1; if (!finite(a) || !finite(b)) { a = finite(a) ? 0 : copysign(1.0, a); b = finite(b) ? 0 : copysign(1.0, b); } if (a > b) return 1; if (a == b) return 0; return -1; } s4 builtin_dcmpg(double a, double b) { if (isnan(a)) return 1; if (isnan(b)) return 1; if (!finite(a) || !finite(b)) { a = finite(a) ? 0 : copysign(1.0, a); b = finite(b) ? 0 : copysign(1.0, b); } if (a > b) return 1; if (a == b) return 0; return -1; } #endif /* !SUPPORT_DOUBLE || !SUPPORT_DOUBLE_CMP || defined(ENABLE_INTRP) */ double builtin_drem(double a, double b) { return fmod(a, b); } /* conversion operations ******************************************************/ #if 0 s8 builtin_i2l(s4 i) { #if U8_AVAILABLE return i; #else s8 v; v.high = 0; v.low = i; return v; #endif } s4 builtin_l2i(s8 l) { #if U8_AVAILABLE return (s4) l; #else return l.low; #endif } #endif #if !(SUPPORT_FLOAT && SUPPORT_I2F) float builtin_i2f(s4 a) { float f = (float) a; return f; } #endif /* !(SUPPORT_FLOAT && SUPPORT_I2F) */ #if !(SUPPORT_DOUBLE && SUPPORT_I2D) double builtin_i2d(s4 a) { double d = (double) a; return d; } #endif /* !(SUPPORT_DOUBLE && SUPPORT_I2D) */ #if !(SUPPORT_LONG && SUPPORT_FLOAT && SUPPORT_L2F) float builtin_l2f(s8 a) { #if U8_AVAILABLE float f = (float) a; return f; #else return 0.0; #endif } #endif /* !(SUPPORT_LONG && SUPPORT_FLOAT && SUPPORT_L2F) */ #if !(SUPPORT_LONG && SUPPORT_DOUBLE && SUPPORT_L2D) double builtin_l2d(s8 a) { #if U8_AVAILABLE double d = (double) a; return d; #else return 0.0; #endif } #endif /* !(SUPPORT_LONG && SUPPORT_DOUBLE && SUPPORT_L2D) */ #if !(SUPPORT_FLOAT && SUPPORT_F2I) || defined(ENABLE_INTRP) || defined(DISABLE_GC) s4 builtin_f2i(float a) { s4 i; i = builtin_d2i((double) a); return i; /* float f; if (isnanf(a)) return 0; if (finitef(a)) { if (a > 2147483647) return 2147483647; if (a < (-2147483648)) return (-2147483648); return (s4) a; } f = copysignf((float) 1.0, a); if (f > 0) return 2147483647; return (-2147483648); */ } #endif /* !(SUPPORT_FLOAT && SUPPORT_F2I) || defined(ENABLE_INTRP) || defined(DISABLE_GC) */ #if !(SUPPORT_FLOAT && SUPPORT_LONG && SUPPORT_F2L) || defined(DISABLE_GC) s8 builtin_f2l(float a) { s8 l; l = builtin_d2l((double) a); return l; /* float f; if (finitef(a)) { if (a > 9223372036854775807L) return 9223372036854775807L; if (a < (-9223372036854775808L)) return (-9223372036854775808L); return (s8) a; } if (isnanf(a)) return 0; f = copysignf((float) 1.0, a); if (f > 0) return 9223372036854775807L; return (-9223372036854775808L); */ } #endif /* !(SUPPORT_FLOAT && SUPPORT_LONG && SUPPORT_F2L) */ #if !(SUPPORT_DOUBLE && SUPPORT_D2I) || defined(ENABLE_INTRP) || defined(DISABLE_GC) s4 builtin_d2i(double a) { double d; if (finite(a)) { if (a >= 2147483647) return 2147483647; if (a <= (-2147483647-1)) return (-2147483647-1); return (s4) a; } if (isnan(a)) return 0; d = copysign(1.0, a); if (d > 0) return 2147483647; return (-2147483647-1); } #endif /* !(SUPPORT_DOUBLE && SUPPORT_D2I) || defined(ENABLE_INTRP) || defined(DISABLE_GC) */ #if !(SUPPORT_DOUBLE && SUPPORT_LONG && SUPPORT_D2L) || defined(DISABLE_GC) s8 builtin_d2l(double a) { double d; if (finite(a)) { if (a >= 9223372036854775807LL) return 9223372036854775807LL; if (a <= (-9223372036854775807LL-1)) return (-9223372036854775807LL-1); return (s8) a; } if (isnan(a)) return 0; d = copysign(1.0, a); if (d > 0) return 9223372036854775807LL; return (-9223372036854775807LL-1); } #endif /* !(SUPPORT_DOUBLE && SUPPORT_LONG && SUPPORT_D2L) */ #if !(SUPPORT_FLOAT && SUPPORT_DOUBLE) double builtin_f2d(float a) { if (finitef(a)) return (double) a; else { if (isnanf(a)) return longBitsToDouble(DBL_NAN); else return copysign(longBitsToDouble(DBL_POSINF), (double) copysignf(1.0, a) ); } } float builtin_d2f(double a) { if (finite(a)) return (float) a; else { if (isnan(a)) return intBitsToFloat(FLT_NAN); else return copysignf(intBitsToFloat(FLT_POSINF), (float) copysign(1.0, a)); } } #endif /* !(SUPPORT_FLOAT && SUPPORT_DOUBLE) */ /* builtin_arraycopy *********************************************************** Builtin for java.lang.System.arraycopy. ATTENTION: This builtin function returns a boolean value to signal the ICMD_BUILTIN if there was an exception. *******************************************************************************/ bool builtin_arraycopy(java_handle_t *src, s4 srcStart, java_handle_t *dest, s4 destStart, s4 len) { arraydescriptor *sdesc; arraydescriptor *ddesc; s4 i; if ((src == NULL) || (dest == NULL)) { exceptions_throw_nullpointerexception(); return false; } sdesc = LLNI_vftbl_direct(src)->arraydesc; ddesc = LLNI_vftbl_direct(dest)->arraydesc; if (!sdesc || !ddesc || (sdesc->arraytype != ddesc->arraytype)) { exceptions_throw_arraystoreexception(); return false; } /* we try to throw exception with the same message as SUN does */ if ((len < 0) || (srcStart < 0) || (destStart < 0) || (srcStart + len < 0) || (srcStart + len > LLNI_array_size(src)) || (destStart + len < 0) || (destStart + len > LLNI_array_size(dest))) { exceptions_throw_arrayindexoutofboundsexception(); return false; } if (sdesc->componentvftbl == ddesc->componentvftbl) { /* We copy primitive values or references of exactly the same type */ s4 dataoffset = sdesc->dataoffset; s4 componentsize = sdesc->componentsize; memmove(((u1 *) dest) + dataoffset + componentsize * destStart, ((u1 *) src) + dataoffset + componentsize * srcStart, (size_t) len * componentsize); } else { /* We copy references of different type */ java_handle_objectarray_t *oas = (java_handle_objectarray_t *) src; java_handle_objectarray_t *oad = (java_handle_objectarray_t *) dest; if (destStart <= srcStart) { for (i = 0; i < len; i++) { java_handle_t *o = oas->data[srcStart + i]; if (!builtin_canstore(oad, o)) return false; oad->data[destStart + i] = o; } } else { /* XXX this does not completely obey the specification! If an exception is thrown only the elements above the current index have been copied. The specification requires that only the elements *below* the current index have been copied before the throw. */ for (i = len - 1; i >= 0; i--) { java_handle_t *o = oas->data[srcStart + i]; if (!builtin_canstore(oad, o)) return false; oad->data[destStart + i] = o; } } } return true; } /* builtin_nanotime ************************************************************ Return the current time in nanoseconds. *******************************************************************************/ s8 builtin_nanotime(void) { struct timeval tv; s8 usecs; if (gettimeofday(&tv, NULL) == -1) vm_abort("gettimeofday failed: %s", strerror(errno)); usecs = (s8) tv.tv_sec * (1000 * 1000) + (s8) tv.tv_usec; return usecs * 1000; } /* builtin_currenttimemillis *************************************************** Return the current time in milliseconds. *******************************************************************************/ s8 builtin_currenttimemillis(void) { s8 msecs; msecs = builtin_nanotime() / 1000 / 1000; return msecs; } /* builtin_clone *************************************************************** Function for cloning objects or arrays. *******************************************************************************/ java_handle_t *builtin_clone(void *env, java_handle_t *o) { arraydescriptor *ad; java_handle_t *ah; u4 size; classinfo *c; java_handle_t *co; /* cloned object header */ /* get the array descriptor */ ad = o->vftbl->arraydesc; /* we are cloning an array */ if (ad != NULL) { ah = (java_handle_t *) o; size = ad->dataoffset + ad->componentsize * LLNI_array_size(ah); co = heap_alloc(size, (ad->arraytype == ARRAYTYPE_OBJECT), NULL, true); if (co == NULL) return NULL; MCOPY(co, o, u1, size); #if defined(ENABLE_GC_CACAO) heap_init_objectheader(co, size); #endif #if defined(ENABLE_THREADS) lock_init_object_lock(co); #endif return co; } /* we are cloning a non-array */ if (!builtin_instanceof(o, class_java_lang_Cloneable)) { exceptions_throw_clonenotsupportedexception(); return NULL; } /* get the class of the object */ c = o->vftbl->class; /* create new object */ co = builtin_new(c); if (co == NULL) return NULL; MCOPY(co, o, u1, c->instancesize); #if defined(ENABLE_GC_CACAO) heap_init_objectheader(co, c->instancesize); #endif #if defined(ENABLE_THREADS) lock_init_object_lock(co); #endif return co; } #if defined(ENABLE_VMLOG) #define NDEBUG #include #endif /* * These are local overrides for various environment variables in Emacs. * Please do not remove this and leave it at the end of the file, where * Emacs will automagically detect them. * --------------------------------------------------------------------- * Local variables: * mode: c * indent-tabs-mode: t * c-basic-offset: 4 * tab-width: 4 * End: * vim:noexpandtab:sw=4:ts=4: */