From: Stefan Ring Date: Tue, 26 Aug 2008 18:01:27 +0000 (+0200) Subject: Merged subtype branch to new head. X-Git-Url: http://wien.tomnetworks.com/gitweb/?p=cacao.git;a=commitdiff_plain;h=0ce178c56bb73f85555e1693ed2019387838b362 Merged subtype branch to new head. --HG-- branch : subtype rename : src/vmcore/class.c => src/vm/class.c rename : src/vm/builtin.c => src/vm/jit/builtin.cpp rename : src/vm/builtin.h => src/vm/jit/builtin.hpp rename : src/vm/jit/emit-common.h => src/vm/jit/emit-common.hpp rename : src/vmcore/linker.c => src/vm/linker.c rename : src/vmcore/linker.h => src/vm/linker.h --- 0ce178c56bb73f85555e1693ed2019387838b362 diff --cc src/vm/class.c index d9ccdf0ae,000000000..a5b5812f6 mode 100644,000000..100644 --- a/src/vm/class.c +++ b/src/vm/class.c @@@ -1,2468 -1,0 +1,2463 @@@ +/* src/vm/class.c - class related functions + + Copyright (C) 1996-2005, 2006, 2007, 2008 + CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO + + 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. + +*/ + + +#include "config.h" + +#include +#include +#include +#include + +#include "vm/types.h" + +#include "arch.h" + +#include "mm/memory.h" + +#include "native/llni.h" + +#include "threads/lock-common.h" +#include "threads/mutex.hpp" + +#include "toolbox/logging.h" + +#include "vm/array.h" +#include "vm/jit/builtin.hpp" +#include "vm/class.h" +#include "vm/classcache.h" +#include "vm/exceptions.hpp" +#include "vm/global.h" +#include "vm/globals.hpp" +#include "vm/javaobjects.hpp" +#include "vm/linker.h" +#include "vm/loader.hpp" +#include "vm/options.h" +#include "vm/resolve.h" + +#if defined(ENABLE_STATISTICS) +# include "vm/statistics.h" +#endif + +#include "vm/suck.hpp" +#include "vm/utf8.h" + +#include "vm/jit/asmpart.h" + + +/* class_set_packagename ******************************************************* + + Derive the package name from the class name and store it in the + struct. + + An internal package name consists of the package name plus the + trailing '/', e.g. "java/lang/". + + For classes in the unnamed package, the package name is set to + NULL. + +*******************************************************************************/ + +void class_set_packagename(classinfo *c) +{ + char *p; + char *start; + + p = UTF_END(c->name) - 1; + start = c->name->text; + + if (c->name->text[0] == '[') { + /* Set packagename of arrays to the element's package. */ + + for (; *start == '['; start++); + + /* Skip the 'L' in arrays of references. */ + + if (*start == 'L') + start++; + } + + /* Search for last '/'. */ + + for (; (p > start) && (*p != '/'); --p); + + /* If we found a '/' we set the package name plus the trailing + '/'. Otherwise we set the packagename to NULL. */ + + if (p > start) + c->packagename = utf_new(start, p - start + 1); + else + c->packagename = NULL; +} + + +/* class_create_classinfo ****************************************************** + + Create a new classinfo struct. The class name is set to the given utf *, + most other fields are initialized to zero. + + Note: classname may be NULL. In this case a not-yet-named classinfo is + created. The name must be filled in later and class_set_packagename + must be called after that. + +*******************************************************************************/ + +classinfo *class_create_classinfo(utf *classname) +{ + classinfo *c; + +#if defined(ENABLE_STATISTICS) + if (opt_stat) + size_classinfo += sizeof(classinfo); +#endif + + /* we use a safe name for temporarily unnamed classes */ + + if (classname == NULL) + classname = utf_not_named_yet; + +#if !defined(NDEBUG) + if (initverbose) + log_message_utf("Creating class: ", classname); +#endif + +#if !defined(ENABLE_GC_BOEHM) + c = (classinfo *) heap_alloc_uncollectable(sizeof(classinfo)); + /*c = NEW(classinfo); + MZERO(c, classinfo, 1);*/ +#else + c = GCNEW_UNCOLLECTABLE(classinfo, 1); + /* GCNEW_UNCOLLECTABLE clears the allocated memory */ +#endif + + c->name = classname; + + /* Set the header.vftbl of all loaded classes to the one of + java.lang.Class, so Java code can use a class as object. */ + + if (class_java_lang_Class != NULL) + if (class_java_lang_Class->vftbl != NULL) + c->object.header.vftbl = class_java_lang_Class->vftbl; + +#if defined(ENABLE_JAVASE) + /* check if the class is a reference class and flag it */ + + if (classname == utf_java_lang_ref_SoftReference) { + c->flags |= ACC_CLASS_REFERENCE_SOFT; + } + else if (classname == utf_java_lang_ref_WeakReference) { + c->flags |= ACC_CLASS_REFERENCE_WEAK; + } + else if (classname == utf_java_lang_ref_PhantomReference) { + c->flags |= ACC_CLASS_REFERENCE_PHANTOM; + } +#endif + + if (classname != utf_not_named_yet) + class_set_packagename(c); + + LOCK_INIT_OBJECT_LOCK(&c->object.header); + + return c; +} + + +/* class_postset_header_vftbl ************************************************** + + Set the header.vftbl of all classes created before java.lang.Class + was linked. This is necessary that Java code can use a class as + object. + +*******************************************************************************/ + +void class_postset_header_vftbl(void) +{ + classinfo *c; + u4 slot; + classcache_name_entry *nmen; + classcache_class_entry *clsen; + + assert(class_java_lang_Class); + + for (slot = 0; slot < hashtable_classcache.size; slot++) { + nmen = (classcache_name_entry *) hashtable_classcache.ptr[slot]; + + for (; nmen; nmen = nmen->hashlink) { + /* iterate over all class entries */ + + for (clsen = nmen->classes; clsen; clsen = clsen->next) { + c = clsen->classobj; + + /* now set the the vftbl */ + + if (c->object.header.vftbl == NULL) + c->object.header.vftbl = class_java_lang_Class->vftbl; + } + } + } +} + +/* class_define **************************************************************** + + Calls the loader and defines a class in the VM. + +*******************************************************************************/ + +classinfo *class_define(utf *name, classloader_t *cl, int32_t length, uint8_t *data, java_handle_t *pd) +{ + classinfo *c; + classinfo *r; + classbuffer *cb; + + if (name != NULL) { + /* check if this class has already been defined */ + + c = classcache_lookup_defined_or_initiated(cl, name); + + if (c != NULL) { + exceptions_throw_linkageerror("duplicate class definition: ", c); + return NULL; + } + } + + /* create a new classinfo struct */ + + c = class_create_classinfo(name); + +#if defined(ENABLE_STATISTICS) + /* measure time */ + + if (opt_getloadingtime) + loadingtime_start(); +#endif + + /* build a classbuffer with the given data */ + + cb = NEW(classbuffer); + + cb->clazz = c; + cb->size = length; + cb->data = data; + cb->pos = cb->data; + + /* preset the defining classloader */ + + c->classloader = cl; + + /* load the class from this buffer */ + + r = load_class_from_classbuffer(cb); + + /* free memory */ + + FREE(cb, classbuffer); + +#if defined(ENABLE_STATISTICS) + /* measure time */ + + if (opt_getloadingtime) + loadingtime_stop(); +#endif + + if (r == NULL) { + /* If return value is NULL, we had a problem and the class is + not loaded. Now free the allocated memory, otherwise we + could run into a DOS. */ + + class_free(c); + + return NULL; + } + +#if defined(ENABLE_JAVASE) +# if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK) + /* Store the protection domain. */ + + c->protectiondomain = pd; +# endif +#endif + + /* Store the newly defined class in the class cache. This call + also checks whether a class of the same name has already been + defined by the same defining loader, and if so, replaces the + newly created class by the one defined earlier. */ + + /* Important: The classinfo given to classcache_store must be + fully prepared because another thread may return + this pointer after the lookup at to top of this + function directly after the class cache lock has + been released. */ + + c = classcache_store(cl, c, true); + + return c; +} + + +/* class_load_attribute_sourcefile ********************************************* + + SourceFile_attribute { + u2 attribute_name_index; + u4 attribute_length; + u2 sourcefile_index; + } + +*******************************************************************************/ + +static bool class_load_attribute_sourcefile(classbuffer *cb) +{ + classinfo *c; + u4 attribute_length; + u2 sourcefile_index; + utf *sourcefile; + + /* get classinfo */ + + c = cb->clazz; + + /* check buffer size */ + + if (!suck_check_classbuffer_size(cb, 4 + 2)) + return false; + + /* check attribute length */ + + attribute_length = suck_u4(cb); + + if (attribute_length != 2) { + exceptions_throw_classformaterror(c, "Wrong size for VALUE attribute"); + return false; + } + + /* there can be no more than one SourceFile attribute */ + + if (c->sourcefile != NULL) { + exceptions_throw_classformaterror(c, "Multiple SourceFile attributes"); + return false; + } + + /* get sourcefile */ + + sourcefile_index = suck_u2(cb); + sourcefile = class_getconstant(c, sourcefile_index, CONSTANT_Utf8); + + if (sourcefile == NULL) + return false; + + /* store sourcefile */ + + c->sourcefile = sourcefile; + + return true; +} + + +/* class_load_attribute_enclosingmethod **************************************** + + EnclosingMethod_attribute { + u2 attribute_name_index; + u4 attribute_length; + u2 class_index; + u2 method_index; + } + +*******************************************************************************/ + +#if defined(ENABLE_JAVASE) +static bool class_load_attribute_enclosingmethod(classbuffer *cb) +{ + classinfo *c; + u4 attribute_length; + u2 class_index; + u2 method_index; + classref_or_classinfo cr; + constant_nameandtype *cn; + + /* get classinfo */ + + c = cb->clazz; + + /* check buffer size */ + + if (!suck_check_classbuffer_size(cb, 4 + 2 + 2)) + return false; + + /* check attribute length */ + + attribute_length = suck_u4(cb); + + if (attribute_length != 4) { + exceptions_throw_classformaterror(c, "Wrong size for VALUE attribute"); + return false; + } + + /* there can be no more than one EnclosingMethod attribute */ + + if (c->enclosingmethod != NULL) { + exceptions_throw_classformaterror(c, "Multiple EnclosingMethod attributes"); + return false; + } + + /* get class index */ + + class_index = suck_u2(cb); + cr.ref = innerclass_getconstant(c, class_index, CONSTANT_Class); + + /* get method index */ + + method_index = suck_u2(cb); + cn = innerclass_getconstant(c, method_index, CONSTANT_NameAndType); + + /* store info in classinfo */ + + c->enclosingclass.any = cr.any; + c->enclosingmethod = cn; + + return true; +} +#endif /* defined(ENABLE_JAVASE) */ + + +/* class_load_attributes ******************************************************* + + Read attributes from ClassFile. + + attribute_info { + u2 attribute_name_index; + u4 attribute_length; + u1 info[attribute_length]; + } + + InnerClasses_attribute { + u2 attribute_name_index; + u4 attribute_length; + } + +*******************************************************************************/ + +bool class_load_attributes(classbuffer *cb) +{ + classinfo *c; + uint16_t attributes_count; + uint16_t attribute_name_index; + utf *attribute_name; + innerclassinfo *info; + classref_or_classinfo inner; + classref_or_classinfo outer; + utf *name; + uint16_t flags; + int i, j; + + c = cb->clazz; + + /* get attributes count */ + + if (!suck_check_classbuffer_size(cb, 2)) + return false; + + attributes_count = suck_u2(cb); + + for (i = 0; i < attributes_count; i++) { + /* get attribute name */ + + if (!suck_check_classbuffer_size(cb, 2)) + return false; + + attribute_name_index = suck_u2(cb); + attribute_name = + class_getconstant(c, attribute_name_index, CONSTANT_Utf8); + + if (attribute_name == NULL) + return false; + + if (attribute_name == utf_InnerClasses) { + /* InnerClasses */ + + if (c->innerclass != NULL) { + exceptions_throw_classformaterror(c, "Multiple InnerClasses attributes"); + return false; + } + + if (!suck_check_classbuffer_size(cb, 4 + 2)) + return false; + + /* skip attribute length */ + suck_u4(cb); + + /* number of records */ + c->innerclasscount = suck_u2(cb); + + if (!suck_check_classbuffer_size(cb, (2 + 2 + 2 + 2) * c->innerclasscount)) + return false; + + /* allocate memory for innerclass structure */ + c->innerclass = MNEW(innerclassinfo, c->innerclasscount); + + for (j = 0; j < c->innerclasscount; j++) { + /* The innerclass structure contains a class with an encoded + name, its defining scope, its simple name and a bitmask of + the access flags. */ + + info = c->innerclass + j; + + inner.ref = innerclass_getconstant(c, suck_u2(cb), CONSTANT_Class); + outer.ref = innerclass_getconstant(c, suck_u2(cb), CONSTANT_Class); + name = innerclass_getconstant(c, suck_u2(cb), CONSTANT_Utf8); + flags = suck_u2(cb); + + /* If the current inner-class is the currently loaded + class check for some special flags. */ + + if (inner.ref->name == c->name) { + /* If an inner-class is not a member, its + outer-class is NULL. */ + + if (outer.ref != NULL) { + c->flags |= ACC_CLASS_MEMBER; + + /* A member class doesn't have an + EnclosingMethod attribute, so set the + enclosing-class to be the same as the + declaring-class. */ + + c->declaringclass = outer; + c->enclosingclass = outer; + } + + /* If an inner-class is anonymous, its name is + NULL. */ + + if (name == NULL) + c->flags |= ACC_CLASS_ANONYMOUS; + } + + info->inner_class = inner; + info->outer_class = outer; + info->name = name; + info->flags = flags; + } + } + else if (attribute_name == utf_SourceFile) { + /* SourceFile */ + + if (!class_load_attribute_sourcefile(cb)) + return false; + } +#if defined(ENABLE_JAVASE) + else if (attribute_name == utf_EnclosingMethod) { + /* EnclosingMethod */ + + if (!class_load_attribute_enclosingmethod(cb)) + return false; + } + else if (attribute_name == utf_Signature) { + /* Signature */ + + if (!loader_load_attribute_signature(cb, &(c->signature))) + return false; + } +#endif + +#if defined(ENABLE_ANNOTATIONS) + else if (attribute_name == utf_RuntimeVisibleAnnotations) { + /* RuntimeVisibleAnnotations */ + if (!annotation_load_class_attribute_runtimevisibleannotations(cb)) + return false; + } + else if (attribute_name == utf_RuntimeInvisibleAnnotations) { + /* RuntimeInvisibleAnnotations */ + if (!annotation_load_class_attribute_runtimeinvisibleannotations(cb)) + return false; + } +#endif + + else { + /* unknown attribute */ + + if (!loader_skip_attribute_body(cb)) + return false; + } + } + + return true; +} + + +/* class_freepool ************************************************************** + + Frees all resources used by this classes Constant Pool. + +*******************************************************************************/ + +static void class_freecpool(classinfo *c) +{ + u4 idx; + u4 tag; + void* info; + + if (c->cptags && c->cpinfos) { + for (idx = 0; idx < c->cpcount; idx++) { + tag = c->cptags[idx]; + info = c->cpinfos[idx]; + + if (info != NULL) { + switch (tag) { + case CONSTANT_Fieldref: + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: + FREE(info, constant_FMIref); + break; + case CONSTANT_Integer: + FREE(info, constant_integer); + break; + case CONSTANT_Float: + FREE(info, constant_float); + break; + case CONSTANT_Long: + FREE(info, constant_long); + break; + case CONSTANT_Double: + FREE(info, constant_double); + break; + case CONSTANT_NameAndType: + FREE(info, constant_nameandtype); + break; + } + } + } + } + + if (c->cptags) + MFREE(c->cptags, u1, c->cpcount); + + if (c->cpinfos) + MFREE(c->cpinfos, void*, c->cpcount); +} + + +/* class_getconstant *********************************************************** + + Retrieves the value at position 'pos' of the constantpool of a + class. If the type of the value is other than 'ctype', an error is + thrown. + +*******************************************************************************/ + +void* class_getconstant(classinfo *c, u4 pos, u4 ctype) +{ + /* check index and type of constantpool entry */ + /* (pos == 0 is caught by type comparison) */ + + if ((pos >= c->cpcount) || (c->cptags[pos] != ctype)) { + exceptions_throw_classformaterror(c, "Illegal constant pool index"); + return NULL; + } + + return c->cpinfos[pos]; +} + + +/* innerclass_getconstant ****************************************************** + + Like class_getconstant, but if cptags is ZERO, null is returned. + +*******************************************************************************/ + +void* innerclass_getconstant(classinfo *c, u4 pos, u4 ctype) +{ + /* invalid position in constantpool */ + + if (pos >= c->cpcount) { + exceptions_throw_classformaterror(c, "Illegal constant pool index"); + return NULL; + } + + /* constantpool entry of type 0 */ + + if (c->cptags[pos] == 0) + return NULL; + + /* check type of constantpool entry */ + + if (c->cptags[pos] != ctype) { + exceptions_throw_classformaterror(c, "Illegal constant pool index"); + return NULL; + } + + return c->cpinfos[pos]; +} + + +/* class_free ****************************************************************** + + Frees all resources used by the class. + +*******************************************************************************/ + +void class_free(classinfo *c) +{ + s4 i; + vftbl_t *v; + + class_freecpool(c); + + if (c->interfaces != NULL) + MFREE(c->interfaces, classinfo*, c->interfacescount); + + if (c->fields) { + for (i = 0; i < c->fieldscount; i++) + field_free(&(c->fields[i])); + MFREE(c->fields, fieldinfo, c->fieldscount); + } + + if (c->methods) { + for (i = 0; i < c->methodscount; i++) + method_free(&(c->methods[i])); + MFREE(c->methods, methodinfo, c->methodscount); + } + + if ((v = c->vftbl) != NULL) { + if (v->arraydesc) + mem_free(v->arraydesc,sizeof(arraydescriptor)); + + for (i = 0; i < v->interfacetablelength; i++) { + MFREE(v->interfacetable[-i], methodptr, v->interfacevftbllength[i]); + } + MFREE(v->interfacevftbllength, s4, v->interfacetablelength); + + i = sizeof(vftbl_t) + sizeof(methodptr) * (v->vftbllength - 1) + + sizeof(methodptr*) * (v->interfacetablelength - + (v->interfacetablelength > 0)); + v = (vftbl_t*) (((methodptr*) v) - + (v->interfacetablelength - 1) * (v->interfacetablelength > 1)); + mem_free(v, i); + } + + if (c->innerclass) + MFREE(c->innerclass, innerclassinfo, c->innerclasscount); + + /* if (c->classvftbl) + mem_free(c->header.vftbl, sizeof(vftbl) + sizeof(methodptr)*(c->vftbl->vftbllength-1)); */ + +/* GCFREE(c); */ +} + + +/* get_array_class ************************************************************* + + Returns the array class with the given name for the given + classloader, or NULL if an exception occurred. + + Note: This function does eager loading. + +*******************************************************************************/ + +static classinfo *get_array_class(utf *name,classloader_t *initloader, + classloader_t *defloader,bool link) +{ + classinfo *c; + + /* lookup this class in the classcache */ + c = classcache_lookup(initloader,name); + if (!c) + c = classcache_lookup_defined(defloader,name); + + if (!c) { + /* we have to create it */ + c = class_create_classinfo(name); + c = load_newly_created_array(c,initloader); + if (c == NULL) + return NULL; + } + + assert(c); + assert(c->state & CLASS_LOADED); + assert(c->classloader == defloader); + + if (link && !(c->state & CLASS_LINKED)) + if (!link_class(c)) + return NULL; + + assert(!link || (c->state & CLASS_LINKED)); + + return c; +} + + +/* class_array_of ************************************************************** + + Returns an array class with the given component class. The array + class is dynamically created if neccessary. + +*******************************************************************************/ + +classinfo *class_array_of(classinfo *component, bool link) +{ + classloader_t *cl; + s4 namelen; + char *namebuf; + utf *u; + classinfo *c; + + cl = component->classloader; + + /* Assemble the array class name */ + namelen = component->name->blength; + + if (component->name->text[0] == '[') { + /* the component is itself an array */ + namebuf = MNEW(char, namelen + 1); + namebuf[0] = '['; + MCOPY(namebuf + 1, component->name->text, char, namelen); + namelen++; + } + else { + /* the component is a non-array class */ + namebuf = MNEW(char, namelen + 3); + namebuf[0] = '['; + namebuf[1] = 'L'; + MCOPY(namebuf + 2, component->name->text, char, namelen); + namebuf[2 + namelen] = ';'; + namelen += 3; + } + + u = utf_new(namebuf, namelen); + + MFREE(namebuf, char, namelen); + + c = get_array_class(u, cl, cl, link); + + return c; +} + + +/* class_multiarray_of ********************************************************* + + Returns an array class with the given dimension and element class. + The array class is dynamically created if neccessary. + +*******************************************************************************/ + +classinfo *class_multiarray_of(s4 dim, classinfo *element, bool link) +{ + s4 namelen; + char *namebuf; + classinfo *c; + + if (dim < 1) { + log_text("Invalid array dimension requested"); + assert(0); + } + + /* Assemble the array class name */ + namelen = element->name->blength; + + if (element->name->text[0] == '[') { + /* the element is itself an array */ + namebuf = MNEW(char, namelen + dim); + memcpy(namebuf + dim, element->name->text, namelen); + namelen += dim; + } + else { + /* the element is a non-array class */ + namebuf = MNEW(char, namelen + 2 + dim); + namebuf[dim] = 'L'; + memcpy(namebuf + dim + 1, element->name->text, namelen); + namelen += (2 + dim); + namebuf[namelen - 1] = ';'; + } + memset(namebuf, '[', dim); + + utf* u = utf_new(namebuf, namelen); + + MFREE(namebuf, char, namelen); + + c = get_array_class(u, + element->classloader, + element->classloader, + link); + + return c; +} + + +/* class_lookup_classref ******************************************************* + + Looks up the constant_classref for a given classname in the classref + tables of a class. + + IN: + cls..............the class containing the reference + name.............the name of the class refered to + + RETURN VALUE: + a pointer to a constant_classref, or + NULL if the reference was not found + +*******************************************************************************/ + +constant_classref *class_lookup_classref(classinfo *cls, utf *name) +{ + constant_classref *ref; + extra_classref *xref; + int count; + + assert(cls); + assert(name); + assert(!cls->classrefcount || cls->classrefs); + + /* first search the main classref table */ + count = cls->classrefcount; + ref = cls->classrefs; + for (; count; --count, ++ref) + if (ref->name == name) + return ref; + + /* next try the list of extra classrefs */ + for (xref = cls->extclassrefs; xref; xref = xref->next) { + if (xref->classref.name == name) + return &(xref->classref); + } + + /* not found */ + return NULL; +} + + +/* class_get_classref ********************************************************** + + Returns the constant_classref for a given classname. + + IN: + cls..............the class containing the reference + name.............the name of the class refered to + + RETURN VALUE: + a pointer to a constant_classref (never NULL) + + NOTE: + The given name is not checked for validity! + +*******************************************************************************/ + +constant_classref *class_get_classref(classinfo *cls, utf *name) +{ + constant_classref *ref; + extra_classref *xref; + + assert(cls); + assert(name); + + ref = class_lookup_classref(cls,name); + if (ref) + return ref; + + xref = NEW(extra_classref); + CLASSREF_INIT(xref->classref,cls,name); + + xref->next = cls->extclassrefs; + cls->extclassrefs = xref; + + return &(xref->classref); +} + + +/* class_get_self_classref ***************************************************** + + Returns the constant_classref to the class itself. + + IN: + cls..............the class containing the reference + + RETURN VALUE: + a pointer to a constant_classref (never NULL) + +*******************************************************************************/ + +constant_classref *class_get_self_classref(classinfo *cls) +{ + /* XXX this should be done in a faster way. Maybe always make */ + /* the classref of index 0 a self reference. */ + return class_get_classref(cls,cls->name); +} + +/* class_get_classref_multiarray_of ******************************************** + + Returns an array type reference with the given dimension and element class + reference. + + IN: + dim..............the requested dimension + dim must be in [1;255]. This is NOT checked! + ref..............the component class reference + + RETURN VALUE: + a pointer to the class reference for the array type + + NOTE: + The referer of `ref` is used as the referer for the new classref. + +*******************************************************************************/ + +constant_classref *class_get_classref_multiarray_of(s4 dim, constant_classref *ref) +{ + s4 namelen; + char *namebuf; + constant_classref *cr; + + assert(ref); + assert(dim >= 1 && dim <= 255); + + /* Assemble the array class name */ + namelen = ref->name->blength; + + if (ref->name->text[0] == '[') { + /* the element is itself an array */ + namebuf = MNEW(char, namelen + dim); + memcpy(namebuf + dim, ref->name->text, namelen); + namelen += dim; + } + else { + /* the element is a non-array class */ + namebuf = MNEW(char, namelen + 2 + dim); + namebuf[dim] = 'L'; + memcpy(namebuf + dim + 1, ref->name->text, namelen); + namelen += (2 + dim); + namebuf[namelen - 1] = ';'; + } + memset(namebuf, '[', dim); + + utf* u = utf_new(namebuf, namelen); + + MFREE(namebuf, char, namelen); + + cr = class_get_classref(ref->referer, u); + + return cr; +} + + +/* class_get_classref_component_of ********************************************* + + Returns the component classref of a given array type reference + + IN: + ref..............the array type reference + + RETURN VALUE: + a reference to the component class, or + NULL if `ref` is not an object array type reference + + NOTE: + The referer of `ref` is used as the referer for the new classref. + +*******************************************************************************/ + +constant_classref *class_get_classref_component_of(constant_classref *ref) +{ + s4 namelen; + char *name; + + assert(ref); + + name = ref->name->text; + if (*name++ != '[') + return NULL; + + namelen = ref->name->blength - 1; + if (*name == 'L') { + name++; + namelen -= 2; + } + else if (*name != '[') { + return NULL; + } + + return class_get_classref(ref->referer, utf_new(name, namelen)); +} + + +/* class_findmethod ************************************************************ + + Searches a 'classinfo' structure for a method having the given name + and descriptor. If descriptor is NULL, it is ignored. + +*******************************************************************************/ + +methodinfo *class_findmethod(classinfo *c, utf *name, utf *desc) +{ + methodinfo *m; + s4 i; + + for (i = 0; i < c->methodscount; i++) { + m = &(c->methods[i]); + + if ((m->name == name) && ((desc == NULL) || (m->descriptor == desc))) + return m; + } + + return NULL; +} + + +/* class_resolvemethod ********************************************************* + + Searches a class and it's super classes for a method. + + Superinterfaces are *not* searched. + +*******************************************************************************/ + +methodinfo *class_resolvemethod(classinfo *c, utf *name, utf *desc) +{ + methodinfo *m; + + while (c) { + m = class_findmethod(c, name, desc); + + if (m) + return m; + + /* JVM Specification bug: + + It is important NOT to resolve special and + methods to super classes or interfaces; yet, this is not + explicited in the specification. Section 5.4.3.3 should be + updated appropriately. */ + + if (name == utf_init || name == utf_clinit) + return NULL; + + c = c->super; + } + + return NULL; +} + + +/* class_resolveinterfacemethod_intern ***************************************** + + Internally used helper function. Do not use this directly. + +*******************************************************************************/ + +static methodinfo *class_resolveinterfacemethod_intern(classinfo *c, + utf *name, utf *desc) +{ + methodinfo *m; + s4 i; + + /* try to find the method in the class */ + + m = class_findmethod(c, name, desc); + + if (m != NULL) + return m; + + /* No method found? Try the super interfaces. */ + + for (i = 0; i < c->interfacescount; i++) { + m = class_resolveinterfacemethod_intern(c->interfaces[i], name, desc); + + if (m != NULL) + return m; + } + + /* no method found */ + + return NULL; +} + + +/* class_resolveclassmethod **************************************************** + + Resolves a reference from REFERER to a method with NAME and DESC in + class C. + + If the method cannot be resolved the return value is NULL. If + EXCEPT is true *exceptionptr is set, too. + +*******************************************************************************/ + +methodinfo *class_resolveclassmethod(classinfo *c, utf *name, utf *desc, + classinfo *referer, bool throwexception) +{ + classinfo *cls; + methodinfo *m; + s4 i; + +/* if (c->flags & ACC_INTERFACE) { */ +/* if (throwexception) */ +/* *exceptionptr = */ +/* new_exception(string_java_lang_IncompatibleClassChangeError); */ +/* return NULL; */ +/* } */ + + /* try class c and its superclasses */ + + cls = c; + + m = class_resolvemethod(cls, name, desc); + + if (m != NULL) + goto found; + + /* Try the super interfaces. */ + + for (i = 0; i < c->interfacescount; i++) { + m = class_resolveinterfacemethod_intern(c->interfaces[i], name, desc); + + if (m != NULL) + goto found; + } + + if (throwexception) + exceptions_throw_nosuchmethoderror(c, name, desc); + + return NULL; + + found: + if ((m->flags & ACC_ABSTRACT) && !(c->flags & ACC_ABSTRACT)) { + if (throwexception) + exceptions_throw_abstractmethoderror(); + + return NULL; + } + + /* XXX check access rights */ + + return m; +} + + +/* class_resolveinterfacemethod ************************************************ + + Resolves a reference from REFERER to a method with NAME and DESC in + interface C. + + If the method cannot be resolved the return value is NULL. If + EXCEPT is true *exceptionptr is set, too. + +*******************************************************************************/ + +methodinfo *class_resolveinterfacemethod(classinfo *c, utf *name, utf *desc, + classinfo *referer, bool throwexception) +{ + methodinfo *mi; + + if (!(c->flags & ACC_INTERFACE)) { + if (throwexception) + exceptions_throw_incompatibleclasschangeerror(c, "Not an interface"); + + return NULL; + } + + mi = class_resolveinterfacemethod_intern(c, name, desc); + + if (mi != NULL) + return mi; + + /* try class java.lang.Object */ + + mi = class_findmethod(class_java_lang_Object, name, desc); + + if (mi != NULL) + return mi; + + if (throwexception) + exceptions_throw_nosuchmethoderror(c, name, desc); + + return NULL; +} + + +/* class_findfield ************************************************************* + + Searches for field with specified name and type in a classinfo + structure. If no such field is found NULL is returned. + +*******************************************************************************/ + +fieldinfo *class_findfield(classinfo *c, utf *name, utf *desc) +{ + s4 i; + + for (i = 0; i < c->fieldscount; i++) + if ((c->fields[i].name == name) && (c->fields[i].descriptor == desc)) + return &(c->fields[i]); + + if (c->super != NULL) + return class_findfield(c->super, name, desc); + + return NULL; +} + + +/* class_findfield_approx ****************************************************** + + Searches in 'classinfo'-structure for a field with the specified + name. + +*******************************************************************************/ + +fieldinfo *class_findfield_by_name(classinfo* c, utf* name) +{ + for (int32_t i = 0; i < c->fieldscount; i++) { + fieldinfo* f = &(c->fields[i]); + + if (f->name == name) + return f; + } + + // Field not found. + exceptions_throw_nosuchfielderror(c, name); + return NULL; +} + + +/****************** Function: class_resolvefield_int *************************** + + This is an internally used helper function. Do not use this directly. + + Tries to resolve a field having the given name and type. + If the field cannot be resolved, NULL is returned. + +*******************************************************************************/ + +static fieldinfo *class_resolvefield_int(classinfo *c, utf *name, utf *desc) +{ + fieldinfo *fi; + s4 i; + + /* search for field in class c */ + + for (i = 0; i < c->fieldscount; i++) { + if ((c->fields[i].name == name) && (c->fields[i].descriptor == desc)) { + return &(c->fields[i]); + } + } + + /* Try super interfaces recursively. */ + + for (i = 0; i < c->interfacescount; i++) { + fi = class_resolvefield_int(c->interfaces[i], name, desc); + + if (fi != NULL) + return fi; + } + + /* Try super class. */ + + if (c->super != NULL) + return class_resolvefield_int(c->super, name, desc); + + /* not found */ + + return NULL; +} + + +/********************* Function: class_resolvefield *************************** + + Resolves a reference from REFERER to a field with NAME and DESC in class C. + + If the field cannot be resolved, an exception is thrown and the + return value is NULL. + +*******************************************************************************/ + +fieldinfo *class_resolvefield(classinfo *c, utf *name, utf *desc, classinfo *referer) +{ + fieldinfo *fi; + + fi = class_resolvefield_int(c, name, desc); + + if (!fi) { + exceptions_throw_nosuchfielderror(c, name); + return NULL; + } + + /* XXX check access rights */ + + return fi; +} + + +/* class_issubclass ************************************************************ + + Checks if sub is a descendant of super. + +*******************************************************************************/ + +bool class_issubclass(classinfo *sub, classinfo *super) +{ + classinfo *c; + + c = sub; + + for (;;) { + /* We reached java/lang/Object and did not find the requested + super class. */ + + if (c == NULL) + return false; + + /* We found the requested super class. */ + + if (c == super) + return true; + + c = c->super; + } +} + + +/* class_isanysubclass ********************************************************* + + Checks a subclass relation between two classes. Implemented + interfaces are interpreted as super classes. + + Return value: 1 ... sub is subclass of super + 0 ... otherwise + +*******************************************************************************/ + +bool class_isanysubclass(classinfo *sub, classinfo *super) +{ + uint32_t diffval; + bool result; + + /* This is the trivial case. */ + + if (sub == super) + return true; + + /* Primitive classes are only subclasses of themselves. */ + + if (class_is_primitive(sub) || class_is_primitive(super)) + return false; + + /* Check for interfaces. */ + + if (super->flags & ACC_INTERFACE) { + result = (sub->vftbl->interfacetablelength > super->index) && + (sub->vftbl->interfacetable[-super->index] != NULL); + } + else { + /* java.lang.Object is the only super class of any + interface. */ + + if (sub->flags & ACC_INTERFACE) + return (super == class_java_lang_Object); + - Mutex_lock(linker_classrenumber_mutex); - - diffval = sub->vftbl->baseval - super->vftbl->baseval; - result = diffval <= (uint32_t) super->vftbl->diffval; - - Mutex_unlock(linker_classrenumber_mutex); ++ result = fast_subtype_check(sub->vftbl, super->vftbl); + } + + return result; +} + + +/* class_is_assignable_from **************************************************** + + Return whether an instance of the "from" class parameter would be + an instance of this class "to" as well. + + ARGUMENTS: + to ..... class + from ... class + + RETURN: + true .... is assignable + false ... is not assignable + +*******************************************************************************/ + +bool class_is_assignable_from(classinfo *to, classinfo *from) +{ + if (!(to->state & CLASS_LINKED)) + if (!link_class(to)) + return false; + + if (!(from->state & CLASS_LINKED)) + if (!link_class(from)) + return false; + + return class_isanysubclass(from, to); +} + + +/* class_is_instance *********************************************************** + + Return if the given Java object is an instance of the given class. + + ARGUMENTS: + c ... class + h ... Java object + + RETURN: + true .... is instance + false ... is not instance + +*******************************************************************************/ + +bool class_is_instance(classinfo *c, java_handle_t *h) +{ + if (!(c->state & CLASS_LINKED)) + if (!link_class(c)) + return false; + + return builtin_instanceof(h, c); +} + + +/* class_get_componenttype ***************************************************** + + Return the component class of the given class. If the given class + is not an array, return NULL. + +*******************************************************************************/ + +classinfo *class_get_componenttype(classinfo *c) +{ + classinfo *component; + arraydescriptor *ad; + + /* XXX maybe we could find a way to do this without linking. */ + /* This way should be safe and easy, however. */ + + if (!(c->state & CLASS_LINKED)) + if (!link_class(c)) + return NULL; + + ad = c->vftbl->arraydesc; + + if (ad == NULL) + return NULL; + + if (ad->arraytype == ARRAYTYPE_OBJECT) + component = ad->componentvftbl->clazz; + else + component = Primitive_get_class_by_type(ad->arraytype); + + return component; +} + + +/* class_get_declaredclasses *************************************************** + + Return an array of declared classes of the given class. + +*******************************************************************************/ + +java_handle_objectarray_t *class_get_declaredclasses(classinfo *c, bool publicOnly) +{ + classref_or_classinfo inner; + classref_or_classinfo outer; + utf *outername; + int declaredclasscount; /* number of declared classes */ + int pos; /* current declared class */ + java_handle_objectarray_t *oa; /* array of declared classes */ + int i; + classinfo *ic; + + declaredclasscount = 0; + + if (!class_is_primitive(c) && !class_is_array(c)) { + /* Determine number of declared classes. */ + + for (i = 0; i < c->innerclasscount; i++) { + /* Get outer-class. If the inner-class is not a member + class, the outer-class is NULL. */ + + outer = c->innerclass[i].outer_class; + + if (outer.any == NULL) + continue; + + /* Check if outer-class is a classref or a real class and + get the class name from the structure. */ + + outername = IS_CLASSREF(outer) ? outer.ref->name : outer.cls->name; + + /* Outer class is this class. */ + + if ((outername == c->name) && + ((publicOnly == 0) || (c->innerclass[i].flags & ACC_PUBLIC))) + declaredclasscount++; + } + } + + /* Allocate Class[] and check for OOM. */ + + oa = builtin_anewarray(declaredclasscount, class_java_lang_Class); + + if (oa == NULL) + return NULL; + + for (i = 0, pos = 0; i < c->innerclasscount; i++) { + inner = c->innerclass[i].inner_class; + outer = c->innerclass[i].outer_class; + + /* Get outer-class. If the inner-class is not a member class, + the outer-class is NULL. */ + + if (outer.any == NULL) + continue; + + /* Check if outer_class is a classref or a real class and get + the class name from the structure. */ + + outername = IS_CLASSREF(outer) ? outer.ref->name : outer.cls->name; + + /* Outer class is this class. */ + + if ((outername == c->name) && + ((publicOnly == 0) || (c->innerclass[i].flags & ACC_PUBLIC))) { + + ic = resolve_classref_or_classinfo_eager(inner, false); + + if (ic == NULL) + return NULL; + + if (!(ic->state & CLASS_LINKED)) + if (!link_class(ic)) + return NULL; + + LLNI_array_direct(oa, pos++) = (java_object_t *) ic; + } + } + + return oa; +} + + +/** + * Return an array of declared constructors of the given class. + * + * @param c class to get the constructors of + * @param publicOnly show only public fields + * + * @return array of java.lang.reflect.Constructor + */ +#if defined(ENABLE_JAVASE) +java_handle_objectarray_t *class_get_declaredconstructors(classinfo *c, bool publicOnly) +{ + methodinfo* m; + java_handle_objectarray_t* oa; + java_handle_t* rc; + int count; + int index; + int i; + + /* Determine number of constructors. */ + + count = 0; + + for (i = 0; i < c->methodscount; i++) { + m = &(c->methods[i]); + + if (((m->flags & ACC_PUBLIC) || (publicOnly == 0)) && + (m->name == utf_init)) + count++; + } + + /* Create array of constructors. */ + + oa = builtin_anewarray(count, class_java_lang_reflect_Constructor); + + if (oa == NULL) + return NULL; + + /* Get the constructors and store them in the array. */ + + for (i = 0, index = 0; i < c->methodscount; i++) { + m = &(c->methods[i]); + + if (((m->flags & ACC_PUBLIC) || (publicOnly == 0)) && + (m->name == utf_init)) { + // Create a java.lang.reflect.Constructor object. + + rc = java_lang_reflect_Constructor_create(m); + + /* Store object into array. */ + + array_objectarray_element_set(oa, index, rc); + index++; + } + } + + return oa; +} +#endif + + +/* class_get_declaredfields **************************************************** + + Return an array of declared fields of the given class. + + ARGUMENTS: + c ............ class to get the fields of + publicOnly ... show only public fields + + RETURN: + array of java.lang.reflect.Field + +*******************************************************************************/ + +#if defined(ENABLE_JAVASE) +java_handle_objectarray_t *class_get_declaredfields(classinfo *c, bool publicOnly) +{ + java_handle_objectarray_t *oa; + fieldinfo *f; + java_handle_t *h; + int count; + int index; + int i; + + /* Determine number of fields. */ + + count = 0; + + for (i = 0; i < c->fieldscount; i++) + if ((c->fields[i].flags & ACC_PUBLIC) || (publicOnly == 0)) + count++; + + /* Create array of fields. */ + + oa = builtin_anewarray(count, class_java_lang_reflect_Field); + + if (oa == NULL) + return NULL; + + /* Get the fields and store them in the array. */ + + for (i = 0, index = 0; i < c->fieldscount; i++) { + f = &(c->fields[i]); + + if ((f->flags & ACC_PUBLIC) || (publicOnly == 0)) { + // Create a java.lang.reflect.Field object. + + h = java_lang_reflect_Field_create(f); + + /* Store object into array. */ + + array_objectarray_element_set(oa, index, h); + index++; + } + } + + return oa; +} +#endif + + +/* class_get_declaredmethods *************************************************** + + Return an array of declared methods of the given class. + + ARGUMENTS: + c ............ class to get the methods of + publicOnly ... show only public methods + + RETURN: + array of java.lang.reflect.Method + +*******************************************************************************/ + +#if defined(ENABLE_JAVASE) +java_handle_objectarray_t *class_get_declaredmethods(classinfo *c, bool publicOnly) +{ + java_handle_objectarray_t *oa; /* result: array of Method-objects */ + methodinfo *m; /* the current method to be represented */ + java_handle_t *h; + int count; + int index; + int i; + + /* JOWENN: array classes do not declare methods according to mauve + test. It should be considered, if we should return to my old + clone method overriding instead of declaring it as a member + function. */ + + if (class_is_array(c)) + return builtin_anewarray(0, class_java_lang_reflect_Method); + + /* Determine number of methods. */ + + count = 0; + + for (i = 0; i < c->methodscount; i++) { + m = &(c->methods[i]); + + if (((m->flags & ACC_PUBLIC) || (publicOnly == false)) && + ((m->name != utf_init) && (m->name != utf_clinit)) && + !(m->flags & ACC_MIRANDA)) + count++; + } + + /* Create array of methods. */ + + oa = builtin_anewarray(count, class_java_lang_reflect_Method); + + if (oa == NULL) + return NULL; + + /* Get the methods and store them in the array. */ + + for (i = 0, index = 0; i < c->methodscount; i++) { + m = &(c->methods[i]); + + if (((m->flags & ACC_PUBLIC) || (publicOnly == false)) && + ((m->name != utf_init) && (m->name != utf_clinit)) && + !(m->flags & ACC_MIRANDA)) { + // Create java.lang.reflect.Method object. + + h = java_lang_reflect_Method_create(m); + + /* Store object into array. */ + + array_objectarray_element_set(oa, index, h); + index++; + } + } + + return oa; +} +#endif + + +/* class_get_declaringclass **************************************************** + + If the class or interface given is a member of another class, + return the declaring class. For array and primitive classes return + NULL. + +*******************************************************************************/ + +classinfo *class_get_declaringclass(classinfo *c) +{ + classref_or_classinfo cr; + classinfo *dc; + + /* Get declaring class. */ + + cr = c->declaringclass; + + if (cr.any == NULL) + return NULL; + + /* Resolve the class if necessary. */ + + if (IS_CLASSREF(cr)) { +/* dc = resolve_classref_eager(cr.ref); */ + dc = resolve_classref_or_classinfo_eager(cr, true); + + if (dc == NULL) + return NULL; + + /* Store the resolved class in the class structure. */ + + cr.cls = dc; + } + + dc = cr.cls; + + return dc; +} + + +/* class_get_enclosingclass **************************************************** + + Return the enclosing class for the given class. + +*******************************************************************************/ + +classinfo *class_get_enclosingclass(classinfo *c) +{ + classref_or_classinfo cr; + classinfo *ec; + + /* Get enclosing class. */ + + cr = c->enclosingclass; + + if (cr.any == NULL) + return NULL; + + /* Resolve the class if necessary. */ + + if (IS_CLASSREF(cr)) { +/* ec = resolve_classref_eager(cr.ref); */ + ec = resolve_classref_or_classinfo_eager(cr, true); + + if (ec == NULL) + return NULL; + + /* Store the resolved class in the class structure. */ + + cr.cls = ec; + } + + ec = cr.cls; + + return ec; +} + + +/** + * Return the enclosing constructor as java.lang.reflect.Constructor + * object for the given class. + * + * @param c class to return the enclosing constructor for + * + * @return java.lang.reflect.Constructor object of the enclosing + * constructor + */ +#if defined(ENABLE_JAVASE) +java_handle_t* class_get_enclosingconstructor(classinfo *c) +{ + methodinfo* m; + java_handle_t* rc; + + m = class_get_enclosingmethod_raw(c); + + if (m == NULL) + return NULL; + + /* Check for . */ + + if (m->name != utf_init) + return NULL; + + // Create a java.lang.reflect.Constructor object. + + rc = java_lang_reflect_Constructor_create(m); + + return rc; +} +#endif + + +/* class_get_enclosingmethod *************************************************** + + Return the enclosing method for the given class. + + IN: + c ... class to return the enclosing method for + + RETURN: + methodinfo of the enclosing method + +*******************************************************************************/ + +methodinfo *class_get_enclosingmethod_raw(classinfo *c) +{ + constant_nameandtype *cn; + classinfo *ec; + methodinfo *m; + + /* get enclosing class and method */ + + ec = class_get_enclosingclass(c); + cn = c->enclosingmethod; + + /* check for enclosing class and method */ + + if (ec == NULL) + return NULL; + + if (cn == NULL) + return NULL; + + /* find method in enclosing class */ + + m = class_findmethod(ec, cn->name, cn->descriptor); + + if (m == NULL) { + exceptions_throw_internalerror("Enclosing method doesn't exist"); + return NULL; + } + + return m; +} + + +/** + * Return the enclosing method as java.lang.reflect.Method object for + * the given class. + * + * @param c class to return the enclosing method for + * + * @return java.lang.reflect.Method object of the enclosing method + */ +#if defined(ENABLE_JAVASE) +java_handle_t* class_get_enclosingmethod(classinfo *c) +{ + methodinfo* m; + java_handle_t* rm; + + m = class_get_enclosingmethod_raw(c); + + if (m == NULL) + return NULL; + + /* check for */ + + if (m->name == utf_init) + return NULL; + + // Create a java.lang.reflect.Method object. + + rm = java_lang_reflect_Method_create(m); + + return rm; +} +#endif + + +/* class_get_interfaces ******************************************************** + + Return an array of interfaces of the given class. + +*******************************************************************************/ + +java_handle_objectarray_t *class_get_interfaces(classinfo *c) +{ + classinfo *ic; + java_handle_objectarray_t *oa; + u4 i; + + if (!(c->state & CLASS_LINKED)) + if (!link_class(c)) + return NULL; + + oa = builtin_anewarray(c->interfacescount, class_java_lang_Class); + + if (oa == NULL) + return NULL; + + for (i = 0; i < c->interfacescount; i++) { + ic = c->interfaces[i]; + + LLNI_array_direct(oa, i) = (java_object_t *) ic; + } + + return oa; +} + + +/* class_get_annotations ******************************************************* + + Get the unparsed declared annotations in a byte array + of the given class. + + IN: + c........the class of which the annotations should be returned + + RETURN VALUE: + The unparsed declared annotations in a byte array + (or NULL if there aren't any). + +*******************************************************************************/ + +java_handle_bytearray_t *class_get_annotations(classinfo *c) +{ +#if defined(ENABLE_ANNOTATIONS) + java_handle_t *annotations; /* unparsed annotations */ + + LLNI_classinfo_field_get(c, annotations, annotations); + + return (java_handle_bytearray_t*)annotations; +#else + return NULL; +#endif +} + + +/* class_get_modifiers ********************************************************* + + Get the modifier flags of the given class. + + IN: + c....the class of which the modifier flags should be returned + ignoreInnerClassesAttrib + RETURN VALUE: + modifier flags + +*******************************************************************************/ + +int32_t class_get_modifiers(classinfo *c, bool ignoreInnerClassesAttrib) +{ + classref_or_classinfo inner; + classref_or_classinfo outer; + utf *innername; + int i; + + if (!ignoreInnerClassesAttrib && (c->innerclasscount != 0)) { + /* search for passed class as inner class */ + + for (i = 0; i < c->innerclasscount; i++) { + inner = c->innerclass[i].inner_class; + outer = c->innerclass[i].outer_class; + + /* Check if inner is a classref or a real class and get + the name of the structure */ + + innername = IS_CLASSREF(inner) ? inner.ref->name : inner.cls->name; + + /* innerclass is this class */ + + if (innername == c->name) { + /* has the class actually an outer class? */ + + if (outer.any) + /* return flags got from the outer class file */ + return c->innerclass[i].flags & ACC_CLASS_REFLECT_MASK; + else + return c->flags & ACC_CLASS_REFLECT_MASK; + } + } + } + + /* passed class is no inner class or it was not requested */ + + return c->flags & ACC_CLASS_REFLECT_MASK; +} + + +/* class_get_signature ********************************************************* + + Return the signature of the given class. For array and primitive + classes return NULL. + +*******************************************************************************/ + +#if defined(ENABLE_JAVASE) +utf *class_get_signature(classinfo *c) +{ + /* For array and primitive classes return NULL. */ + + if (class_is_array(c) || class_is_primitive(c)) + return NULL; + + return c->signature; +} +#endif + + +/* class_printflags ************************************************************ + + Prints flags of a class. + +*******************************************************************************/ + +#if !defined(NDEBUG) +void class_printflags(classinfo *c) +{ + if (c == NULL) { + printf("NULL"); + return; + } + + if (c->flags & ACC_PUBLIC) printf(" PUBLIC"); + if (c->flags & ACC_PRIVATE) printf(" PRIVATE"); + if (c->flags & ACC_PROTECTED) printf(" PROTECTED"); + if (c->flags & ACC_STATIC) printf(" STATIC"); + if (c->flags & ACC_FINAL) printf(" FINAL"); + if (c->flags & ACC_SYNCHRONIZED) printf(" SYNCHRONIZED"); + if (c->flags & ACC_VOLATILE) printf(" VOLATILE"); + if (c->flags & ACC_TRANSIENT) printf(" TRANSIENT"); + if (c->flags & ACC_NATIVE) printf(" NATIVE"); + if (c->flags & ACC_INTERFACE) printf(" INTERFACE"); + if (c->flags & ACC_ABSTRACT) printf(" ABSTRACT"); +} +#endif + + +/* class_print ***************************************************************** + + Prints classname plus flags. + +*******************************************************************************/ + +#if !defined(NDEBUG) +void class_print(classinfo *c) +{ + if (c == NULL) { + printf("NULL"); + return; + } + + utf_display_printable_ascii(c->name); + class_printflags(c); +} +#endif + + +/* class_classref_print ******************************************************** + + Prints classname plus referer class. + +*******************************************************************************/ + +#if !defined(NDEBUG) +void class_classref_print(constant_classref *cr) +{ + if (cr == NULL) { + printf("NULL"); + return; + } + + utf_display_printable_ascii(cr->name); + printf("(ref.by "); + if (cr->referer) + class_print(cr->referer); + else + printf("NULL"); + printf(")"); +} +#endif + + +/* class_println *************************************************************** + + Prints classname plus flags and new line. + +*******************************************************************************/ + +#if !defined(NDEBUG) +void class_println(classinfo *c) +{ + class_print(c); + printf("\n"); +} +#endif + + +/* class_classref_println ****************************************************** + + Prints classname plus referer class and new line. + +*******************************************************************************/ + +#if !defined(NDEBUG) +void class_classref_println(constant_classref *cr) +{ + class_classref_print(cr); + printf("\n"); +} +#endif + + +/* class_classref_or_classinfo_print ******************************************* + + Prints classname plus referer class. + +*******************************************************************************/ + +#if !defined(NDEBUG) +void class_classref_or_classinfo_print(classref_or_classinfo c) +{ + if (c.any == NULL) { + printf("(classref_or_classinfo) NULL"); + return; + } + if (IS_CLASSREF(c)) + class_classref_print(c.ref); + else + class_print(c.cls); +} +#endif + + +/* class_classref_or_classinfo_println ***************************************** + + Prints classname plus referer class and a newline. + +*******************************************************************************/ + +#if !defined(NDEBUG) +void class_classref_or_classinfo_println(classref_or_classinfo c) +{ + class_classref_or_classinfo_print(c); + printf("\n"); +} +#endif + + +/* class_showconstantpool ****************************************************** + + Dump the constant pool of the given class to stdout. + +*******************************************************************************/ + +#if !defined(NDEBUG) +void class_showconstantpool (classinfo *c) +{ + u4 i; + void* e; + + printf ("---- dump of constant pool ----\n"); + + for (i=0; icpcount; i++) { + printf ("#%d: ", (int) i); + + e = c -> cpinfos [i]; + if (e) { + + switch (c -> cptags [i]) { + case CONSTANT_Class: + printf ("Classreference -> "); + utf_display_printable_ascii ( ((constant_classref*)e) -> name ); + break; + case CONSTANT_Fieldref: + printf ("Fieldref -> "); + field_fieldref_print((constant_FMIref *) e); + break; + case CONSTANT_Methodref: + printf ("Methodref -> "); + method_methodref_print((constant_FMIref *) e); + break; + case CONSTANT_InterfaceMethodref: + printf ("InterfaceMethod -> "); + method_methodref_print((constant_FMIref *) e); + break; + case CONSTANT_String: + printf ("String -> "); + utf_display_printable_ascii (e); + break; + case CONSTANT_Integer: + printf ("Integer -> %d", (int) ( ((constant_integer*)e) -> value) ); + break; + case CONSTANT_Float: + printf ("Float -> %f", ((constant_float*)e) -> value); + break; + case CONSTANT_Double: + printf ("Double -> %f", ((constant_double*)e) -> value); + break; + case CONSTANT_Long: + { + u8 v = ((constant_long*)e) -> value; +#if U8_AVAILABLE + printf ("Long -> %ld", (long int) v); +#else + printf ("Long -> HI: %ld, LO: %ld\n", + (long int) v.high, (long int) v.low); +#endif + } + break; + case CONSTANT_NameAndType: + { + constant_nameandtype *cnt = e; + printf ("NameAndType: "); + utf_display_printable_ascii (cnt->name); + printf (" "); + utf_display_printable_ascii (cnt->descriptor); + } + break; + case CONSTANT_Utf8: + printf ("Utf8 -> "); + utf_display_printable_ascii (e); + break; + default: + log_text("Invalid type of ConstantPool-Entry"); + assert(0); + } + } + + printf ("\n"); + } +} +#endif /* !defined(NDEBUG) */ + + +/* class_showmethods *********************************************************** + + Dump info about the fields and methods of the given class to stdout. + +*******************************************************************************/ + +#if !defined(NDEBUG) +void class_showmethods (classinfo *c) +{ + s4 i; + + printf("--------- Fields and Methods ----------------\n"); + printf("Flags: "); + class_printflags(c); + printf("\n"); + + printf("This: "); + utf_display_printable_ascii(c->name); + printf("\n"); + + if (c->super) { + printf("Super: "); + utf_display_printable_ascii(c->super->name); + printf ("\n"); + } + + printf("Index: %d\n", c->index); + + printf("Interfaces:\n"); + for (i = 0; i < c->interfacescount; i++) { + printf(" "); + utf_display_printable_ascii(c->interfaces[i]->name); + printf (" (%d)\n", c->interfaces[i]->index); + } + + printf("Fields:\n"); + for (i = 0; i < c->fieldscount; i++) + field_println(&(c->fields[i])); + + printf("Methods:\n"); + for (i = 0; i < c->methodscount; i++) { + methodinfo *m = &(c->methods[i]); + + if (!(m->flags & ACC_STATIC)) + printf("vftblindex: %d ", m->vftblindex); + + method_println(m); + } + + printf ("Virtual function table:\n"); + for (i = 0; i < c->vftbl->vftbllength; i++) + printf ("entry: %d, %ld\n", i, (long int) (c->vftbl->table[i])); +} +#endif /* !defined(NDEBUG) */ + + +/* + * 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: + */ diff --cc src/vm/jit/builtin.cpp index a343bd406,000000000..5dbd12a75 mode 100644,000000..100644 --- a/src/vm/jit/builtin.cpp +++ b/src/vm/jit/builtin.cpp @@@ -1,2424 -1,0 +1,2422 @@@ +/* src/vm/jit/builtin.cpp - functions for unsupported operations + + Copyright (C) 1996-2005, 2006, 2007, 2008 + CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO + + 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. + +*/ + + +#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.hpp" +#include "mm/memory.h" + +#include "native/llni.h" + +#include "threads/lock-common.h" +#include "threads/mutex.hpp" +#include "threads/thread.hpp" + +#include "toolbox/logging.h" +#include "toolbox/util.h" + +#include "vm/array.h" +#include "vm/jit/builtin.hpp" +#include "vm/class.h" +#include "vm/cycles-stats.h" +#include "vm/exceptions.hpp" +#include "vm/global.h" +#include "vm/globals.hpp" +#include "vm/initialize.h" +#include "vm/linker.h" +#include "vm/loader.hpp" +#include "vm/options.h" +#include "vm/primitive.hpp" +#include "vm/rt-timing.h" +#include "vm/string.hpp" + +#include "vm/jit/asmpart.h" +#include "vm/jit/stubs.hpp" +#include "vm/jit/trace.hpp" + +#if defined(ENABLE_VMLOG) +#include +#endif + + +/* include builtin tables *****************************************************/ + +#include "vm/jit/builtintable.inc" + + +CYCLES_STATS_DECLARE(builtin_new ,100,5) +CYCLES_STATS_DECLARE(builtin_overhead , 80,1) + + +/*============================================================================*/ +/* BUILTIN TABLE MANAGEMENT FUNCTIONS */ +/*============================================================================*/ + +/* builtintable_init *********************************************************** + + Parse the descriptors of builtin functions and create the parsed + descriptors. + +*******************************************************************************/ + +static bool builtintable_init(void) +{ + descriptor_pool *descpool; + builtintable_entry *bte; + methodinfo *m; + + // Create new dump memory area. + DumpMemoryArea dma; + + /* 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++) { + bte->name = utf_new_char(bte->cname); + bte->descriptor = utf_new_char(bte->cdescriptor); + + if (!descriptor_pool_add(descpool, bte->descriptor, NULL)) + 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)) + 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)) + 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) { + m = method_new_builtin(bte); + BuiltinStub::generate(m, 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); + + /* no stubs should be needed for this table */ + + assert(!bte->flags & BUILTINTABLE_FLAG_STUB); + } + + for (bte = builtintable_function; 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) { + m = method_new_builtin(bte); + BuiltinStub::generate(m, bte); + } + } + + 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) +{ + TRACESUBSYSTEMINITIALIZATION("builtin_init"); + + /* 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) */ + + +/*============================================================================*/ +/* INTERNAL BUILTIN FUNCTIONS */ +/*============================================================================*/ + +/* 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 + + NOTE: This builtin can be called from NATIVE code only. + +*******************************************************************************/ + +bool builtin_instanceof(java_handle_t *o, classinfo *c) +{ + classinfo *oc; + + if (o == NULL) + return 0; + + LLNI_class_get(o, oc); + + return class_isanysubclass(oc, c); +} + + + +/* builtin_checkcast *********************************************************** + + The same as builtin_instanceof but with the exception + that 1 is returned when (o == NULL). + + NOTE: This builtin can be called from NATIVE code only. + +*******************************************************************************/ + +bool builtin_checkcast(java_handle_t *o, classinfo *c) +{ + classinfo *oc; + + if (o == NULL) + return 1; + + LLNI_class_get(o, oc); + + if (class_isanysubclass(oc, c)) + 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 bool 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) { + if (!desc->elementvftbl) + return 0; + /* 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->clazz, + target->elementvftbl->clazz); + } + + if (desc->dimension < target->dimension) + return 0; + + /* {desc has higher dimension than target} */ + + return class_isanysubclass(pseudo_class_Arraystub, + target->elementvftbl->clazz); +} + + +/* 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. + + NOTE: This is a FAST builtin and can be called from JIT code only. + +*******************************************************************************/ + +bool builtin_fast_arraycheckcast(java_object_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); +} + + +/* builtin_fast_arrayinstanceof ************************************************ + + NOTE: This is a FAST builtin and can be called from JIT code only. + +*******************************************************************************/ + +bool builtin_fast_arrayinstanceof(java_object_t *o, classinfo *targetclass) +{ + if (o == NULL) + return 0; + + return builtin_fast_arraycheckcast(o, targetclass); +} + + +/* builtin_arrayinstanceof ***************************************************** + + NOTE: This builtin can be called from NATIVE code only. + +*******************************************************************************/ + +bool builtin_arrayinstanceof(java_handle_t *h, classinfo *targetclass) +{ + bool result; + + LLNI_CRITICAL_START; + + result = builtin_fast_arrayinstanceof(LLNI_UNWRAP(h), targetclass); + + LLNI_CRITICAL_END; + + return result; +} + + +/* builtin_throw_exception ***************************************************** + + Sets the exception pointer with the thrown exception and prints some + debugging information. + + NOTE: This is a FAST builtin and can be called from JIT code, + or from asm_vm_call_method. + +*******************************************************************************/ + +void *builtin_throw_exception(java_object_t *xptr) +{ +#if !defined(NDEBUG) + /* print exception trace */ + + if (opt_TraceExceptions) + trace_exception_builtin(xptr); +#endif /* !defined(NDEBUG) */ + + /* actually set the exception */ + + exceptions_set_exception(LLNI_QUICKWRAP(xptr)); + + /* Return a NULL pointer. This is required for vm_call_method to + check for an exception. This is for convenience. */ + + return NULL; +} + + +/* builtin_retrieve_exception ************************************************** + + Gets and clears the exception pointer of the current thread. + + RETURN VALUE: + the exception object, or NULL if no exception was thrown. + + NOTE: This is a FAST builtin and can be called from JIT code, + or from the signal handlers. + +*******************************************************************************/ + +java_object_t *builtin_retrieve_exception(void) +{ + java_handle_t *h; + java_object_t *o; + + /* actually get and clear the exception */ + + h = exceptions_get_and_clear_exception(); + o = LLNI_UNWRAP(h); + + return o; +} + + +/* builtin_canstore ************************************************************ + + Checks, if an object can be stored in an array. + + RETURN VALUE: + 1......possible + 0......otherwise (throws an ArrayStoreException) + + NOTE: This is a SLOW builtin and can be called from JIT & NATIVE code. + +*******************************************************************************/ + +bool builtin_canstore(java_handle_objectarray_t *oa, java_handle_t *o) +{ + bool result; + + LLNI_CRITICAL_START; + + result = builtin_fast_canstore(LLNI_DIRECT(oa), LLNI_UNWRAP(o)); + + LLNI_CRITICAL_END; + + /* if not possible, throw an exception */ + + if (result == 0) + exceptions_throw_arraystoreexception(); + + return result; +} + + +/* builtin_fast_canstore ******************************************************* + + Checks, if an object can be stored in an array. + + RETURN VALUE: + 1......possible + 0......otherwise (no exception thrown!) + + NOTE: This is a FAST builtin and can be called from JIT code only. + +*******************************************************************************/ + ++bool fast_subtype_check(struct _vftbl *s, struct _vftbl *t) ++{ ++ int i; ++ if (s->subtype_display[t->subtype_depth] == t) ++ return true; ++ if (t->subtype_offset != OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE])) ++ return false; ++ for (i=0; isubtype_overflow_length; i++) ++ if (s->subtype_overflow[i] == t) ++ return true; ++ return false; ++} ++ +bool builtin_fast_canstore(java_objectarray_t *oa, java_object_t *o) +{ + arraydescriptor *desc; + arraydescriptor *valuedesc; + vftbl_t *componentvftbl; + vftbl_t *valuevftbl; + int32_t baseval; + uint32_t diffval; + bool 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; + - linker_classrenumber_mutex->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; ++ result = fast_subtype_check(valuevftbl, componentvftbl); + } - - linker_classrenumber_mutex->unlock(); + } + 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); + } + + /* return result */ + + return result; +} + + +/* This is an optimized version where a is guaranteed to be one-dimensional */ +bool builtin_fast_canstore_onedim(java_objectarray_t *a, java_object_t *o) +{ + arraydescriptor *desc; + vftbl_t *elementvftbl; + vftbl_t *valuevftbl; + int32_t baseval; + uint32_t diffval; + bool 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; + - linker_classrenumber_mutex->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; ++ result = fast_subtype_check(valuevftbl, elementvftbl); + } + - linker_classrenumber_mutex->unlock(); - + return result; +} + + +/* This is an optimized version where a is guaranteed to be a + * one-dimensional array of a class type */ +bool builtin_fast_canstore_onedim_class(java_objectarray_t *a, java_object_t *o) +{ + vftbl_t *elementvftbl; + vftbl_t *valuevftbl; + uint32_t diffval; + bool 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; + - linker_classrenumber_mutex->lock(); - - diffval = valuevftbl->baseval - elementvftbl->baseval; - result = diffval <= (uint32_t) elementvftbl->diffval; - - linker_classrenumber_mutex->unlock(); ++ result = fast_subtype_check(valuevftbl, elementvftbl); + + 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 + + NOTE: This builtin can be called from NATIVE code only. + +*******************************************************************************/ + +java_handle_t *builtin_new(classinfo *c) +{ + java_handle_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 = (java_handle_t*) heap_alloc(c->instancesize, c->flags & ACC_CLASS_HAS_POINTERS, + c->finalizer, true); + + if (!o) + return NULL; + +#if !defined(ENABLE_GC_CACAO) && defined(ENABLE_HANDLES) + /* XXX this is only a dirty hack to make Boehm work with handles */ + + o = LLNI_WRAP((java_object_t *) o); +#endif + + LLNI_vftbl_direct(o) = c->vftbl; + +#if defined(ENABLE_THREADS) + lock_init_object_lock(LLNI_DIRECT(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; +} + +#if defined(ENABLE_ESCAPE_REASON) +java_handle_t *builtin_escape_reason_new(classinfo *c) { + print_escape_reasons(); + return builtin_java_new(c); +} +#endif + +#if defined(ENABLE_TLH) +java_handle_t *builtin_tlh_new(classinfo *c) +{ + java_handle_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 = tlh_alloc(&(THREADOBJECT->tlh), c->instancesize); + */ + o = NULL; + + if (o == NULL) { + o = (java_handle_t*) heap_alloc(c->instancesize, c->flags & ACC_CLASS_HAS_POINTERS, + c->finalizer, true); + } + + if (!o) + return NULL; + +# if !defined(ENABLE_GC_CACAO) && defined(ENABLE_HANDLES) + /* XXX this is only a dirty hack to make Boehm work with handles */ + + o = LLNI_WRAP((java_object_t *) o); +# endif + + LLNI_vftbl_direct(o) = c->vftbl; + +# if defined(ENABLE_THREADS) + lock_init_object_lock(LLNI_DIRECT(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; +} +#endif + + +/* builtin_java_new ************************************************************ + + NOTE: This is a SLOW builtin and can be called from JIT code only. + +*******************************************************************************/ + +java_handle_t *builtin_java_new(java_handle_t *clazz) +{ + return builtin_new(LLNI_classinfo_unwrap(clazz)); +} + + +/* 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. + + NOTE: This is a FAST builtin and can be called from JIT code only. + +*******************************************************************************/ + +java_object_t *builtin_fast_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) + return NULL; + + /* is the class linked */ + + if (!(c->state & CLASS_LINKED)) + return NULL; + + if (!(c->state & CLASS_INITIALIZED)) + return NULL; + + o = (java_handle_t*) 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 + + NOTE: This builtin can be called from NATIVE code only. + +*******************************************************************************/ + +java_handle_t *builtin_newarray(int32_t size, classinfo *arrayclass) +{ + arraydescriptor *desc; + s4 dataoffset; + s4 componentsize; + s4 actualsize; + java_handle_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 = (java_handle_t*) heap_alloc(actualsize, (desc->arraytype == ARRAYTYPE_OBJECT), NULL, true); + + if (a == NULL) + return NULL; + +#if !defined(ENABLE_GC_CACAO) && defined(ENABLE_HANDLES) + /* XXX this is only a dirty hack to make Boehm work with handles */ + + a = LLNI_WRAP((java_object_t *) a); +#endif + + LLNI_vftbl_direct(a) = arrayclass->vftbl; + +#if defined(ENABLE_THREADS) + lock_init_object_lock(LLNI_DIRECT(a)); +#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_java_newarray ******************************************************* + + NOTE: This is a SLOW builtin and can be called from JIT code only. + +*******************************************************************************/ + +java_handle_t *builtin_java_newarray(int32_t size, java_handle_t *arrayclazz) +{ + return builtin_newarray(size, LLNI_classinfo_unwrap(arrayclazz)); +} + + +/* 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 + + NOTE: This builtin can be called from NATIVE code only. + +*******************************************************************************/ + +java_handle_objectarray_t *builtin_anewarray(int32_t 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_type **************************************************** + + Creates an array of [type]s on the heap. + + RETURN VALUE: + pointer to the array or NULL if no memory is available + + NOTE: This is a SLOW builtin and can be called from JIT & NATIVE code. + +*******************************************************************************/ + +#define BUILTIN_NEWARRAY_TYPE(type, arraytype) \ +java_handle_##type##array_t *builtin_newarray_##type(int32_t size) \ +{ \ + return (java_handle_##type##array_t *) \ + builtin_newarray(size, primitivetype_table[arraytype].arrayclass); \ +} + +BUILTIN_NEWARRAY_TYPE(boolean, ARRAYTYPE_BOOLEAN) +BUILTIN_NEWARRAY_TYPE(byte, ARRAYTYPE_BYTE) +BUILTIN_NEWARRAY_TYPE(char, ARRAYTYPE_CHAR) +BUILTIN_NEWARRAY_TYPE(short, ARRAYTYPE_SHORT) +BUILTIN_NEWARRAY_TYPE(int, ARRAYTYPE_INT) +BUILTIN_NEWARRAY_TYPE(long, ARRAYTYPE_LONG) +BUILTIN_NEWARRAY_TYPE(float, ARRAYTYPE_FLOAT) +BUILTIN_NEWARRAY_TYPE(double, ARRAYTYPE_DOUBLE) + + +/* 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->clazz; + + /* 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; + + array_objectarray_element_set((java_handle_objectarray_t *) a, i, ea); + } + + return a; +} + + +/* builtin_multianewarray ****************************************************** + + Wrapper for builtin_multianewarray_intern which checks all + dimensions before we start allocating. + + NOTE: This is a SLOW builtin and can be called from JIT code only. + +******************************************************************************/ + +java_handle_objectarray_t *builtin_multianewarray(int n, + java_handle_t *arrayclazz, + long *dims) +{ + classinfo *c; + 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; + } + } + + c = LLNI_classinfo_unwrap(arrayclazz); + + /* now call the real function */ + + return (java_handle_objectarray_t *) + builtin_multianewarray_intern(n, c, dims); +} + + +/* builtin_verbosecall_enter *************************************************** + + Print method call with arguments for -verbose:call. + + XXX: Remove mew once all archs use the new tracer! + +*******************************************************************************/ + +#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) +{ + log_text("builtin_verbosecall_enter: Do not call me anymore!"); +} +#endif +#endif /* !defined(NDEBUG) */ + + +/* builtin_verbosecall_exit **************************************************** + + Print method exit for -verbose:call. + + XXX: Remove mew once all archs use the new tracer! + +*******************************************************************************/ + +#if !defined(NDEBUG) +void builtin_verbosecall_exit(s8 l, double d, float f, methodinfo *m) +{ + log_text("builtin_verbosecall_exit: Do not call me anymore!"); +} +#endif /* !defined(NDEBUG) */ + + +/*============================================================================*/ +/* MISCELLANEOUS MATHEMATICAL 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) */ + + +/*============================================================================*/ +/* AUTOMATICALLY REPLACED FUNCTIONS */ +/*============================================================================*/ + +/* builtin_arraycopy *********************************************************** + + Builtin for java.lang.System.arraycopy. + + NOTE: This is a SLOW builtin and can be called from JIT & NATIVE code. + +*******************************************************************************/ + +void 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; + } + + sdesc = LLNI_vftbl_direct(src)->arraydesc; + ddesc = LLNI_vftbl_direct(dest)->arraydesc; + + if (!sdesc || !ddesc || (sdesc->arraytype != ddesc->arraytype)) { + exceptions_throw_arraystoreexception(); + return; + } + + // Check if offsets and length are positive. + if ((srcStart < 0) || (destStart < 0) || (len < 0)) { + exceptions_throw_arrayindexoutofboundsexception(); + return; + } + + // Check if ranges are valid. + if ((((uint32_t) srcStart + (uint32_t) len) > (uint32_t) LLNI_array_size(src)) || + (((uint32_t) destStart + (uint32_t) len) > (uint32_t) LLNI_array_size(dest))) { + exceptions_throw_arrayindexoutofboundsexception(); + return; + } + + // Special case. + if (len == 0) { + return; + } + + if (sdesc->componentvftbl == ddesc->componentvftbl) { + /* We copy primitive values or references of exactly the same type */ + + s4 dataoffset = sdesc->dataoffset; + s4 componentsize = sdesc->componentsize; + + LLNI_CRITICAL_START; + + MMOVE(((u1 *) LLNI_DIRECT(dest)) + dataoffset + componentsize * destStart, + ((u1 *) LLNI_DIRECT(src)) + dataoffset + componentsize * srcStart, + u1, (size_t) len * componentsize); + + LLNI_CRITICAL_END; + } + 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; + + o = array_objectarray_element_get(oas, srcStart + i); + + if (!builtin_canstore(oad, o)) + return; + + array_objectarray_element_set(oad, 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; + + o = array_objectarray_element_get(oas, srcStart + i); + + if (!builtin_canstore(oad, o)) + return; + + array_objectarray_element_set(oad, destStart + i, o); + } + } + } +} + + +/* 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. + + NOTE: This is a SLOW builtin and can be called from JIT & NATIVE code. + +*******************************************************************************/ + +java_handle_t *builtin_clone(void *env, java_handle_t *o) +{ + arraydescriptor *ad; + u4 size; + classinfo *c; + java_handle_t *co; /* cloned object header */ + + /* get the array descriptor */ + + ad = LLNI_vftbl_direct(o)->arraydesc; + + /* we are cloning an array */ + + if (ad != NULL) { + size = ad->dataoffset + ad->componentsize * LLNI_array_size(o); + + co = (java_handle_t*) heap_alloc(size, (ad->arraytype == ARRAYTYPE_OBJECT), NULL, true); + + if (co == NULL) + return NULL; + +#if !defined(ENABLE_GC_CACAO) && defined(ENABLE_HANDLES) + /* XXX this is only a dirty hack to make Boehm work with handles */ + + co = LLNI_WRAP((java_object_t *) co); +#endif + + LLNI_CRITICAL_START; + + MCOPY(LLNI_DIRECT(co), LLNI_DIRECT(o), u1, size); + +#if defined(ENABLE_GC_CACAO) + heap_init_objectheader(LLNI_DIRECT(co), size); +#endif + +#if defined(ENABLE_THREADS) + lock_init_object_lock(LLNI_DIRECT(co)); +#endif + + LLNI_CRITICAL_END; + + 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 */ + + LLNI_class_get(o, c); + + /* create new object */ + + co = builtin_new(c); + + if (co == NULL) + return NULL; + + LLNI_CRITICAL_START; + + MCOPY(LLNI_DIRECT(co), LLNI_DIRECT(o), u1, c->instancesize); + +#if defined(ENABLE_GC_CACAO) + heap_init_objectheader(LLNI_DIRECT(co), c->instancesize); +#endif + +#if defined(ENABLE_THREADS) + lock_init_object_lock(LLNI_DIRECT(co)); +#endif + + LLNI_CRITICAL_END; + + return co; +} + + +#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) */ + + +#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: + */ diff --cc src/vm/jit/builtin.hpp index 017e87cac,000000000..2f94b09fd mode 100644,000000..100644 --- a/src/vm/jit/builtin.hpp +++ b/src/vm/jit/builtin.hpp @@@ -1,354 -1,0 +1,356 @@@ +/* src/vm/jit/builtin.hpp - prototypes of builtin functions + + Copyright (C) 1996-2005, 2006, 2007, 2008 + CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO + + 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. + +*/ + + +#ifndef _BUILTIN_HPP +#define _BUILTIN_HPP + +/* forward typedefs ***********************************************************/ + +typedef struct builtintable_entry builtintable_entry; + +#include "config.h" +#include "vm/types.h" + +#include "arch.h" +#include "md-abi.h" + +#include "toolbox/logging.h" + +#include "vm/descriptor.h" +#include "vm/utf8.h" + + +/* define infinity for floating point numbers */ + +#define FLT_NAN 0x7fc00000 +#define FLT_POSINF 0x7f800000 +#define FLT_NEGINF 0xff800000 + +/* define infinity for double floating point numbers */ + +#define DBL_NAN 0x7ff8000000000000LL +#define DBL_POSINF 0x7ff0000000000000LL +#define DBL_NEGINF 0xfff0000000000000LL + + +/* float versions are not defined in GNU classpath's fdlibm */ + +#define copysignf copysign +#define finitef finite +#define fmodf fmod +#define isnanf isnan + + +/* builtin functions table ****************************************************/ + +struct builtintable_entry { + s4 opcode; /* opcode which is replaced */ + u4 flags; /* e.g. check for exception */ + functionptr fp; /* function pointer of builtin */ + u1 *stub; /* pointer to builtin stub code */ + const char* cclassname; /* char name of the class */ + const char* cname; /* char name of the function */ + const char* cdescriptor; /* char name of the descriptor */ + utf *classname; /* class of the function */ + utf *name; /* name of the function */ + utf *descriptor; /* descriptor of the function */ + methoddesc *md; +}; + + +/* builtin table flag defines *************************************************/ + +#define BUILTINTABLE_FLAG_STUB 0x0001 /* builtin needs a stub */ +#define BUILTINTABLE_FLAG_EXCEPTION 0x0002 /* check for excepion on return */ + + +/* function prototypes ********************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +bool builtin_init(void); + +builtintable_entry *builtintable_get_internal(functionptr fp); +builtintable_entry *builtintable_get_automatic(s4 opcode); + +bool builtintable_replace_function(void *iptr); + + +/**********************************************************************/ +/* BUILTIN FUNCTIONS */ +/**********************************************************************/ + +/* NOTE: Builtin functions which are used in the BUILTIN* opcodes must + * have a BUILTIN_... macro defined as seen below. In code dealing + * with the BUILTIN* opcodes the functions may only be addressed by + * these macros, never by their actual name! (This helps to make this + * code more portable.) + * + * C and assembler code which does not deal with the BUILTIN* opcodes, + * can use the builtin functions normally (like all other functions). + * + * IMPORTANT: + * For each builtin function which is used in a BUILTIN* opcode there + * must be an entry in the builtin_desc table in jit/jit.c. + * + * Below each prototype is either the BUILTIN_ macro definition or a + * comment specifiying that this function is not used in BUILTIN* + * opcodes. + * + * (The BUILTIN* opcodes are ICMD_BUILTIN1, ICMD_BUILTIN2 and + * ICMD_BUILTIN3.) + */ + ++bool fast_subtype_check(struct _vftbl *, struct _vftbl *); ++ +bool builtin_instanceof(java_handle_t *obj, classinfo *c); +/* NOT AN OP */ +bool builtin_checkcast(java_handle_t *obj, classinfo *c); +/* NOT AN OP */ +bool builtin_arrayinstanceof(java_handle_t *h, classinfo *targetclass); +/* NOT AN OP */ +bool builtin_fast_arrayinstanceof(java_object_t *o, classinfo *targetclass); +#define BUILTIN_arrayinstanceof (functionptr) builtin_fast_arrayinstanceof +bool builtin_fast_arraycheckcast(java_object_t *o, classinfo *targetclass); +#define BUILTIN_arraycheckcast (functionptr) builtin_fast_arraycheckcast + +bool builtin_canstore(java_handle_objectarray_t *oa, java_handle_t *o); +/* NOT AN OP */ +bool builtin_fast_canstore(java_objectarray_t *oa, java_object_t *o); +#define BUILTIN_FAST_canstore (functionptr) builtin_fast_canstore + +void *builtin_throw_exception(java_object_t *exception); +/* NOT AN OP */ +java_object_t *builtin_retrieve_exception(void); +/* NOT AN OP */ + +java_handle_t *builtin_new(classinfo *c); +/* NOT AN OP */ +java_handle_t *builtin_java_new(java_handle_t *c); +#define BUILTIN_new (functionptr) builtin_java_new + +#if defined(ENABLE_TLH) +#define BUILTIN_tlh_new (functionptr) builtin_tlh_new +java_handle_t *builtin_tlh_new(classinfo *c); +#endif + +#if defined(ENABLE_ESCAPE_REASON) +#define BUILTIN_escape_reason_new (functionptr)builtin_escape_reason_new +java_handle_t *builtin_escape_reason_new(classinfo *c); +#endif + +java_object_t *builtin_fast_new(classinfo *c); +#define BUILTIN_FAST_new (functionptr) builtin_fast_new + +java_handle_t *builtin_newarray(int32_t size, classinfo *arrayclass); +/* NOT AN OP */ +java_handle_t *builtin_java_newarray(int32_t size, java_handle_t *arrayclass); +#define BUILTIN_newarray (functionptr) builtin_java_newarray + +java_handle_objectarray_t *builtin_anewarray(int32_t size, classinfo *componentclass); +/* NOT AN OP */ + +java_handle_booleanarray_t *builtin_newarray_boolean(int32_t size); +#define BUILTIN_newarray_boolean (functionptr) builtin_newarray_boolean +java_handle_chararray_t *builtin_newarray_char(int32_t size); +#define BUILTIN_newarray_char (functionptr) builtin_newarray_char +java_handle_floatarray_t *builtin_newarray_float(int32_t size); +#define BUILTIN_newarray_float (functionptr) builtin_newarray_float +java_handle_doublearray_t *builtin_newarray_double(int32_t size); +#define BUILTIN_newarray_double (functionptr) builtin_newarray_double +java_handle_bytearray_t *builtin_newarray_byte(int32_t size); +#define BUILTIN_newarray_byte (functionptr) builtin_newarray_byte +java_handle_shortarray_t *builtin_newarray_short(int32_t size); +#define BUILTIN_newarray_short (functionptr) builtin_newarray_short +java_handle_intarray_t *builtin_newarray_int(int32_t size); +#define BUILTIN_newarray_int (functionptr) builtin_newarray_int +java_handle_longarray_t *builtin_newarray_long(int32_t size); +#define BUILTIN_newarray_long (functionptr) builtin_newarray_long + +java_handle_objectarray_t *builtin_multianewarray(int n, + java_handle_t *arrayclass, + long *dims); +#define BUILTIN_multianewarray (functionptr) builtin_multianewarray + +#if defined(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); +/* NOT AN OP */ +#endif /* defined(TRACE_ARGS_NUM) */ + +void builtin_verbosecall_exit(s8 l, double d, float f, methodinfo *m); +/* NOT AN OP */ + +s4 builtin_idiv(s4 a, s4 b); +#define BUILTIN_idiv (functionptr) builtin_idiv +s4 builtin_irem(s4 a, s4 b); +#define BUILTIN_irem (functionptr) builtin_irem + +s8 builtin_ladd(s8 a, s8 b); +#define BUILTIN_ladd (functionptr) builtin_ladd +s8 builtin_lsub(s8 a, s8 b); +#define BUILTIN_lsub (functionptr) builtin_lsub +s8 builtin_lmul(s8 a, s8 b); +#define BUILTIN_lmul (functionptr) builtin_lmul + +s8 builtin_ldiv(s8 a, s8 b); +#define BUILTIN_ldiv (functionptr) builtin_ldiv +s8 builtin_lrem(s8 a, s8 b); +#define BUILTIN_lrem (functionptr) builtin_lrem + +s8 builtin_lshl(s8 a, s4 b); +#define BUILTIN_lshl (functionptr) builtin_lshl +s8 builtin_lshr(s8 a, s4 b); +#define BUILTIN_lshr (functionptr) builtin_lshr +s8 builtin_lushr(s8 a, s4 b); +#define BUILTIN_lushr (functionptr) builtin_lushr +s8 builtin_land(s8 a, s8 b); +#define BUILTIN_land (functionptr) builtin_land +s8 builtin_lor(s8 a, s8 b); +#define BUILTIN_lor (functionptr) builtin_lor +s8 builtin_lxor(s8 a, s8 b); +#define BUILTIN_lxor (functionptr) builtin_lxor +s8 builtin_lneg(s8 a); +#define BUILTIN_lneg (functionptr) builtin_lneg +s4 builtin_lcmp(s8 a, s8 b); +#define BUILTIN_lcmp (functionptr) builtin_lcmp + +float builtin_fadd(float a, float b); +#define BUILTIN_fadd (functionptr) builtin_fadd +float builtin_fsub(float a, float b); +#define BUILTIN_fsub (functionptr) builtin_fsub +float builtin_fmul(float a, float b); +#define BUILTIN_fmul (functionptr) builtin_fmul +float builtin_fdiv(float a, float b); +#define BUILTIN_fdiv (functionptr) builtin_fdiv +float builtin_fneg(float a); +#define BUILTIN_fneg (functionptr) builtin_fneg +s4 builtin_fcmpl(float a, float b); +#define BUILTIN_fcmpl (functionptr) builtin_fcmpl +s4 builtin_fcmpg(float a, float b); +#define BUILTIN_fcmpg (functionptr) builtin_fcmpg +float builtin_frem(float a, float b); +#define BUILTIN_frem (functionptr) builtin_frem + +double builtin_dadd(double a, double b); +#define BUILTIN_dadd (functionptr) builtin_dadd +double builtin_dsub(double a, double b); +#define BUILTIN_dsub (functionptr) builtin_dsub +double builtin_dmul(double a, double b); +#define BUILTIN_dmul (functionptr) builtin_dmul +double builtin_ddiv(double a, double b); +#define BUILTIN_ddiv (functionptr) builtin_ddiv +double builtin_dneg(double a); +#define BUILTIN_dneg (functionptr) builtin_dneg +s4 builtin_dcmpl(double a, double b); +#define BUILTIN_dcmpl (functionptr) builtin_dcmpl +s4 builtin_dcmpg(double a, double b); +#define BUILTIN_dcmpg (functionptr) builtin_dcmpg +double builtin_drem(double a, double b); +#define BUILTIN_drem (functionptr) builtin_drem + +s8 builtin_i2l(s4 i); +/* NOT AN OP */ +float builtin_i2f(s4 i); +#define BUILTIN_i2f (functionptr) builtin_i2f +double builtin_i2d(s4 i); +#define BUILTIN_i2d (functionptr) builtin_i2d +s4 builtin_l2i(s8 l); +/* NOT AN OP */ +float builtin_l2f(s8 l); +#define BUILTIN_l2f (functionptr) builtin_l2f +double builtin_l2d(s8 l); +#define BUILTIN_l2d (functionptr) builtin_l2d + +s4 builtin_f2i(float a); +#define BUILTIN_f2i (functionptr) builtin_f2i +s4 asm_builtin_f2i(float a); +/* NOT AN OP */ +s8 builtin_f2l(float a); +#define BUILTIN_f2l (functionptr) builtin_f2l +s8 asm_builtin_f2l(float a); +/* NOT AN OP */ + +double builtin_f2d(float a); +#define BUILTIN_f2d (functionptr) builtin_f2d + +s4 builtin_d2i(double a); +#define BUILTIN_d2i (functionptr) builtin_d2i +s4 asm_builtin_d2i(double a); +/* NOT AN OP */ +s8 builtin_d2l(double a); +#define BUILTIN_d2l (functionptr) builtin_d2l +s8 asm_builtin_d2l(double a); +/* NOT AN OP */ + +float builtin_d2f(double a); +#define BUILTIN_d2f (functionptr) builtin_d2f + +java_handle_t *builtin_clone(void *env, java_handle_t *o); +#define BUILTIN_clone (functionptr) builtin_clone + +void builtin_arraycopy(java_handle_t *src, s4 srcStart, + java_handle_t *dest, s4 destStart, s4 len); +#define BUILTIN_arraycopy (functionptr) builtin_arraycopy + +s8 builtin_nanotime(void); +s8 builtin_currenttimemillis(void); +#define BUILTIN_currenttimemillis (functionptr) builtin_currenttimemillis + +#if defined(ENABLE_CYCLES_STATS) +void builtin_print_cycles_stats(FILE *file); +#endif + +#ifdef __cplusplus +} +#endif + +#endif // _BUILTIN_HPP + + +/* + * 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: + */ diff --cc src/vm/jit/emit-common.hpp index 880f633cd,000000000..02e90d6b7 mode 100644,000000..100644 --- a/src/vm/jit/emit-common.hpp +++ b/src/vm/jit/emit-common.hpp @@@ -1,212 -1,0 +1,216 @@@ +/* src/vm/jit/emit-common.hpp - common code emitter functions + + Copyright (C) 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. + +*/ + + +#ifndef _EMIT_COMMON_H +#define _EMIT_COMMON_H + +#include "config.h" +#include "vm/types.h" + +#include "arch.h" + +#include "vm/jit/codegen-common.hpp" +#include "vm/jit/jit.hpp" + + +/* branch labels **************************************************************/ + +#define BRANCH_LABEL_1 1 +#define BRANCH_LABEL_2 2 +#define BRANCH_LABEL_3 3 +#define BRANCH_LABEL_4 4 +#define BRANCH_LABEL_5 5 +#define BRANCH_LABEL_6 6 ++#define BRANCH_LABEL_7 7 ++#define BRANCH_LABEL_8 8 ++#define BRANCH_LABEL_9 9 ++#define BRANCH_LABEL_10 10 + + +/* constant range macros ******************************************************/ + +#if SIZEOF_VOID_P == 8 + +# define IS_IMM8(c) \ + (((s8) (c) >= -128) && ((s8) (c) <= 127)) + +# define IS_IMM32(c) \ + (((s8) (c) >= (-2147483647-1)) && ((s8) (c) <= 2147483647)) + +#else + +# define IS_IMM8(c) \ + (((s4) (c) >= -128) && ((s4) (c) <= 127)) + +# define IS_IMM16(c) \ + (((s4) (c) >= -32768) && ((s4) (c) <= 32767)) + +#endif + + +/* code generation functions **************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +s4 emit_load(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg); +s4 emit_load_s1(jitdata *jd, instruction *iptr, s4 tempreg); +s4 emit_load_s2(jitdata *jd, instruction *iptr, s4 tempreg); +s4 emit_load_s3(jitdata *jd, instruction *iptr, s4 tempreg); + +#if SIZEOF_VOID_P == 4 +s4 emit_load_low(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg); +s4 emit_load_s1_low(jitdata *jd, instruction *iptr, s4 tempreg); +s4 emit_load_s2_low(jitdata *jd, instruction *iptr, s4 tempreg); +s4 emit_load_s3_low(jitdata *jd, instruction *iptr, s4 tempreg); + +s4 emit_load_high(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg); +s4 emit_load_s1_high(jitdata *jd, instruction *iptr, s4 tempreg); +s4 emit_load_s2_high(jitdata *jd, instruction *iptr, s4 tempreg); +s4 emit_load_s3_high(jitdata *jd, instruction *iptr, s4 tempreg); +#endif + +void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d); +void emit_store_dst(jitdata *jd, instruction *iptr, s4 d); + +#if SIZEOF_VOID_P == 4 +void emit_store_low(jitdata *jd, instruction *iptr, varinfo *dst, s4 d); +void emit_store_high(jitdata *jd, instruction *iptr, varinfo *dst, s4 d); +#endif + +void emit_copy(jitdata *jd, instruction *iptr); + +void emit_iconst(codegendata *cd, s4 d, s4 value); +void emit_lconst(codegendata *cd, s4 d, s8 value); + +/* branch-emitting functions */ +void emit_bccz(codegendata *cd, basicblock *target, s4 condition, s4 reg, u4 options); +void emit_bcc(codegendata *cd, basicblock *target, s4 condition, u4 options); + +/* wrapper for unconditional branches */ +void emit_br(codegendata *cd, basicblock *target); + +/* wrappers for branches on one integer register */ + +#if SUPPORT_BRANCH_CONDITIONAL_ONE_INTEGER_REGISTER +void emit_beqz(codegendata *cd, basicblock *target, s4 reg); +void emit_bnez(codegendata *cd, basicblock *target, s4 reg); +void emit_bltz(codegendata *cd, basicblock *target, s4 reg); +void emit_bgez(codegendata *cd, basicblock *target, s4 reg); +void emit_bgtz(codegendata *cd, basicblock *target, s4 reg); +void emit_blez(codegendata *cd, basicblock *target, s4 reg); +#endif + +/* wrappers for branches on two integer registers */ + +#if SUPPORT_BRANCH_CONDITIONAL_TWO_INTEGER_REGISTERS +void emit_beq(codegendata *cd, basicblock *target, s4 s1, s4 s2); +void emit_bne(codegendata *cd, basicblock *target, s4 s1, s4 s2); +#endif + +/* wrappers for branches on condition codes */ + +#if SUPPORT_BRANCH_CONDITIONAL_CONDITION_REGISTER +void emit_beq(codegendata *cd, basicblock *target); +void emit_bne(codegendata *cd, basicblock *target); +void emit_blt(codegendata *cd, basicblock *target); +void emit_bge(codegendata *cd, basicblock *target); +void emit_bgt(codegendata *cd, basicblock *target); +void emit_ble(codegendata *cd, basicblock *target); +#endif + +#if SUPPORT_BRANCH_CONDITIONAL_UNSIGNED_CONDITIONS +void emit_bult(codegendata *cd, basicblock *target); +void emit_bule(codegendata *cd, basicblock *target); +void emit_buge(codegendata *cd, basicblock *target); +void emit_bugt(codegendata *cd, basicblock *target); +#endif + +#if defined(__POWERPC__) || defined(__POWERPC64__) +void emit_bnan(codegendata *cd, basicblock *target); +#endif + +/* label-branches */ +void emit_label_bccz(codegendata *cd, s4 label, s4 condition, s4 reg, u4 options); +void emit_label(codegendata *cd, s4 label); +void emit_label_bcc(codegendata *cd, s4 label, s4 condition, u4 options); + +void emit_label_br(codegendata *cd, s4 label); + +#if SUPPORT_BRANCH_CONDITIONAL_ONE_INTEGER_REGISTER +void emit_label_beqz(codegendata *cd, s4 label, s4 reg); +#endif + +#if SUPPORT_BRANCH_CONDITIONAL_CONDITION_REGISTER +void emit_label_beq(codegendata *cd, s4 label); +void emit_label_bne(codegendata *cd, s4 label); +void emit_label_blt(codegendata *cd, s4 label); +void emit_label_bge(codegendata *cd, s4 label); +void emit_label_bgt(codegendata *cd, s4 label); +void emit_label_ble(codegendata *cd, s4 label); +#endif + +/* machine dependent branch-emitting function */ +void emit_branch(codegendata *cd, s4 disp, s4 condition, s4 reg, u4 options); + +void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg); +void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, s4 s2); +void emit_arraystore_check(codegendata *cd, instruction *iptr); +void emit_classcast_check(codegendata *cd, instruction *iptr, s4 condition, s4 reg, s4 s1); +void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg); +void emit_exception_check(codegendata *cd, instruction *iptr); + +void emit_trap_compiler(codegendata *cd); +void emit_trap_countdown(codegendata *cd, s4 *counter); +uint32_t emit_trap(codegendata *cd); + +void emit_patcher_traps(jitdata *jd); + +void emit_verbosecall_enter(jitdata *jd); +void emit_verbosecall_exit(jitdata *jd); + +#ifdef __cplusplus +} +#endif + +#endif /* _EMIT_COMMON_H */ + + +/* + * 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: + */ diff --cc src/vm/linker.c index 0080c250b,000000000..c1b00e40b mode 100644,000000..100644 --- a/src/vm/linker.c +++ b/src/vm/linker.c @@@ -1,1320 -1,0 +1,1374 @@@ +/* src/vm/linker.c - class linker functions + + Copyright (C) 1996-2005, 2006, 2007, 2008 + CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO + + 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. + +*/ + + +#include "config.h" + +#include +#include + +#include "vm/types.h" + +#include "mm/memory.h" + +#include "native/native.h" + +#include "threads/lock-common.h" +#include "threads/mutex.hpp" + +#include "toolbox/logging.h" + +#include "vm/access.h" +#include "vm/array.h" +#include "vm/class.h" +#include "vm/classcache.h" +#include "vm/exceptions.hpp" +#include "vm/globals.hpp" +#include "vm/loader.hpp" +#include "vm/options.h" +#include "vm/primitive.hpp" +#include "vm/rt-timing.h" +#include "vm/string.hpp" +#include "vm/vm.hpp" + +#include "vm/jit/asmpart.h" +#include "vm/jit/stubs.hpp" + + +/* debugging macros ***********************************************************/ + +#if !defined(NDEBUG) +# define TRACELINKCLASS(c) \ + do { \ + if (opt_TraceLinkClass) { \ + log_start(); \ + log_print("[Linking "); \ + class_print((c)); \ + log_print("]"); \ + log_finish(); \ + } \ + } while (0) +#else +# define TRACELINKCLASS(c) +#endif + + +/* #include "vm/resolve.h" */ +/* copied prototype to avoid bootstrapping problem: */ +classinfo *resolve_classref_or_classinfo_eager(classref_or_classinfo cls, bool checkaccess); + +#if defined(ENABLE_STATISTICS) +# include "vm/statistics.h" +#endif + +#if !defined(NDEBUG) && defined(ENABLE_INLINING) +#define INLINELOG(code) do { if (opt_TraceInlining) { code } } while (0) +#else +#define INLINELOG(code) +#endif + + +/* global variables ***********************************************************/ + +static s4 interfaceindex; /* sequential numbering of interfaces */ +static s4 classvalue; + - Mutex *linker_classrenumber_mutex; - + +/* private functions **********************************************************/ + +static classinfo *link_class_intern(classinfo *c); +static arraydescriptor *link_array(classinfo *c); +static void linker_compute_class_values(classinfo *c); +static void linker_compute_subclasses(classinfo *c); +static bool linker_addinterface(classinfo *c, classinfo *ic); +static s4 class_highestinterface(classinfo *c); + + +/* linker_init ***************************************************************** + + Initializes the linker subsystem and links classes required for the + primitive table. + +*******************************************************************************/ + +void linker_preinit(void) +{ + TRACESUBSYSTEMINITIALIZATION("linker_preinit"); + + /* Reset interface index. */ + + interfaceindex = 0; + - #if defined(ENABLE_THREADS) - /* create the global mutex */ - - linker_classrenumber_mutex = Mutex_new(); - #endif - + /* Link the most basic classes. */ + + if (!link_class(class_java_lang_Object)) + vm_abort("linker_preinit: linking java/lang/Object failed"); + +#if defined(ENABLE_JAVASE) + if (!link_class(class_java_lang_Cloneable)) + vm_abort("linker_preinit: linking java/lang/Cloneable failed"); + + if (!link_class(class_java_io_Serializable)) + vm_abort("linker_preinit: linking java/io/Serializable failed"); +#endif +} + + +/* linker_init ***************************************************************** + + Links all classes required in the VM. + +*******************************************************************************/ + +void linker_init(void) +{ + TRACESUBSYSTEMINITIALIZATION("linker_init"); + + /* Link java.lang.Class as first class of the system, because we + need it's vftbl for all other classes so we can use a class as + object. */ + + if (!link_class(class_java_lang_Class)) + vm_abort("linker_init: linking java/lang/Class failed"); + + /* Now set the header.vftbl of all classes which were created + before java.lang.Class was linked. */ + + class_postset_header_vftbl(); + + /* Link primitive-type wrapping classes. */ + +#if defined(ENABLE_JAVASE) + if (!link_class(class_java_lang_Void)) + vm_abort("linker_init: linking failed"); +#endif + + if (!link_class(class_java_lang_Boolean)) + vm_abort("linker_init: linking failed"); + + if (!link_class(class_java_lang_Byte)) + vm_abort("linker_init: linking failed"); + + if (!link_class(class_java_lang_Character)) + vm_abort("linker_init: linking failed"); + + if (!link_class(class_java_lang_Short)) + vm_abort("linker_init: linking failed"); + + if (!link_class(class_java_lang_Integer)) + vm_abort("linker_init: linking failed"); + + if (!link_class(class_java_lang_Long)) + vm_abort("linker_init: linking failed"); + + if (!link_class(class_java_lang_Float)) + vm_abort("linker_init: linking failed"); + + if (!link_class(class_java_lang_Double)) + vm_abort("linker_init: linking failed"); + + /* Link important system classes. */ + + if (!link_class(class_java_lang_String)) + vm_abort("linker_init: linking java/lang/String failed"); + +#if defined(ENABLE_JAVASE) + if (!link_class(class_java_lang_ClassLoader)) + vm_abort("linker_init: linking failed"); + + if (!link_class(class_java_lang_SecurityManager)) + vm_abort("linker_init: linking failed"); +#endif + + if (!link_class(class_java_lang_System)) + vm_abort("linker_init: linking failed"); + + if (!link_class(class_java_lang_Thread)) + vm_abort("linker_init: linking failed"); + +#if defined(ENABLE_JAVASE) + if (!link_class(class_java_lang_ThreadGroup)) + vm_abort("linker_init: linking failed"); +#endif + + if (!link_class(class_java_lang_Throwable)) + vm_abort("linker_init: linking failed"); + +#if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH) + if (!link_class(class_java_lang_VMSystem)) + vm_abort("linker_init: linking failed"); + + if (!link_class(class_java_lang_VMThread)) + vm_abort("linker_init: linking failed"); + + if (!link_class(class_java_lang_VMThrowable)) + vm_abort("linker_init: linking failed"); +#endif + + /* Important system exceptions. */ + + if (!link_class(class_java_lang_Exception)) + vm_abort("linker_init: linking failed"); + + if (!link_class(class_java_lang_ClassNotFoundException)) + vm_abort("linker_init: linking failed"); + + if (!link_class(class_java_lang_RuntimeException)) + vm_abort("linker_init: linking failed"); + + /* some classes which may be used more often */ + +#if defined(ENABLE_JAVASE) + if (!link_class(class_java_lang_StackTraceElement)) + vm_abort("linker_init: linking failed"); + + if (!link_class(class_java_lang_reflect_Constructor)) + vm_abort("linker_init: linking failed"); + + if (!link_class(class_java_lang_reflect_Field)) + vm_abort("linker_init: linking failed"); + + if (!link_class(class_java_lang_reflect_Method)) + vm_abort("linker_init: linking failed"); + +# if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH) + if (!link_class(class_java_lang_reflect_VMConstructor)) + vm_abort("linker_init: linking failed"); + + if (!link_class(class_java_lang_reflect_VMField)) + vm_abort("linker_init: linking failed"); + + if (!link_class(class_java_lang_reflect_VMMethod)) + vm_abort("linker_init: linking failed"); +# endif + + if (!link_class(class_java_security_PrivilegedAction)) + vm_abort("linker_init: linking failed"); + + if (!link_class(class_java_util_Vector)) + vm_abort("linker_init: linking failed"); + + if (!link_class(class_java_util_HashMap)) + vm_abort("linker_init: linking failed"); + +# if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK) + if (!link_class(class_sun_misc_Signal)) + vm_abort("linker_init: linking failed"); + + if (!link_class(class_sun_reflect_MagicAccessorImpl)) + vm_abort("linker_init: linking failed"); +# endif + + if (!link_class(arrayclass_java_lang_Object)) + vm_abort("linker_init: linking failed"); +#endif + + + /* create pseudo classes used by the typechecker */ + + /* pseudo class for Arraystubs (extends java.lang.Object) */ + + pseudo_class_Arraystub = + class_create_classinfo(utf_new_char("$ARRAYSTUB$")); + pseudo_class_Arraystub->state |= CLASS_LOADED; + pseudo_class_Arraystub->super = class_java_lang_Object; + +#if defined(ENABLE_JAVASE) + + pseudo_class_Arraystub->interfacescount = 2; + pseudo_class_Arraystub->interfaces = MNEW(classinfo*, 2); + pseudo_class_Arraystub->interfaces[0] = class_java_lang_Cloneable; + pseudo_class_Arraystub->interfaces[1] = class_java_io_Serializable; + +#elif defined(ENABLE_JAVAME_CLDC1_1) + + pseudo_class_Arraystub->interfacescount = 0; + pseudo_class_Arraystub->interfaces = NULL; + +#else +# error unknown Java configuration +#endif + + if (!classcache_store_unique(pseudo_class_Arraystub)) + vm_abort("linker_init: could not cache pseudo_class_Arraystub"); + + if (!link_class(pseudo_class_Arraystub)) + vm_abort("linker_init: linking pseudo_class_Arraystub failed"); + + /* pseudo class representing the null type */ + + pseudo_class_Null = class_create_classinfo(utf_new_char("$NULL$")); + pseudo_class_Null->state |= CLASS_LOADED; + pseudo_class_Null->super = class_java_lang_Object; + + if (!classcache_store_unique(pseudo_class_Null)) + vm_abort("linker_init: could not cache pseudo_class_Null"); + + if (!link_class(pseudo_class_Null)) + vm_abort("linker_init: linking failed"); + + /* pseudo class representing new uninitialized objects */ + + pseudo_class_New = class_create_classinfo(utf_new_char("$NEW$")); + pseudo_class_New->state |= CLASS_LOADED; + pseudo_class_New->state |= CLASS_LINKED; /* XXX is this allright? */ + pseudo_class_New->super = class_java_lang_Object; + + if (!classcache_store_unique(pseudo_class_New)) + vm_abort("linker_init: could not cache pseudo_class_New"); + + /* Correct vftbl-entries (retarded loading and linking of class + java/lang/String). */ + + stringtable_update(); +} + + +/* link_class ****************************************************************** + + Wrapper function for link_class_intern to ease monitor enter/exit + and exception handling. + +*******************************************************************************/ + +classinfo *link_class(classinfo *c) +{ + classinfo *r; +#if defined(ENABLE_RT_TIMING) + struct timespec time_start, time_end; +#endif + + RT_TIMING_GET_TIME(time_start); + + if (c == NULL) { + exceptions_throw_nullpointerexception(); + return NULL; + } + + LOCK_MONITOR_ENTER(c); + + /* Maybe the class is currently linking or is already linked.*/ + + if ((c->state & CLASS_LINKING) || (c->state & CLASS_LINKED)) { + LOCK_MONITOR_EXIT(c); + + return c; + } + +#if defined(ENABLE_STATISTICS) + /* measure time */ + + if (opt_getcompilingtime) + compilingtime_stop(); + + if (opt_getloadingtime) + loadingtime_start(); +#endif + + /* call the internal function */ + + r = link_class_intern(c); + + /* If return value is NULL, we had a problem and the class is not + linked. */ + + if (r == NULL) + c->state &= ~CLASS_LINKING; + +#if defined(ENABLE_STATISTICS) + /* measure time */ + + if (opt_getloadingtime) + loadingtime_stop(); + + if (opt_getcompilingtime) + compilingtime_start(); +#endif + + LOCK_MONITOR_EXIT(c); + + RT_TIMING_GET_TIME(time_end); + + RT_TIMING_TIME_DIFF(time_start,time_end,RT_TIMING_LINK_TOTAL); + + return r; +} + + +/* linker_overwrite_method ***************************************************** + + Overwrite a method with another one, update method flags and check + assumptions. + + IN: + mg................the general method being overwritten + ms................the overwriting (more specialized) method + wl................worklist where to add invalidated methods + + RETURN VALUE: + true..............everything ok + false.............an exception has been thrown + +*******************************************************************************/ + +static bool linker_overwrite_method(methodinfo *mg, + methodinfo *ms, + method_worklist **wl) +{ + classinfo *cg; + classinfo *cs; + + cg = mg->clazz; + cs = ms->clazz; + + /* overriding a final method is illegal */ + + if (mg->flags & ACC_FINAL) { + exceptions_throw_verifyerror(mg, "Overriding final method"); + return false; + } + + /* method ms overwrites method mg */ + +#if defined(ENABLE_VERIFIER) + /* Add loading constraints (for the more general types of method mg). */ + /* Not for , as it is not invoked virtually. */ + + if ((ms->name != utf_init) + && !classcache_add_constraints_for_params( + cs->classloader, cg->classloader, mg)) + { + return false; + } +#endif + + /* inherit the vftbl index, and record the overwriting */ + + ms->vftblindex = mg->vftblindex; + ms->overwrites = mg; + + /* update flags and check assumptions */ + /* methods are a special case, as they are never dispatched dynamically */ + + if ((ms->flags & ACC_METHOD_IMPLEMENTED) && ms->name != utf_init) { + do { + +#if defined(ENABLE_TLH) + if (mg->flags & ACC_METHOD_MONOMORPHY_USED) { + printf("%s/%s is evil! the siner is %s/%s\n", mg->clazz->name->text, mg->name->text, + ms->clazz->name->text, ms->name->text); + ms->flags |= ACC_METHOD_PARENT_MONOMORPHY_USED; + } +#endif + + if (mg->flags & ACC_METHOD_IMPLEMENTED) { + /* this adds another implementation */ + + mg->flags &= ~ACC_METHOD_MONOMORPHIC; + + INLINELOG( printf("becomes polymorphic: "); method_println(mg); ); + + method_break_assumption_monomorphic(mg, wl); + } + else { + /* this is the first implementation */ + + mg->flags |= ACC_METHOD_IMPLEMENTED; + + INLINELOG( printf("becomes implemented: "); method_println(mg); ); + } + + ms = mg; + mg = mg->overwrites; + } while (mg != NULL); + } + + return true; +} + + +/* link_class_intern *********************************************************** + + Tries to link a class. The function calculates the length in bytes + that an instance of this class requires as well as the VTBL for + methods and interface methods. + +*******************************************************************************/ + ++static int build_display_inner(classinfo *topc, classinfo *c, int i) ++{ ++ int depth; ++ if (!c) ++ return 0; ++ do { ++ if (c->vftbl->arraydesc) ++ { ++ arraydescriptor *a = c->vftbl->arraydesc; ++ if (a->elementvftbl && a->elementvftbl->clazz->super) ++ { ++ classinfo *cls = a->elementvftbl->clazz->super; ++ int n; ++ for (n=0; ndimension; n++) ++ cls = class_array_of(cls, true); ++ depth = build_display_inner(topc, cls, i+1); ++ break; ++ } ++ if (a->componentvftbl && a->elementvftbl) ++ { ++ depth = build_display_inner(topc, a->componentvftbl->clazz, i+1); ++ break; ++ } ++ } ++ depth = build_display_inner(topc, c->super, i+1); ++ } while (false); ++ if (depth >= DISPLAY_SIZE) ++ { ++ if (depth == DISPLAY_SIZE) ++ { ++ topc->vftbl->subtype_overflow_length = i+1; ++ topc->vftbl->subtype_overflow = malloc(sizeof(void*) * (i+1)); ++#if defined(ENABLE_STATISTICS) ++ if (opt_stat) ++ count_vftbl_len += sizeof(void*) * (i+1); ++#endif ++ } ++ topc->vftbl->subtype_overflow[depth - DISPLAY_SIZE] = c->vftbl; ++ return depth + 1; ++ } ++ topc->vftbl->subtype_display[depth] = c->vftbl; ++ return depth + 1; ++} ++ ++static void build_display(classinfo *c) ++{ ++ int depth; ++ int i; ++ ++ depth = build_display_inner(c, c, 0) - 1; ++ c->vftbl->subtype_depth = depth; ++ if (depth >= DISPLAY_SIZE) ++ { ++ c->vftbl->subtype_offset = OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE]); ++ } ++ else ++ { ++ c->vftbl->subtype_offset = OFFSET(vftbl_t, subtype_display[0]) + sizeof(void*) * depth; ++ for (i=depth+1; i<=DISPLAY_SIZE; i++) ++ c->vftbl->subtype_display[i] = NULL; ++ c->vftbl->subtype_overflow_length = 0; ++ } ++} ++ +static classinfo *link_class_intern(classinfo *c) +{ + classinfo *super; /* super class */ + classinfo *tc; /* temporary class variable */ + s4 supervftbllength; /* vftbllegnth of super class */ + s4 vftbllength; /* vftbllength of current class */ + s4 interfacetablelength; /* interface table length */ + vftbl_t *v; /* vftbl of current class */ + s4 i; /* interface/method/field counter */ + arraydescriptor *arraydesc; /* descriptor for array classes */ + method_worklist *worklist; /* worklist for recompilation */ +#if defined(ENABLE_RT_TIMING) + struct timespec time_start, time_resolving, time_compute_vftbl, + time_abstract, time_compute_iftbl, time_fill_vftbl, + time_offsets, time_fill_iftbl, time_finalizer, + time_subclasses; +#endif + + RT_TIMING_GET_TIME(time_start); + + TRACELINKCLASS(c); + + /* the class must be loaded */ + + /* XXX should this be a specific exception? */ + assert(c->state & CLASS_LOADED); + + /* This is check in link_class. */ + + assert(!(c->state & CLASS_LINKED)); + + /* cache the self-reference of this class */ + /* we do this for cases where the defining loader of the class */ + /* has not yet been recorded as an initiating loader for the class */ + /* this is needed so subsequent code can assume that self-refs */ + /* will always resolve lazily */ + /* No need to do it for the bootloader - it is always registered */ + /* as initiating loader for the classes it loads. */ + if (c->classloader) + classcache_store(c->classloader,c,false); + + /* this class is currently linking */ + + c->state |= CLASS_LINKING; + + arraydesc = NULL; + worklist = NULL; + + /* Link the super interfaces. */ + + for (i = 0; i < c->interfacescount; i++) { + tc = c->interfaces[i]; + + if (!(tc->state & CLASS_LINKED)) + if (!link_class(tc)) + return NULL; + } + + /* check super class */ + + super = NULL; + + /* Check for java/lang/Object. */ + + if (c->super == NULL) { + c->index = 0; + c->instancesize = sizeof(java_object_t); + + vftbllength = supervftbllength = 0; + + c->finalizer = NULL; + } + else { + /* Get super class. */ + + super = c->super; + + /* Link the super class if necessary. */ + + if (!(super->state & CLASS_LINKED)) + if (!link_class(super)) + return NULL; + + /* OR the ACC_CLASS_HAS_POINTERS and the ACC_CLASS_REFERENCE_* + flags. */ + + c->flags |= (super->flags & + (ACC_CLASS_HAS_POINTERS | ACC_CLASS_REFERENCE_MASK)); + + /* handle array classes */ + + if (c->name->text[0] == '[') + if (!(arraydesc = link_array(c))) + return NULL; + + if (c->flags & ACC_INTERFACE) + c->index = interfaceindex++; + else + c->index = super->index + 1; + + c->instancesize = super->instancesize; + + vftbllength = supervftbllength = super->vftbl->vftbllength; + + c->finalizer = super->finalizer; + } + RT_TIMING_GET_TIME(time_resolving); + + + /* compute vftbl length */ + + for (i = 0; i < c->methodscount; i++) { + methodinfo *m = &(c->methods[i]); + + if (!(m->flags & ACC_STATIC)) { /* is instance method */ + tc = super; + + while (tc) { + s4 j; + + for (j = 0; j < tc->methodscount; j++) { + if (method_canoverwrite(m, &(tc->methods[j]))) { + if (tc->methods[j].flags & ACC_PRIVATE) + goto notfoundvftblindex; + + /* package-private methods in other packages */ + /* must not be overridden */ + /* (see Java Language Specification 8.4.8.1) */ + if ( !(tc->methods[j].flags & (ACC_PUBLIC | ACC_PROTECTED)) + && !SAME_PACKAGE(c,tc) ) + { + goto notfoundvftblindex; + } + + if (!linker_overwrite_method(&(tc->methods[j]), m, &worklist)) + return NULL; + + goto foundvftblindex; + } + } + + tc = tc->super; + } + + notfoundvftblindex: + m->vftblindex = (vftbllength++); + foundvftblindex: + ; + } + } + RT_TIMING_GET_TIME(time_compute_vftbl); + + + /* Check all interfaces of an abstract class (maybe be an + interface too) for unimplemented methods. Such methods are + called miranda-methods and are marked with the ACC_MIRANDA + flag. VMClass.getDeclaredMethods does not return such + methods. */ + + if (c->flags & ACC_ABSTRACT) { + classinfo *ic; + methodinfo *im; + s4 abstractmethodscount; + s4 j; + s4 k; + + abstractmethodscount = 0; + + /* check all interfaces of the abstract class */ + + for (i = 0; i < c->interfacescount; i++) { + ic = c->interfaces[i]; + + for (j = 0; j < ic->methodscount; j++) { + im = &(ic->methods[j]); + + /* skip `' and `' */ + + if ((im->name == utf_clinit) || (im->name == utf_init)) + continue; + + for (tc = c; tc != NULL; tc = tc->super) { + for (k = 0; k < tc->methodscount; k++) { + if (method_canoverwrite(im, &(tc->methods[k]))) + goto noabstractmethod; + } + } + + abstractmethodscount++; + + noabstractmethod: + ; + } + } + + if (abstractmethodscount > 0) { + methodinfo *am; + + /* reallocate methods memory */ + + c->methods = MREALLOC(c->methods, methodinfo, c->methodscount, + c->methodscount + abstractmethodscount); + + for (i = 0; i < c->interfacescount; i++) { + ic = c->interfaces[i]; + + for (j = 0; j < ic->methodscount; j++) { + im = &(ic->methods[j]); + + /* skip `' and `' */ + + if ((im->name == utf_clinit) || (im->name == utf_init)) + continue; + + for (tc = c; tc != NULL; tc = tc->super) { + for (k = 0; k < tc->methodscount; k++) { + if (method_canoverwrite(im, &(tc->methods[k]))) + goto noabstractmethod2; + } + } + + /* Copy the method found into the new c->methods + array and tag it as miranda-method. */ + + am = &(c->methods[c->methodscount]); + c->methodscount++; + + MCOPY(am, im, methodinfo, 1); + + am->vftblindex = (vftbllength++); + am->clazz = c; + am->flags |= ACC_MIRANDA; + + noabstractmethod2: + ; + } + } + } + } + RT_TIMING_GET_TIME(time_abstract); + + +#if defined(ENABLE_STATISTICS) + if (opt_stat) + count_vftbl_len += + sizeof(vftbl_t) + (sizeof(methodptr) * (vftbllength - 1)); +#endif + + /* compute interfacetable length */ + + interfacetablelength = 0; + + for (tc = c; tc != NULL; tc = tc->super) { + for (i = 0; i < tc->interfacescount; i++) { + s4 h = class_highestinterface(tc->interfaces[i]) + 1; + + if (h > interfacetablelength) + interfacetablelength = h; + } + } + RT_TIMING_GET_TIME(time_compute_iftbl); + + /* allocate virtual function table */ + + v = (vftbl_t *) mem_alloc(sizeof(vftbl_t) + + sizeof(methodptr) * (vftbllength - 1) + + sizeof(methodptr*) * (interfacetablelength - (interfacetablelength > 0))); + v = (vftbl_t *) (((methodptr *) v) + + (interfacetablelength - 1) * (interfacetablelength > 1)); + + c->vftbl = v; + v->clazz = c; + v->vftbllength = vftbllength; + v->interfacetablelength = interfacetablelength; + v->arraydesc = arraydesc; + + /* store interface index in vftbl */ + + if (c->flags & ACC_INTERFACE) + v->baseval = -(c->index); + + /* copy virtual function table of super class */ + + for (i = 0; i < supervftbllength; i++) + v->table[i] = super->vftbl->table[i]; + + /* Fill the remaining vftbl slots with the AbstractMethodError + stub (all after the super class slots, because they are already + initialized). */ + + for (; i < vftbllength; i++) { +#if defined(ENABLE_JIT) +# if defined(ENABLE_INTRP) + if (opt_intrp) + v->table[i] = (methodptr) (ptrint) &intrp_asm_abstractmethoderror; + else +# endif + v->table[i] = (methodptr) (ptrint) &asm_abstractmethoderror; +#else + v->table[i] = (methodptr) (ptrint) &intrp_asm_abstractmethoderror; +#endif + } + + /* add method stubs into virtual function table */ + + for (i = 0; i < c->methodscount; i++) { + methodinfo *m = &(c->methods[i]); + + assert(m->stubroutine == NULL); + + /* Don't create a compiler stub for abstract methods as they + throw an AbstractMethodError with the default stub in the + vftbl. This entry is simply copied by sub-classes. */ + + if (m->flags & ACC_ABSTRACT) + continue; + +#if defined(ENABLE_JIT) +# if defined(ENABLE_INTRP) + if (opt_intrp) + m->stubroutine = intrp_createcompilerstub(m); + else +#endif + m->stubroutine = CompilerStub_generate(m); +#else + m->stubroutine = intrp_createcompilerstub(m); +#endif + + /* static methods are not in the vftbl */ + + if (m->flags & ACC_STATIC) + continue; + + /* insert the stubroutine into the vftbl */ + + v->table[m->vftblindex] = (methodptr) (ptrint) m->stubroutine; + } + RT_TIMING_GET_TIME(time_fill_vftbl); + + /* compute instance size and offset of each field */ + + for (i = 0; i < c->fieldscount; i++) { + s4 dsize; + fieldinfo *f = &(c->fields[i]); + + if (!(f->flags & ACC_STATIC)) { + dsize = descriptor_typesize(f->parseddesc); + c->instancesize = MEMORY_ALIGN(c->instancesize, dsize); + f->offset = c->instancesize; + c->instancesize += dsize; + } + } + RT_TIMING_GET_TIME(time_offsets); + + /* initialize interfacetable and interfacevftbllength */ + + v->interfacevftbllength = MNEW(s4, interfacetablelength); + +#if defined(ENABLE_STATISTICS) + if (opt_stat) + count_vftbl_len += (4 + sizeof(s4)) * v->interfacetablelength; +#endif + + for (i = 0; i < interfacetablelength; i++) { + v->interfacevftbllength[i] = 0; + v->interfacetable[-i] = NULL; + } + + /* add interfaces */ + + for (tc = c; tc != NULL; tc = tc->super) + for (i = 0; i < tc->interfacescount; i++) + if (!linker_addinterface(c, tc->interfaces[i])) + return NULL; + + RT_TIMING_GET_TIME(time_fill_iftbl); + + /* add finalizer method (not for java.lang.Object) */ + + if (super) { + methodinfo *fi; + + fi = class_findmethod(c, utf_finalize, utf_void__void); + + if (fi) + if (!(fi->flags & ACC_STATIC)) + c->finalizer = fi; + } + RT_TIMING_GET_TIME(time_finalizer); + + /* final tasks */ + + linker_compute_subclasses(c); + ++ /* FIXME: this is completely useless now */ + RT_TIMING_GET_TIME(time_subclasses); + ++ build_display(c); ++ + /* revert the linking state and class is linked */ + + c->state = (c->state & ~CLASS_LINKING) | CLASS_LINKED; + + /* check worklist */ + + /* XXX must this also be done in case of exception? */ + + while (worklist != NULL) { + method_worklist *wi = worklist; + + worklist = worklist->next; + + INLINELOG( printf("MUST BE RECOMPILED: "); method_println(wi->m); ); + jit_invalidate_code(wi->m); + + /* XXX put worklist into dump memory? */ + FREE(wi, method_worklist); + } + + RT_TIMING_TIME_DIFF(time_start ,time_resolving ,RT_TIMING_LINK_RESOLVE); + RT_TIMING_TIME_DIFF(time_resolving ,time_compute_vftbl,RT_TIMING_LINK_C_VFTBL); + RT_TIMING_TIME_DIFF(time_compute_vftbl,time_abstract ,RT_TIMING_LINK_ABSTRACT); + RT_TIMING_TIME_DIFF(time_abstract ,time_compute_iftbl,RT_TIMING_LINK_C_IFTBL); + RT_TIMING_TIME_DIFF(time_compute_iftbl,time_fill_vftbl ,RT_TIMING_LINK_F_VFTBL); + RT_TIMING_TIME_DIFF(time_fill_vftbl ,time_offsets ,RT_TIMING_LINK_OFFSETS); + RT_TIMING_TIME_DIFF(time_offsets ,time_fill_iftbl ,RT_TIMING_LINK_F_IFTBL); + RT_TIMING_TIME_DIFF(time_fill_iftbl ,time_finalizer ,RT_TIMING_LINK_FINALIZER); + RT_TIMING_TIME_DIFF(time_finalizer ,time_subclasses ,RT_TIMING_LINK_SUBCLASS); + + /* just return c to show that we didn't had a problem */ + + return c; +} + + +/* link_array ****************************************************************** + + This function is called by link_class to create the arraydescriptor + for an array class. + + This function returns NULL if the array cannot be linked because + the component type has not been linked yet. + +*******************************************************************************/ + +static arraydescriptor *link_array(classinfo *c) +{ + classinfo *comp; + s4 namelen; + arraydescriptor *desc; + vftbl_t *compvftbl; + utf *u; + + comp = NULL; + namelen = c->name->blength; + + /* Check the component type */ + + switch (c->name->text[1]) { + case '[': + /* c is an array of arrays. */ + u = utf_new(c->name->text + 1, namelen - 1); + if (!(comp = load_class_from_classloader(u, c->classloader))) + return NULL; + break; + + case 'L': + /* c is an array of objects. */ + u = utf_new(c->name->text + 2, namelen - 3); + if (!(comp = load_class_from_classloader(u, c->classloader))) + return NULL; + break; + } + + /* If the component type has not been linked, link it now */ + + assert(!comp || (comp->state & CLASS_LOADED)); + + if (comp && !(comp->state & CLASS_LINKED)) + if (!link_class(comp)) + return NULL; + + /* Allocate the arraydescriptor */ + + desc = NEW(arraydescriptor); + + if (comp) { + /* c is an array of references */ + desc->arraytype = ARRAYTYPE_OBJECT; + desc->componentsize = sizeof(void*); + desc->dataoffset = OFFSET(java_objectarray_t, data); + + compvftbl = comp->vftbl; + + if (!compvftbl) { + log_text("Component class has no vftbl"); + assert(0); + } + + desc->componentvftbl = compvftbl; + + if (compvftbl->arraydesc) { + desc->elementvftbl = compvftbl->arraydesc->elementvftbl; + + if (compvftbl->arraydesc->dimension >= 255) { + log_text("Creating array of dimension >255"); + assert(0); + } + + desc->dimension = compvftbl->arraydesc->dimension + 1; + desc->elementtype = compvftbl->arraydesc->elementtype; + + } else { + desc->elementvftbl = compvftbl; + desc->dimension = 1; + desc->elementtype = ARRAYTYPE_OBJECT; + } + + } else { + /* c is an array of a primitive type */ + switch (c->name->text[1]) { + case 'Z': + desc->arraytype = ARRAYTYPE_BOOLEAN; + desc->dataoffset = OFFSET(java_booleanarray_t,data); + desc->componentsize = sizeof(u1); + break; + + case 'B': + desc->arraytype = ARRAYTYPE_BYTE; + desc->dataoffset = OFFSET(java_bytearray_t,data); + desc->componentsize = sizeof(u1); + break; + + case 'C': + desc->arraytype = ARRAYTYPE_CHAR; + desc->dataoffset = OFFSET(java_chararray_t,data); + desc->componentsize = sizeof(u2); + break; + + case 'D': + desc->arraytype = ARRAYTYPE_DOUBLE; + desc->dataoffset = OFFSET(java_doublearray_t,data); + desc->componentsize = sizeof(double); + break; + + case 'F': + desc->arraytype = ARRAYTYPE_FLOAT; + desc->dataoffset = OFFSET(java_floatarray_t,data); + desc->componentsize = sizeof(float); + break; + + case 'I': + desc->arraytype = ARRAYTYPE_INT; + desc->dataoffset = OFFSET(java_intarray_t,data); + desc->componentsize = sizeof(s4); + break; + + case 'J': + desc->arraytype = ARRAYTYPE_LONG; + desc->dataoffset = OFFSET(java_longarray_t,data); + desc->componentsize = sizeof(s8); + break; + + case 'S': + desc->arraytype = ARRAYTYPE_SHORT; + desc->dataoffset = OFFSET(java_shortarray_t,data); + desc->componentsize = sizeof(s2); + break; + + default: + exceptions_throw_noclassdeffounderror(c->name); + return NULL; + } + + desc->componentvftbl = NULL; + desc->elementvftbl = NULL; + desc->dimension = 1; + desc->elementtype = desc->arraytype; + } + + return desc; +} + + +/* linker_compute_subclasses *************************************************** + + XXX + + ATTENTION: DO NOT REMOVE ANY OF THE LOCKING MECHANISMS BELOW: + This function needs to take the class renumber lock and stop the + world during class renumbering. The lock is used in C code which + is not that performance critical. Whereas JIT code uses critical + sections to atomically access the class values. + +*******************************************************************************/ + +static void linker_compute_subclasses(classinfo *c) +{ - Mutex_lock(linker_classrenumber_mutex); + + if (!(c->flags & ACC_INTERFACE)) { + c->nextsub = NULL; + c->sub = NULL; ++ c->vftbl->baseval = 1; /* so it does not look like an interface */ + } + + if (!(c->flags & ACC_INTERFACE) && (c->super != NULL)) { + c->nextsub = c->super->sub; + c->super->sub = c; + } + + classvalue = 0; + - /* compute class values */ - - linker_compute_class_values(class_java_lang_Object); - - Mutex_unlock(linker_classrenumber_mutex); +} + + +/* linker_compute_class_values ************************************************* + + XXX + +*******************************************************************************/ + +static void linker_compute_class_values(classinfo *c) +{ + classinfo *subs; + + c->vftbl->baseval = ++classvalue; + + subs = c->sub; + + while (subs) { + linker_compute_class_values(subs); + + subs = subs->nextsub; + } + + c->vftbl->diffval = classvalue - c->vftbl->baseval; +} + + +/* linker_addinterface ********************************************************* + + Is needed by link_class for adding a VTBL to a class. All + interfaces implemented by ic are added as well. + + RETURN VALUE: + true.........everything ok + false........an exception has been thrown + +*******************************************************************************/ + +static bool linker_addinterface(classinfo *c, classinfo *ic) +{ + s4 j, k; + vftbl_t *v; + s4 i; + classinfo *sc; + methodinfo *m; + + v = c->vftbl; + i = ic->index; + + if (i >= v->interfacetablelength) + vm_abort("Internal error: interfacetable overflow"); + + /* if this interface has already been added, return immediately */ + + if (v->interfacetable[-i] != NULL) + return true; + + if (ic->methodscount == 0) { /* fake entry needed for subtype test */ + v->interfacevftbllength[i] = 1; + v->interfacetable[-i] = MNEW(methodptr, 1); + v->interfacetable[-i][0] = NULL; + } + else { + v->interfacevftbllength[i] = ic->methodscount; + v->interfacetable[-i] = MNEW(methodptr, ic->methodscount); + +#if defined(ENABLE_STATISTICS) + if (opt_stat) + count_vftbl_len += sizeof(methodptr) * + (ic->methodscount + (ic->methodscount == 0)); +#endif + + for (j = 0; j < ic->methodscount; j++) { + for (sc = c; sc != NULL; sc = sc->super) { + for (k = 0; k < sc->methodscount; k++) { + m = &(sc->methods[k]); + + if (method_canoverwrite(m, &(ic->methods[j]))) { + /* method m overwrites the (abstract) method */ +#if defined(ENABLE_VERIFIER) + /* Add loading constraints (for the more + general types of the method + ic->methods[j]). */ + if (!classcache_add_constraints_for_params( + c->classloader, ic->classloader, + &(ic->methods[j]))) + { + return false; + } +#endif + + /* XXX taken from gcj */ + /* check for ACC_STATIC: IncompatibleClassChangeError */ + + /* check for !ACC_PUBLIC: IllegalAccessError */ + + /* check for ACC_ABSTRACT: AbstracMethodError, + not sure about that one */ + + v->interfacetable[-i][j] = v->table[m->vftblindex]; + goto foundmethod; + } + } + } + + /* If no method was found, insert the AbstractMethodError + stub. */ + +#if defined(ENABLE_JIT) +# if defined(ENABLE_INTRP) + if (opt_intrp) + v->interfacetable[-i][j] = + (methodptr) (ptrint) &intrp_asm_abstractmethoderror; + else +# endif + v->interfacetable[-i][j] = + (methodptr) (ptrint) &asm_abstractmethoderror; +#else + v->interfacetable[-i][j] = + (methodptr) (ptrint) &intrp_asm_abstractmethoderror; +#endif + + foundmethod: + ; + } + } + + /* add superinterfaces of this interface */ + + for (j = 0; j < ic->interfacescount; j++) + if (!linker_addinterface(c, ic->interfaces[j])) + return false; + + /* everything ok */ + + return true; +} + + +/* class_highestinterface ****************************************************** + + Used by the function link_class to determine the amount of memory + needed for the interface table. + +*******************************************************************************/ + +static s4 class_highestinterface(classinfo *c) +{ + s4 h; + s4 h2; + s4 i; + + /* check for ACC_INTERFACE bit already done in link_class_intern */ + + h = c->index; + + for (i = 0; i < c->interfacescount; i++) { + h2 = class_highestinterface(c->interfaces[i]); + + if (h2 > h) + h = h2; + } + + return h; +} + + +/* + * 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: + */ diff --cc src/vm/linker.h index 6733c5ed1,000000000..124f8b731 mode 100644,000000..100644 --- a/src/vm/linker.h +++ b/src/vm/linker.h @@@ -1,172 -1,0 +1,173 @@@ +/* src/vm/linker.h - class linker header + + Copyright (C) 1996-2005, 2006, 2007, 2008 + CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO + + 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. + +*/ + + +#ifndef _LINKER_H +#define _LINKER_H + +/* forward typedefs ***********************************************************/ + +typedef struct _vftbl vftbl_t; +typedef struct arraydescriptor arraydescriptor; +typedef struct primitivetypeinfo primitivetypeinfo; + + +#include "config.h" +#include "vm/types.h" + +#include "threads/mutex.hpp" + +#include "vm/class.h" +#include "vm/references.h" + + +/* virtual function table ****************************************************** + + The vtbl has a bidirectional layout with open ends at both sides. + interfacetablelength gives the number of entries of the interface + table at the start of the vftbl. The vftbl pointer points to + &interfacetable[0]. vftbllength gives the number of entries of + table at the end of the vftbl. + + runtime type check (checkcast): + + Different methods are used for runtime type check depending on the + argument of checkcast/instanceof. + + A check against a class is implemented via relative numbering on + the class hierachy tree. The tree is numbered in a depth first + traversal setting the base field and the diff field. The diff field + gets the result of (high - base) so that a range check can be + implemented by an unsigned compare. A sub type test is done by + checking the inclusion of base of the sub class in the range of the + superclass. + + A check against an interface is implemented via the + interfacevftbl. If the interfacevftbl contains a nonnull value a + class is a subclass of this interface. + + interfacetable: + + Like standard virtual methods interface methods are called using + virtual function tables. All interfaces are numbered sequentially + (starting with zero). For each class there exist an interface table + of virtual function tables for each implemented interface. The + length of the interface table is determined by the highest number + of an implemented interface. + + The following example assumes a class which implements interface 0 and 3: + + interfacetablelength = 4 + + | ... | +----------+ + +-----------+ | method 2 |---> method z + | class | | method 1 |---> method y + +-----------+ | method 0 |---> method x + | ivftbl 0 |----------> +----------+ + vftblptr ---> +-----------+ + | ivftbl -1 |--> NULL +----------+ + | ivftbl -2 |--> NULL | method 1 |---> method x + | ivftbl -3 |-----+ | method 0 |---> method a + +-----------+ +----> +----------+ + + +---------------+ + | length 3 = 2 | + | length 2 = 0 | + | length 1 = 0 | + | length 0 = 3 | + interfacevftbllength ---> +---------------+ + +*******************************************************************************/ + ++#define DISPLAY_SIZE 4 ++ +struct _vftbl { + methodptr *interfacetable[1]; /* interface table (access via macro) */ + classinfo *clazz; /* class, the vtbl belongs to */ + arraydescriptor *arraydesc; /* for array classes, otherwise NULL */ + s4 vftbllength; /* virtual function table length */ + s4 interfacetablelength; /* interface table length */ + s4 baseval; /* base for runtime type check */ + /* (-index for interfaces) */ + s4 diffval; /* high - base for runtime type check */ ++ ++ s4 subtype_depth; ++ ptrint subtype_offset; ++ struct _vftbl *subtype_display[DISPLAY_SIZE+1]; /* the last one is cache */ ++ s4 subtype_overflow_length; ++ struct _vftbl **subtype_overflow; ++ + s4 *interfacevftbllength; /* length of interface vftbls */ + methodptr table[1]; /* class vftbl */ +}; + + +/* arraydescriptor ************************************************************* + + For every array class an arraydescriptor is allocated which + describes the array class. The arraydescriptor is referenced from + the vftbl of the array class. + +*******************************************************************************/ + +struct arraydescriptor { + vftbl_t *componentvftbl; /* vftbl of the component type, NULL for primit. */ + vftbl_t *elementvftbl; /* vftbl of the element type, NULL for primitive */ + s2 arraytype; /* ARRAYTYPE_* constant */ + s2 dimension; /* dimension of the array (always >= 1) */ + s4 dataoffset; /* offset of the array data from object pointer */ + s4 componentsize; /* size of a component in bytes */ + s2 elementtype; /* ARRAYTYPE_* constant */ +}; + + - /* global variables ***********************************************************/ - - /* This lock must be taken while renumbering classes or while atomically */ - /* accessing classes. */ - - extern Mutex *linker_classrenumber_mutex; - - +/* function prototypes ********************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +void linker_preinit(void); +void linker_init(void); +classinfo *link_class(classinfo *c); + +#ifdef __cplusplus +} +#endif + +#endif /* _LINKER_H */ + + +/* + * 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: + */