#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"
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;
}
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
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 \
#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)
--- /dev/null
+ /* 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 <assert.h>
+ #include <errno.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <sys/time.h>
+
+ #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 <vmlog_cacao.h>
+ #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 <vmlog_cacao.c>
+ #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:
+ */
--- /dev/null
- * must be an entry in the builtin_desc table in jit/jit.c.
+ /* 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 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:
+ */
--- /dev/null
-#if defined(ENABLE_STATISTICS)
+ /* 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 <assert.h>
+ #include <stdint.h>
+
+ #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_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:
+ */
--- /dev/null
+ /* 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 <assert.h>
+ #include <stdint.h>
+
+ #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<patchref_t>* patchers;
+ #else
+ List* patchers;
+ #endif
+
++#if defined (ENABLE_JITCACHE)
++#ifdef __cplusplus
++ List<cachedref_t>* 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:
+ */
--- /dev/null
+ /* 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 <assert.h>
+ #include <string.h>
+
++#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 <vmlog_cacao.h>
+ #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<branch_label_ref_t*>();
+ cd->linenumbers = new DumpList<Linenumber>();
+ }
+
+
+ /* 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<branch_label_ref_t*>();
+ cd->linenumbers = new DumpList<Linenumber>();
+
+ /* 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; i<code->rplpointcount; ++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:
+ */
#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"
--- /dev/null
+ /* 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 <assert.h>
+ #include <stdint.h>
+
+ #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 <clinit>'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:
+ */
--- /dev/null
- /* for mkdir() */
+/* 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)
+
- #include "toolbox/list.h"
++#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 <sys/stat.h>
+
+#include <assert.h>
+#include <stdint.h>
+
+#include "md.h"
+
- #include "vm/builtin.h"
+#include "toolbox/logging.h"
+
+#include "mm/memory.h"
+#include "mm/codememory.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/method.h"
+#include "vm/options.h"
+#include "vm/resolve.h"
+#include "vm/types.h"
+
+#include "vm/jit/asmpart.h"
- #include "vm/field.h"
+#include "vm/jit/exceptiontable.h"
+#include "vm/jit/methodtree.h"
+
+#include "vm/references.h"
- #include "vm/string.hpp"
- #include "vm/os.hpp"
- #include "vm/jit/jitcache.hpp"
- #include "threads/thread.hpp"
+#include "vm/utf8.h"
+
+}
+
- code->cachedrefs = list_create(OFFSET(cachedref_t, linkage));
+
+/* 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)
+{
- 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 = new List<cachedref_t>();
+}
+
+
+/* jitcache_list_reset **********************************************************
+
+ Resets the cached reference list inside a codeinfo.
+
+*******************************************************************************/
+
+void jitcache_list_reset(codeinfo *code)
+{
- FREE(code->cachedrefs, list_t);
++ 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 */
+
- cachedref_t *cr;
-
++ 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)
+{
- cr = (cachedref_t *) list_first(code->cachedrefs);
- while (cr) {
-
- if (cr->disp == disp)
- return cr;
+ /* walk through all cached references for the given codeinfo */
+
- cr = (cachedref_t *) list_next(code->cachedrefs, cr);
++ for (List<cachedref_t>::iterator it = code->cachedrefs->begin();
++ it != code->cachedrefs->end(); it++)
++ {
+
- cachedref_t *jitcache_new_cached_ref(cachedreftype type, s4 md_patch, void* ref, s4 disp)
++ if (it->disp == disp)
++ return &(*it);
+ }
+
+ return NULL;
+}
+
+
+/* jitcache_new_cachedref ******************************************************
+
+ Creates and initializes a new cachedref
+
+*******************************************************************************/
+
- 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 jitcache_new_cached_ref(cachedreftype type, s4 md_patch, void* ref, s4 disp)
+{
- cr->type = type;
- cr->md_patch= md_patch;
- cr->disp = disp;
- cr->ref = ref;
++ cachedref_t cr;
+
+ /* set reference information */
+
- /* jitcache_add_cachedref_jd ***************************************************
++ cr.type = type;
++ cr.md_patch= md_patch;
++ cr.disp = disp;
++ cr.ref = ref;
+
+ return cr;
+}
- 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.
++/* jitcache_add_cachedref_intern ***********************************************
+
- void jitcache_add_cached_ref_intern(codeinfo *code, cachedref_t *cachedref)
++ Creates a new cached ref appends it to the list in the codeinfo structure.
+
+*******************************************************************************/
+
- cachedref_t *list_cr;
-
- list_cr = (cachedref_t *) list_first(code->cachedrefs);
++void jitcache_add_cached_ref_intern(codeinfo *code, cachedref_t cachedref)
+{
- while (list_cr)
++ List<cachedref_t>::iterator it = code->cachedrefs->begin();
+
- if (list_cr->disp == cachedref->disp)
++ while (it != code->cachedrefs->end())
+ {
- assert(list_cr->type == cachedref->type);
- assert(list_cr->ref == cachedref->ref);
++ if (it->disp == cachedref.disp)
+ {
- list_cr = (cachedref_t *) list_next(code->cachedrefs, list_cr);
++ assert(it->type == cachedref.type);
++ assert(it->ref == cachedref.ref);
+
+ /* Cachedref for already existing object found. No need to store
+ * it.
+ */
+ return;
+ }
+
- list_add_first(code->cachedrefs, cachedref);
++ it++;
+ }
+
- patchref_t *patchref;
++ 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)
+{
- cachedref_t *cachedref;
++ patchref_t patchref;
+ codegendata *cd;
+ ptrint disp;
- patchref = (patchref_t *) list_first(jd->code->patchers);
++ 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);
+
- if (patchref
- && (patchref->mpc) <= disp
- && (patchref->mpc + sizeof(patchref->mcode)) >= disp)
++ patchref = jd->code->patchers->front();
+
- */
++ if ((patchref.mpc) <= disp
++ && (patchref.mpc + sizeof(patchref.mcode)) >= disp)
+ {
+ /* patchers and cachedref overlap: cached ref must
+ * be handled after the patcher.
- * If the need arises to handle more cached refs a list can
- * be used.
- */
- assert(!patchref->attached_ref);
++ */
+
+ if (opt_DebugJitCache)
+ {
+ log_message_method("cached ref overlaps with patchref: ", jd->m);
+ }
+
+ /* There can be only one cached ref per patcher currently.
- patchref->attached_ref = cachedref;
++ * If the need arises to handle more cached refs a list can
++ * be used.
++ */
++ assert(!patchref.attached_ref);
+
- cachedref_t *cr;
++ 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)
+{
- return mkdir(path, mode);
++ 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 <stdlib.h>
+#include <stdio.h>
+
+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] = '/';
+ }
+ }
+
- patchref_t *pr;
++ 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;
- list_t *patchers = code->patchers;
+ int j;
+
- system_write(fd, (const void *) &patchers->size, sizeof(patchers->size));
++ int size = code->patchers->size();
+
+ /* serialize patchers list */
- log_println("store_to_file_patchers - patchers size %d", patchers->size);
++ system_write(fd, (const void *) &size, sizeof(size));
+ if (opt_DebugJitCache)
- for (pr = (patchref_t *) list_first(patchers); pr != NULL; pr = (patchref_t *) list_next(patchers, pr))
++ log_println("store_to_file_patchers - patchers size %d", size);
+
- temp_ptr = to_offset(code->mcode, (u1 *) pr->mpc);
++ for (List<patchref_t>::iterator it = code->patchers->begin();
++ it != code->patchers->end(); it++)
+ {
- temp_ptr = to_offset(code->mcode, (u1 *) pr->datap);
++ temp_ptr = to_offset(code->mcode, (u1 *) it->mpc);
+ system_write(fd, (const void *) &temp_ptr, sizeof(temp_ptr));
+
- system_write(fd, (const void *) &pr->disp, sizeof(pr->disp));
++ temp_ptr = to_offset(code->mcode, (u1 *) it->datap);
+ system_write(fd, (const void *) &temp_ptr, sizeof(temp_ptr));
+
- if (patcher_functions[j].patcher == pr->patcher)
++ system_write(fd, (const void *) &it->disp, sizeof(it->disp));
+
+ temp = -1;
+ j = 0;
+ while (patcher_functions[j].patcher)
+ {
- (*patcher_functions[j].serializer)(fd, pr, code->m);
++ if (patcher_functions[j].patcher == it->patcher)
+ {
+ temp = j;
+ system_write(fd, (const void *) &j, sizeof(j));
+
- system_write(fd, (const void *) &pr->attached_ref, sizeof(pr->attached_ref));
++ (*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));
+ }
+
- if (pr->attached_ref)
++ if (it->attached_ref)
++ temp = 1;
++
++ system_write(fd, (const void *) &temp, sizeof(temp));
+
- store_cachedref(fd, pr->attached_ref);
++ if (it->attached_ref)
+ {
- FREE(pr->attached_ref, cachedref_t);
- pr->attached_ref = NULL;
++ store_cachedref(fd, it->attached_ref);
+
+ /* Release the cached reference now because it should not be used
+ * in the current Cacao process.
+ */
- system_write(fd, (const void *) &pr->mcode, sizeof(pr->mcode));
++ FREE(it->attached_ref, cachedref_t);
++ it->attached_ref = NULL;
+ }
+
- cachedref_t *cr;
-
- list_t *cachedrefs = code->cachedrefs;
++ 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)
+{
- log_println("store_to_file_cachedrefs - cachedrefs size %d", cachedrefs->size);
++ int size = code->cachedrefs->size();
+ if (opt_DebugJitCache)
- system_write(fd, (const void *) &cachedrefs->size, sizeof(cachedrefs->size));
++ log_println("store_to_file_cachedrefs - cachedrefs size %d", size);
+
+ /* serialize cachedrefs list */
- for (cr = (cachedref_t *) list_first(cachedrefs);
- cr != NULL;
- cr = (cachedref_t *) list_next(cachedrefs, cr))
- store_cachedref(fd, cr);
++ system_write(fd, (const void *) &size, sizeof(size));
+
- linenumbertable_entry_t *lte;
++ for (List<cachedref_t>::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;
- int i;
- linenumbertable_t *linenumbertable;
-
- linenumbertable = code->linenumbertable;
+ int count = 0;
- count = code->linenumbertable->length;
+
+ if (code->linenumbertable)
- lte = linenumbertable->entries;
- for (i = 0; i < count; i++)
++ 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)
+ {
- system_write(fd, (const void *) <e->linenumber, sizeof(lte->linenumber));
++ for (std::vector<Linenumber>::iterator it = code->linenumbertable->_linenumbers.begin();
++ it != code->linenumbertable->_linenumbers.end(); it++)
+ {
- temp_ptr = to_offset(code->entrypoint, lte->pc);
++ int temp = it->get_linenumber();
++ system_write(fd, (const void *) &temp, sizeof(temp));
+
-
- lte++;
++ temp_ptr = to_offset(code->entrypoint, it->get_pc());
+ system_write(fd, (const void *) &temp_ptr, sizeof(temp_ptr));
- patchref_t *pr = NEW(patchref_t);
+ }
+ }
+
+}
+
+
+/* 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++)
+ {
- pr->mpc = (ptrint) to_abs(code->mcode, temp_ptr);
++ patchref_t pr;
+
+ system_read(fd, (void *) &temp_ptr, sizeof(temp_ptr));
- pr->datap = (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));
- system_read(fd, (void *) &pr->disp, sizeof(pr->disp));
++ pr.datap = (ptrint) to_abs(code->mcode, temp_ptr);
+
- pr->patcher = patcher_functions[temp].patcher;
++ 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;
+ }
- (*patcher_functions[temp].deserializer)(pr, fd, code->m);
++ pr.patcher = patcher_functions[temp].patcher;
+
- system_read(fd, (void *) &pr->attached_ref, sizeof(pr->attached_ref));
++ (*patcher_functions[temp].deserializer)(&pr, fd, code->m);
+
+ /* Load the pointer value to decide whether a cached reference must
+ * be loaded or not. */
- if (pr->attached_ref)
++ system_read(fd, (void *) &temp, sizeof(temp));
+
- pr->attached_ref = NULL;
- load_cachedref(&pr->attached_ref, fd, code);
++ if (temp)
+ {
- system_read(fd, (void *) &pr->mcode, sizeof(pr->mcode));
++ pr.attached_ref = 0;
++ load_cachedref(&pr.attached_ref, fd, code);
+ }
+
- pr->done = false;
++ system_read(fd, (void *) &pr.mcode, sizeof(pr.mcode));
+
- list_add_first(code->patchers, pr);
++ pr.done = false;
+
- linenumbertable_entry_t *lte;
++ 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)
+{
- code->linenumbertable = NEW(linenumbertable_t);
+ void *temp_ptr;
+ int i;
+
- system_read(fd, (void *) &code->linenumbertable->length, sizeof(code->linenumbertable->length));
++ code->linenumbertable = new LinenumberTable();
+
- log_println("load_linenumbertable - linenumbertable size %d", code->linenumbertable->length);
-
- lte = MNEW(linenumbertable_entry_t, code->linenumbertable->length);
- code->linenumbertable->entries = lte;
++ int size;
++ system_read(fd, (void *) &size, sizeof(size));
+
+ if (opt_DebugJitCache)
- for (i = 0;i < code->linenumbertable->length; i++)
++ log_println("load_linenumbertable - linenumbertable size %d", size);
+
- system_read(fd, (void *) <e->linenumber, sizeof(lte->linenumber));
++ for (i = 0;i < size; i++)
+ {
- lte->pc = to_abs(code->entrypoint, temp_ptr);
++ int linenumber;
++ system_read(fd, (void *) &linenumber, sizeof(linenumber));
+
+ system_read(fd, (void *) &temp_ptr, sizeof(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:
+ */
--- /dev/null
- #include "vm/jit/patcher-common.h"
-
+/* 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 <stdint.h>
+
- typedef struct cachedref_t {
+#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.
+
+*******************************************************************************/
+
- listnode_t linkage;
- } 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 */
- typedef struct jitcache_patcher_function_list_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 ***********************************/
+
- } jitcache_patcher_function_list_t;
++struct jitcache_patcher_function_list_t {
+ functionptr patcher;
+ serializerfptr serializer;
+ deserializerfptr deserializer;
++};
+
+/* 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:
+ */
--- /dev/null
-private:
+ /* 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 <stdint.h>
+
+ #ifdef __cplusplus
+ #include <functional>
+ #include <vector>
+ #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<Linenumber, codeinfo*, void> {
+ public:
+ // Unary resolve function.
+ void operator() (Linenumber& ln, const codeinfo* code) const
+ {
+ ln.resolve(code);
+ }
+ };
+
+
+ /**
+ * Linenumber table of a Java method.
+ */
+ class LinenumberTable {
++public:
+ std::vector<Linenumber> _linenumbers;
++private:
+
+ // Comparator class.
+ class comparator : public std::binary_function<Linenumber, void*, bool> {
+ 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:
+ */
--- /dev/null
+ /* 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 <assert.h>
+ #include <stdint.h>
+
+ #include <algorithm>
+ #include <functional>
+
+ #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<patchref_t>();
+ }
+
+
+ /* 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<patchref_t, void*, bool> {
+ 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<patchref_t>::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<patchref_t>::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; i<patcher_depth; i++) printf("\t")
+ #endif /* !defined(NDEBUG) */
+
+ java_handle_t *patcher_handler(u1 *pc)
+ {
+ codeinfo *code;
+ patchref_t *pr;
+ bool result;
+ java_handle_t *e;
+ #if !defined(NDEBUG)
+ patcher_function_list_t *l;
+ int i;
+ #endif
+
+ /* define the patcher function */
+
+ bool (*patcher_function)(patchref_t *);
+
+ /* search the codeinfo for the given PC */
+
+ code = code_find_codeinfo_for_pc(pc);
+ assert(code);
+
+ // Enter a mutex on the patcher list.
+ code->patchers->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:
+ */
+
--- /dev/null
+ /* 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:
+ */
#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"
*******************************************************************************/
++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);
}
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);
}
# 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)