From: Robert Schuster Date: Fri, 10 Oct 2008 14:17:15 +0000 (+0200) Subject: * Updated to jitcache-arm-x86 branch d4f6023b26c5+d1b5b1c106ac X-Git-Url: http://wien.tomnetworks.com/gitweb/?p=cacao.git;a=commitdiff_plain;h=f24e856e3c43a10dcc8581fd5ddbdda200d63aba * Updated to jitcache-arm-x86 branch d4f6023b26c5+d1b5b1c106ac --HG-- branch : jitcache-arm-x86 rename : src/vm/builtin.c => src/vm/jit/builtin.cpp rename : src/vm/builtin.h => src/vm/jit/builtin.hpp rename : src/vm/jit/code.c => src/vm/jit/code.cpp rename : src/vm/jit/code.h => src/vm/jit/code.hpp rename : src/vm/jit/codegen-common.c => src/vm/jit/codegen-common.cpp rename : src/vm/jit/jit.c => src/vm/jit/jit.cpp rename : src/vm/jit/patcher-common.c => src/vm/jit/patcher-common.cpp rename : src/vm/jit/patcher-common.h => src/vm/jit/patcher-common.hpp --- f24e856e3c43a10dcc8581fd5ddbdda200d63aba diff --cc src/vm/class.c index a775a758a,1774c3ac0..1fa771c7b --- a/src/vm/class.c +++ b/src/vm/class.c @@@ -50,9 -51,8 +51,9 @@@ #include "vm/global.h" #include "vm/globals.hpp" #include "vm/javaobjects.hpp" +#include "vm/jit/jitcache.hpp" #include "vm/linker.h" - #include "vm/loader.h" + #include "vm/loader.hpp" #include "vm/options.h" #include "vm/resolve.h" @@@ -176,11 -176,8 +177,11 @@@ classinfo *class_create_classinfo(utf * if (classname != utf_not_named_yet) class_set_packagename(c); +#if defined (ENABLE_JITCACHE) + c->cache_file_fd = 0; +#endif - LOCK_INIT_OBJECT_LOCK(&c->object.header); + Lockword_init(&(c->object.header.lockword)); return c; } diff --cc src/vm/jit/Makefile.am index 6b248b466,ce48bfff7..c8d27ba74 --- a/src/vm/jit/Makefile.am +++ b/src/vm/jit/Makefile.am @@@ -114,17 -114,9 +114,17 @@@ TRAP_SOURCES = trap.h endif +if ENABLE_JITCACHE +JITCACHE_SOURCES = \ + jitcache.cpp \ + jitcache.hpp + +endif + + if ENABLE_REPLACEMENT REPLACE_SOURCES += \ - replace.c + replace.cpp endif if ENABLE_VERIFIER @@@ -181,14 -175,13 +183,14 @@@ libjit_la_SOURCES = methodtree.h \ parse.c \ parse.h \ - patcher-common.c \ - patcher-common.h \ + patcher-common.cpp \ + patcher-common.hpp \ $(RECOMPILE_SOURCES) \ $(REG_SOURCES) \ + $(JITCACHE_SOURCES) \ $(REPLACE_SOURCES) \ - show.c \ - show.h \ + show.cpp \ + show.hpp \ $(STACK_SOURCES) \ stacktrace.cpp \ stacktrace.hpp \ diff --cc src/vm/jit/arm/codegen.c index c62b078f7,09f3d0b5f..efe6d3d74 --- a/src/vm/jit/arm/codegen.c +++ b/src/vm/jit/arm/codegen.c @@@ -51,15 -51,14 +51,15 @@@ #include "vm/jit/abi.h" #include "vm/jit/asmpart.h" - #include "vm/jit/codegen-common.h" + #include "vm/jit/codegen-common.hpp" #include "vm/jit/dseg.h" - #include "vm/jit/emit-common.h" - #include "vm/jit/jit.h" + #include "vm/jit/emit-common.hpp" + #include "vm/jit/jit.hpp" +#include "vm/jit/jitcache.hpp" - #include "vm/jit/linenumbertable.h" + #include "vm/jit/linenumbertable.hpp" #include "vm/jit/methodheader.h" #include "vm/jit/parse.h" - #include "vm/jit/patcher-common.h" + #include "vm/jit/patcher-common.hpp" #include "vm/jit/reg.h" #if defined(ENABLE_LSRA) diff --cc src/vm/jit/builtin.cpp index 000000000,c735a277c..f4d23e8eb mode 000000,100644..100644 --- a/src/vm/jit/builtin.cpp +++ b/src/vm/jit/builtin.cpp @@@ -1,0 -1,2340 +1,2415 @@@ + /* 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.hpp" + #include "threads/mutex.hpp" + #include "threads/thread.hpp" + + #include "toolbox/logging.h" + #include "toolbox/util.h" + + #include "vm/array.hpp" + #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_by_key ***************************************************** ++ ++ Returns a key for the given builtintable_entry object which is suitable ++ for retrieving the instance again by calling builtintable_get_by_key. ++ ++ The key can be regarded fixed between multiple runs of the JVM. ++ ++*******************************************************************************/ ++ ++s4 builtintable_get_key(builtintable_entry *bte) ++{ ++ s4 entries; ++/* ++ int i; ++ entries = sizeof(builtintable_internal) / sizeof(builtintable_entry) - 1; ++ for (i = 0; i < entries; i++) ++ if (&builtintable_internal[i] == bte) ++ return i + 1; ++ ++ entries = sizeof(builtintable_automatic) / sizeof(builtintable_entry) - 1; ++ for (i = 0; i < entries; i++) ++ if (&builtintable_automatic[i] == bte) ++ return -i; ++ ++ entries = sizeof(builtintable_function) / sizeof(builtintable_entry) - 1; ++ for (i = 0; i < entries; i++) ++ if (&builtintable_function[i] == bte) ++ return -1000 - i; ++*/ ++ ++ entries = sizeof(builtintable_internal) / sizeof(builtintable_entry) - 1; ++ if (&builtintable_internal[0] <= bte ++ && &builtintable_internal[entries - 1] >= bte) ++ { ++ return (s4) (bte - &builtintable_internal[0]) + 1; ++ } ++ ++ entries = sizeof(builtintable_automatic) / sizeof(builtintable_entry) - 1; ++ if (&builtintable_automatic[0] <= bte ++ && &builtintable_automatic[entries - 1] >= bte) ++ { ++ return -(s4) (bte - &builtintable_automatic[0]); ++ } ++ ++ entries = sizeof(builtintable_function) / sizeof(builtintable_entry) - 1; ++ if (&builtintable_function[0] <= bte ++ && &builtintable_function[entries - 1] >= bte) ++ { ++ return -1000 - (s4) (bte - &builtintable_function[0]); ++ } ++ ++ /* builtintable_entry is not in our tables. */ ++ assert (0); ++ ++ return 0; ++} ++ ++/* builtintable_get_by_key ***************************************************** ++ ++ Retrieves an entry in the internal and automatic builtin functions tables ++ using a key that was retrived previously with builtintable_get_key() ++ ++*******************************************************************************/ ++ ++builtintable_entry *builtintable_get_by_key(s4 key) ++{ ++ /* If key is positive it is the index into builtintable_internal. If it is ++ * negative it is the index into builtintable_automatic. If it is <= -1000 ++ * it is the index into builtintable_function. ++ */ ++ return (key > 0) ++ ? &builtintable_internal[key - 1] ++ : (key > -1000 ? &builtintable_automatic[-key] : &builtintable_function[-(1000 + key)]); ++} ++ + /* 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 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; + } + + 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; + } + + 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(); + + 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) + LLNI_DIRECT(o)->lockword.init(); + #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) + LLNI_DIRECT(o)->lockword.init(); + # 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) + LLNI_DIRECT(o)->lockword.init(); + #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) + LLNI_DIRECT(a)->lockword.init(); + #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; + + c = a + b; + + return c; + } + + s8 builtin_lsub(s8 a, s8 b) + { + s8 c; + + c = a - b; + + return c; + } + + s8 builtin_lneg(s8 a) + { + s8 c; + + c = -a; + + return c; + } + #endif /* !(SUPPORT_LONG && SUPPORT_LONG_ADD) */ + + + #if !(SUPPORT_LONG && SUPPORT_LONG_MUL) + s8 builtin_lmul(s8 a, s8 b) + { + s8 c; + + c = a * b; + + 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; + + c = a / b; + + return c; + } + + s8 builtin_lrem(s8 a, s8 b) + { + s8 c; + + c = a % b; + + 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; + + c = a << (b & 63); + + return c; + } + + s8 builtin_lshr(s8 a, s4 b) + { + s8 c; + + c = a >> (b & 63); + + return c; + } + + s8 builtin_lushr(s8 a, s4 b) + { + s8 c; + + c = ((u8) a) >> (b & 63); + + return c; + } + #endif /* !(SUPPORT_LONG && SUPPORT_LONG_SHIFT) */ + + + #if !(SUPPORT_LONG && SUPPORT_LONG_LOGICAL) + s8 builtin_land(s8 a, s8 b) + { + s8 c; + + c = a & b; + + return c; + } + + s8 builtin_lor(s8 a, s8 b) + { + s8 c; + + c = a | b; + + return c; + } + + s8 builtin_lxor(s8 a, s8 b) + { + s8 c; + + c = a ^ b; + + return c; + } + #endif /* !(SUPPORT_LONG && SUPPORT_LONG_LOGICAL) */ + + + #if !(SUPPORT_LONG && SUPPORT_LONG_CMP) + s4 builtin_lcmp(s8 a, s8 b) + { + if (a < b) + return -1; + + if (a > b) + return 1; + + return 0; + } + #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 !(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) + { + float f = (float) a; + return f; + } + #endif /* !(SUPPORT_LONG && SUPPORT_FLOAT && SUPPORT_L2F) */ + + + #if !(SUPPORT_LONG && SUPPORT_DOUBLE && SUPPORT_L2D) + double builtin_l2d(s8 a) + { + double d = (double) a; + return d; + } + #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) + LLNI_DIRECT(co)->lockword.init(); + #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) + LLNI_DIRECT(co)->lockword.init(); + #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 000000000,2a0345529..3a7747dc2 mode 000000,100644..100644 --- a/src/vm/jit/builtin.hpp +++ b/src/vm/jit/builtin.hpp @@@ -1,0 -1,350 +1,352 @@@ + /* 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); + ++s4 builtintable_get_key(builtintable_entry *); ++builtintable_entry *builtintable_get_by_key(s4 key); + 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. ++ * must be an entry in the tables in vm/builtintable.inc. + * + * 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 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 + + float builtin_i2f(s4 i); + #define BUILTIN_i2f (functionptr) builtin_i2f + double builtin_i2d(s4 i); + #define BUILTIN_i2d (functionptr) builtin_i2d + 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/code.cpp index 000000000,b39852d2e..a991de289 mode 000000,100644..100644 --- a/src/vm/jit/code.cpp +++ b/src/vm/jit/code.cpp @@@ -1,0 -1,289 +1,299 @@@ + /* src/vm/jit/code.cpp - codeinfo struct for representing compiled code + + 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 "arch.h" + + #include "mm/memory.h" + + #include "vm/options.h" + #include "vm/vm.hpp" + + #include "vm/jit/code.hpp" + #include "vm/jit/codegen-common.hpp" ++#include "vm/jit/jitcache.hpp" + #include "vm/jit/patcher-common.hpp" + #include "vm/jit/methodtree.h" + + + /* code_init ******************************************************************* + + Initialize the code-subsystem. + + *******************************************************************************/ + + void code_init(void) + { + /* Check if offset of codeinfo.m == 0 (see comment in code.h). */ + + if (OFFSET(codeinfo, m) != 0) + vm_abort("code_init: offset of codeinfo.m != 0: %d != 0", OFFSET(codeinfo, m)); + } + + + /* code_codeinfo_new *********************************************************** + + Create a new codeinfo for the given method. + + IN: + m................method to create a new codeinfo for + + The following fields are set in codeinfo: + m + patchers ++ cachedrefs + + RETURN VALUE: + a new, initialized codeinfo, or + NULL if an exception occurred. + + *******************************************************************************/ + + codeinfo *code_codeinfo_new(methodinfo *m) + { + codeinfo *code; + + code = NEW(codeinfo); + + code->m = m; + + patcher_list_create(code); + -#if defined(ENABLE_STATISTICS) ++#if defined (ENABLE_JITCACHE) ++ jitcache_list_create(code); ++#endif ++ ++#if defined (ENABLE_STATISTICS) + if (opt_stat) + size_codeinfo += sizeof(codeinfo); + #endif + + return code; + } + + + /* code_find_codeinfo_for_pc *************************************************** + + Return the codeinfo for the compilation unit that contains the + given PC. + + ARGUMENTS: + pc...............machine code position + + RETURN VALUE: + the codeinfo * for the given PC + + *******************************************************************************/ + + codeinfo *code_find_codeinfo_for_pc(void *pc) + { + void *pv; + + pv = methodtree_find(pc); + + return code_get_codeinfo_for_pv(pv); + } + + + /* code_find_codeinfo_for_pc *************************************************** + + Return the codeinfo for the compilation unit that contains the + given PC. This method does not check the return value and is used + by the GC. + + IN: + pc...............machine code position + + RETURN VALUE: + the codeinfo * for the given PC, or NULL + + *******************************************************************************/ + + codeinfo *code_find_codeinfo_for_pc_nocheck(void *pc) + { + void *pv; + + pv = methodtree_find_nocheck(pc); + + if (pv == NULL) + return NULL; + + return code_get_codeinfo_for_pv(pv); + } + + + /* code_get_methodinfo_for_pv ************************************************** + + Return the methodinfo for the given PV. + + IN: + pv...............PV + + RETURN VALUE: + the methodinfo * + + *******************************************************************************/ + + methodinfo *code_get_methodinfo_for_pv(void *pv) + { + codeinfo *code; + + code = code_get_codeinfo_for_pv(pv); + + /* This is the case for asm_vm_call_method. */ + + if (code == NULL) + return NULL; + + return code->m; + } + + + /* code_get_sync_slot_count **************************************************** + + Return the number of stack slots used for storing the synchronized object + (and the return value around lock_monitor_exit calls) by the given code. + + IN: + code.............the codeinfo of the code in question + (must be != NULL) + + RETURN VALUE: + the number of stack slots used for synchronization + + *******************************************************************************/ + + #if defined(ENABLE_REPLACEMENT) + int code_get_sync_slot_count(codeinfo *code) + { + #ifdef ENABLE_THREADS + int count; + + assert(code); + + if (!checksync) + return 0; + + if (!code_is_synchronized(code)) + return 0; + + count = 1; + + #if defined(__POWERPC__) + /* powerpc needs an extra slot */ + count++; + #endif + + return count; + + #else /* !ENABLE_THREADS */ + + return 0; + + #endif /* ENABLE_THREADS */ + } + #endif /* defined(ENABLE_REPLACEMENT) */ + + + /* code_codeinfo_free ********************************************************** + + Free the memory used by a codeinfo. + + IN: + code.............the codeinfo to free + + *******************************************************************************/ + + void code_codeinfo_free(codeinfo *code) + { + if (code == NULL) + return; + + if (code->mcode != NULL) + CFREE((void *) (ptrint) code->mcode, code->mcodelength); + + patcher_list_free(code); + ++#if defined(ENABLE_JITCACHE) ++ jitcache_list_free(code); ++#endif ++ + #if defined(ENABLE_REPLACEMENT) + replace_free_replacement_points(code); + #endif + + FREE(code, codeinfo); + + #if defined(ENABLE_STATISTICS) + if (opt_stat) + size_codeinfo -= sizeof(codeinfo); + #endif + } + + + /* code_free_code_of_method **************************************************** + + Free all codeinfos of the given method + + IN: + m................the method of which the codeinfos are to be freed + + *******************************************************************************/ + + void code_free_code_of_method(methodinfo *m) + { + codeinfo *nextcode; + codeinfo *code; + + if (!m) + return; + + nextcode = m->code; + while (nextcode) { + code = nextcode; + nextcode = code->prev; + code_codeinfo_free(code); + } + + m->code = NULL; + } + + /* + * 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/code.hpp index 000000000,cd082dd19..fcdb08c68 mode 000000,100644..100644 --- a/src/vm/jit/code.hpp +++ b/src/vm/jit/code.hpp @@@ -1,0 -1,252 +1,263 @@@ + /* src/vm/jit/code.hpp - codeinfo struct for representing compiled code + + 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 _CODE_HPP + #define _CODE_HPP + + #include "config.h" + + #include + #include + + #include "vm/types.h" + + #include "toolbox/list.hpp" + + #include "vm/global.h" + #include "vm/method.h" + + #include "vm/jit/exceptiontable.h" ++#if defined (ENABLE_JITCACHE) ++#include "vm/jit/jitcache.hpp" ++#endif + #include "vm/jit/linenumbertable.hpp" + #include "vm/jit/methodheader.h" + #include "vm/jit/patcher-common.hpp" + #include "vm/jit/replace.hpp" + + + /* constants ******************************************************************/ + + #define CODE_FLAG_INVALID 0x0001 + #define CODE_FLAG_LEAFMETHOD 0x0002 + #define CODE_FLAG_SYNCHRONIZED 0x0004 + #define CODE_FLAG_TLH 0x0008 + + + /* codeinfo ******************************************************************* + + A codeinfo represents a particular realization of a method in + machine code. + + ATTENTION: The methodinfo entry in the code-structure MUST have the + offset 0, otherwise we have a problem in our compiler stub. This is + checked with an assert in code_init(). + + *******************************************************************************/ + + struct codeinfo { + methodinfo *m; /* method this is a realization of */ + codeinfo *prev; /* previous codeinfo of this method */ + + uint32_t flags; /* OR of CODE_FLAG_ constants */ + + u1 optlevel; /* optimization level of this code */ + s4 basicblockcount; /* number of basic blocks */ + + int32_t synchronizedoffset; /* stack offset of synchronized obj. */ + + /* machine code */ + u1 *mcode; /* pointer to machine code */ + u1 *entrypoint; /* machine code entry point */ + s4 mcodelength; /* length of generated machine code */ + + exceptiontable_t *exceptiontable; + LinenumberTable* linenumbertable; + + /* patcher list */ + #ifdef __cplusplus + List* patchers; + #else + List* patchers; + #endif + ++#if defined (ENABLE_JITCACHE) ++#ifdef __cplusplus ++ List* cachedrefs; ++#else ++ List* cachedrefs; ++#endif ++#endif ++ + /* replacement */ + s4 stackframesize; /* size of the stackframe in slots */ + + #if defined(ENABLE_REPLACEMENT) + rplpoint *rplpoints; /* replacement points */ + rplalloc *regalloc; /* register allocation info */ + s4 rplpointcount; /* number of replacement points */ + s4 globalcount; /* number of global allocations */ + s4 regalloccount; /* number of total allocations */ + s4 memuse; /* number of arg + local slots */ + u1 savedintcount; /* number of callee saved int regs */ + u1 savedfltcount; /* number of callee saved flt regs */ + # if defined(HAS_ADDRESS_REGISTER_FILE) + u1 savedadrcount; /* number of callee saved adr regs */ + # endif + u1 *savedmcode; /* saved code under patches */ + #endif + + #if defined(ENABLE_PROFILING) + u4 frequency; /* number of method invocations */ + u4 *bbfrequency; + s8 cycles; /* number of cpu cycles */ + #endif + }; + + + #ifdef __cplusplus + extern "C" { + #endif + + /* inline functions ***********************************************************/ + + /* code_xxx_invalid ************************************************************ + + Functions for CODE_FLAG_INVALID. + + *******************************************************************************/ + + inline static int code_is_invalid(codeinfo *code) + { + return (code->flags & CODE_FLAG_INVALID); + } + + inline static void code_flag_invalid(codeinfo *code) + { + code->flags |= CODE_FLAG_INVALID; + } + + inline static void code_unflag_invalid(codeinfo *code) + { + code->flags &= ~CODE_FLAG_INVALID; + } + + + /* code_xxx_leafmethod ********************************************************* + + Functions for CODE_FLAG_LEAFMETHOD. + + *******************************************************************************/ + + inline static int code_is_leafmethod(codeinfo *code) + { + return (code->flags & CODE_FLAG_LEAFMETHOD); + } + + inline static void code_flag_leafmethod(codeinfo *code) + { + code->flags |= CODE_FLAG_LEAFMETHOD; + } + + inline static void code_unflag_leafmethod(codeinfo *code) + { + code->flags &= ~CODE_FLAG_LEAFMETHOD; + } + + + /* code_xxx_synchronized ******************************************************* + + Functions for CODE_FLAG_SYNCHRONIZED. + + *******************************************************************************/ + + inline static int code_is_synchronized(codeinfo *code) + { + return (code->flags & CODE_FLAG_SYNCHRONIZED); + } + + inline static void code_flag_synchronized(codeinfo *code) + { + code->flags |= CODE_FLAG_SYNCHRONIZED; + } + + inline static void code_unflag_synchronized(codeinfo *code) + { + code->flags &= ~CODE_FLAG_SYNCHRONIZED; + } + + + /* code_get_codeinfo_for_pv **************************************************** + + Return the codeinfo for the given PV. + + IN: + pv...............PV + + RETURN VALUE: + the codeinfo * + + *******************************************************************************/ + + inline static codeinfo *code_get_codeinfo_for_pv(void *pv) + { + codeinfo *code; + + assert(pv != NULL); + + code = *((codeinfo **) (((uintptr_t) pv) + CodeinfoPointer)); + + return code; + } + + + /* function prototypes ********************************************************/ + + void code_init(void); + + codeinfo *code_codeinfo_new(methodinfo *m); + void code_codeinfo_free(codeinfo *code); + + codeinfo *code_find_codeinfo_for_pc(void *pc); + codeinfo *code_find_codeinfo_for_pc_nocheck(void *pc); + + methodinfo *code_get_methodinfo_for_pv(void *pv); + + #if defined(ENABLE_REPLACEMENT) + int code_get_sync_slot_count(codeinfo *code); + #endif /* defined(ENABLE_REPLACEMENT) */ + + void code_free_code_of_method(methodinfo *m); + + #ifdef __cplusplus + } + #endif + + #endif // _CODE_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/codegen-common.cpp index 000000000,c4a4c64f8..1210915ea mode 000000,100644..100644 --- a/src/vm/jit/codegen-common.cpp +++ b/src/vm/jit/codegen-common.cpp @@@ -1,0 -1,1075 +1,1081 @@@ + /* src/vm/jit/codegen-common.cpp - architecture independent code generator stuff + + 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. + + All functions assume the following code area / data area layout: + + +-----------+ + | | + | code area | code area grows to higher addresses + | | + +-----------+ <-- start of procedure + | | + | data area | data area grows to lower addresses + | | + +-----------+ + + The functions first write into a temporary code/data area allocated by + "codegen_init". "codegen_finish" copies the code and data area into permanent + memory. All functions writing values into the data area return the offset + relative the begin of the code area (start of procedure). + + */ + + + #include "config.h" + + #include + #include + ++#include "vm/jit/jitcache.hpp" ++ + #include "vm/types.h" + + #include "codegen.h" + #include "md.h" + #include "md-abi.h" + + #include "mm/memory.h" + + #include "toolbox/avl.h" + #include "toolbox/list.hpp" + #include "toolbox/logging.h" + + #include "native/llni.h" + #include "native/localref.hpp" + #include "native/native.hpp" + + #include "threads/thread.hpp" + + #include "vm/jit/builtin.hpp" + #include "vm/exceptions.hpp" + #include "vm/method.h" + #include "vm/options.h" + #include "vm/string.hpp" + + # include "vm/statistics.h" + + + #include "vm/jit/abi.h" + #include "vm/jit/asmpart.h" + #include "vm/jit/code.hpp" + #include "vm/jit/codegen-common.hpp" + + #if defined(ENABLE_DISASSEMBLER) + # include "vm/jit/disass.h" + #endif + + #include "vm/jit/dseg.h" + #include "vm/jit/emit-common.hpp" + #include "vm/jit/jit.hpp" + #include "vm/jit/linenumbertable.hpp" + #include "vm/jit/methodheader.h" + #include "vm/jit/methodtree.h" + #include "vm/jit/patcher-common.hpp" + #include "vm/jit/replace.hpp" + #if defined(ENABLE_SSA) + # include "vm/jit/optimizing/lsra.h" + # include "vm/jit/optimizing/ssa.h" + #endif + #include "vm/jit/stacktrace.hpp" + #include "vm/jit/trace.hpp" + + #if defined(ENABLE_INTRP) + #include "vm/jit/intrp/intrp.h" + #endif + + #if defined(ENABLE_VMLOG) + #include + #endif + + #include "show.hpp" + + + /* codegen_init **************************************************************** + + TODO + + *******************************************************************************/ + + void codegen_init(void) + { + } + + + /* codegen_setup *************************************************************** + + Allocates and initialises code area, data area and references. + + *******************************************************************************/ + + void codegen_setup(jitdata *jd) + { + methodinfo *m; + codegendata *cd; + + /* get required compiler data */ + + m = jd->m; + cd = jd->cd; + + /* initialize members */ + + cd->flags = 0; + + cd->mcodebase = (u1*) DumpMemory::allocate(MCODEINITSIZE); + cd->mcodeend = cd->mcodebase + MCODEINITSIZE; + cd->mcodesize = MCODEINITSIZE; + + /* initialize mcode variables */ + + cd->mcodeptr = cd->mcodebase; + cd->lastmcodeptr = cd->mcodebase; + + #if defined(ENABLE_INTRP) + /* native dynamic superinstructions variables */ + + if (opt_intrp) { + cd->ncodebase = (u1*) DumpMemory::allocate(NCODEINITSIZE); + cd->ncodesize = NCODEINITSIZE; + + /* initialize ncode variables */ + + cd->ncodeptr = cd->ncodebase; + + cd->lastinstwithoutdispatch = ~0; /* no inst without dispatch */ + cd->superstarts = NULL; + } + #endif + + cd->dseg = NULL; + cd->dseglen = 0; + + cd->jumpreferences = NULL; + + #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP) + cd->datareferences = NULL; + #endif + + cd->brancheslabel = new DumpList(); + cd->linenumbers = new DumpList(); + } + + + /* codegen_reset *************************************************************** + + Resets the codegen data structure so we can recompile the method. + + *******************************************************************************/ + + static void codegen_reset(jitdata *jd) + { + codeinfo *code; + codegendata *cd; + basicblock *bptr; + + /* get required compiler data */ + + code = jd->code; + cd = jd->cd; + + /* reset error flag */ + + cd->flags &= ~CODEGENDATA_FLAG_ERROR; + + /* reset some members, we reuse the code memory already allocated + as this should have almost the correct size */ + + cd->mcodeptr = cd->mcodebase; + cd->lastmcodeptr = cd->mcodebase; + + cd->dseg = NULL; + cd->dseglen = 0; + + cd->jumpreferences = NULL; + + #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP) + cd->datareferences = NULL; + #endif + + cd->brancheslabel = new DumpList(); + cd->linenumbers = new DumpList(); + + /* We need to clear the mpc and the branch references from all + basic blocks as they will definitely change. */ + + for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) { + bptr->mpc = -1; + bptr->branchrefs = NULL; + } + + /* We need to clear all the patcher references from the codeinfo + since they all will be regenerated */ + + patcher_list_reset(code); + + #if defined(ENABLE_REPLACEMENT) + code->rplpoints = NULL; + code->rplpointcount = 0; + code->regalloc = NULL; + code->regalloccount = 0; + code->globalcount = 0; + #endif + } + + + /* codegen_generate ************************************************************ + + Generates the code for the currently compiled method. + + *******************************************************************************/ + + bool codegen_generate(jitdata *jd) + { + codegendata *cd; + + /* get required compiler data */ + + cd = jd->cd; + + /* call the machine-dependent code generation function */ + + if (!codegen_emit(jd)) + return false; + + /* check for an error */ + + if (CODEGENDATA_HAS_FLAG_ERROR(cd)) { + /* check for long-branches flag, if it is set we recompile the + method */ + + #if !defined(NDEBUG) + if (compileverbose) + log_message_method("Re-generating code: ", jd->m); + #endif + + /* XXX maybe we should tag long-branches-methods for recompilation */ + + if (CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) { + /* we have to reset the codegendata structure first */ + + codegen_reset(jd); + + /* and restart the compiler run */ + + if (!codegen_emit(jd)) + return false; + } + else { + vm_abort("codegen_generate: unknown error occurred during codegen_emit: flags=%x\n", cd->flags); + } + + #if !defined(NDEBUG) + if (compileverbose) + log_message_method("Re-generating code done: ", jd->m); + #endif + } + + /* reallocate the memory and finish the code generation */ + + codegen_finish(jd); + + /* everything's ok */ + + return true; + } + + + /* codegen_close *************************************************************** + + TODO + + *******************************************************************************/ + + void codegen_close(void) + { + /* TODO: release avl tree on i386 and x86_64 */ + } + + + /* codegen_increase ************************************************************ + + Doubles code area. + + *******************************************************************************/ + + void codegen_increase(codegendata *cd) + { + u1 *oldmcodebase; + + /* save old mcodebase pointer */ + + oldmcodebase = cd->mcodebase; + + /* reallocate to new, doubled memory */ + + cd->mcodebase = (u1*) DumpMemory::reallocate(cd->mcodebase, + cd->mcodesize, + cd->mcodesize * 2); + cd->mcodesize *= 2; + cd->mcodeend = cd->mcodebase + cd->mcodesize; + + /* set new mcodeptr */ + + cd->mcodeptr = cd->mcodebase + (cd->mcodeptr - oldmcodebase); + + #if defined(__I386__) || defined(__MIPS__) || defined(__X86_64__) || defined(__M68K__) || defined(ENABLE_INTRP) \ + || defined(__SPARC_64__) + /* adjust the pointer to the last patcher position */ + + if (cd->lastmcodeptr != NULL) + cd->lastmcodeptr = cd->mcodebase + (cd->lastmcodeptr - oldmcodebase); + #endif + } + + + /* codegen_ncode_increase ****************************************************** + + Doubles code area. + + *******************************************************************************/ + + #if defined(ENABLE_INTRP) + u1 *codegen_ncode_increase(codegendata *cd, u1 *ncodeptr) + { + u1 *oldncodebase; + + /* save old ncodebase pointer */ + + oldncodebase = cd->ncodebase; + + /* reallocate to new, doubled memory */ + + cd->ncodebase = DMREALLOC(cd->ncodebase, + u1, + cd->ncodesize, + cd->ncodesize * 2); + cd->ncodesize *= 2; + + /* return the new ncodeptr */ + + return (cd->ncodebase + (ncodeptr - oldncodebase)); + } + #endif + + + /* codegen_add_branch_ref ****************************************************** + + Prepends an branch to the list. + + *******************************************************************************/ + + void codegen_add_branch_ref(codegendata *cd, basicblock *target, s4 condition, s4 reg, u4 options) + { + branchref *br; + s4 branchmpc; + + STATISTICS(count_branches_unresolved++); + + /* calculate the mpc of the branch instruction */ + + branchmpc = cd->mcodeptr - cd->mcodebase; + + br = (branchref*) DumpMemory::allocate(sizeof(branchref)); + + br->branchmpc = branchmpc; + br->condition = condition; + br->reg = reg; + br->options = options; + br->next = target->branchrefs; + + target->branchrefs = br; + } + + + /* codegen_resolve_branchrefs ************************************************** + + Resolves and patches the branch references of a given basic block. + + *******************************************************************************/ + + void codegen_resolve_branchrefs(codegendata *cd, basicblock *bptr) + { + branchref *br; + u1 *mcodeptr; + + /* Save the mcodeptr because in the branch emitting functions + we generate code somewhere inside already generated code, + but we're still in the actual code generation phase. */ + + mcodeptr = cd->mcodeptr; + + /* just to make sure */ + + assert(bptr->mpc >= 0); + + for (br = bptr->branchrefs; br != NULL; br = br->next) { + /* temporary set the mcodeptr */ + + cd->mcodeptr = cd->mcodebase + br->branchmpc; + + /* emit_bccz and emit_branch emit the correct code, even if we + pass condition == BRANCH_UNCONDITIONAL or reg == -1. */ + + emit_bccz(cd, bptr, br->condition, br->reg, br->options); + } + + /* restore mcodeptr */ + + cd->mcodeptr = mcodeptr; + } + + + /* codegen_branch_label_add **************************************************** + + Append an branch to the label-branch list. + + *******************************************************************************/ + + void codegen_branch_label_add(codegendata *cd, s4 label, s4 condition, s4 reg, u4 options) + { + // Calculate the current mpc. + int32_t mpc = cd->mcodeptr - cd->mcodebase; + + branch_label_ref_t* br = (branch_label_ref_t*) DumpMemory::allocate(sizeof(branch_label_ref_t)); + + br->mpc = mpc; + br->label = label; + br->condition = condition; + br->reg = reg; + br->options = options; + + // Add the branch to the list. + cd->brancheslabel->push_back(br); + } + + + /* codegen_set_replacement_point_notrap **************************************** + + Record the position of a non-trappable replacement point. + + *******************************************************************************/ + + #if defined(ENABLE_REPLACEMENT) + #if !defined(NDEBUG) + void codegen_set_replacement_point_notrap(codegendata *cd, s4 type) + #else + void codegen_set_replacement_point_notrap(codegendata *cd) + #endif + { + assert(cd->replacementpoint); + assert(cd->replacementpoint->type == type); + assert(cd->replacementpoint->flags & RPLPOINT_FLAG_NOTRAP); + + cd->replacementpoint->pc = (u1*) (ptrint) (cd->mcodeptr - cd->mcodebase); + + cd->replacementpoint++; + } + #endif /* defined(ENABLE_REPLACEMENT) */ + + + /* codegen_set_replacement_point *********************************************** + + Record the position of a trappable replacement point. + + *******************************************************************************/ + + #if defined(ENABLE_REPLACEMENT) + #if !defined(NDEBUG) + void codegen_set_replacement_point(codegendata *cd, s4 type) + #else + void codegen_set_replacement_point(codegendata *cd) + #endif + { + assert(cd->replacementpoint); + assert(cd->replacementpoint->type == type); + assert(!(cd->replacementpoint->flags & RPLPOINT_FLAG_NOTRAP)); + + cd->replacementpoint->pc = (u1*) (ptrint) (cd->mcodeptr - cd->mcodebase); + + cd->replacementpoint++; + + #if !defined(NDEBUG) + /* XXX actually we should use an own REPLACEMENT_NOPS here! */ + if (opt_TestReplacement) + PATCHER_NOPS; + #endif + + /* XXX assert(cd->lastmcodeptr <= cd->mcodeptr); */ + + cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE; + } + #endif /* defined(ENABLE_REPLACEMENT) */ + + + /* codegen_finish ************************************************************** + + Finishes the code generation. A new memory, large enough for both + data and code, is allocated and data and code are copied together + to their final layout, unresolved jumps are resolved, ... + + *******************************************************************************/ + + void codegen_finish(jitdata *jd) + { + codeinfo *code; + codegendata *cd; + s4 mcodelen; + #if defined(ENABLE_INTRP) + s4 ncodelen; + #endif + s4 alignedmcodelen; + jumpref *jr; + u1 *epoint; + s4 alignedlen; + + /* get required compiler data */ + + code = jd->code; + cd = jd->cd; + + /* prevent compiler warning */ + + #if defined(ENABLE_INTRP) + ncodelen = 0; + #endif + + /* calculate the code length */ + + mcodelen = (s4) (cd->mcodeptr - cd->mcodebase); + + #if defined(ENABLE_STATISTICS) + if (opt_stat) { + count_code_len += mcodelen; + count_data_len += cd->dseglen; + } + #endif + + alignedmcodelen = MEMORY_ALIGN(mcodelen, MAX_ALIGN); + + #if defined(ENABLE_INTRP) + if (opt_intrp) + ncodelen = cd->ncodeptr - cd->ncodebase; + else { + ncodelen = 0; /* avoid compiler warning */ + } + #endif + + cd->dseglen = MEMORY_ALIGN(cd->dseglen, MAX_ALIGN); + alignedlen = alignedmcodelen + cd->dseglen; + + #if defined(ENABLE_INTRP) + if (opt_intrp) { + alignedlen += ncodelen; + } + #endif + + /* allocate new memory */ + + code->mcodelength = mcodelen + cd->dseglen; + code->mcode = CNEW(u1, alignedlen); + + /* set the entrypoint of the method */ + + assert(code->entrypoint == NULL); + code->entrypoint = epoint = (code->mcode + cd->dseglen); + + /* fill the data segment (code->entrypoint must already be set!) */ + + dseg_finish(jd); + + /* copy code to the new location */ + + MCOPY((void *) code->entrypoint, cd->mcodebase, u1, mcodelen); + + #if defined(ENABLE_INTRP) + /* relocate native dynamic superinstruction code (if any) */ + + if (opt_intrp) { + cd->mcodebase = code->entrypoint; + + if (ncodelen > 0) { + u1 *ncodebase = code->mcode + cd->dseglen + alignedmcodelen; + + MCOPY((void *) ncodebase, cd->ncodebase, u1, ncodelen); + + /* flush the instruction and data caches */ + + md_cacheflush(ncodebase, ncodelen); + + /* set some cd variables for dynamic_super_rerwite */ + + cd->ncodebase = ncodebase; + + } else { + cd->ncodebase = NULL; + } + + dynamic_super_rewrite(cd); + } + #endif + + /* Create the exception table. */ + + exceptiontable_create(jd); + + /* Create the linenumber table. */ + + code->linenumbertable = new LinenumberTable(jd); + + /* jump table resolving */ + + for (jr = cd->jumpreferences; jr != NULL; jr = jr->next) ++ { + *((functionptr *) ((ptrint) epoint + jr->tablepos)) = + (functionptr) ((ptrint) epoint + (ptrint) jr->target->mpc); + ++ JITCACHE_ADD_CACHED_REF(code, CRT_JUMPREFERENCE, jr->target->mpc, jr->tablepos); ++ } ++ + /* patcher resolving */ + + patcher_resolve(jd); + + #if defined(ENABLE_REPLACEMENT) + /* replacement point resolving */ + { + int i; + rplpoint *rp; + + rp = code->rplpoints; + for (i=0; irplpointcount; ++i, ++rp) { + rp->pc = (u1*) ((ptrint) epoint + (ptrint) rp->pc); + } + } + #endif /* defined(ENABLE_REPLACEMENT) */ + + /* Insert method into methodtree to find the entrypoint. */ + + methodtree_insert(code->entrypoint, code->entrypoint + mcodelen); + + #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP) + /* resolve data segment references */ + + dseg_resolve_datareferences(jd); + #endif + + /* flush the instruction and data caches */ + + md_cacheflush(code->mcode, code->mcodelength); + } + + + /* codegen_start_native_call *************************************************** + + Prepares the stuff required for a native (JNI) function call: + + - adds a stackframe info structure to the chain, for stacktraces + - prepares the local references table on the stack + + The layout of the native stub stackframe should look like this: + + +---------------------------+ <- java SP (of parent Java function) + | return address | + +---------------------------+ <- data SP + | | + | stackframe info structure | + | | + +---------------------------+ + | | + | local references table | + | | + +---------------------------+ + | | + | saved registers (if any) | + | | + +---------------------------+ + | | + | arguments (if any) | + | | + +---------------------------+ <- current SP (native stub) + + *******************************************************************************/ + + java_handle_t *codegen_start_native_call(u1 *sp, u1 *pv) + { + stackframeinfo_t *sfi; + localref_table *lrt; + methodinfo *m; + int32_t framesize; + + uint8_t *datasp; + uint8_t *javasp; + uint64_t *arg_regs; + uint64_t *arg_stack; + + STATISTICS(count_calls_java_to_native++); + + /* Get the methodinfo. */ + + m = code_get_methodinfo_for_pv(pv); + + assert(m); + + framesize = *((int32_t *) (pv + FrameSize)); + + assert(framesize >= (int32_t) (sizeof(stackframeinfo_t) + sizeof(localref_table))); + + /* calculate needed values */ + + #if defined(__ALPHA__) || defined(__ARM__) + datasp = sp + framesize - SIZEOF_VOID_P; + javasp = sp + framesize; + arg_regs = (uint64_t *) sp; + arg_stack = (uint64_t *) javasp; + #elif defined(__MIPS__) + /* MIPS always uses 8 bytes to store the RA */ + datasp = sp + framesize - 8; + javasp = sp + framesize; + #elif defined(__S390__) + datasp = sp + framesize - 8; + javasp = sp + framesize; + arg_regs = (uint64_t *) (sp + 96); + arg_stack = (uint64_t *) javasp; + #elif defined(__I386__) || defined(__M68K__) || defined(__X86_64__) + datasp = sp + framesize; + javasp = sp + framesize + SIZEOF_VOID_P; + arg_regs = (uint64_t *) sp; + arg_stack = (uint64_t *) javasp; + #elif defined(__POWERPC__) + datasp = sp + framesize; + javasp = sp + framesize; + arg_regs = (uint64_t *) (sp + LA_SIZE + 4 * SIZEOF_VOID_P); + arg_stack = (uint64_t *) javasp; + #elif defined(__POWERPC64__) + datasp = sp + framesize; + javasp = sp + framesize; + arg_regs = (uint64_t *) (sp + PA_SIZE + LA_SIZE + 4 * SIZEOF_VOID_P); + arg_stack = (uint64_t *) javasp; + #else + /* XXX is was unable to do this port for SPARC64, sorry. (-michi) */ + /* XXX maybe we need to pass the RA as argument there */ + vm_abort("codegen_start_native_call: unsupported architecture"); + #endif + + /* get data structures from stack */ + + sfi = (stackframeinfo_t *) (datasp - sizeof(stackframeinfo_t)); + lrt = (localref_table *) (datasp - sizeof(stackframeinfo_t) - + sizeof(localref_table)); + + #if defined(ENABLE_JNI) + /* add current JNI local references table to this thread */ + + localref_table_add(lrt); + #endif + + #if !defined(NDEBUG) + # if defined(__ALPHA__) || defined(__I386__) || defined(__M68K__) || defined(__POWERPC__) || defined(__POWERPC64__) || defined(__S390__) || defined(__X86_64__) + /* print the call-trace if necesarry */ + /* BEFORE: filling the local reference table */ + + if (opt_TraceJavaCalls) + trace_java_call_enter(m, arg_regs, arg_stack); + # endif + #endif + + #if defined(ENABLE_HANDLES) + /* place all references into the local reference table */ + /* BEFORE: creating stackframeinfo */ + + localref_native_enter(m, arg_regs, arg_stack); + #endif + + /* Add a stackframeinfo for this native method. We don't have RA + and XPC here. These are determined in + stacktrace_stackframeinfo_add. */ + + stacktrace_stackframeinfo_add(sfi, pv, sp, NULL, NULL); + + /* Return a wrapped classinfo for static methods. */ + + if (m->flags & ACC_STATIC) + return (java_handle_t *) LLNI_classinfo_wrap(m->clazz); + else + return NULL; + } + + + /* codegen_finish_native_call ************************************************** + + Removes the stuff required for a native (JNI) function call. + Additionally it checks for an exceptions and in case, get the + exception object and clear the pointer. + + *******************************************************************************/ + + java_object_t *codegen_finish_native_call(u1 *sp, u1 *pv) + { + stackframeinfo_t *sfi; + java_handle_t *e; + java_object_t *o; + codeinfo *code; + methodinfo *m; + int32_t framesize; + + uint8_t *datasp; + uint64_t *ret_regs; + + /* get information from method header */ + + code = code_get_codeinfo_for_pv(pv); + + framesize = *((int32_t *) (pv + FrameSize)); + + assert(code); + + /* get the methodinfo */ + + m = code->m; + assert(m); + + /* calculate needed values */ + + #if defined(__ALPHA__) || defined(__ARM__) + datasp = sp + framesize - SIZEOF_VOID_P; + ret_regs = (uint64_t *) sp; + #elif defined(__MIPS__) + /* MIPS always uses 8 bytes to store the RA */ + datasp = sp + framesize - 8; + #elif defined(__S390__) + datasp = sp + framesize - 8; + ret_regs = (uint64_t *) (sp + 96); + #elif defined(__I386__) + datasp = sp + framesize; + ret_regs = (uint64_t *) (sp + 2 * SIZEOF_VOID_P); + #elif defined(__M68K__) + datasp = sp + framesize; + ret_regs = (uint64_t *) (sp + 2 * 8); + #elif defined(__X86_64__) + datasp = sp + framesize; + ret_regs = (uint64_t *) sp; + #elif defined(__POWERPC__) + datasp = sp + framesize; + ret_regs = (uint64_t *) (sp + LA_SIZE + 2 * SIZEOF_VOID_P); + #elif defined(__POWERPC64__) + datasp = sp + framesize; + ret_regs = (uint64_t *) (sp + PA_SIZE + LA_SIZE + 2 * SIZEOF_VOID_P); + #else + vm_abort("codegen_finish_native_call: unsupported architecture"); + #endif + + /* get data structures from stack */ + + sfi = (stackframeinfo_t *) (datasp - sizeof(stackframeinfo_t)); + + /* Remove current stackframeinfo from chain. */ + + stacktrace_stackframeinfo_remove(sfi); + + #if defined(ENABLE_HANDLES) + /* unwrap the return value from the local reference table */ + /* AFTER: removing the stackframeinfo */ + /* BEFORE: releasing the local reference table */ + + localref_native_exit(m, ret_regs); + #endif + + /* get and unwrap the exception */ + /* AFTER: removing the stackframe info */ + /* BEFORE: releasing the local reference table */ + + e = exceptions_get_and_clear_exception(); + o = LLNI_UNWRAP(e); + + #if defined(ENABLE_JNI) + /* release JNI local references table for this thread */ + + localref_frame_pop_all(); + localref_table_remove(); + #endif + + #if !defined(NDEBUG) + # if defined(__ALPHA__) || defined(__I386__) || defined(__M68K__) || defined(__POWERPC__) || defined(__POWERPC64__) || defined(__S390__) || defined(__X86_64__) + /* print the call-trace if necesarry */ + /* AFTER: unwrapping the return value */ + + if (opt_TraceJavaCalls) + trace_java_call_exit(m, ret_regs); + # endif + #endif + + return o; + } + + + /* codegen_reg_of_var ********************************************************** + + This function determines a register, to which the result of an + operation should go, when it is ultimatively intended to store the + result in pseudoregister v. If v is assigned to an actual + register, this register will be returned. Otherwise (when v is + spilled) this function returns tempregnum. If not already done, + regoff and flags are set in the stack location. + + *******************************************************************************/ + + s4 codegen_reg_of_var(u2 opcode, varinfo *v, s4 tempregnum) + { + if (!(v->flags & INMEMORY)) + return v->vv.regoff; + + return tempregnum; + } + + + /* codegen_reg_of_dst ********************************************************** + + This function determines a register, to which the result of an + operation should go, when it is ultimatively intended to store the + result in iptr->dst.var. If dst.var is assigned to an actual + register, this register will be returned. Otherwise (when it is + spilled) this function returns tempregnum. If not already done, + regoff and flags are set in the stack location. + + *******************************************************************************/ + + s4 codegen_reg_of_dst(jitdata *jd, instruction *iptr, s4 tempregnum) + { + return codegen_reg_of_var(iptr->opc, VAROP(iptr->dst), tempregnum); + } + + + /* codegen_emit_phi_moves **************************************************** + + Emits phi moves at the end of the basicblock. + + *******************************************************************************/ + + #if defined(ENABLE_SSA) + void codegen_emit_phi_moves(jitdata *jd, basicblock *bptr) + { + int lt_d,lt_s,i; + lsradata *ls; + codegendata *cd; + varinfo *s, *d; + instruction tmp_i; + + cd = jd->cd; + ls = jd->ls; + + MCODECHECK(512); + + /* Moves from phi functions with highest indices have to be */ + /* inserted first, since this is the order as is used for */ + /* conflict resolution */ + + for(i = ls->num_phi_moves[bptr->nr] - 1; i >= 0 ; i--) { + lt_d = ls->phi_moves[bptr->nr][i][0]; + lt_s = ls->phi_moves[bptr->nr][i][1]; + #if defined(SSA_DEBUG_VERBOSE) + if (compileverbose) + printf("BB %3i Move %3i <- %3i ", bptr->nr, lt_d, lt_s); + #endif + if (lt_s == UNUSED) { + #if defined(SSA_DEBUG_VERBOSE) + if (compileverbose) + printf(" ... not processed \n"); + #endif + continue; + } + + d = VAR(ls->lifetime[lt_d].v_index); + s = VAR(ls->lifetime[lt_s].v_index); + + + if (d->type == -1) { + #if defined(SSA_DEBUG_VERBOSE) + if (compileverbose) + printf("...returning - phi lifetimes where joined\n"); + #endif + continue; + } + + if (s->type == -1) { + #if defined(SSA_DEBUG_VERBOSE) + if (compileverbose) + printf("...returning - phi lifetimes where joined\n"); + #endif + continue; + } + + tmp_i.opc = 0; + tmp_i.s1.varindex = ls->lifetime[lt_s].v_index; + tmp_i.dst.varindex = ls->lifetime[lt_d].v_index; + emit_copy(jd, &tmp_i); + + #if defined(SSA_DEBUG_VERBOSE) + if (compileverbose) { + if (IS_INMEMORY(d->flags) && IS_INMEMORY(s->flags)) { + /* mem -> mem */ + printf("M%3i <- M%3i",d->vv.regoff,s->vv.regoff); + } + else if (IS_INMEMORY(s->flags)) { + /* mem -> reg */ + printf("R%3i <- M%3i",d->vv.regoff,s->vv.regoff); + } + else if (IS_INMEMORY(d->flags)) { + /* reg -> mem */ + printf("M%3i <- R%3i",d->vv.regoff,s->vv.regoff); + } + else { + /* reg -> reg */ + printf("R%3i <- R%3i",d->vv.regoff,s->vv.regoff); + } + printf("\n"); + } + #endif /* defined(SSA_DEBUG_VERBOSE) */ + } + } + #endif /* defined(ENABLE_SSA) */ + + + /* REMOVEME When we have exception handling in C. */ + + void *md_asm_codegen_get_pv_from_pc(void *ra) + { + return md_codegen_get_pv_from_pc(ra); + } + + + /* + * 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/i386/codegen.c index 133b1bf61,1252e136a..b7e808cab --- a/src/vm/jit/i386/codegen.c +++ b/src/vm/jit/i386/codegen.c @@@ -54,16 -54,15 +54,16 @@@ #include "vm/jit/abi.h" #include "vm/jit/asmpart.h" - #include "vm/jit/codegen-common.h" + #include "vm/jit/codegen-common.hpp" #include "vm/jit/dseg.h" - #include "vm/jit/emit-common.h" - #include "vm/jit/jit.h" + #include "vm/jit/emit-common.hpp" + #include "vm/jit/jit.hpp" +#include "vm/jit/jitcache.hpp" - #include "vm/jit/linenumbertable.h" + #include "vm/jit/linenumbertable.hpp" #include "vm/jit/parse.h" - #include "vm/jit/patcher-common.h" + #include "vm/jit/patcher-common.hpp" #include "vm/jit/reg.h" - #include "vm/jit/replace.h" + #include "vm/jit/replace.hpp" #include "vm/jit/stacktrace.hpp" #include "vm/jit/trap.h" diff --cc src/vm/jit/jit.cpp index 000000000,b889cd59c..e7dddde59 mode 000000,100644..100644 --- a/src/vm/jit/jit.cpp +++ b/src/vm/jit/jit.cpp @@@ -1,0 -1,1178 +1,1197 @@@ + /* src/vm/jit/jit.cpp - Just-In-Time compiler + + 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 "md.h" + + #include "mm/memory.h" + + #include "native/native.hpp" + + #include "toolbox/logging.h" + + #include "threads/mutex.hpp" + + #include "vm/class.h" + #include "vm/global.h" + #include "vm/globals.hpp" + #include "vm/initialize.h" + #include "vm/loader.hpp" + #include "vm/method.h" + #include "vm/options.h" + #include "vm/rt-timing.h" + #include "vm/statistics.h" + + #include "vm/jit/asmpart.h" + + #include "vm/jit/cfg.h" + + #include "vm/jit/codegen-common.hpp" + #include "vm/jit/disass.h" + #include "vm/jit/dseg.h" + #include "vm/jit/jit.hpp" + #include "vm/jit/parse.h" + #include "vm/jit/reg.h" + + #include "vm/jit/show.hpp" + #include "vm/jit/stack.h" + #include "vm/jit/stubs.hpp" + ++#if defined(ENABLE_JITCACHE) ++# include "vm/jit/jitcache.hpp" ++#endif ++ + #if defined(ENABLE_OPAGENT) + #include "vm/jit/oprofile-agent.hpp" + #endif + + #include "vm/jit/allocator/simplereg.h" + #if defined(ENABLE_LSRA) && !defined(ENABLE_SSA) + # include "vm/jit/allocator/lsra.h" + #endif + + #if defined(ENABLE_SSA) + # include "vm/jit/optimizing/lsra.h" + # include "vm/jit/optimizing/ssa.h" + #endif + + #if defined(ENABLE_INLINING) + # include "vm/jit/inline/inline.h" + #endif + + #include "vm/jit/ir/bytecode.h" + + #include "vm/jit/loop/analyze.h" + #include "vm/jit/loop/graph.h" + #include "vm/jit/loop/loop.h" + + #if defined(ENABLE_IFCONV) + # include "vm/jit/optimizing/ifconv.h" + #endif + + #include "vm/jit/optimizing/reorder.h" + + #if defined(ENABLE_PYTHON) + # include "vm/jit/python.h" + #endif + + #include "vm/jit/verify/typecheck.h" + + + /* debug macros ***************************************************************/ + + #if !defined(NDEBUG) + #define DEBUG_JIT_COMPILEVERBOSE(x) \ + do { \ + if (compileverbose) { \ + log_message_method(x, m); \ + } \ + } while (0) + #else + #define DEBUG_JIT_COMPILEVERBOSE(x) /* nothing */ + #endif + + #if !defined(NDEBUG) + # define TRACECOMPILERCALLS() \ + do { \ + if (opt_TraceCompilerCalls) { \ + log_start(); \ + log_print("[JIT compiler started: method="); \ + method_print(m); \ + log_print("]"); \ + log_finish(); \ + } \ + } while (0) + #else + # define TRACECOMPILERCALLS() + #endif + + + /* jit_init ******************************************************************** + + Initializes the JIT subsystem. + + *******************************************************************************/ + + void jit_init(void) + { + TRACESUBSYSTEMINITIALIZATION("jit_init"); + + #if defined(ENABLE_JIT) + /* initialize stack analysis subsystem */ + + (void) stack_init(); + #endif + + /* initialize show subsystem */ + + #if !defined(NDEBUG) + (void) show_init(); + #endif + + /* initialize codegen subsystem */ + + codegen_init(); + + /* initialize code subsystem */ + + (void) code_init(); + + /* Machine dependent initialization. */ + + #if defined(ENABLE_JIT) + # if defined(ENABLE_INTRP) + if (opt_intrp) + intrp_md_init(); + else + # endif + md_init(); + #else + intrp_md_init(); + #endif + + #if defined(ENABLE_OPAGENT) + if (opt_EnableOpagent) + OprofileAgent::initialize(); + #endif + } + + + /* jit_close ******************************************************************* + + Close the JIT subsystem. + + *******************************************************************************/ + + void jit_close(void) + { + #if defined(ENABLE_OPAGENT) + if (opt_EnableOpagent) + OprofileAgent::close(); + #endif + } + + + /* dummy function, used when there is no JavaVM code available */ + + static u1 *do_nothing_function(void) + { + return NULL; + } + + + /* jit_jitdata_new ************************************************************* + + Allocates and initalizes a new jitdata structure. + + *******************************************************************************/ + + jitdata *jit_jitdata_new(methodinfo *m) + { + jitdata *jd; + codeinfo *code; + + /* allocate jitdata structure and fill it */ + + jd = (jitdata*) DumpMemory::allocate(sizeof(jitdata)); + + jd->m = m; + jd->cd = (codegendata*) DumpMemory::allocate(sizeof(codegendata)); + jd->rd = (registerdata*) DumpMemory::allocate(sizeof(registerdata)); + #if defined(ENABLE_LOOP) + jd->ld = (loopdata*) DumpMemory::allocate(sizeof(loopdata)); + #endif + + /* Allocate codeinfo memory from the heap as we need to keep them. */ + + code = code_codeinfo_new(m); + + /* Set codeinfo flags. */ + + #if defined(ENABLE_THREADS) + if (checksync && (m->flags & ACC_SYNCHRONIZED)) + code_flag_synchronized(code); + + if (checksync && (m->flags & ACC_SYNCHRONIZED)) + code_unflag_leafmethod(code); + else + #endif + code_flag_leafmethod(code); + + /* initialize variables */ + + jd->code = code; + jd->flags = 0; + jd->exceptiontable = NULL; + jd->exceptiontablelength = 0; + jd->returncount = 0; + jd->branchtoentry = false; + jd->branchtoend = false; + jd->returncount = 0; + jd->returnblock = NULL; + jd->maxlocals = m->maxlocals; + + return jd; + } + + + /* jit_compile ***************************************************************** + + Translates one method to machine code. + + *******************************************************************************/ + + static u1 *jit_compile_intern(jitdata *jd); + + u1 *jit_compile(methodinfo *m) + { + u1 *r; + jitdata *jd; + + STATISTICS(count_jit_calls++); + + /* Initialize the static function's class. */ + + /* ATTENTION: This MUST be done before the method lock is aquired, + otherwise we could run into a deadlock with 's that + call static methods of it's own class. */ + + if ((m->flags & ACC_STATIC) && !(m->clazz->state & CLASS_INITIALIZED)) { + #if !defined(NDEBUG) + if (initverbose) + log_message_class("Initialize class ", m->clazz); + #endif + + if (!initialize_class(m->clazz)) + return NULL; + + /* check if the method has been compiled during initialization */ + + if ((m->code != NULL) && (m->code->entrypoint != NULL)) + return m->code->entrypoint; + } + + /* enter a monitor on the method */ + + m->mutex->lock(); + + /* if method has been already compiled return immediately */ + + if (m->code != NULL) { + m->mutex->unlock(); + + assert(m->code->entrypoint); + return m->code->entrypoint; + } + + TRACECOMPILERCALLS(); + + STATISTICS(count_methods++); + ++#if defined (ENABLE_JITCACHE) ++ ++ if (jitcache_load (m)) ++ { ++ m->mutex->unlock(); ++ ++ return m->code->entrypoint; ++ } ++ ++#endif ++ + #if defined(ENABLE_STATISTICS) + /* measure time */ + + if (opt_getcompilingtime) + compilingtime_start(); + #endif + + // Create new dump memory area. + DumpMemoryArea dma; + + /* create jitdata structure */ + + jd = jit_jitdata_new(m); + + /* set the flags for the current JIT run */ + + jd->flags = JITDATA_FLAG_PARSE; + + #if defined(ENABLE_VERIFIER) + if (opt_verify) + jd->flags |= JITDATA_FLAG_VERIFY; + #endif + + #if defined(ENABLE_PROFILING) + if (opt_prof) + jd->flags |= JITDATA_FLAG_INSTRUMENT; + #endif + + #if defined(ENABLE_IFCONV) + if (opt_ifconv) + jd->flags |= JITDATA_FLAG_IFCONV; + #endif + + #if defined(ENABLE_INLINING) && defined(ENABLE_INLINING_DEBUG) + if (opt_Inline && opt_InlineAll) + jd->flags |= JITDATA_FLAG_INLINE; + #endif + + if (opt_showintermediate) + jd->flags |= JITDATA_FLAG_SHOWINTERMEDIATE; + + if (opt_showdisassemble) + jd->flags |= JITDATA_FLAG_SHOWDISASSEMBLE; + + if (opt_verbosecall) + jd->flags |= JITDATA_FLAG_VERBOSECALL; + + #if defined(ENABLE_REPLACEMENT) && defined(ENABLE_INLINING) + if (opt_Inline && (jd->m->hitcountdown > 0) && (jd->code->optlevel == 0)) { + jd->flags |= JITDATA_FLAG_COUNTDOWN; + } + #endif + + #if defined(ENABLE_JIT) + # if defined(ENABLE_INTRP) + if (!opt_intrp) + # endif + /* initialize the register allocator */ + { + reg_setup(jd); + } + #endif + + /* setup the codegendata memory */ + + codegen_setup(jd); + + /* now call internal compile function */ + + r = jit_compile_intern(jd); + + if (r == NULL) { + /* We had an exception! Finish stuff here if necessary. */ + + /* release codeinfo */ + + code_codeinfo_free(jd->code); + + #if defined(ENABLE_PROFILING) + /* Release memory for basic block profiling information. */ + + if (JITDATA_HAS_FLAG_INSTRUMENT(jd)) + if (jd->code->bbfrequency != NULL) + MFREE(jd->code->bbfrequency, u4, jd->code->basicblockcount); + #endif + } + else { + DEBUG_JIT_COMPILEVERBOSE("Running: "); + } + ++#if defined (ENABLE_JITCACHE) ++ jitcache_store(m); ++#endif ++ + #if defined(ENABLE_STATISTICS) + /* measure time */ + + if (opt_getcompilingtime) + compilingtime_stop(); + #endif + + #if defined(ENABLE_OPAGENT) + if (opt_EnableOpagent) + OprofileAgent::newmethod(m); + #endif + + /* leave the monitor */ + + m->mutex->unlock(); + + /* return pointer to the methods entry point */ + + return r; + } + + + /* jit_recompile *************************************************************** + + Recompiles a Java method. + + *******************************************************************************/ + + u1 *jit_recompile(methodinfo *m) + { + u1 *r; + jitdata *jd; + u1 optlevel; + + /* check for max. optimization level */ + + optlevel = (m->code) ? m->code->optlevel : 0; + + #if 0 + if (optlevel == 1) { + /* log_message_method("not recompiling: ", m); */ + return NULL; + } + #endif + + DEBUG_JIT_COMPILEVERBOSE("Recompiling start: "); + + STATISTICS(count_jit_calls++); + + #if defined(ENABLE_STATISTICS) + /* measure time */ + + if (opt_getcompilingtime) + compilingtime_start(); + #endif + + // Create new dump memory area. + DumpMemoryArea dma; + + /* create jitdata structure */ + + jd = jit_jitdata_new(m); + + /* set the current optimization level to the previous one plus 1 */ + + jd->code->optlevel = optlevel + 1; + + /* get the optimization flags for the current JIT run */ + + #if defined(ENABLE_VERIFIER) + jd->flags |= JITDATA_FLAG_VERIFY; + #endif + + /* jd->flags |= JITDATA_FLAG_REORDER; */ + if (opt_showintermediate) + jd->flags |= JITDATA_FLAG_SHOWINTERMEDIATE; + if (opt_showdisassemble) + jd->flags |= JITDATA_FLAG_SHOWDISASSEMBLE; + if (opt_verbosecall) + jd->flags |= JITDATA_FLAG_VERBOSECALL; + + #if defined(ENABLE_INLINING) + if (opt_Inline) + jd->flags |= JITDATA_FLAG_INLINE; + #endif + + #if defined(ENABLE_JIT) + # if defined(ENABLE_INTRP) + if (!opt_intrp) + # endif + /* initialize the register allocator */ + + reg_setup(jd); + #endif + + /* setup the codegendata memory */ + + codegen_setup(jd); + + /* now call internal compile function */ + + r = jit_compile_intern(jd); + + if (r == NULL) { + /* We had an exception! Finish stuff here if necessary. */ + + /* release codeinfo */ + + code_codeinfo_free(jd->code); + } + + #if defined(ENABLE_STATISTICS) + /* measure time */ + + if (opt_getcompilingtime) + compilingtime_stop(); + #endif + + #if defined(ENABLE_OPAGENT) + if (opt_EnableOpagent) + OprofileAgent::newmethod(m); + #endif + + DEBUG_JIT_COMPILEVERBOSE("Recompiling done: "); + + /* return pointer to the methods entry point */ + + return r; + } + + #if defined(ENABLE_PM_HACKS) + #include "vm/jit/jit_pm_1.inc" + #endif + + /* jit_compile_intern ********************************************************** + + Static internal function which does the actual compilation. + + *******************************************************************************/ + + static u1 *jit_compile_intern(jitdata *jd) + { + methodinfo *m; + codegendata *cd; + codeinfo *code; + + #if defined(ENABLE_RT_TIMING) + struct timespec time_start,time_checks,time_parse,time_stack, + time_typecheck,time_loop,time_ifconv,time_alloc, + time_codegen; + #endif + + RT_TIMING_GET_TIME(time_start); + + /* get required compiler data */ + + #if defined(ENABLE_LSRA) || defined(ENABLE_SSA) + jd->ls = NULL; + #endif + m = jd->m; + code = jd->code; + cd = jd->cd; + + #if defined(ENABLE_DEBUG_FILTER) + show_filters_apply(jd->m); + #endif + + // Handle native methods and create a native stub. + if (m->flags & ACC_NATIVE) { + NativeMethods& nm = VM::get_current()->get_nativemethods(); + void* f = nm.resolve_method(m); + + if (f == NULL) + return NULL; + + code = NativeStub::generate(m, (functionptr) f); + + /* Native methods are never recompiled. */ + + assert(!m->code); + + m->code = code; + + return code->entrypoint; + } + + /* if there is no javacode, print error message and return empty method */ + + if (m->jcode == NULL) { + DEBUG_JIT_COMPILEVERBOSE("No code given for: "); + + code->entrypoint = (u1 *) (ptrint) do_nothing_function; + m->code = code; + + return code->entrypoint; /* return empty method */ + } + + #if defined(ENABLE_STATISTICS) + if (opt_stat) { + count_javacodesize += m->jcodelength + 18; + count_tryblocks += jd->exceptiontablelength; + count_javaexcsize += jd->exceptiontablelength * SIZEOF_VOID_P; + } + #endif + + RT_TIMING_GET_TIME(time_checks); + + #if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK) + /* Code for Sun's OpenJDK (see + hotspot/src/share/vm/classfile/verifier.cpp + (Verifier::is_eligible_for_verification)): Don't verify + dynamically-generated bytecodes. */ + + # if defined(ENABLE_VERIFIER) + if (class_issubclass(m->clazz, class_sun_reflect_MagicAccessorImpl)) + jd->flags &= ~JITDATA_FLAG_VERIFY; + # endif + #endif + + /* call the compiler passes ***********************************************/ + + DEBUG_JIT_COMPILEVERBOSE("Parsing: "); + + /* call parse pass */ + + if (!parse(jd)) { + DEBUG_JIT_COMPILEVERBOSE("Exception while parsing: "); + + return NULL; + } + RT_TIMING_GET_TIME(time_parse); + + DEBUG_JIT_COMPILEVERBOSE("Parsing done: "); + + #if defined(ENABLE_JIT) + # if defined(ENABLE_INTRP) + if (!opt_intrp) { + # endif + DEBUG_JIT_COMPILEVERBOSE("Analysing: "); + + /* call stack analysis pass */ + + if (!stack_analyse(jd)) { + DEBUG_JIT_COMPILEVERBOSE("Exception while analysing: "); + + return NULL; + } + RT_TIMING_GET_TIME(time_stack); + + DEBUG_JIT_COMPILEVERBOSE("Analysing done: "); + + #ifdef ENABLE_VERIFIER + if (JITDATA_HAS_FLAG_VERIFY(jd)) { + DEBUG_JIT_COMPILEVERBOSE("Typechecking: "); + + /* call typecheck pass */ + if (!typecheck(jd)) { + DEBUG_JIT_COMPILEVERBOSE("Exception while typechecking: "); + + return NULL; + } + + DEBUG_JIT_COMPILEVERBOSE("Typechecking done: "); + } + #endif + RT_TIMING_GET_TIME(time_typecheck); + + #if defined(ENABLE_LOOP) + if (opt_loops) { + depthFirst(jd); + analyseGraph(jd); + optimize_loops(jd); + jit_renumber_basicblocks(jd); + } + #endif + RT_TIMING_GET_TIME(time_loop); + + #if defined(ENABLE_IFCONV) + if (JITDATA_HAS_FLAG_IFCONV(jd)) { + if (!ifconv_static(jd)) + return NULL; + jit_renumber_basicblocks(jd); + } + #endif + RT_TIMING_GET_TIME(time_ifconv); + + /* inlining */ + + #if defined(ENABLE_INLINING) && (!defined(ENABLE_ESCAPE) || 1) + if (JITDATA_HAS_FLAG_INLINE(jd)) { + if (!inline_inline(jd)) + return NULL; + } + #endif + + #if defined(ENABLE_SSA) + if (opt_lsra) { + fix_exception_handlers(jd); + } + #endif + + /* Build the CFG. This has to be done after stack_analyse, as + there happens the JSR elimination. */ + + if (!cfg_build(jd)) + return NULL; + + #if defined(ENABLE_PROFILING) + /* Basic block reordering. I think this should be done after + if-conversion, as we could lose the ability to do the + if-conversion. */ + + if (JITDATA_HAS_FLAG_REORDER(jd)) { + if (!reorder(jd)) + return NULL; + jit_renumber_basicblocks(jd); + } + #endif + + #if defined(ENABLE_PM_HACKS) + #include "vm/jit/jit_pm_2.inc" + #endif + DEBUG_JIT_COMPILEVERBOSE("Allocating registers: "); + + #if defined(ENABLE_LSRA) && !defined(ENABLE_SSA) + /* allocate registers */ + if (opt_lsra) { + if (!lsra(jd)) + return NULL; + + STATISTICS(count_methods_allocated_by_lsra++); + + } else + # endif /* defined(ENABLE_LSRA) && !defined(ENABLE_SSA) */ + #if defined(ENABLE_SSA) + /* allocate registers */ + if ( + (opt_lsra && + jd->code->optlevel > 0) + /* strncmp(jd->m->name->text, "hottie", 6) == 0*/ + /*&& jd->exceptiontablelength == 0*/ + ) { + /*printf("=== %s ===\n", jd->m->name->text);*/ + jd->ls = (lsradata*) DumpMemory::allocate(sizeof(lsradata)); + jd->ls = NULL; + ssa(jd); + /*lsra(jd);*/ regalloc(jd); + /*eliminate_subbasicblocks(jd);*/ + STATISTICS(count_methods_allocated_by_lsra++); + + } else + # endif /* defined(ENABLE_SSA) */ + { + STATISTICS(count_locals_conflicts += (jd->maxlocals - 1) * (jd->maxlocals)); + + regalloc(jd); + } + + STATISTICS(simplereg_make_statistics(jd)); + + DEBUG_JIT_COMPILEVERBOSE("Allocating registers done: "); + # if defined(ENABLE_INTRP) + } + # endif + #endif /* defined(ENABLE_JIT) */ + RT_TIMING_GET_TIME(time_alloc); + + #if defined(ENABLE_PROFILING) + /* Allocate memory for basic block profiling information. This + _must_ be done after loop optimization and register allocation, + since they can change the basic block count. */ + + if (JITDATA_HAS_FLAG_INSTRUMENT(jd)) + code->bbfrequency = MNEW(u4, jd->basicblockcount); + #endif + + DEBUG_JIT_COMPILEVERBOSE("Generating code: "); + + /* now generate the machine code */ + + #if defined(ENABLE_JIT) + # if defined(ENABLE_INTRP) + if (opt_intrp) { + #if defined(ENABLE_VERIFIER) + if (opt_verify) { + DEBUG_JIT_COMPILEVERBOSE("Typechecking (stackbased): "); + + if (!typecheck_stackbased(jd)) { + DEBUG_JIT_COMPILEVERBOSE("Exception while typechecking (stackbased): "); + return NULL; + } + } + #endif + if (!intrp_codegen(jd)) { + DEBUG_JIT_COMPILEVERBOSE("Exception while generating code: "); + + return NULL; + } + } else + # endif + { + if (!codegen_generate(jd)) { + DEBUG_JIT_COMPILEVERBOSE("Exception while generating code: "); + + return NULL; + } + } + #else + if (!intrp_codegen(jd)) { + DEBUG_JIT_COMPILEVERBOSE("Exception while generating code: "); + + return NULL; + } + #endif + RT_TIMING_GET_TIME(time_codegen); + + DEBUG_JIT_COMPILEVERBOSE("Generating code done: "); + + #if !defined(NDEBUG) && defined(ENABLE_REPLACEMENT) + /* activate replacement points inside newly created code */ + + if (opt_TestReplacement) + replace_activate_replacement_points(code, false); + #endif + + #if !defined(NDEBUG) + #if defined(ENABLE_DEBUG_FILTER) + if (jd->m->filtermatches & SHOW_FILTER_FLAG_SHOW_METHOD) + #endif + { + /* intermediate and assembly code listings */ + + if (JITDATA_HAS_FLAG_SHOWINTERMEDIATE(jd)) { + show_method(jd, SHOW_CODE); + } + else if (JITDATA_HAS_FLAG_SHOWDISASSEMBLE(jd)) { + # if defined(ENABLE_DISASSEMBLER) + DISASSEMBLE(code->entrypoint, + code->entrypoint + (code->mcodelength - cd->dseglen)); + # endif + } + + if (opt_showddatasegment) + dseg_display(jd); + } + #endif + + /* switch to the newly generated code */ + + assert(code); + assert(code->entrypoint); + + /* add the current compile version to the methodinfo */ + + code->prev = m->code; + m->code = code; + + RT_TIMING_TIME_DIFF(time_start,time_checks,RT_TIMING_JIT_CHECKS); + RT_TIMING_TIME_DIFF(time_checks,time_parse,RT_TIMING_JIT_PARSE); + RT_TIMING_TIME_DIFF(time_parse,time_stack,RT_TIMING_JIT_STACK); + RT_TIMING_TIME_DIFF(time_stack,time_typecheck,RT_TIMING_JIT_TYPECHECK); + RT_TIMING_TIME_DIFF(time_typecheck,time_loop,RT_TIMING_JIT_LOOP); + RT_TIMING_TIME_DIFF(time_loop,time_alloc,RT_TIMING_JIT_ALLOC); + RT_TIMING_TIME_DIFF(time_alloc,time_codegen,RT_TIMING_JIT_CODEGEN); + RT_TIMING_TIME_DIFF(time_start,time_codegen,RT_TIMING_JIT_TOTAL); + + /* return pointer to the methods entry point */ + + return code->entrypoint; + } + + + /* jit_invalidate_code ********************************************************* + + Mark the compiled code of the given method as invalid and take care that + it is replaced if necessary. + + XXX Not fully implemented, yet. + + *******************************************************************************/ + + void jit_invalidate_code(methodinfo *m) + { + codeinfo *code; + + code = m->code; + + if (code == NULL || code_is_invalid(code)) + return; + + code_flag_invalid(code); + + /* activate mappable replacement points */ + + #if defined(ENABLE_REPLACEMENT) + replace_activate_replacement_points(code, true); + #else + vm_abort("invalidating code only works with ENABLE_REPLACEMENT"); + #endif + } + + + /* jit_request_optimization **************************************************** + + Request optimization of the given method. If the code of the method is + unoptimized, it will be invalidated, so the next jit_get_current_code(m) + triggers an optimized recompilation. + If the method is already optimized, this function does nothing. + + IN: + m................the method + + *******************************************************************************/ + + void jit_request_optimization(methodinfo *m) + { + codeinfo *code; + + code = m->code; + + if (code && code->optlevel == 0) + jit_invalidate_code(m); + } + + + /* jit_get_current_code ******************************************************** + + Get the currently valid code for the given method. If there is no valid + code, (re)compile the method. + + IN: + m................the method + + RETURN VALUE: + the codeinfo* for the current code, or + NULL if an exception has been thrown during recompilation. + + *******************************************************************************/ + + codeinfo *jit_get_current_code(methodinfo *m) + { + assert(m); + + /* if we have valid code, return it */ + + if (m->code && !code_is_invalid(m->code)) + return m->code; + + /* otherwise: recompile */ + + if (!jit_recompile(m)) + return NULL; + + assert(m->code); + + return m->code; + } + + + /* jit_asm_compile ************************************************************* + + This method is called from asm_vm_call_method and does: + + - create stackframe info for exceptions + - compile the method + - patch the entrypoint of the method into the calculated address in + the JIT code + - flushes the instruction cache. + + *******************************************************************************/ + + #if defined(ENABLE_JIT) + #if !defined(JIT_COMPILER_VIA_SIGNAL) + extern "C" { + void* jit_asm_compile(methodinfo *m, void* mptr, void* sp, void* ra) + { + stackframeinfo_t sfi; + void *entrypoint; + void *pa; + uintptr_t *p; + + /* create the stackframeinfo (subtract 1 from RA as it points to the */ + /* instruction after the call) */ + + stacktrace_stackframeinfo_add(&sfi, NULL, sp, ra, ((uint8_t*) ra) - 1); + + /* actually compile the method */ + + entrypoint = jit_compile(m); + + /* remove the stackframeinfo */ + + stacktrace_stackframeinfo_remove(&sfi); + + /* there was a problem during compilation */ + + if (entrypoint == NULL) + return NULL; + + /* get the method patch address */ + + pa = md_jit_method_patch_address(sfi.pv, (void *) ra, mptr); + + /* patch the method entry point */ + + p = (uintptr_t*) pa; + + *p = (uintptr_t) entrypoint; + + /* flush the instruction cache */ + + md_icacheflush(pa, SIZEOF_VOID_P); + + return entrypoint; + } + } + #endif + + /* jit_compile_handle ********************************************************** + + This method is called from the appropriate signal handler which + handles compiler-traps and does the following: + + - compile the method + - patch the entrypoint of the method into the calculated address in + the JIT code + - flush the instruction cache + + *******************************************************************************/ + + void *jit_compile_handle(methodinfo *m, void *pv, void *ra, void *mptr) + { + void *newpv; /* new compiled method PV */ + void *pa; /* patch address */ + uintptr_t *p; /* convenience pointer */ + + /* Compile the method. */ + + newpv = jit_compile(m); + + /* There was a problem during compilation. */ + + if (newpv == NULL) + return NULL; + + /* Get the method patch address. */ + + pa = md_jit_method_patch_address(pv, ra, mptr); + + /* Patch the method entry point. */ + + p = (uintptr_t *) pa; + + *p = (uintptr_t) newpv; + + /* Flush both caches. */ + + md_cacheflush(pa, SIZEOF_VOID_P); + + return newpv; + } + #endif /* defined(ENABLE_JIT) */ + + + /* jit_complement_condition **************************************************** + + Returns the complement of the passed conditional instruction. + + We use the order of the different conditions, e.g.: + + ICMD_IFEQ 153 + ICMD_IFNE 154 + + If the passed opcode is odd, we simply add 1 to get the complement. + If the opcode is even, we subtract 1. + + Exception: + + ICMD_IFNULL 198 + ICMD_IFNONNULL 199 + + *******************************************************************************/ + + s4 jit_complement_condition(s4 opcode) + { + switch (opcode) { + case ICMD_IFNULL: + return ICMD_IFNONNULL; + + case ICMD_IFNONNULL: + return ICMD_IFNULL; + + default: + /* check if opcode is odd */ + + if (opcode & 0x1) + return opcode + 1; + else + return opcode - 1; + } + } + + + /* jit_renumber_basicblocks **************************************************** + + Set the ->nr of all blocks so it increases when traversing ->next. + + IN: + jitdata..........the current jitdata + + *******************************************************************************/ + + void jit_renumber_basicblocks(jitdata *jd) + { + s4 nr; + basicblock *bptr; + + nr = 0; + for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) { + bptr->nr = nr++; + } + + /* we have one block more than jd->basicblockcount (the end marker) */ + + assert(nr == jd->basicblockcount + 1); + } + + + /* jit_check_basicblock_numbers ************************************************ + + Assert that the ->nr of the first block is zero and increases by 1 each + time ->next is traversed. + This function should be called before any analysis that relies on + the basicblock numbers. + + IN: + jitdata..........the current jitdata + + NOTE: Aborts with an assertion if the condition is not met! + + *******************************************************************************/ + + #if !defined(NDEBUG) + void jit_check_basicblock_numbers(jitdata *jd) + { + s4 nr; + basicblock *bptr; + + nr = 0; + for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) { + assert(bptr->nr == nr); + nr++; + } + + /* we have one block more than jd->basicblockcount (the end marker) */ + + assert(nr == jd->basicblockcount + 1); + } + #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/jitcache.cpp index baf6634b4,000000000..2cd93a282 mode 100644,000000..100644 --- a/src/vm/jit/jitcache.cpp +++ b/src/vm/jit/jitcache.cpp @@@ -1,2414 -1,0 +1,2393 @@@ +/* src/vm/jit/jitcache.c - JIT caching stuff + + Copyright (C) 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" + +#if defined(ENABLE_JITCACHE) + - /* for mkdir() */ ++#include "threads/thread.hpp" ++ ++#include "toolbox/list.hpp" ++ ++#include "vm/field.hpp" ++ ++#include "vm/jit/builtin.hpp" ++#include "vm/jit/code.hpp" ++#include "vm/jit/codegen-common.hpp" ++#include "vm/jit/jit.hpp" ++#include "vm/jit/jitcache.hpp" ++#include "vm/jit/linenumbertable.hpp" ++#include "vm/jit/patcher-common.hpp" ++ ++#include "vm/os.hpp" ++#include "vm/string.hpp" + +extern "C" { + ++/* for mkdir() */ +#include + +#include +#include + +#include "md.h" + - #include "toolbox/list.h" +#include "toolbox/logging.h" + +#include "mm/memory.h" +#include "mm/codememory.h" + - #include "vm/builtin.h" +#include "vm/method.h" +#include "vm/options.h" +#include "vm/resolve.h" +#include "vm/types.h" + +#include "vm/jit/asmpart.h" - #include "vm/jit/jit.h" - #include "vm/jit/code.h" - #include "vm/jit/patcher-common.h" - #include "vm/jit/codegen-common.h" - #include "vm/jit/linenumbertable.h" +#include "vm/jit/exceptiontable.h" +#include "vm/jit/methodtree.h" + +#include "vm/references.h" - #include "vm/field.h" +#include "vm/utf8.h" + +} + - #include "vm/string.hpp" - #include "vm/os.hpp" - #include "vm/jit/jitcache.hpp" - #include "threads/thread.hpp" + +/* TODO: Wrap this in vm/system.h" */ +#include "unistd.h" + +#define CACHEROOT "/tmp/cacao-jitcache/" + +/* small grained helper functions */ +char *get_dest_dir(methodinfo *); +char *get_dest_file(methodinfo *); + +int mkdir_hier(char *, mode_t); +int open_to_read(char *); +int open_to_write(char *); + +void *to_abs(void *, void *); +void *to_offset(void *, void *); + +void store_utf(int, utf *); +void store_classinfo(int, classinfo *); +void store_builtin(int, builtintable_entry *); +void store_string(int, java_object_t *); +void store_methodinfo(int, methodinfo *); +void store_fieldinfo(int, fieldinfo *); +void store_cachedref(int, cachedref_t *); + +void load_utf(utf **, int); +void load_classinfo(classinfo **, int, methodinfo *); +void load_builtin(builtintable_entry **, int); +void load_string(java_object_t **, int); +void load_methodinfo(methodinfo **, int, methodinfo *); +void load_fieldinfo(fieldinfo **, int, methodinfo *); +void load_cachedref(cachedref_t **, int, codeinfo *); + +/* medium grained helper functions */ +void load_from_file_patchers(codeinfo *, int); +void load_from_file_cachedrefs(codeinfo *, int); +void load_from_file_exceptiontable(codeinfo *, int); +void load_from_file_linenumbertable(codeinfo *, int); + +void store_to_file_patchers(int, codeinfo *); +void store_to_file_cachedrefs(int, codeinfo *); +void store_to_file_linenumbertable(int, codeinfo *); +void store_to_file_exceptiontable(int, codeinfo *); + +/* file handling functions */ +void update_method_table(methodinfo *, int); +int seek_method_table(methodinfo *, int); +int get_cache_file_readable(methodinfo *); +int get_cache_file_writable(methodinfo *); + +/* serializer forward declarations */ +void s_dummy(int, patchref_t *, methodinfo *); +void s_unresolved_class(int, patchref_t *, methodinfo *); +void s_unresolved_field(int, patchref_t *, methodinfo *); +void s_unresolved_method(int, patchref_t *, methodinfo *); +void s_constant_classref(int, patchref_t *, methodinfo *); +void s_classinfo(int, patchref_t *, methodinfo *); +void s_methodinfo(int, patchref_t *, methodinfo *); +void s_fieldinfo(int, patchref_t *, methodinfo *); +void s_string(int, patchref_t *, methodinfo *); + +/* deserializer forward declarations */ +void d_dummy(patchref_t *, int, methodinfo *); +void d_unresolved_class(patchref_t *, int, methodinfo *); +void d_unresolved_field(patchref_t *, int, methodinfo *); +void d_unresolved_method(patchref_t *, int, methodinfo *); +void d_constant_classref(patchref_t *, int, methodinfo *); +void d_classinfo(patchref_t *, int, methodinfo *); +void d_methodinfo(patchref_t *, int, methodinfo *); +void d_fieldinfo(patchref_t *, int, methodinfo *); +void d_string(patchref_t *, int, methodinfo *); + +/* The order of entries follows the order of + * declarations in patcher-common.h + */ + +static jitcache_patcher_function_list_t patcher_functions[] = { + { PATCHER_resolve_class, s_unresolved_class, d_unresolved_class }, + { PATCHER_initialize_class, s_classinfo, d_classinfo }, + { PATCHER_resolve_classref_to_classinfo, s_constant_classref, d_constant_classref }, + { PATCHER_resolve_classref_to_vftbl, s_constant_classref, d_constant_classref }, + { PATCHER_resolve_classref_to_index, s_constant_classref, d_constant_classref }, + { PATCHER_resolve_classref_to_flags, s_constant_classref, d_constant_classref }, + { PATCHER_resolve_native_function, s_methodinfo, d_methodinfo }, + + /* old patcher functions */ + { PATCHER_get_putstatic, s_unresolved_field, d_unresolved_field }, + +#if defined(__I386__) + { PATCHER_getfield, s_unresolved_field, d_unresolved_field }, + { PATCHER_putfield, s_unresolved_field, d_unresolved_field }, +#else + { PATCHER_get_putfield, s_unresolved_field, d_unresolved_field }, +#endif + +#if defined(__I386__) || defined(__X86_64__) + { PATCHER_putfieldconst, s_unresolved_field, d_unresolved_field }, /* 10 */ +#endif + + { PATCHER_invokestatic_special, s_unresolved_method, d_unresolved_method }, + { PATCHER_invokevirtual, s_unresolved_method, d_unresolved_method }, + { PATCHER_invokeinterface, s_unresolved_method, d_unresolved_method }, + +#if defined(__ALPHA__) || defined(__I386__) || defined(__MIPS__) || defined(__POWERPC__) || defined(__POWERPC64__) || defined(__S390__) || defined(__X86_64__) || defined(__M68K__) + { PATCHER_checkcast_interface, s_constant_classref, d_constant_classref }, + { PATCHER_instanceof_interface, s_constant_classref, d_constant_classref }, +#endif + +#if defined(__S390__) + { PATCHER_checkcast_instanceof_interface, s_dummy, d_dummy }, +#endif + +#if defined(__I386__) + { PATCHER_aconst, s_constant_classref, d_constant_classref }, /* 16 */ + { PATCHER_builtin_multianewarray, s_constant_classref, d_constant_classref }, + { PATCHER_builtin_arraycheckcast, s_constant_classref, d_constant_classref }, + { PATCHER_checkcast_instanceof_flags, s_constant_classref, d_constant_classref }, + { PATCHER_checkcast_class, s_constant_classref, d_constant_classref }, + { PATCHER_instanceof_class, s_constant_classref, d_constant_classref }, +#endif + + { NULL, s_dummy, d_dummy } +}; + +#define JC_MRU_SIZE 100 +static classinfo *jc_mru_list[JC_MRU_SIZE]; +int mru_last_free = 0; +int mru_start = 0; + +/* jitcache_mru_add ************************************************************ + + Adds a classinfo to the most recently used (MRU) list. The MRU uses a simple + strategy: it will store entries until it is full, further candidates replace + the + +*******************************************************************************/ + +void jitcache_mru_add(classinfo *c, int fd) +{ + classinfo *old_c; + assert(!c->cache_file_fd); + + c->cache_file_fd = fd; + + if (mru_last_free < JC_MRU_SIZE) { + jc_mru_list[mru_last_free] = c; + + mru_last_free++; + + return; + } + else { + mru_start--; + if (mru_start < 0) + mru_start = JC_MRU_SIZE - 1; + + old_c = jc_mru_list[mru_start]; + + assert (old_c); + assert (old_c->cache_file_fd); + os::close(old_c->cache_file_fd); + old_c->cache_file_fd = 0; + + jc_mru_list[mru_start] = c; + } + +} + +void jitcache_mru_remove(classinfo *c) +{ + int i, j; + + for (i = 0; i < JC_MRU_SIZE; i++) + if (jc_mru_list[i] == c) { + jc_mru_list[j] = NULL; + + for (j = i; i < mru_last_free - 1; j++) + jc_mru_list[j] = jc_mru_list[j+1]; + + mru_last_free--; + } + + assert (0); +} + +/* jitcache_list_create ******************************************************** + + Creates an empty cached reference list for the given codeinfo. + +*******************************************************************************/ + +void jitcache_list_create(codeinfo *code) +{ - code->cachedrefs = list_create(OFFSET(cachedref_t, linkage)); ++ code->cachedrefs = new List(); +} + + +/* jitcache_list_reset ********************************************************** + + Resets the cached reference list inside a codeinfo. + +*******************************************************************************/ + +void jitcache_list_reset(codeinfo *code) +{ - cachedref_t *pr; - - /* free all elements of the list */ - - while((pr = (cachedref_t *) list_first(code->cachedrefs)) != NULL) { - list_remove(code->cachedrefs, pr); - - FREE(pr, cachedref_t); - - #if defined(ENABLE_STATISTICS) - if (opt_stat) - size_cachedref -= sizeof(cachedref_t); - #endif - } ++ code->cachedrefs->clear(); +} + + +/* jitcache_list_free *********************************************************** + + Frees the cached reference list and all its entries for the given codeinfo. + +*******************************************************************************/ + +void jitcache_list_free(codeinfo *code) +{ + /* free all elements of the list */ + + jitcache_list_reset(code); + + /* free the list itself */ + - FREE(code->cachedrefs, list_t); ++ delete code->cachedrefs; ++ code->cachedrefs = 0; +} + + +/* jitcache_list_find *********************************************************** + + Find an entry inside the cached reference list for the given codeinfo + by specifying the displacement in the code/data segment. + + NOTE: Caller should hold the patcher list lock or maintain + exclusive access otherwise. + +*******************************************************************************/ + +static cachedref_t *jitcache_list_find(codeinfo *code, s4 disp) +{ - cachedref_t *cr; - + /* walk through all cached references for the given codeinfo */ + - cr = (cachedref_t *) list_first(code->cachedrefs); - while (cr) { - - if (cr->disp == disp) - return cr; ++ for (List::iterator it = code->cachedrefs->begin(); ++ it != code->cachedrefs->end(); it++) ++ { + - cr = (cachedref_t *) list_next(code->cachedrefs, cr); ++ if (it->disp == disp) ++ return &(*it); + } + + return NULL; +} + + +/* jitcache_new_cachedref ****************************************************** + + Creates and initializes a new cachedref + +*******************************************************************************/ + - cachedref_t *jitcache_new_cached_ref(cachedreftype type, s4 md_patch, void* ref, s4 disp) ++cachedref_t jitcache_new_cached_ref(cachedreftype type, s4 md_patch, void* ref, s4 disp) +{ - cachedref_t *cr; - - /* allocate cachedref on heap (at least freed together with codeinfo) */ - - cr = NEW(cachedref_t); - - #if defined(ENABLE_STATISTICS) - if (opt_stat) - size_cachedref += sizeof(cachedref_t); - #endif ++ cachedref_t cr; + + /* set reference information */ + - cr->type = type; - cr->md_patch= md_patch; - cr->disp = disp; - cr->ref = ref; ++ cr.type = type; ++ cr.md_patch= md_patch; ++ cr.disp = disp; ++ cr.ref = ref; + + return cr; +} - /* jitcache_add_cachedref_jd *************************************************** ++/* jitcache_add_cachedref_intern *********************************************** + - Creates a new cached ref appends it to the list in the codeinfo structure - *or* attaches it to the *last* patchref_t if it overlaps with the address - of the cached reference. ++ Creates a new cached ref appends it to the list in the codeinfo structure. + +*******************************************************************************/ + - void jitcache_add_cached_ref_intern(codeinfo *code, cachedref_t *cachedref) ++void jitcache_add_cached_ref_intern(codeinfo *code, cachedref_t cachedref) +{ - cachedref_t *list_cr; - - list_cr = (cachedref_t *) list_first(code->cachedrefs); ++ List::iterator it = code->cachedrefs->begin(); + - while (list_cr) ++ while (it != code->cachedrefs->end()) + { - if (list_cr->disp == cachedref->disp) ++ if (it->disp == cachedref.disp) + { - assert(list_cr->type == cachedref->type); - assert(list_cr->ref == cachedref->ref); ++ assert(it->type == cachedref.type); ++ assert(it->ref == cachedref.ref); + + /* Cachedref for already existing object found. No need to store + * it. + */ + return; + } + - list_cr = (cachedref_t *) list_next(code->cachedrefs, list_cr); ++ it++; + } + - list_add_first(code->cachedrefs, cachedref); ++ code->cachedrefs->push_front(cachedref); +} + +/* jitcache_add_cachedref_jd *************************************************** + + Creates a new cached ref appends it to the list in the codeinfo structure + *or* attaches it to the *last* patchref_t if it overlaps with the address + of the cached reference. + +*******************************************************************************/ + +void jitcache_add_cached_ref_jd(jitdata *jd, cachedreftype type, void* ref) +{ + jitcache_add_cached_ref_md_jd(jd, type, 0, ref); +} + + +/* jitcache_add_cachedref_md_jd ************************************************ + + Creates a new cached ref appends it to the list in the codeinfo structure + *or* attaches it to the *last* patchref_t if it overlaps with the address + of the cached reference. + +*******************************************************************************/ + +void jitcache_add_cached_ref_md_jd(jitdata *jd, cachedreftype type, s4 md_patch, void* ref) +{ - patchref_t *patchref; ++ patchref_t patchref; + codegendata *cd; + ptrint disp; - cachedref_t *cachedref; ++ cachedref_t cachedref; + + if (type >= CRT_OBJECT_HEADER && !ref) + return; + + cd = jd->cd; + + disp = (ptrint) (cd->mcodeptr - cd->mcodebase) - SIZEOF_VOID_P; + cachedref = jitcache_new_cached_ref(type, md_patch, ref, disp); + - patchref = (patchref_t *) list_first(jd->code->patchers); ++ patchref = jd->code->patchers->front(); + - if (patchref - && (patchref->mpc) <= disp - && (patchref->mpc + sizeof(patchref->mcode)) >= disp) ++ if ((patchref.mpc) <= disp ++ && (patchref.mpc + sizeof(patchref.mcode)) >= disp) + { + /* patchers and cachedref overlap: cached ref must + * be handled after the patcher. - */ ++ */ + + if (opt_DebugJitCache) + { + log_message_method("cached ref overlaps with patchref: ", jd->m); + } + + /* There can be only one cached ref per patcher currently. - * If the need arises to handle more cached refs a list can - * be used. - */ - assert(!patchref->attached_ref); ++ * If the need arises to handle more cached refs a list can ++ * be used. ++ */ ++ assert(!patchref.attached_ref); + - patchref->attached_ref = cachedref; ++ patchref.attached_ref = &cachedref; + } + else + jitcache_add_cached_ref_intern(jd->code, cachedref); +} + + +/* jitcache_add_cachedref ****************************************************** + + Creates a new cached references and appends it to the list. + +*******************************************************************************/ + +void jitcache_add_cached_ref(codeinfo *code, cachedreftype type, void* ref, s4 disp) +{ - cachedref_t *cr; ++ cachedref_t cr; + + /* allocate cachedref on heap (at least freed together with codeinfo) */ + cr = jitcache_new_cached_ref(type, 0, ref,disp); + + jitcache_add_cached_ref_intern(code, cr); +} + + + +/* jitcache_handle_cached_ref ************************************************** + + Creates a new cached references and appends it to the list. + +*******************************************************************************/ + +void jitcache_handle_cached_ref(cachedref_t *cr, codeinfo *code) +{ + u1 **location; + + location = (u1 **) (code->entrypoint + cr->disp); + + /* Write the restored reference into the code. */ ++#if defined (__ARM__) + if (cr->md_patch) + patch_md(cr->md_patch, (ptrint) location, cr->ref); + else ++#endif + *location = (u1 *) cr->ref; + + md_cacheflush(location, SIZEOF_VOID_P); + + FREE(cr, cachedref_t); +} + +#include +#include + +bool filter(utf *classname) +{ + static bool printed = false; + char *buf = NULL; + int i = 0; + int max_index = 30000; + const char *classes[] = { + "Test$FooBar", + "Test", + "FieldTest", + "UnresolvedClass", + "java/lang/ThreadGroup", + "java/lang/Object", + "java/util/Vector", + "java/util/Vector$1", + "java/util/AbstractList", + "java/util/AbstractCollection", + "java/lang/Thread", + "java/lang/String", + "java/lang/ClassLoader", + "java/lang/VMClassLoader", + "java/util/HashMap", + "java/util/HashSet", + "java/util/AbstractSet", + "gnu/classpath/SystemProperties", + "java/util/Properties", + "java/util/Hashtable", + "java/util/Dictionary", + "java/util/Hashtable$HashEntry", + "java/util/AbstractMap$SimpleEntry", + "java/lang/StringBuilder", + "java/lang/AbstractStringBuffer", + "java/util/Collections$SynchronizedSet", + "java/util/Collections$SynchronizedCollection", + "java/util/Hashtable$3", + "java/util/Hashtable$EntryIterator", + "java/util/Collections$SynchronizedIterator", + "java/lang/Boolean", + "java/util/Collections", + "java/util/Collections$EmptySet", + "java/util/Collections$EmptyList", + "java/util/Collections$EmptyMap", + "java/util/Collections$ReverseComparator", + "java/util/Collections$UnmodifiableMap", + "java/io/File", + "java/util/StringTokenizer", + "java/util/ArrayList", + "java/io/VMFile", + "java/lang/System", + "java/lang/VMSystem", + "java/io/FileDescriptor", + "gnu/java/io/FileChannelImpl", + "java/lang/Runtime", + "gnu/classpath/VMStackWalker", + "gnu/java/io/VMChannel", + "gnu/java/io/VMChannel$State", + "gnu/java/io/VMChannel$Kind", + "java/nio/channels/FileChannelImpl", + "java/nio/channels/spi/AbstractInterruptibleChannel", + "java/lang/Number", + "java/io/FileInputStream", + "java/io/InputStream", + "java/io/BufferedInputStream", + "java/io/FilterInputStream", + "java/io/PrintStream", + "java/io/OutputStream", + "java/io/BufferedOutputStream", + "java/io/FilterOutputStream", + "java/net/URL", + "java/util/Locale", + "java/lang/Math", + "gnu/java/lang/CharData", + "java/lang/Character", + "java/net/URL$1", + "java/security/VMAccessController", + "java/lang/ThreadLocal", + "java/security/CodeSource", + "**placeholder**", + "java/security/PermissionCollection", + "Test$1", + "java/security/ProtectionDomain", + "java/security/AccessControlContext", + "gnu/java/util/WeakIdentityHashMap", + "gnu/java/util/WeakIdentityHashMap$WeakEntrySet", + "java/lang/ref/ReferenceQueue", + "java/util/LinkedList", + "java/util/AbstractSequentialList", + "gnu/java/util/WeakIdentityHashMap$WeakBucket$WeakEntry", + "java/util/LinkedList$Entry", + "java/lang/Class", + "java/lang/reflect/VMConstructor", + "java/lang/reflect/Constructor", + "java/lang/reflect/Modifier", + "gnu/java/net/protocol/file/Handler", + "java/net/URLStreamHandler", + "java/util/ArrayList", + "java/security/SecureClassLoader", + "java/lang/Exception", + "java/lang/Throwable", + "java/lang/VMThrowable", + "gnu/java/net/loader/FileURLLoader", + "gnu/java/net/loader/URLLoader", + "java/security/Policy", + "gnu/java/security/provider/DefaultPolicy", + "gnu/java/net/loader/Resource", + "gnu/java/net/loader/FileResource", + "java/io/FileInputStream", + "gnu/java/nio/FileChannelImpl", + "java/nio/ByteBuffer", + "java/nio/Buffer", + "java/nio/ByteOrder", + "java/security/Permissions$PermissionsHash", + "java/nio/charset/Charset", + "gnu/java/nio/charset/Provider", + "gnu/java/nio/charset/Provider$1", + "gnu/java/nio/charset/US_ASCII", + "java/util/Collections$UnmodifiableSet/", + "java/util/Collections$UnmodifiableCollection", + "java/util/Collections$UnmodifiableIterator", + "gnu/java/nio/charset/ISO_8859_1", + "gnu/java/nio/charset/UTF_8", + "gnu/java/nio/charset/UTF_16BE", + "gnu/java/nio/charset/UTF_16LE", + "gnu/java/nio/charset/UTF_16", + "gnu/java/nio/charset/UnicodeLittle", + "gnu/java/nio/charset/Windows1250", + "gnu/java/nio/charset/Windows1250", + "gnu/java/nio/charset/ByteCharset", + "gnu/java/nio/charset/Windows1251", + "gnu/java/nio/charset/Windows1252", + "gnu/java/nio/charset/Windows1253", + "gnu/java/nio/charset/Windows1254", + "gnu/java/nio/charset/Windows1257", + "gnu/java/nio/charset/ISO_8859_2", + "gnu/java/nio/charset/ISO_8859_4", + "gnu/java/nio/charset/ISO_8859_5", + "gnu/java/nio/charset/ISO_8859_7", + "gnu/java/nio/charset/ISO_8859_9", + "gnu/java/nio/charset/ISO_8859_13", + "gnu/java/nio/charset/ISO_8859_15", + "gnu/java/nio/charset/KOI_8", + "gnu/java/nio/charset/ISO_8859_1$Encoder", + "java/nio/charset/CharsetEncoder", + "gnu/java/nio/charset/ByteEncodeLoopHelper", + "java/nio/charset/CodingErrorAction", + "java/nio/CharBuffer", + "java/nio/CharBufferImpl", + "gnu/java/nio/charset/ByteEncodeLoopHelper", + "java/nio/charset/CoderResult", + "java/nio/charset/CoderResult$1", + "java/nio/charset/CoderResult$2", + "java/nio/charset/CoderResult$Cache", + "java/awt/Toolkit", + "gnu/java/awt/peer/gtk/GtkToolkit", + "gnu/java/awt/peer/gtk/GtkGenericPeer", + "java/util/WeakHashMap", + "java/util/WeakHashMap$1", + "java/util/WeakHashMap$WeakEntrySet", + "gnu/java/awt/peer/gtk/GtkWindowPeer", + "gnu/java/awt/peer/gtk/GtkCheckboxPeer", + "gnu/java/awt/peer/gtk/GtkFileDialogPeer", + "gnu/java/awt/peer/gtk/GtkMainThread", + "java/security/AccessController", + "java/security/Permission", + "java/lang/ClassLoader$StaticData", + "java/lang/VMString", + "gnu/java/lang/CPStringBuilder", + "gnu/java/lang/VMCPStringBuilder", + "java/io/FileOutputStream", + "gnu/java/nio/VMChannel", + "gnu/java/nio/VMChannel$State", + "gnu/java/nio/VMChannel$Kind", + "java/nio/channels/FileChannel", + "gnu/classpath/VMSystemProperties", + "java/lang/StringBuffer", + "java/lang/VMRuntime", + "java/lang/VMObject", + "java/lang/VMThread", + "java/lang/VMClass", + "java/lang/InheritableThreadLocal", + "java/lang/ClassNotFoundException", + "java/net/URLClassLoader", + "java/lang/ClassLoader$1", + "java/nio/ByteBufferImpl", + "java/io/FilePermission", + "gnu/java/nio/charset/ISO_8859_1$Encoder$1", + "java/nio/charset/spi/CharsetProvider", + "gnu/java/net/loader/URLStreamHandlerCache", + "java/util/HashMap$HashIterator", + "java/util/HashMap$HashEntry", + "java/util/AbstractMap", + "java/util/AbstractMap$1", + "java/lang/RuntimeException", + "java/util/Collections$UnmodifiableSet", + "java/lang/ref/Reference", + "java/lang/ref/WeakReference", + "gnu/java/util/WeakIdentityHashMap$WeakBucket", + "gnu/java/util/WeakIdentityHashMap$WeakEntrySet$1", + "java/lang/String$CaseInsensitiveComparator", + "java/lang/Throwable$StaticData", + "java/lang/StackTraceElement", + "java/lang/VMMath", + "java/lang/Double", + "java/lang/VMDouble", + "java/lang/Long", + "java/lang/Float", + "java/lang/VMFloat", + "java/security/Permissions", /* 200 */ + "java/security/AllPermission", + "java/security/AllPermission$AllPermissionCollection", + "java/util/AbstractMap$1$1", /* 203 */ + "java/lang/Integer", + + NULL }; + + if (getenv("FILTER_VERBOSE") && !printed) + { + i = 0; + while (classes[i]) + { + log_println("[%d] - %s", i, classes[i]); + i++; + } + + printed = true; + } + + buf = getenv("INDEX"); + if (buf) + sscanf(buf, "%d", &max_index); + + i = 0; + while (classes[i] && i <= max_index) + { + + if (!strcmp(classes[i], classname->text)) + return true; + + i++; + } + + if ((buf = getenv("FILTER_VERBOSE"))) + { + log_println("filtered: %s", classname->text); + } + + return false; +} + +void filter_match() +{ + /* Wohoo! */ +} + +/** + * Causes filter_match() on which one can set a breakpoint in the debugger + * in the following conditions: + * + * If the environment variable NO_FILTER is set, then filter_match() is not + * called at all. This disables filter capabilities. + * + * If environment variable TEST_CLASS is set and the method belong to this + * class and there is no variable TEST_METHOD then filter_match() is called. + * + * If TEST_CLASS and TEST_METHOD match the methodinfo and TEST_DESCRIPTOR is + * not set. + * + * If TEST_CLASS, TEST_METHOD and TEST_DESCRIPTOR match the methodinfo's values. + */ +void filter_single(methodinfo *m) +{ + char *buf = NULL; + + buf = getenv("NO_FILTER"); + if (buf) + return; + + buf = getenv("TEST_CLASS"); + if (!buf || strcmp(m->clazz->name->text, buf)) + return; + + buf = getenv("TEST_METHOD"); + if (!buf) + { + filter_match(); + return; + } + else if (strcmp(m->name->text, buf)) + return; + + buf = getenv("TEST_DESCRIPTOR"); + if (!buf) + { + filter_match(); + return; + } + else if (strcmp(m->descriptor->text, buf)) + return; + + filter_match(); +} + +Mutex *jitcache_lock; + +/* jitcache_store ************************************************************** + + Saves the generated machine code to disk. + +*******************************************************************************/ +void jitcache_store (methodinfo *m) +{ + static int init_lock = true; + void *temp; + int fd; + + if (init_lock) + { + jitcache_lock = new Mutex(); + init_lock = false; + } + +/* + filter_single(m); + + if (!filter(m->clazz->name)) + return; +*/ + + /* Never try to store native method stubs because those include a reference + * a dynamically resolved function. + * + * TODO: Handle those, too. + */ + if (m->flags & ACC_NATIVE) + return; + + fd = get_cache_file_writable(m); + if (!fd) + { + if (opt_DebugJitCache) + log_message_method("[jitcache] store: got no file descriptor for ", m); + + return; + } + + /* Write (and some read) file operations beyond this point. + * Acquire lock first because another thread may try to load a different + * method from this class. + */ +/* Mutex_lock(&m->clazz->cache_file_lock);*/ + jitcache_lock->lock(); + + if (opt_DebugJitCache) + log_message_method("[jitcache] store: ", m); + + update_method_table(m, fd); + + /* flags, optlevel, basicblockcount, synchronizedoffset, stackframesize, entrypoint, mcodelength, mcode + */ + system_write(fd, (const void *) &m->code->flags, sizeof(m->code->flags)); + + system_write(fd, (const void *) &m->code->optlevel, sizeof(m->code->optlevel)); + system_write(fd, (const void *) &m->code->basicblockcount, sizeof(m->code->basicblockcount)); + + system_write(fd, (const void *) &m->code->synchronizedoffset, sizeof(m->code->synchronizedoffset)); + + system_write(fd, (const void *) &m->code->stackframesize, sizeof(m->code->stackframesize)); + + temp = to_offset(m->code->mcode, m->code->entrypoint); + system_write(fd, (const void *) &temp, sizeof(temp)); + + system_write(fd, (const void *) &m->code->mcodelength, sizeof(m->code->mcodelength)); + + system_write(fd, (const void *) m->code->mcode, m->code->mcodelength); + + store_to_file_exceptiontable(fd, m->code); + + store_to_file_linenumbertable(fd, m->code); + + store_to_file_patchers(fd, m->code); + + store_to_file_cachedrefs(fd, m->code); + +/* Mutex_unlock(&m->clazz->cache_file_lock);*/ + jitcache_lock->unlock(); + +} + +/* jitcache_load *************************************************************** + + Try to load previously generated machine code from disk. + + Returns non-zero if successfull. + +*******************************************************************************/ + +u1 jitcache_load (methodinfo *m) +{ + codeinfo *code; + u1 *endpc; + int fd; + +/* + if (!filter(m->clazz->name)) + return false; +*/ + + /* Never try to store native method stubs because those include a reference + * a dynamically resolved function. + */ + if (m->flags & ACC_NATIVE) + return false; + + fd = get_cache_file_readable(m); + if (fd <= 0) + { + if (opt_DebugJitCache) + log_message_method("[jitcache] load: got no file descriptor for ", m); + + return false; + } + + if(!seek_method_table(m, fd)) + { + os::close(fd); + + return false; + } + + if (opt_DebugJitCache) + log_message_method("[jitcache] load: ", m); + + code = code_codeinfo_new(m); + m->code = code; + + /* flags, optlevel, basicblockcount, synchronizedoffset, stackframesize, entrypoint, mcodelength, mcode + */ + system_read(fd, (void *) &code->flags, sizeof(code->flags)); + + system_read(fd, (void *) &code->optlevel, sizeof(code->optlevel)); + system_read(fd, (void *) &code->basicblockcount, sizeof(code->basicblockcount)); + + system_read(fd, (void *) &code->synchronizedoffset, sizeof(code->synchronizedoffset)); + + system_read(fd, (void *) &code->stackframesize, sizeof(code->stackframesize)); + + system_read(fd, (void *) &code->entrypoint, sizeof(code->entrypoint)); + + system_read(fd, (void *) &code->mcodelength, sizeof(code->mcodelength)); + + code->mcode = CNEW(u1, code->mcodelength); + system_read(fd, (void *) code->mcode, code->mcodelength); + code->entrypoint = (u1 *) to_abs(code->mcode, code->entrypoint); + + load_from_file_exceptiontable(code, fd); + + load_from_file_linenumbertable(code, fd); + + load_from_file_patchers(code, fd); + + load_from_file_cachedrefs(code, fd); + + os::close(fd); + + endpc = (u1 *) ((ptrint) code->mcode) + code->mcodelength; + + /* Insert method into methodtree to find the entrypoint. */ + + methodtree_insert(code->entrypoint, endpc); + + /* flush the instruction and data caches */ + + md_cacheflush(code->mcode, code->mcodelength); + + if (opt_DebugJitCache) + { + log_println("[jitcache] load - registered method: %x -> %x", code->entrypoint, endpc); + } + + return true; +} + +void jitcache_quit() +{ + int i; + + for (i = 0; i < mru_last_free; i++) + { + os::close(jc_mru_list[i]->cache_file_fd); + jc_mru_list[i]->cache_file_fd = 0; + jc_mru_list[i] = 0; + } + + mru_last_free = 0; + + /* Closes all open file descriptors. */ +} + +void jitcache_freeclass(classinfo *c) +{ + if (c->cache_file_fd) + jitcache_mru_remove(c); +} + +/* Helper functions */ +void update_method_table(methodinfo *m, int fd) +{ + int state = 0, i, temp, offset = 0; + + system_lseek(fd, 0, SEEK_SET); + + system_read(fd, (void *) &state, sizeof(state)); + + /* table does not exist yet and needs to be created first */ + if (state != 1) + { + system_lseek(fd, 0, SEEK_SET); + state = 1; + system_write(fd, &state, sizeof(state)); + + temp = -1; + for (i = 0; i < m->clazz->methodscount; i++) + system_write(fd, &temp, sizeof(temp)); + } + + /* get last offset in file */ + offset = system_lseek(fd, 0, SEEK_END); + + /* find out the index in the methods array */ + temp = -1; + for (i = 0; i < m->clazz->methodscount; i++) + if (&m->clazz->methods[i] == m) + { + temp = i; + break; + } + assert(temp != -1); + + /* seek to the method's entry in the table */ + system_lseek(fd, temp * sizeof(int) + sizeof(int), SEEK_SET); + + /* enter the location */ + system_write(fd, &offset, sizeof(offset)); + + system_lseek(fd, offset, SEEK_SET); +} + +int seek_method_table(methodinfo *m, int fd) +{ + int state = 0, i, temp, offset; + + system_lseek(fd, 0, SEEK_SET); + + system_read(fd, (void *) &state, sizeof(state)); + + /* if table does not exist, we cannot load any machine code from this file */ + if (state != 1) + return 0; + + /* find out the index in the methods array */ + temp = -1; + for (i = 0; i < m->clazz->methodscount; i++) + if (&m->clazz->methods[i] == m) + { + temp = i; + break; + } + assert(temp != -1); + + /* seek to the method's entry in the table */ + system_lseek(fd, temp * sizeof(int) + sizeof(int), SEEK_SET); + + /* get the location */ + system_read(fd, &offset, sizeof(offset)); + + if (offset > 0) + { + system_lseek(fd, offset, SEEK_SET); + return offset; + } + + return 0; +} + +int get_cache_file_readable(methodinfo *m) +{ + char *dest_file; + int fd; + + if (m->clazz->cache_file_fd) + return dup(m->clazz->cache_file_fd); + + + /* load from filesystem */ + dest_file = get_dest_file(m); + + if (os::access(dest_file, F_OK) != 0) + { + if (opt_DebugJitCache) + log_message_method("[jitcache] no cache file found for ", m); + ++ perror("get_cache_file_writable: "); ++ + os::free(dest_file); + + return 0; + } + +/* + filter_single(m); +*/ + + fd = open_to_read(dest_file); + + os::free(dest_file); + +/* + if (fd > 0) + jitcache_mru_add(m->clazz, fd); +*/ + return fd; +} + +int get_cache_file_writable(methodinfo *m) +{ + char *dest_file, *dest_dir; + int fd; + + if (m->clazz->cache_file_fd) + return m->clazz->cache_file_fd; + + /* try to get the file first */ + dest_file = get_dest_file(m); + fd = open_to_write(dest_file); + + /* file does not exist. We need to create it and possibly + * the directory hierarchy as well. + */ + if (fd <= 0) { + dest_dir = get_dest_dir(m); + + if (os::access(dest_dir, F_OK) != 0) + { + if (mkdir_hier(dest_dir, S_IRWXU | S_IRWXG) != 0) + { ++ perror("get_cache_file_writable: "); ++ + if (opt_DebugJitCache) + log_println("[jitcache] unable to create cache directory: %s", dest_dir); + + os::free(dest_dir); + os::free(dest_file); + + return 0; + } + } + + os::free(dest_dir); + + /* try to open the file again. */ + fd = open_to_write(dest_file); + os::free(dest_file); + + if (fd <= 0) ++ { ++ perror("get_cache_file_writable2: "); + return 0; ++ } + } + + os::free(dest_file); + + jitcache_mru_add(m->clazz, fd); + + return fd; +} + +/* mkdir_hier ****************************************************************** + + Creates a directory hierarchy on the filesystem. + +*******************************************************************************/ +int mkdir_hier(char *path, mode_t mode) +{ + int index; + int length = os::strlen(path); + + for (index = 0; index < length; index++) + { + if (path[index] == '/') + { + path[index] = 0; + mkdir(path, mode); + + path[index] = '/'; + } + } + - return mkdir(path, mode); ++ if (!mkdir(path, mode) || errno == EEXIST) ++ return 0; +} + +/* get_dest_file **************************************************************** + + Returns a string denoting the file in which the method's machine code + (along with the other data) is stored. + +*******************************************************************************/ + +char *get_dest_file(methodinfo *m) +{ + int len_cacheroot = os::strlen(CACHEROOT); + int len_classname = utf_bytes(m->clazz->name); + + char *dest_file = (char *) os::calloc(sizeof(u1), + len_cacheroot + + len_classname + + 2); + + strcat(dest_file, CACHEROOT); + utf_cat(dest_file, m->clazz->name); + + return dest_file; +} + +/* get_dest_dir **************************************************************** + + Returns a string denoting the directory in which the method's machine code + (along with the other data) is stored. + +*******************************************************************************/ + +char *get_dest_dir(methodinfo *m) +{ + int len_cacheroot = os::strlen(CACHEROOT); + int len_packagename = utf_bytes(m->clazz->packagename); + + char *dest_dir = (char *) os::calloc(sizeof(u1), + len_cacheroot + + len_packagename + 2); + + strcat(dest_dir, CACHEROOT); + utf_cat(dest_dir, m->clazz->packagename); + + /* Make trailing slash from package name to 0 */ + dest_dir[len_cacheroot + len_packagename + 2 - 1] = 0; + + return dest_dir; +} + +/* to_abs ********************************************************************** + + Generates an absolute pointer from an offset. You need this after loading + a value from the disk which is absolute at runtime. + +*******************************************************************************/ + +void *to_abs(void *base, void *offset) +{ + return (void *) ((ptrint) base + (ptrint) offset); +} + +/* to_offset ******************************************************************* + + Generates an offset from an absolute pointer. This has to be done to each + absolute pointer before storing it to disk. + +*******************************************************************************/ + +void *to_offset(void *base, void *abs) +{ + return (void *) ((ptrint) abs - (ptrint) base); +} + +/* open_to_read **************************************************************** + + Open a file for reading. + +*******************************************************************************/ + +int open_to_read(char *dest_file) +{ + int fd; +/* + fd = system_open(dest_file, O_RDONLY, 0); +*/ + fd = system_open(dest_file, + O_RDWR, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + + return fd; +} + +/* open_to_write *************************************************************** + + Open a file for writing. + +*******************************************************************************/ + +int open_to_write(char *dest_file) +{ + int fd; + +/* fd = system_open(filename, + O_CREAT | O_WRONLY, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); +*/ + fd = system_open(dest_file, + O_CREAT | O_RDWR, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + + return fd; +} + +/* store_utf ******************************************************************* + + Writes a utf object to disk (via filedescriptor). + +*******************************************************************************/ +void store_utf(int fd, utf *s) +{ + int len; + + if (!s) + { + len = -1; + system_write(fd, (const void *) &len, sizeof(len)); + } + else + { + len = utf_bytes(s); + system_write(fd, (const void *) &len, sizeof(len)); + system_write(fd, s->text, len); + } +} + +/* load_utf ******************************************************************** + + Loads a UTF8 constant from the given filedescriptor and initializes + the given pointer with it. + In case the stored constant's length is -1 the returned string is NULL. + +*******************************************************************************/ +void load_utf(utf **s, int fd) +{ + int len = 0; + char *tmp; + + system_read(fd, (void *) &len, sizeof(len)); + + if (len == -1) + *s = NULL; + else + { + tmp = (char *) os::calloc(sizeof(char), len); + + system_read(fd, tmp, len); + + *s = utf_new(tmp, len); + +/* os::free(tmp);*/ + } +} + + +/* store_to_file_patchers ****************************************************** + + Writes the patchers structure of a codeinfo to disk. + +*******************************************************************************/ +void store_to_file_patchers(int fd, codeinfo *code) +{ + int temp = 0; + void *temp_ptr; - patchref_t *pr; + int j; + - list_t *patchers = code->patchers; ++ int size = code->patchers->size(); + + /* serialize patchers list */ - system_write(fd, (const void *) &patchers->size, sizeof(patchers->size)); ++ system_write(fd, (const void *) &size, sizeof(size)); + if (opt_DebugJitCache) - log_println("store_to_file_patchers - patchers size %d", patchers->size); ++ log_println("store_to_file_patchers - patchers size %d", size); + - for (pr = (patchref_t *) list_first(patchers); pr != NULL; pr = (patchref_t *) list_next(patchers, pr)) ++ for (List::iterator it = code->patchers->begin(); ++ it != code->patchers->end(); it++) + { - temp_ptr = to_offset(code->mcode, (u1 *) pr->mpc); ++ temp_ptr = to_offset(code->mcode, (u1 *) it->mpc); + system_write(fd, (const void *) &temp_ptr, sizeof(temp_ptr)); + - temp_ptr = to_offset(code->mcode, (u1 *) pr->datap); ++ temp_ptr = to_offset(code->mcode, (u1 *) it->datap); + system_write(fd, (const void *) &temp_ptr, sizeof(temp_ptr)); + - system_write(fd, (const void *) &pr->disp, sizeof(pr->disp)); ++ system_write(fd, (const void *) &it->disp, sizeof(it->disp)); + + temp = -1; + j = 0; + while (patcher_functions[j].patcher) + { - if (patcher_functions[j].patcher == pr->patcher) ++ if (patcher_functions[j].patcher == it->patcher) + { + temp = j; + system_write(fd, (const void *) &j, sizeof(j)); + - (*patcher_functions[j].serializer)(fd, pr, code->m); ++ (*patcher_functions[j].serializer)(fd, &(*it), code->m); + + if (patcher_functions[j].serializer == s_dummy) + log_println("store_to_file_patchers: unhandled patcher function for %d", j); + break; + } + j++; + } + + if (temp == -1) + { + log_println("warning! unknown patcher function stored!"); + system_write(fd, (const void *) &temp, sizeof(temp)); + } + - system_write(fd, (const void *) &pr->attached_ref, sizeof(pr->attached_ref)); ++ if (it->attached_ref) ++ temp = 1; ++ ++ system_write(fd, (const void *) &temp, sizeof(temp)); + - if (pr->attached_ref) ++ if (it->attached_ref) + { - store_cachedref(fd, pr->attached_ref); ++ store_cachedref(fd, it->attached_ref); + + /* Release the cached reference now because it should not be used + * in the current Cacao process. + */ - FREE(pr->attached_ref, cachedref_t); - pr->attached_ref = NULL; ++ FREE(it->attached_ref, cachedref_t); ++ it->attached_ref = NULL; + } + - system_write(fd, (const void *) &pr->mcode, sizeof(pr->mcode)); ++ system_write(fd, (const void *) &it->mcode, sizeof(it->mcode)); + } +} + + +/* store_to_file_cachedrefs ***************************************************** + + Writes the cachedrefs structure of a codeinfo to disk. + +*******************************************************************************/ +void store_to_file_cachedrefs(int fd, codeinfo *code) +{ - cachedref_t *cr; - - list_t *cachedrefs = code->cachedrefs; ++ int size = code->cachedrefs->size(); + if (opt_DebugJitCache) - log_println("store_to_file_cachedrefs - cachedrefs size %d", cachedrefs->size); ++ log_println("store_to_file_cachedrefs - cachedrefs size %d", size); + + /* serialize cachedrefs list */ - system_write(fd, (const void *) &cachedrefs->size, sizeof(cachedrefs->size)); ++ system_write(fd, (const void *) &size, sizeof(size)); + - for (cr = (cachedref_t *) list_first(cachedrefs); - cr != NULL; - cr = (cachedref_t *) list_next(cachedrefs, cr)) - store_cachedref(fd, cr); ++ for (List::iterator it = code->cachedrefs->begin(); ++ it != code->cachedrefs->end(); it++) ++ store_cachedref(fd, &(*it)); +} + +/* store_cachedref ************************************************************* + + Stores a single cachedref_t instance to disk. + +*******************************************************************************/ + +void store_cachedref(int fd, cachedref_t *cr) +{ + system_write(fd, (const void *) &cr->type, sizeof(cr->type)); + system_write(fd, (const void *) &cr->md_patch, sizeof(cr->md_patch)); + system_write(fd, (const void *) &cr->disp, sizeof(cr->disp)); + + switch (cr->type) { + case CRT_CODEINFO: + case CRT_ENTRYPOINT: + case CRT_CODEGEN_FINISH_NATIVE_CALL: + case CRT_ASM_HANDLE_EXCEPTION: + case CRT_ASM_HANDLE_NAT_EXCEPTION: + /* Nothing to store. */ + break; + case CRT_NUM: + system_write(fd, (const void *) &cr->ref, sizeof(s4)); + break; + case CRT_OBJECT_HEADER: + case CRT_CLASSINFO: + case CRT_CLASSINFO_INDEX: + case CRT_CLASSINFO_INTERFACETABLE: + case CRT_CLASSINFO_VFTBL: + /* Store classinfo */ + store_classinfo(fd, (classinfo *) cr->ref); + break; + case CRT_BUILTIN: + case CRT_BUILTIN_FP: + store_builtin(fd, (builtintable_entry *) cr->ref); + break; + case CRT_STRING: + store_string(fd, (java_object_t *) cr->ref); + break; + case CRT_METHODINFO_STUBROUTINE: + case CRT_METHODINFO_TABLE: + case CRT_METHODINFO_INTERFACETABLE: + case CRT_METHODINFO_METHODOFFSET: + store_methodinfo(fd, (methodinfo *) cr->ref); + break; + case CRT_FIELDINFO_VALUE: + case CRT_FIELDINFO_OFFSET: + case CRT_FIELDINFO_OFFSET_HIGH: + store_fieldinfo(fd, (fieldinfo *) cr->ref); + break; + case CRT_JUMPREFERENCE: + system_write(fd, (const void *) &cr->ref, sizeof(cr->ref)); + + break; + default: + log_println("store_cachedref: Invalid cachedref type: %d", cr->type); + assert(0); + } +} + + +/* store_to_file_exceptiontable ************************************************ + + Writes the exceptiontable structure of a codeinfo to disk. + +*******************************************************************************/ +void store_to_file_exceptiontable(int fd, codeinfo *code) +{ + int count = 0; + void *temp_ptr; + int i; + utf *name; + + /* serialize exceptiontable */ + + /* temp will contain the amount of exceptiontable entries or zero + * if none exists. + */ + if (code->exceptiontable) + count = code->exceptiontable->length; + + system_write(fd, (const void *) &count, sizeof(count)); + if (opt_DebugJitCache) + log_println("store_exceptiontable - exceptiontable size %d", count); + + for (i = 0; i < count; i++) + { + exceptiontable_entry_t *entry = &code->exceptiontable->entries[i]; + + temp_ptr = to_offset(code->mcode, entry->endpc); + system_write(fd, (const void *) &temp_ptr, sizeof(temp_ptr)); + + temp_ptr = to_offset(code->mcode, entry->startpc); + system_write(fd, (const void *) &temp_ptr, sizeof(temp_ptr)); + + temp_ptr = to_offset(code->mcode, entry->handlerpc); + system_write(fd, (const void *) &temp_ptr, sizeof(temp_ptr)); + + /* store class name of entry->catchtype */ + if (entry->catchtype.any) + { + name = CLASSREF_OR_CLASSINFO_NAME(entry->catchtype); + store_utf(fd, name); + } + else + store_utf(fd, NULL); + + } + +} + + +/* store_to_file_linenumbertable *********************************************** + + Writes the linenumbertable structure of a codeinfo to disk. + +*******************************************************************************/ +void store_to_file_linenumbertable(int fd, codeinfo *code) +{ + void *temp_ptr; - linenumbertable_entry_t *lte; + int count = 0; - int i; - linenumbertable_t *linenumbertable; - - linenumbertable = code->linenumbertable; + + if (code->linenumbertable) - count = code->linenumbertable->length; ++ count = code->linenumbertable->_linenumbers.size(); + + /* serialize patchers list */ + system_write(fd, (const void *) &count, sizeof(count)); + + if (opt_DebugJitCache) + log_println("store_to_file_linenumbertable - linenumbertable size %d", count); + + if (count) + { - lte = linenumbertable->entries; - for (i = 0; i < count; i++) ++ for (std::vector::iterator it = code->linenumbertable->_linenumbers.begin(); ++ it != code->linenumbertable->_linenumbers.end(); it++) + { - system_write(fd, (const void *) <e->linenumber, sizeof(lte->linenumber)); ++ int temp = it->get_linenumber(); ++ system_write(fd, (const void *) &temp, sizeof(temp)); + - temp_ptr = to_offset(code->entrypoint, lte->pc); ++ temp_ptr = to_offset(code->entrypoint, it->get_pc()); + system_write(fd, (const void *) &temp_ptr, sizeof(temp_ptr)); - - lte++; + } + } + +} + + +/* load_from_file_patchers ***************************************************** + + Loads the patchers structure of codeinfo from a file. + +*******************************************************************************/ +void load_from_file_patchers(codeinfo *code, int fd) +{ + int temp = 0; + u1 *temp_ptr; + int count = 0; + int i; + + /* serialize patchers list */ + system_read(fd, (void *) &count, sizeof(count)); + + if (opt_DebugJitCache /* Insert method into methodtree to find the entrypoint. */ +) + log_println("load_from_file_patchers - patcher size %d", count); + + patcher_list_create(code); + + for (i = 0;i < count; i++) + { - patchref_t *pr = NEW(patchref_t); ++ patchref_t pr; + + system_read(fd, (void *) &temp_ptr, sizeof(temp_ptr)); - pr->mpc = (ptrint) to_abs(code->mcode, temp_ptr); ++ pr.mpc = (ptrint) to_abs(code->mcode, temp_ptr); + + system_read(fd, (void *) &temp_ptr, sizeof(temp_ptr)); - pr->datap = (ptrint) to_abs(code->mcode, temp_ptr); ++ pr.datap = (ptrint) to_abs(code->mcode, temp_ptr); + - system_read(fd, (void *) &pr->disp, sizeof(pr->disp)); ++ system_read(fd, (void *) &pr.disp, sizeof(pr.disp)); + + system_read(fd, (void *) &temp, sizeof(temp)); + if (temp == -1) + { + vm_abort("Invalid patcher function index loaded!"); + temp = 0; + } - pr->patcher = patcher_functions[temp].patcher; ++ pr.patcher = patcher_functions[temp].patcher; + - (*patcher_functions[temp].deserializer)(pr, fd, code->m); ++ (*patcher_functions[temp].deserializer)(&pr, fd, code->m); + + /* Load the pointer value to decide whether a cached reference must + * be loaded or not. */ - system_read(fd, (void *) &pr->attached_ref, sizeof(pr->attached_ref)); ++ system_read(fd, (void *) &temp, sizeof(temp)); + - if (pr->attached_ref) ++ if (temp) + { - pr->attached_ref = NULL; - load_cachedref(&pr->attached_ref, fd, code); ++ pr.attached_ref = 0; ++ load_cachedref(&pr.attached_ref, fd, code); + } + - system_read(fd, (void *) &pr->mcode, sizeof(pr->mcode)); ++ system_read(fd, (void *) &pr.mcode, sizeof(pr.mcode)); + - pr->done = false; ++ pr.done = false; + - list_add_first(code->patchers, pr); ++ code->patchers->push_front(pr); + } +} + +/* load_from_file_cachedrefs *************************************************** + + Loads the cachedrefs structure of codeinfo from a file. + + Note: code->entrypoint *must* be valid at this point! + + Binary format: + int - number of cachedref_t instances in the file + cachedref_t - see load_cachedref + +*******************************************************************************/ +void load_from_file_cachedrefs(codeinfo *code, int fd) +{ + cachedref_t *cr; + int count = 0; + int i; + + /* serialize cachedrefs list */ + system_read(fd, (void *) &count, sizeof(count)); + + if (opt_DebugJitCache) + log_println("load_from_file_cachedrefs - cachedrefs size %d", count); + + jitcache_list_reset(code); + + cr = NEW(cachedref_t); + + for (i = 0;i < count; i++) + { + load_cachedref(&cr, fd, code); + + /* Write the restored reference into the code. */ ++#if defined (__ARM__) + if (cr->md_patch) + patch_md(cr->md_patch, ((ptrint) code->entrypoint) + cr->disp, cr->ref); + else ++#endif + { + *((u1 **) (code->entrypoint + cr->disp)) = (u1 *) cr->ref; + } + + } + + FREE(cr, cachedref_t); +} + + +/* load_cachedref ************************************************************** + + Loads a cached reference from disk and + + Binary format: + s4 - disp value + cachedreftype - type value + * - cached ref specific (depends on type) + +*******************************************************************************/ + +void load_cachedref(cachedref_t **result_cr, int fd, codeinfo *code) +{ + cachedref_t *cr; + classinfo *ci; + methodinfo *mi; + fieldinfo *fi; + builtintable_entry *bte; + java_object_t *h; + + if (*result_cr) + cr = *result_cr; + else + *result_cr = cr = NEW(cachedref_t); + + system_read(fd, (void *) &cr->type, sizeof(cr->type)); + system_read(fd, (void *) &cr->md_patch, sizeof(cr->md_patch)); + system_read(fd, (void *) &cr->disp, sizeof(cr->disp)); + + switch (cr->type) { + case CRT_CODEINFO: + /* Just set the current codeinfo. */ + cr->ref = (void*) code; + break; + case CRT_NUM: + system_read(fd, (void *) &cr->ref, sizeof(s4)); + break; + case CRT_ENTRYPOINT: + /* Just set the current entrypoint. */ + cr->ref = (void*) code->entrypoint; + break; + case CRT_CODEGEN_FINISH_NATIVE_CALL: + /* Just set the pointer to codegen_finish_native_call. */ + cr->ref = (void*) (ptrint) codegen_finish_native_call; + break; + case CRT_ASM_HANDLE_EXCEPTION: + /* Just set the pointer to asm_handle_exception. */ + cr->ref = (void*) (ptrint) asm_handle_exception; + break; + case CRT_ASM_HANDLE_NAT_EXCEPTION: + /* Just put the pointer to asm_handle_nat_exception. */ + cr->ref = (void*) (ptrint) asm_handle_nat_exception; + break; + case CRT_OBJECT_HEADER: + /* Load classinfo */ + load_classinfo(&ci, fd, code->m); + cr->ref = &ci->object.header; + break; + case CRT_BUILTIN: + load_builtin(&bte, fd); + /* TODO: For the time being prefer the stub if it exists, otherwise + * use the function pointer directlty. + * This should go away with a moving garbage collector. + */ + cr->ref = (void*) (bte->stub == NULL ? (ptrint) bte->fp : (ptrint) bte->stub); + + break; + case CRT_BUILTIN_FP: + load_builtin(&bte, fd); + cr->ref = (void*) (ptrint) bte->fp; + + break; + case CRT_STRING: + load_string(&h, fd); + cr->ref = (void*) h; + break; + case CRT_CLASSINFO: + /* Load classinfo */ + load_classinfo(&ci, fd, code->m); + cr->ref = (void*) ci; + + break; + case CRT_CLASSINFO_INDEX: + /* Load classinfo */ + load_classinfo(&ci, fd, code->m); + cr->ref = (void*) ci->index; + break; + case CRT_CLASSINFO_INTERFACETABLE: + /* Load classinfo */ + load_classinfo(&ci, fd, code->m); + cr->ref = (void*) (OFFSET(vftbl_t, interfacetable[0]) - + ci->index * sizeof(methodptr*)); + break; + case CRT_CLASSINFO_VFTBL: + /* Load classinfo */ + load_classinfo(&ci, fd, code->m); + cr->ref = (void*) ci->vftbl; + break; + case CRT_METHODINFO_STUBROUTINE: + load_methodinfo(&mi, fd, code->m); + cr->ref = (void*) mi->stubroutine; + break; + case CRT_METHODINFO_TABLE: + load_methodinfo(&mi, fd, code->m); + cr->ref = (void*) ((OFFSET(vftbl_t, table[0]) + + sizeof(methodptr) * mi->vftblindex)); + break; + case CRT_METHODINFO_INTERFACETABLE: + load_methodinfo(&mi, fd, code->m); + cr->ref = (void*) (OFFSET(vftbl_t, interfacetable[0]) - + sizeof(methodptr) * mi->clazz->index); + break; + case CRT_METHODINFO_METHODOFFSET: + load_methodinfo(&mi, fd, code->m); + cr->ref = (void*) ((sizeof(methodptr) * (mi - mi->clazz->methods))); + break; + case CRT_FIELDINFO_VALUE: + load_fieldinfo(&fi, fd, code->m); + + cr->ref = (void*) fi->value; + break; + case CRT_FIELDINFO_OFFSET: + load_fieldinfo(&fi, fd, code->m); + + cr->ref = (void*) fi->offset; + break; + case CRT_FIELDINFO_OFFSET_HIGH: + /* Should be used on 32 bit archs only. */ + load_fieldinfo(&fi, fd, code->m); + + cr->ref = (void*) (fi->offset + 4); + break; + case CRT_JUMPREFERENCE: + system_read(fd, (void *) &cr->ref, sizeof(cr->ref)); + + cr->ref = (void*) ((ptrint) cr->ref + (ptrint) code->entrypoint); + break; + default: + log_println("Invalid (or unhandled) cachedreference type: %d", cr->type); + assert(0); + break; + } + + + if (opt_DebugJitCache) + { + if (cr->md_patch) + log_println("[%X, %d]: replace (md) %X with %X", code->entrypoint + cr->disp, cr->type, 0xFFF & (u4) (*(u1 **) (code->entrypoint + cr->disp)), cr->ref); + else + { + log_println("[%X, %d]: replace %X with %X", code->entrypoint + cr->disp, cr->type, *((u1 **) (code->entrypoint + cr->disp)), cr->ref); + if ((cr->type == CRT_BUILTIN || cr->type == CRT_BUILTIN_FP) && (void*) (*((u1 **) (code->entrypoint + cr->disp))) != cr->ref) + log_println("[!!!] differing builtin function pointer: %s", bte->cname); + } + } + + +} + +/* load_from_file_exceptiontable *********************************************** + + Loads the exceptiontable structure of codeinfo from a file. + +*******************************************************************************/ +void load_from_file_exceptiontable(codeinfo *code, int fd) +{ + int i; + u1 *temp_ptr; + utf *classname; + constant_classref *classref; + exceptiontable_entry_t *ete; + + code->exceptiontable = NEW(exceptiontable_t); + + system_read(fd, (void *) &code->exceptiontable->length, sizeof(code->exceptiontable->length)); + + if (opt_DebugJitCache) + log_println("load_exceptiontable - exceptiontable size %d", code->exceptiontable->length); + + + ete = MNEW(exceptiontable_entry_t, code->exceptiontable->length); + code->exceptiontable->entries = ete; + + for (i = 0; i < code->exceptiontable->length; i++) + { + system_read(fd, (void *) &temp_ptr, sizeof(temp_ptr)); + ete->endpc = to_abs(code->mcode, temp_ptr); + + system_read(fd, (void *) &temp_ptr, sizeof(temp_ptr)); + ete->startpc = to_abs(code->mcode, temp_ptr); + + system_read(fd, (void *) &temp_ptr, sizeof(temp_ptr)); + ete->handlerpc = to_abs(code->mcode, temp_ptr); + + /* load class name of entry->catchtype */ + load_utf(&classname, fd); + + if (classname) + { + classref = NEW(constant_classref); + CLASSREF_INIT(*classref, code->m->clazz, classname); + + ete->catchtype = CLASSREF_OR_CLASSINFO(classref); + } + else + ete->catchtype.any = NULL; + + ete++; + } + +} + + +/* load_from_file_linenumbertable ********************************************** + + Loads the linenumbertable structure of codeinfo from a file. + +*******************************************************************************/ +void load_from_file_linenumbertable(codeinfo *code, int fd) +{ - linenumbertable_entry_t *lte; + void *temp_ptr; + int i; + - code->linenumbertable = NEW(linenumbertable_t); ++ code->linenumbertable = new LinenumberTable(); + - system_read(fd, (void *) &code->linenumbertable->length, sizeof(code->linenumbertable->length)); ++ int size; ++ system_read(fd, (void *) &size, sizeof(size)); + + if (opt_DebugJitCache) - log_println("load_linenumbertable - linenumbertable size %d", code->linenumbertable->length); - - lte = MNEW(linenumbertable_entry_t, code->linenumbertable->length); - code->linenumbertable->entries = lte; ++ log_println("load_linenumbertable - linenumbertable size %d", size); + - for (i = 0;i < code->linenumbertable->length; i++) ++ for (i = 0;i < size; i++) + { - system_read(fd, (void *) <e->linenumber, sizeof(lte->linenumber)); ++ int linenumber; ++ system_read(fd, (void *) &linenumber, sizeof(linenumber)); + + system_read(fd, (void *) &temp_ptr, sizeof(temp_ptr)); - lte->pc = to_abs(code->entrypoint, temp_ptr); + - lte++; ++ code->linenumbertable->_linenumbers.push_back( ++ Linenumber(linenumber, to_abs(code->entrypoint, temp_ptr))); + } +} + + +/* s_dummy ********************************************************************* + + Patcher serialization function which does nothing and can therefore be used + as a placeholder for not yet written serializers. + +*******************************************************************************/ +void s_dummy(int fd, patchref_t *pr, methodinfo *m) +{ + /* Intentionally does nothing. */ +} + +/* s_unresolved_class ********************************************************** + + Serializes a unresolved_class reference. + + Binary format: + - utf string - classname + +*******************************************************************************/ +void s_unresolved_class(int fd, patchref_t *pr, methodinfo *m) +{ + unresolved_class *uc; + + uc = (unresolved_class *) pr->ref; + + /* Store the class name ... */ + store_utf(fd, uc->classref->name); + +/* + log_println("s_unresolved_class:"); + log_message_utf("class:", uc->classref->name); +*/ +} + +/* s_unresolved_field ********************************************************** + + Serializes a unresolved_field reference. + + Binary format: + s4 - unresolved_field.flags + int - index into class' cpinfo that denotes the unresolved_field's + constant_FMIref + +*******************************************************************************/ +void s_unresolved_field(int fd, patchref_t *pr, methodinfo *m) +{ + int i; + + unresolved_field *ref = (unresolved_field *) pr->ref; + +/* + log_println("s_unresolved_field:"); + log_message_utf("field name: ", ref->fieldref->name); + log_message_utf("field desc: ", ref->fieldref->descriptor); + log_message_utf("field's class: ", FIELDREF_CLASSNAME(ref->fieldref)); +*/ + system_write(fd, (const void *) &ref->flags, sizeof(ref->flags)); + + for (i = 0; i < m->clazz->cpcount; i++) + { + if (m->clazz->cpinfos[i] == (void*) ref->fieldref) + { + system_write(fd, (const void *) &i, sizeof(i)); + + return; + } + } + /* We should be out at this point. */ + + vm_abort("fieldref not found"); +} + +/* s_unresolved_method ********************************************************** + + Serializes a unresolved_method reference. + + Binary format: + undecided + +*******************************************************************************/ +void s_unresolved_method(int fd, patchref_t *pr, methodinfo *m) +{ + int i; + + unresolved_method *ref = (unresolved_method *) pr->ref; + + system_write(fd, (const void *) &ref->flags, sizeof(ref->flags)); + + for (i = 0; i < m->clazz->cpcount; i++) + { + if (m->clazz->cpinfos[i] == (void*) ref->methodref) + { + system_write(fd, (const void *) &i, sizeof(i)); + + return; + } + } + /* We should be out at this point. */ + + vm_abort("methodref not found"); +} + +/* s_classinfo ***************************************************************** + + Serializes a classinfo reference. + +*******************************************************************************/ +void s_classinfo(int fd, patchref_t *pr, methodinfo *m) +{ + classinfo *ci; + + ci = (classinfo *) pr->ref; + + store_classinfo(fd, ci); +} + +/* s_methodinfo **************************************************************** + + Serializes a methodinfo reference. + +*******************************************************************************/ +void s_methodinfo(int fd, patchref_t *pr, methodinfo *m) +{ + methodinfo *mi; + + mi = (methodinfo *) pr->ref; + + store_methodinfo(fd, mi); +} + +/* store_methodinfo ************************************************************ + + Serializes a methodinfo reference. + + Binary format: + utf - method name + utf - method descriptor + utf - class to which method belongs + +*******************************************************************************/ +void store_methodinfo(int fd, methodinfo *mi) +{ + store_utf(fd, mi->name); + store_utf(fd, mi->descriptor); + store_utf(fd, mi->clazz->name); +} + +/* s_fieldinfo **************************************************************** + + Serializes a fieldinfo reference. + + Binary format: + utf - field name + utf - field descriptor + utf - class to which field belongs + +*******************************************************************************/ +void s_fieldinfo(int fd, patchref_t *pr, methodinfo *m) +{ + fieldinfo *fi; + + fi = (fieldinfo *) pr->ref; + + store_fieldinfo(fd, fi); +} + +void store_fieldinfo(int fd, fieldinfo *fi) +{ + store_utf(fd, fi->name); + store_utf(fd, fi->descriptor); + store_utf(fd, fi->clazz->name); +} + +/* s_constant_classref ********************************************************* + + Serializes a constant_classref reference. + + Binary format: + - utf string - constant_classref's classname + +*******************************************************************************/ +void s_constant_classref(int fd, patchref_t *pr, methodinfo *m) +{ + constant_classref *cr = (constant_classref *) pr->ref; + + store_utf(fd, cr->name); +} + + +/* store_builtin ******************************************************************* + + Serializes a constant_classref reference. + + Binary format: + - s4 - key from builtintable_get_key() + +*******************************************************************************/ +void store_builtin(int fd, builtintable_entry *bte) +{ + s4 key; + + key = builtintable_get_key(bte); + + system_write(fd, (const void *) &key, sizeof(key)); +} + +/* store_string **************************************************************** + + Serializes a java_object_t reference which denotes a string. + + Binary format: + - utf - utf bytes of the string instance + +*******************************************************************************/ +void store_string(int fd, java_object_t *h) +{ + utf *string; + + string = javastring_toutf((java_handle_t *) h, false); + + store_utf(fd, string); +} + + +/* d_dummy ********************************************************************* + + Patcher deserialization function which does nothing and can therefore be used + as a placeholder for not yet written deserializers. + +*******************************************************************************/ +void d_dummy(patchref_t *pr, int fd, methodinfo *m) +{ + /* Intentionally do nothing. */ +} + +/* + * Loads UTF8 classname and creates an unresolved_class for it + * using the class to which the patchref_t belongs as the referer. + */ +void d_unresolved_class(patchref_t *pr, int fd, methodinfo *m) +{ + utf *classname; + constant_classref *classref; + unresolved_class *uc; + + classref = NEW(constant_classref); + + load_utf(&classname, fd); + + CLASSREF_INIT(*classref, m->clazz, classname); + + uc = create_unresolved_class(m, classref, NULL); + + pr->ref = (void*) uc; + +/* FREE(classref, constant_classref);*/ + +/* os::free(classname); */ +} + +void d_unresolved_field(patchref_t *pr, int fd, methodinfo *m) +{ + int i; + + unresolved_field *ref = NEW(unresolved_field); + + system_read(fd, (void *) &ref->flags, sizeof(ref->flags)); + + system_read(fd, (void *) &i, sizeof(i)); + ref->fieldref = (constant_FMIref *) m->clazz->cpinfos[i]; + + ref->referermethod = m; + + UNRESOLVED_SUBTYPE_SET_EMTPY(ref->valueconstraints); + + pr->ref = (void*) ref; +} + +void d_unresolved_method(patchref_t *pr, int fd, methodinfo *m) +{ + int i; + + unresolved_method *ref = NEW(unresolved_method); + + system_read(fd, (void *) &ref->flags, sizeof(ref->flags)); + + system_read(fd, (void *) &i, sizeof(i)); + ref->methodref = (constant_FMIref *) m->clazz->cpinfos[i]; + + ref->referermethod = m; + ref->paramconstraints = NULL; + UNRESOLVED_SUBTYPE_SET_EMTPY(ref->instancetypes); + + pr->ref = (void*) ref; +} + +void d_classinfo(patchref_t *pr, int fd, methodinfo *m) +{ + classinfo *ci; + + load_classinfo(&ci, fd, m); + + pr->ref = (void*) ci; +} + +void d_methodinfo(patchref_t *pr, int fd, methodinfo *m) +{ + methodinfo *lm; + + load_methodinfo(&lm, fd, m); + + pr->ref = (void*) lm; +} + +void load_methodinfo(methodinfo **lm, int fd, methodinfo *m) +{ + utf *m_name; + utf *m_desc; + utf *classname; + classinfo *clazz; + constant_classref ref; + + load_utf(&m_name, fd); + load_utf(&m_desc, fd); + load_utf(&classname, fd); + + CLASSREF_INIT(ref, m->clazz, classname); + + clazz = resolve_classref_eager(&ref); + + *lm = class_findmethod(clazz, m_name, m_desc); +} + +void d_fieldinfo(patchref_t *pr, int fd, methodinfo *m) +{ + fieldinfo *fi; + + load_fieldinfo(&fi, fd, m); + + pr->ref = (void*) fi; +} + +void load_fieldinfo(fieldinfo **fi, int fd, methodinfo *m) +{ + utf *f_name; + utf *f_desc; + utf *classname; + classinfo *clazz; + constant_classref ref; + + load_utf(&f_name, fd); + load_utf(&f_desc, fd); + load_utf(&classname, fd); + + CLASSREF_INIT(ref, m->clazz, classname); + + clazz = resolve_classref_eager(&ref); +/* + if (!(clazz->state & CLASS_INITIALIZED)) + if (!initialize_class(clazz)) +*/ + *fi = class_findfield(clazz, f_name, f_desc); +} + +/* + * Loads UTF8 classname and initializes a constant_classref for it + * using the class to which the patchref_t belongs as the referer. + */ +void d_constant_classref(patchref_t *pr, int fd, methodinfo *m) +{ + utf *classname; + constant_classref *cr = NEW(constant_classref); + + load_utf(&classname, fd); + + CLASSREF_INIT(*cr, m->clazz, classname); + + pr->ref = (void*) cr; + +/* os::free(classname);*/ +} + +void load_builtin(builtintable_entry **bte, int fd) +{ + s4 key; + + system_read(fd, (void *) &key, sizeof(key)); + + *bte = builtintable_get_by_key(key); +} + +void load_string(java_object_t **h, int fd) +{ + utf *string; + + load_utf(&string, fd); + +/* *h = javastring_new(string);*/ + *h = literalstring_new(string); +} + +/* store_classinfo ************************************************************* + + Serializes a classinfo reference. + + Binary format: + - utf string - classinfo's classname + +*******************************************************************************/ +void store_classinfo(int fd, classinfo *ci) +{ + /* Store the class name ... */ + store_utf(fd, ci->name); +} + +/* load_classinfo ************************************************************* + + Deserializes a classinfo reference. + + Binary format: see store_classinfo + +*******************************************************************************/ +void load_classinfo(classinfo **ci, int fd, methodinfo *m) +{ + utf *classname; + constant_classref *classref; + + classref = NEW(constant_classref); + + load_utf(&classname, fd); + + CLASSREF_INIT(*classref, m->clazz, classname); + + *ci = resolve_classref_eager(classref); +} + +#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/jitcache.hpp index 8bb1c58c7,000000000..250b046fc mode 100644,000000..100644 --- a/src/vm/jit/jitcache.hpp +++ b/src/vm/jit/jitcache.hpp @@@ -1,183 -1,0 +1,182 @@@ +/* src/vm/jit/jitcache.h - jit compiler output caching + + Copyright (C) 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 _JITCACHE_H +#define _JITCACHE_H + ++#include "vm/jit/patcher-common.hpp" ++ +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(ENABLE_JITCACHE) + +#include "config.h" + +#include + - #include "vm/jit/patcher-common.h" - +#include "vm/class.h" +#include "vm/method.h" + +typedef enum cachedreftype { + CRT_CODEINFO, + CRT_NUM, + CRT_ENTRYPOINT, + CRT_CODEGEN_FINISH_NATIVE_CALL, + CRT_ASM_HANDLE_EXCEPTION, /* 4 */ + CRT_ASM_HANDLE_NAT_EXCEPTION, + CRT_OBJECT_HEADER, + CRT_BUILTIN, /* 7 */ + CRT_BUILTIN_FP, + CRT_STRING, + CRT_CLASSINFO, /* 10 */ + CRT_CLASSINFO_INDEX, + CRT_CLASSINFO_INTERFACETABLE, + CRT_CLASSINFO_VFTBL, + CRT_METHODINFO_STUBROUTINE, /* 14 */ + CRT_METHODINFO_TABLE, + CRT_METHODINFO_INTERFACETABLE, + CRT_METHODINFO_METHODOFFSET, + CRT_FIELDINFO_VALUE, /* 18 */ + CRT_FIELDINFO_OFFSET, + CRT_FIELDINFO_OFFSET_HIGH, + CRT_JUMPREFERENCE /* 21 */ +} cachedreftype; + +/* cachedref_t ***************************************************************** + + A cached reference contains information about a code or data position + which needs patching after restoring the it from disk. + +*******************************************************************************/ + - typedef struct cachedref_t { ++struct cachedref_t { + cachedreftype type; /* type of the cached reference */ + s4 md_patch; /* machine dependent back patching */ + s4 disp; /* displacement of ref in the data segment */ + void* ref; /* reference passed */ - listnode_t linkage; - } cachedref_t; ++}; + +/* +typedef struct mru_entry_t { + classinfo *clazz; + mutex_t lock; +} +*/ + +/* typedefs *******************************************************************/ + +typedef void (*serializerfptr) (int, patchref_t *, methodinfo *); +typedef void (*deserializerfptr) (patchref_t *, int, methodinfo *); + +/* jitcache_patcher_function_list_t typedef ***********************************/ + - typedef struct jitcache_patcher_function_list_t { ++struct jitcache_patcher_function_list_t { + functionptr patcher; + serializerfptr serializer; + deserializerfptr deserializer; - } jitcache_patcher_function_list_t; ++}; + +/* function prototypes ********************************************************/ + +void jitcache_list_create(codeinfo *code); + +void jitcache_list_reset(codeinfo *code); + +void jitcache_list_free(codeinfo *code); + +void jitcache_add_cached_ref_jd(jitdata *jd, cachedreftype type, void* ref); + +void jitcache_add_cached_ref_md_jd(jitdata *jd, cachedreftype type, s4 md_patch, void* ref); + +void jitcache_add_cached_ref(codeinfo *code, cachedreftype type, void* ref, s4 disp); + +void jitcache_store(methodinfo *m); + +u1 jitcache_load(methodinfo *m); + +void jitcache_handle_cached_ref(cachedref_t *cr, codeinfo *code); + +void jitcache_quit(); + +void jitcache_freeclass(classinfo *); + +#define JITCACHE_ADD_CACHED_REF_JD(jd, type, ref) \ + (jitcache_add_cached_ref_jd(jd, type, (void*) ref)) + +#define JITCACHE_ADD_CACHED_REF_JD_COND(jd, type, ref, COND) \ + if (COND) \ + (jitcache_add_cached_ref_jd(jd, type, (void*) ref)) + +#define JITCACHE_ADD_CACHED_REF_MD_JD(jd, type, md_patch, ref) \ + (jitcache_add_cached_ref_md_jd(jd, type, md_patch, (void*) ref)) + +#define JITCACHE_ADD_CACHED_REF(code, type, ref, disp) \ + (jitcache_add_cached_ref(code, type, (void*) ref, disp)) + +#define JITCACHE_ADD_CACHED_REF_COND(code, type, ref, disp, COND) \ + if (COND) \ + jitcache_add_cached_ref(code, type, (void*) ref, disp) + +#else + +#define JITCACHE_ADD_CACHED_REF_JD(jd, type, ref) \ + while (0) { } + +#define JITCACHE_ADD_CACHED_REF_JD_COND(jd, type, ref, COND) \ + while (0) { } + +#define JITCACHE_ADD_CACHED_REF_MD_JD(jd, type, md_patch, ref) \ + while (0) { } + +#define JITCACHE_ADD_CACHED_REF(code, type, ref, disp) \ + while (0) { } + +#define JITCACHE_ADD_CACHED_REF_COND(code, type, ref, disp, COND) \ + while (0) { } + +#endif /* ENABLE_JITCACHE */ + +#ifdef __cplusplus +} +#endif + + +#endif /* _JITCACHE_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/linenumbertable.hpp index 000000000,620cc1a31..0d6143e17 mode 000000,100644..100644 --- a/src/vm/jit/linenumbertable.hpp +++ b/src/vm/jit/linenumbertable.hpp @@@ -1,0 -1,145 +1,147 @@@ + /* src/vm/jit/linenumbertable.hpp - linenumber table + + Copyright (C) 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 _LINENUMBERTABLE_HPP + #define _LINENUMBERTABLE_HPP + + #include "config.h" + + #include + + #ifdef __cplusplus + #include + #include + #endif + + #include "toolbox/list.hpp" + + #include "vm/method.h" + + #include "vm/jit/jit.hpp" + #include "vm/jit/code.hpp" + + #include "vm/jit/ir/instruction.hpp" + + + #ifdef __cplusplus + + /** + * Represents a Java line number. + */ + class Linenumber { + private: + // TODO Add constants. + /* -1......start of inlined body */ + /* -2......end of inlined body */ + /* <= -3...special entry with methodinfo * */ + /* (see doc/inlining_stacktrace.txt) */ + + int32_t _linenumber; + void* _pc; + + public: + Linenumber(int32_t linenumber, void* pc) : _linenumber(linenumber), _pc(pc) {} + + inline int32_t get_linenumber() const { return _linenumber; } + inline void* get_pc () const { return _pc; } + + void resolve(const codeinfo* code); + }; + + + /** + * Unary function to resolve Linenumber objects. + */ + class LinenumberResolver : public std::binary_function { + public: + // Unary resolve function. + void operator() (Linenumber& ln, const codeinfo* code) const + { + ln.resolve(code); + } + }; + + + /** + * Linenumber table of a Java method. + */ + class LinenumberTable { -private: ++public: + std::vector _linenumbers; ++private: + + // Comparator class. + class comparator : public std::binary_function { + public: + bool operator() (const Linenumber& ln, const void* pc) const + { + return (pc >= ln.get_pc()); + } + }; + + public: + LinenumberTable(jitdata* jd); ++ LinenumberTable() { } + ~LinenumberTable(); + + int32_t find(methodinfo **pm, void* pc); + }; + + #else + + typedef struct LinenumberTable LinenumberTable; + + #endif + + #include "vm/jit/codegen-common.hpp" + + #ifdef __cplusplus + extern "C" { + #endif + + void linenumbertable_list_entry_add(codegendata *cd, int32_t linenumber); + void linenumbertable_list_entry_add_inline_start(codegendata *cd, instruction *iptr); + void linenumbertable_list_entry_add_inline_end(codegendata *cd, instruction *iptr); + + #ifdef __cplusplus + } // extern "C" + #endif + + #endif // _LINENUMBERTABLE_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/patcher-common.cpp index 000000000,134ea9057..0a903eca9 mode 000000,100644..100644 --- a/src/vm/jit/patcher-common.cpp +++ b/src/vm/jit/patcher-common.cpp @@@ -1,0 -1,521 +1,556 @@@ + /* src/vm/jit/patcher-common.cpp - architecture independent code patching stuff + + Copyright (C) 2007, 2008 + CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO + Copyright (C) 2008 Theobroma Systems Ltd. + + 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 "codegen.h" /* for PATCHER_NOPS */ + #include "md.h" + + #include "mm/memory.h" + + #include "native/native.hpp" + + #include "toolbox/list.hpp" + #include "toolbox/logging.h" /* XXX remove me! */ + + #include "vm/exceptions.hpp" + #include "vm/initialize.h" + #include "vm/options.h" + #include "vm/resolve.h" + #include "vm/vm.hpp" /* for vm_abort */ + + #include "vm/jit/code.hpp" + #include "vm/jit/disass.h" + #include "vm/jit/jit.hpp" + #include "vm/jit/patcher-common.hpp" + + + /* patcher_function_list ******************************************************* + + This is a list which maps patcher function pointers to the according + names of the patcher functions. It is only usefull for debugging + purposes. + + *******************************************************************************/ + + #if !defined(NDEBUG) + typedef struct patcher_function_list_t { + functionptr patcher; + const char* name; + } patcher_function_list_t; + + static patcher_function_list_t patcher_function_list[] = { + { PATCHER_initialize_class, "initialize_class" }, + { PATCHER_resolve_class, "resolve_class" }, + { PATCHER_resolve_native_function, "resolve_native_function" }, + { PATCHER_invokestatic_special, "invokestatic_special" }, + { PATCHER_invokevirtual, "invokevirtual" }, + { PATCHER_invokeinterface, "invokeinterface" }, + { NULL, "-UNKNOWN PATCHER FUNCTION-" } + }; + #endif + + + /* patcher_list_create ********************************************************* + + Creates an empty patcher list for the given codeinfo. + + *******************************************************************************/ + + void patcher_list_create(codeinfo *code) + { + code->patchers = new List(); + } + + + /* patcher_list_reset ********************************************************** + + Resets the patcher list inside a codeinfo. This is usefull when + resetting a codeinfo for recompiling. + + *******************************************************************************/ + + void patcher_list_reset(codeinfo *code) + { + #if defined(ENABLE_STATISTICS) + if (opt_stat) + size_patchref -= sizeof(patchref_t) * code->patchers->size(); + #endif + + // Free all elements of the list. + code->patchers->clear(); + } + + /* patcher_list_free *********************************************************** + + Frees the patcher list and all its entries for the given codeinfo. + + *******************************************************************************/ + + void patcher_list_free(codeinfo *code) + { + // Free all elements of the list. + patcher_list_reset(code); + + // Free the list itself. + delete code->patchers; + } + + + /** + * Find an entry inside the patcher list for the given codeinfo by + * specifying the program counter of the patcher position. + * + * NOTE: Caller should hold the patcher list lock or maintain + * exclusive access otherwise. + * + * @param pc Program counter to find. + * + * @return Pointer to patcher. + */ + + struct foo : public std::binary_function { + bool operator() (const patchref_t& pr, const void* pc) const + { + return (pr.mpc == (uintptr_t) pc); + } + }; + + static patchref_t* patcher_list_find(codeinfo* code, void* pc) + { + // Search for a patcher with the given PC. + List::iterator it = std::find_if(code->patchers->begin(), code->patchers->end(), std::bind2nd(foo(), pc)); + + if (it == code->patchers->end()) + return NULL; + + return &(*it); + } + + + /* patcher_add_patch_ref ******************************************************* + + Appends a new patcher reference to the list of patching positions. + + *******************************************************************************/ + + void patcher_add_patch_ref(jitdata *jd, functionptr patcher, void* ref, s4 disp) + { + codegendata *cd; + codeinfo *code; + s4 patchmpc; + + cd = jd->cd; + code = jd->code; + patchmpc = cd->mcodeptr - cd->mcodebase; + + #if !defined(NDEBUG) + if (patcher_list_find(code, (void*) (intptr_t) patchmpc) != NULL) + vm_abort("patcher_add_patch_ref: different patchers at same position."); + #endif + + // Set patcher information (mpc is resolved later). + patchref_t pr; + + pr.mpc = patchmpc; + pr.datap = 0; + pr.disp = disp; + pr.patcher = patcher; + pr.ref = ref; + pr.mcode = 0; + pr.done = false; + ++#if defined(ENABLE_JITCACHE) ++ pr.attached_ref = NULL; ++#endif ++ + // Store patcher in the list (NOTE: structure is copied). + code->patchers->push_back(pr); + + #if defined(ENABLE_STATISTICS) + if (opt_stat) + size_patchref += sizeof(patchref_t); + #endif + + #if defined(ENABLE_JIT) && (defined(__I386__) || defined(__M68K__) || defined(__SPARC_64__) || defined(__X86_64__)) + + /* XXX We can remove that when we don't use UD2 anymore on i386 + and x86_64. */ + + /* On some architectures the patcher stub call instruction might + be longer than the actual instruction generated. On this + architectures we store the last patcher call position and after + the basic block code generation is completed, we check the + range and maybe generate some nop's. */ + /* The nops are generated in codegen_emit in each codegen */ + + cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE; + #endif + } + + + /** + * Resolve all patchers in the current JIT run. + * + * @param jd JIT data-structure + */ + void patcher_resolve(jitdata* jd) + { + // Get required compiler data. + codeinfo* code = jd->code; + + for (List::iterator it = code->patchers->begin(); it != code->patchers->end(); it++) { + patchref_t& pr = *it; + + pr.mpc += (intptr_t) code->entrypoint; + pr.datap = (intptr_t) (pr.disp + code->entrypoint); + } + } + + + /** + * Check if the patcher is already patched. This is done by comparing + * the machine instruction. + * + * @param pr Patcher structure. + * + * @return true if patched, false otherwise. + */ + bool patcher_is_patched(patchref_t* pr) + { + // Validate the instruction at the patching position is the same + // instruction as the patcher structure contains. + uint32_t mcode = *((uint32_t*) pr->mpc); + + if (mcode != pr->mcode) { + // The code differs. + return false; + } + + return true; + } + + + /** + * + */ + bool patcher_is_patched_at(void* pc) + { + codeinfo* code = code_find_codeinfo_for_pc(pc); + + // Get the patcher for the given PC. + patchref_t* pr = patcher_list_find(code, pc); + + if (pr == NULL) { + // The given PC is not a patcher position. + return false; + } + + // Validate the instruction. + return patcher_is_patched(pr); + } + + + /* patcher_handler ************************************************************* + + Handles the request to patch JIT code at the given patching + position. This function is normally called by the signal + handler. + + NOTE: The patcher list lock is used to maintain exclusive + access of the patched position (in fact of the whole code). + After patching has suceeded, the patcher reference should be + removed from the patcher list to avoid double patching. + + *******************************************************************************/ + + #if !defined(NDEBUG) + /* XXX this indent is not thread safe! */ + /* XXX if you want it thread safe, place patcher_depth in threadobject! */ + static int patcher_depth = 0; + #define TRACE_PATCHER_INDENT for (i=0; ipatchers->lock(); + + /* search the patcher information for the given PC */ + + pr = patcher_list_find(code, pc); + + if (pr == NULL) + vm_abort("patcher_handler: Unable to find patcher reference."); + + if (pr->done) { + #if !defined(NDEBUG) + if (opt_DebugPatcher) { + log_println("patcher_handler: double-patching detected!"); + } + #endif + code->patchers->unlock(); + return NULL; + } + + #if !defined(NDEBUG) + if (opt_DebugPatcher) { + for (l = patcher_function_list; l->patcher != NULL; l++) + if (l->patcher == pr->patcher) + break; + + TRACE_PATCHER_INDENT; printf("patching in "); method_print(code->m); printf(" at %p\n", (void *) pr->mpc); + TRACE_PATCHER_INDENT; printf("\tpatcher function = %s <%p>\n", l->name, (void *) (intptr_t) pr->patcher); + + TRACE_PATCHER_INDENT; + printf("\tmachine code before = "); + + # if defined(ENABLE_DISASSEMBLER) + disassinstr((u1*) (void*) pr->mpc); + # else + printf("%x at %p (disassembler disabled)\n", *((uint32_t*) pr->mpc), (void*) pr->mpc); + # endif + + patcher_depth++; + assert(patcher_depth > 0); + } + #endif + + /* cast the passed function to a patcher function */ + + patcher_function = (bool (*)(patchref_t *)) (ptrint) pr->patcher; + + /* call the proper patcher function */ + + result = (patcher_function)(pr); + + #if !defined(NDEBUG) + if (opt_DebugPatcher) { + assert(patcher_depth > 0); + patcher_depth--; + + TRACE_PATCHER_INDENT; + printf("\tmachine code after = "); + + # if defined(ENABLE_DISASSEMBLER) + disassinstr((u1*) (void*) pr->mpc); + # else + printf("%x at %p (disassembler disabled)\n", *((uint32_t*) pr->mpc), (void*) pr->mpc); + # endif + + if (result == false) { + TRACE_PATCHER_INDENT; printf("\tPATCHER EXCEPTION!\n"); + } + } + #endif + ++#if defined(ENABLE_JITCACHE) ++ /* Put cached reference into the code and remove it from the patcher */ ++ if (pr->attached_ref) ++ { ++ jitcache_handle_cached_ref(pr->attached_ref, code); ++ pr->attached_ref = NULL; ++ } ++#endif ++ + /* check for return value and exit accordingly */ + + if (result == false) { + e = exceptions_get_and_clear_exception(); + + code->patchers->unlock(); + + return e; + } + + pr->done = true; /* XXX this is only preliminary to prevent double-patching */ + + code->patchers->unlock(); + + return NULL; + } + + + /* patcher_initialize_class **************************************************** + + Initalizes a given classinfo pointer. + This function does not patch any data. + + *******************************************************************************/ + + bool patcher_initialize_class(patchref_t *pr) + { + classinfo *c; + + /* get stuff from the patcher reference */ + + c = (classinfo *) pr->ref; + + /* check if the class is initialized */ + + if (!(c->state & CLASS_INITIALIZED)) + if (!initialize_class(c)) + return false; + + /* patch back original code */ + + patcher_patch_code(pr); + + return true; + } + + + /* patcher_resolve_class ******************************************************* + + Resolves a given unresolved class reference. + This function does not patch any data. + + *******************************************************************************/ + + #ifdef ENABLE_VERIFIER + bool patcher_resolve_class(patchref_t *pr) + { + unresolved_class *uc; + + /* get stuff from the patcher reference */ + + uc = (unresolved_class *) pr->ref; + + /* resolve the class and check subtype constraints */ + + if (!resolve_class_eager_no_access_check(uc)) + return false; + + /* patch back original code */ + + patcher_patch_code(pr); + + return true; + } + #endif /* ENABLE_VERIFIER */ + + + /* patcher_resolve_native_function ********************************************* + + Resolves the native function for a given methodinfo. + This function patches one data segment word. + + *******************************************************************************/ + + bool patcher_resolve_native_function(patchref_t *pr) + { + methodinfo *m; + uint8_t *datap; + + /* get stuff from the patcher reference */ + + m = (methodinfo *) pr->ref; + datap = (uint8_t *) pr->datap; + + /* resolve native function */ + + NativeMethods& nm = VM::get_current()->get_nativemethods(); + void* f = nm.resolve_method(m); + + if (f == NULL) + return false; + + /* patch native function pointer */ + + *((intptr_t*) datap) = (intptr_t) f; + + /* synchronize data cache */ + + md_dcacheflush(datap, SIZEOF_VOID_P); + + /* patch back original code */ + + patcher_patch_code(pr); + + return true; + } + ++/** Placeholder functions to calm down linker */ ++#if defined(__I386__) ++bool patcher_resolve_classref_to_classinfo(patchref_t *pr) ++{ ++ return true; ++} ++ ++bool patcher_resolve_classref_to_vftbl(patchref_t *pr) ++{ ++ return true; ++} ++ ++bool patcher_resolve_classref_to_index(patchref_t *pr) ++{ ++ return true; ++} ++ ++bool patcher_resolve_classref_to_flags(patchref_t *pr) ++{ ++ return true; ++} ++#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/patcher-common.hpp index 000000000,72ed1ec0b..7a10d4d22 mode 000000,100644..100644 --- a/src/vm/jit/patcher-common.hpp +++ b/src/vm/jit/patcher-common.hpp @@@ -1,0 -1,211 +1,224 @@@ + /* src/vm/jit/patcher-common.hpp - architecture independent code patching stuff + + Copyright (C) 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 _PATCHER_COMMON_HPP + #define _PATCHER_COMMON_HPP + + /* forward typedefs ***********************************************************/ + ++typedef struct cachedref_t cachedref_t; + typedef struct patchref_t patchref_t; + + #include "config.h" + #include "vm/types.h" + + #include "toolbox/list.hpp" + + #include "vm/global.h" + + #include "vm/jit/jit.hpp" + ++#if defined (ENABLE_JITCACHE) ++struct cached_ref_t; ++#endif + + /* patchref_t ****************************************************************** + + A patcher reference contains information about a code position + which needs additional code patching during runtime. + + *******************************************************************************/ + + struct patchref_t { + ptrint mpc; /* absolute position in code segment */ + ptrint datap; /* absolute position in data segment */ + s4 disp; /* displacement of ref in the data segment */ + functionptr patcher; /* patcher function to call */ + void* ref; /* reference passed */ + uint32_t mcode; /* machine code to be patched back in */ + bool done; /* XXX preliminary: patch already applied? */ ++#if defined (ENABLE_JITCACHE) ++ cachedref_t *attached_ref; ++ /* cached reference which must be resolved * ++ * patcher has been run. */ ++#endif + }; + + + /* macros *********************************************************************/ + + + /* function prototypes ********************************************************/ + + #ifdef __cplusplus + extern "C" { + #endif + + void patcher_list_create(codeinfo *code); + void patcher_list_reset(codeinfo *code); + void patcher_list_free(codeinfo *code); + + void patcher_add_patch_ref(jitdata *jd, functionptr patcher, void* ref, s4 disp); + + void patcher_resolve(jitdata* jd); + + bool patcher_is_patched(patchref_t* pr); + bool patcher_is_patched_at(void* pc); + + // MD function. + bool patcher_is_valid_trap_instruction_at(void* pc); + + java_handle_t *patcher_handler(u1 *pc); + + + /* empty patcher (just patches back original mcode) ***************************/ + + void patcher_patch_code(patchref_t *pr); + + + /* patcher prototypes and macros **********************************************/ + + /* new patcher functions */ + + bool patcher_resolve_class(patchref_t *pr); + #define PATCHER_resolve_class (functionptr) patcher_resolve_class + + bool patcher_initialize_class(patchref_t *pr); + #define PATCHER_initialize_class (functionptr) patcher_initialize_class + + bool patcher_resolve_classref_to_classinfo(patchref_t *pr); + #define PATCHER_resolve_classref_to_classinfo (functionptr) patcher_resolve_classref_to_classinfo + + bool patcher_resolve_classref_to_vftbl(patchref_t *pr); + #define PATCHER_resolve_classref_to_vftbl (functionptr) patcher_resolve_classref_to_vftbl + + bool patcher_resolve_classref_to_index(patchref_t *pr); + #define PATCHER_resolve_classref_to_index (functionptr) patcher_resolve_classref_to_index + + bool patcher_resolve_classref_to_flags(patchref_t *pr); + #define PATCHER_resolve_classref_to_flags (functionptr) patcher_resolve_classref_to_flags + + bool patcher_resolve_native_function(patchref_t *pr); + #define PATCHER_resolve_native_function (functionptr) patcher_resolve_native_function + + /* old patcher functions */ + + bool patcher_get_putstatic(patchref_t *pr); + #define PATCHER_get_putstatic (functionptr) patcher_get_putstatic + + #if defined(__I386__) + + bool patcher_getfield(patchref_t *pr); + #define PATCHER_getfield (functionptr) patcher_getfield + + bool patcher_putfield(patchref_t *pr); + #define PATCHER_putfield (functionptr) patcher_putfield + + #else + + bool patcher_get_putfield(patchref_t *pr); + #define PATCHER_get_putfield (functionptr) patcher_get_putfield + + #endif /* defined(__I386__) */ + + #if defined(__I386__) || defined(__X86_64__) + + bool patcher_putfieldconst(patchref_t *pr); + #define PATCHER_putfieldconst (functionptr) patcher_putfieldconst + + #endif /* defined(__I386__) || defined(__X86_64__) */ + + bool patcher_invokestatic_special(patchref_t *pr); + #define PATCHER_invokestatic_special (functionptr) patcher_invokestatic_special + + bool patcher_invokevirtual(patchref_t *pr); + #define PATCHER_invokevirtual (functionptr) patcher_invokevirtual + + bool patcher_invokeinterface(patchref_t *pr); + #define PATCHER_invokeinterface (functionptr) patcher_invokeinterface + + #if defined(__ALPHA__) || defined(__I386__) || defined(__MIPS__) || defined(__POWERPC__) || defined(__POWERPC64__) || defined(__S390__) || defined(__X86_64__) || defined(__M68K__) + + bool patcher_checkcast_interface(patchref_t *pr); + #define PATCHER_checkcast_interface (functionptr) patcher_checkcast_interface + + bool patcher_instanceof_interface(patchref_t *pr); + #define PATCHER_instanceof_interface (functionptr) patcher_instanceof_interface + + #endif /* defined(__ALPHA__) || defined(__I386__) || defined(__MIPS__) || defined(__POWERPC__) || defined(__POWERPC64__) || defined(__S390__) || defined(__X86_64__) || defined(__M68K__) */ + + #if defined(__S390__) + + bool patcher_checkcast_instanceof_interface(patchref_t *pr); + #define PATCHER_checkcast_instanceof_interface (functionptr) patcher_checkcast_instanceof_interface + + #endif /* defined(__S390__) */ + + #if defined(__I386__) + + bool patcher_aconst(patchref_t *pr); + #define PATCHER_aconst (functionptr) patcher_aconst + + bool patcher_builtin_multianewarray(patchref_t *pr); + #define PATCHER_builtin_multianewarray (functionptr) patcher_builtin_multianewarray + + bool patcher_builtin_arraycheckcast(patchref_t *pr); + #define PATCHER_builtin_arraycheckcast (functionptr) patcher_builtin_arraycheckcast + + bool patcher_checkcast_instanceof_flags(patchref_t *pr); + #define PATCHER_checkcast_instanceof_flags (functionptr) patcher_checkcast_instanceof_flags + + bool patcher_checkcast_class(patchref_t *pr); + #define PATCHER_checkcast_class (functionptr) patcher_checkcast_class + + bool patcher_instanceof_class(patchref_t *pr); + #define PATCHER_instanceof_class (functionptr) patcher_instanceof_class + + #endif /* defined(__I386__) */ + ++#if defined (__ARM__) ++void patch_md(s4 md_patch, ptrint dest, void* ref); ++#endif /* defined(__ARM__) */ ++ + #ifdef __cplusplus + } // extern "C" + #endif + + #endif // _PATCHER_COMMON_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/statistics.c index 37d194607,878e8b822..46aa681f7 --- a/src/vm/statistics.c +++ b/src/vm/statistics.c @@@ -46,8 -46,8 +46,10 @@@ #include "toolbox/logging.h" ++#include "threads/thread.hpp" ++ #include "vm/class.h" - #include "vm/field.h" + #include "vm/field.hpp" #include "vm/global.h" #include "vm/method.h" #include "vm/options.h" @@@ -304,12 -302,12 +306,25 @@@ s8 getcputime(void *******************************************************************************/ ++Mutex *loadingtime_lock = Mutex_new(); ++ void loadingtime_start(void) { ++ Mutex_lock(loadingtime_lock); ++ loadingtime_recursion++; if (loadingtime_recursion == 1) loadingstarttime = getcputime(); ++ else { ++ int end = getcputime(); ++ loadingtime += (end - loadingstarttime); ++ ++ loadingstarttime = loadingstoptime = end; ++ } ++ ++ ++ Mutex_unlock(loadingtime_lock); } @@@ -321,12 -319,12 +336,18 @@@ void loadingtime_stop(void) { -- if (loadingtime_recursion == 1) { -- loadingstoptime = getcputime(); -- loadingtime += (loadingstoptime - loadingstarttime); ++ Mutex_lock(loadingtime_lock); ++ ++ loadingstoptime = getcputime(); ++ loadingtime += (loadingstoptime - loadingstarttime); ++ ++ if (loadingtime_recursion > 1) { ++ loadingstarttime = loadingstoptime; } loadingtime_recursion--; ++ ++ Mutex_unlock(loadingtime_lock); } diff --cc src/vm/vm.cpp index dc956a961,4721b8549..b713e8209 --- a/src/vm/vm.cpp +++ b/src/vm/vm.cpp @@@ -89,8 -88,7 +88,7 @@@ # include "vm/jit/disass.h" #endif - #include "vm/jit/jit.h" -#include "vm/jit/jit.hpp" +#include "vm/jit/jitcache.hpp" #include "vm/jit/methodtree.h" #if defined(ENABLE_PROFILING)