|  | // prims.cc - Code for core of runtime environment. | 
|  |  | 
|  | /* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007  Free Software Foundation | 
|  |  | 
|  | This file is part of libgcj. | 
|  |  | 
|  | This software is copyrighted work licensed under the terms of the | 
|  | Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for | 
|  | details.  */ | 
|  |  | 
|  | #include <config.h> | 
|  | #include <platform.h> | 
|  |  | 
|  | #include <stdlib.h> | 
|  | #include <stdarg.h> | 
|  | #include <stdio.h> | 
|  | #include <string.h> | 
|  | #include <signal.h> | 
|  |  | 
|  | #ifdef HAVE_UNISTD_H | 
|  | #include <unistd.h> | 
|  | #endif | 
|  |  | 
|  | #include <gcj/cni.h> | 
|  | #include <jvm.h> | 
|  | #include <java-signal.h> | 
|  | #include <java-threads.h> | 
|  | #include <java-interp.h> | 
|  |  | 
|  | #ifdef ENABLE_JVMPI | 
|  | #include <jvmpi.h> | 
|  | #include <java/lang/ThreadGroup.h> | 
|  | #endif | 
|  |  | 
|  | #ifdef INTERPRETER | 
|  | #include <jvmti.h> | 
|  | #include "jvmti-int.h" | 
|  | #endif | 
|  |  | 
|  | #ifndef DISABLE_GETENV_PROPERTIES | 
|  | #include <java-props.h> | 
|  | #define PROCESS_GCJ_PROPERTIES process_gcj_properties() | 
|  | #else | 
|  | #define PROCESS_GCJ_PROPERTIES | 
|  | #endif // DISABLE_GETENV_PROPERTIES | 
|  |  | 
|  | #include <java/lang/Class.h> | 
|  | #include <java/lang/ClassLoader.h> | 
|  | #include <java/lang/Runtime.h> | 
|  | #include <java/lang/String.h> | 
|  | #include <java/lang/Thread.h> | 
|  | #include <java/lang/ThreadGroup.h> | 
|  | #include <java/lang/ArrayIndexOutOfBoundsException.h> | 
|  | #include <java/lang/ArithmeticException.h> | 
|  | #include <java/lang/ClassFormatError.h> | 
|  | #include <java/lang/ClassNotFoundException.h> | 
|  | #include <java/lang/InternalError.h> | 
|  | #include <java/lang/NegativeArraySizeException.h> | 
|  | #include <java/lang/NoClassDefFoundError.h> | 
|  | #include <java/lang/NullPointerException.h> | 
|  | #include <java/lang/OutOfMemoryError.h> | 
|  | #include <java/lang/System.h> | 
|  | #include <java/lang/VMClassLoader.h> | 
|  | #include <java/lang/reflect/Modifier.h> | 
|  | #include <java/io/PrintStream.h> | 
|  | #include <java/lang/UnsatisfiedLinkError.h> | 
|  | #include <java/lang/VirtualMachineError.h> | 
|  | #include <gnu/gcj/runtime/ExtensionClassLoader.h> | 
|  | #include <gnu/gcj/runtime/FinalizerThread.h> | 
|  | #include <execution.h> | 
|  |  | 
|  | #ifdef INTERPRETER | 
|  | #include <gnu/classpath/jdwp/Jdwp.h> | 
|  | #include <gnu/classpath/jdwp/VMVirtualMachine.h> | 
|  | #endif // INTERPRETER | 
|  |  | 
|  | #include <gnu/java/lang/MainThread.h> | 
|  |  | 
|  | #ifdef USE_LTDL | 
|  | #include <ltdl.h> | 
|  | #endif | 
|  |  | 
|  | // Execution engine for compiled code. | 
|  | _Jv_CompiledEngine _Jv_soleCompiledEngine; | 
|  |  | 
|  | // Execution engine for code compiled with -findirect-classes | 
|  | _Jv_IndirectCompiledEngine _Jv_soleIndirectCompiledEngine; | 
|  |  | 
|  | // We allocate a single OutOfMemoryError exception which we keep | 
|  | // around for use if we run out of memory. | 
|  | static java::lang::OutOfMemoryError *no_memory; | 
|  |  | 
|  | // Number of bytes in largest array object we create.  This could be | 
|  | // increased to the largest size_t value, so long as the appropriate | 
|  | // functions are changed to take a size_t argument instead of jint. | 
|  | #define MAX_OBJECT_SIZE (((size_t)1<<31) - 1) | 
|  |  | 
|  | // Properties set at compile time. | 
|  | const char **_Jv_Compiler_Properties = NULL; | 
|  | int _Jv_Properties_Count = 0; | 
|  |  | 
|  | #ifndef DISABLE_GETENV_PROPERTIES | 
|  | // Property key/value pairs. | 
|  | property_pair *_Jv_Environment_Properties; | 
|  | #endif | 
|  |  | 
|  | // Stash the argv pointer to benefit native libraries that need it. | 
|  | const char **_Jv_argv; | 
|  | int _Jv_argc; | 
|  |  | 
|  | // Debugging options | 
|  | static bool remoteDebug = false; | 
|  | #ifdef INTERPRETER | 
|  | static char defaultJdwpOptions[] = ""; | 
|  | static char *jdwpOptions = defaultJdwpOptions; | 
|  |  | 
|  | // Typedefs for JVMTI agent functions. | 
|  | typedef jint jvmti_agent_onload_func (JavaVM *vm, char *options, | 
|  | void *reserved); | 
|  | typedef jint jvmti_agent_onunload_func (JavaVM *vm); | 
|  |  | 
|  | // JVMTI agent function pointers. | 
|  | static jvmti_agent_onload_func *jvmti_agentonload = NULL; | 
|  | static jvmti_agent_onunload_func *jvmti_agentonunload = NULL; | 
|  | static char *jvmti_agent_opts; | 
|  | #endif // INTERPRETER | 
|  |  | 
|  | // Argument support. | 
|  | int | 
|  | _Jv_GetNbArgs (void) | 
|  | { | 
|  | // _Jv_argc is 0 if not explicitly initialized. | 
|  | return _Jv_argc; | 
|  | } | 
|  |  | 
|  | const char * | 
|  | _Jv_GetSafeArg (int index) | 
|  | { | 
|  | if (index >=0 && index < _Jv_GetNbArgs ()) | 
|  | return _Jv_argv[index]; | 
|  | else | 
|  | return ""; | 
|  | } | 
|  |  | 
|  | void | 
|  | _Jv_SetArgs (int argc, const char **argv) | 
|  | { | 
|  | _Jv_argc = argc; | 
|  | _Jv_argv = argv; | 
|  | } | 
|  |  | 
|  | #ifdef ENABLE_JVMPI | 
|  | // Pointer to JVMPI notification functions. | 
|  | void (*_Jv_JVMPI_Notify_OBJECT_ALLOC) (JVMPI_Event *event); | 
|  | void (*_Jv_JVMPI_Notify_THREAD_START) (JVMPI_Event *event); | 
|  | void (*_Jv_JVMPI_Notify_THREAD_END) (JVMPI_Event *event); | 
|  | #endif | 
|  |  | 
|  |  | 
|  | #if defined (HANDLE_SEGV) || defined(HANDLE_FPE) | 
|  | /* Unblock a signal.  Unless we do this, the signal may only be sent | 
|  | once.  */ | 
|  | static void | 
|  | unblock_signal (int signum __attribute__ ((__unused__))) | 
|  | { | 
|  | #ifdef _POSIX_VERSION | 
|  | sigset_t sigs; | 
|  |  | 
|  | sigemptyset (&sigs); | 
|  | sigaddset (&sigs, signum); | 
|  | sigprocmask (SIG_UNBLOCK, &sigs, NULL); | 
|  | #endif | 
|  | } | 
|  | #endif | 
|  |  | 
|  | #ifdef HANDLE_SEGV | 
|  | SIGNAL_HANDLER (catch_segv) | 
|  | { | 
|  | unblock_signal (SIGSEGV); | 
|  | MAKE_THROW_FRAME (nullp); | 
|  | java::lang::NullPointerException *nullp | 
|  | = new java::lang::NullPointerException; | 
|  | throw nullp; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | #ifdef HANDLE_FPE | 
|  | SIGNAL_HANDLER (catch_fpe) | 
|  | { | 
|  | unblock_signal (SIGFPE); | 
|  | #ifdef HANDLE_DIVIDE_OVERFLOW | 
|  | HANDLE_DIVIDE_OVERFLOW; | 
|  | #else | 
|  | MAKE_THROW_FRAME (arithexception); | 
|  | #endif | 
|  | java::lang::ArithmeticException *arithexception | 
|  | = new java::lang::ArithmeticException (JvNewStringLatin1 ("/ by zero")); | 
|  | throw arithexception; | 
|  | } | 
|  | #endif | 
|  |  | 
|  |  | 
|  | jboolean | 
|  | _Jv_equalUtf8Consts (const Utf8Const* a, const Utf8Const *b) | 
|  | { | 
|  | int len; | 
|  | const _Jv_ushort *aptr, *bptr; | 
|  | if (a == b) | 
|  | return true; | 
|  | if (a->hash != b->hash) | 
|  | return false; | 
|  | len = a->length; | 
|  | if (b->length != len) | 
|  | return false; | 
|  | aptr = (const _Jv_ushort *)a->data; | 
|  | bptr = (const _Jv_ushort *)b->data; | 
|  | len = (len + 1) >> 1; | 
|  | while (--len >= 0) | 
|  | if (*aptr++ != *bptr++) | 
|  | return false; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /* True iff A is equal to STR. | 
|  | HASH is STR->hashCode(). | 
|  | */ | 
|  |  | 
|  | jboolean | 
|  | _Jv_equal (Utf8Const* a, jstring str, jint hash) | 
|  | { | 
|  | if (a->hash != (_Jv_ushort) hash) | 
|  | return false; | 
|  | jint len = str->length(); | 
|  | jint i = 0; | 
|  | jchar *sptr = _Jv_GetStringChars (str); | 
|  | unsigned char* ptr = (unsigned char*) a->data; | 
|  | unsigned char* limit = ptr + a->length; | 
|  | for (;; i++, sptr++) | 
|  | { | 
|  | int ch = UTF8_GET (ptr, limit); | 
|  | if (i == len) | 
|  | return ch < 0; | 
|  | if (ch != *sptr) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /* Like _Jv_equal, but stop after N characters.  */ | 
|  | jboolean | 
|  | _Jv_equaln (Utf8Const *a, jstring str, jint n) | 
|  | { | 
|  | jint len = str->length(); | 
|  | jint i = 0; | 
|  | jchar *sptr = _Jv_GetStringChars (str); | 
|  | unsigned char* ptr = (unsigned char*) a->data; | 
|  | unsigned char* limit = ptr + a->length; | 
|  | for (; n-- > 0; i++, sptr++) | 
|  | { | 
|  | int ch = UTF8_GET (ptr, limit); | 
|  | if (i == len) | 
|  | return ch < 0; | 
|  | if (ch != *sptr) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Determines whether the given Utf8Const object contains | 
|  | // a type which is primitive or some derived form of it, eg. | 
|  | // an array or multi-dimensional array variant. | 
|  | jboolean | 
|  | _Jv_isPrimitiveOrDerived(const Utf8Const *a) | 
|  | { | 
|  | unsigned char *aptr = (unsigned char *) a->data; | 
|  | unsigned char *alimit = aptr + a->length; | 
|  | int ac = UTF8_GET(aptr, alimit); | 
|  |  | 
|  | // Skips any leading array marks. | 
|  | while (ac == '[') | 
|  | ac = UTF8_GET(aptr, alimit); | 
|  |  | 
|  | // There should not be another character. This implies that | 
|  | // the type name is only one character long. | 
|  | if (UTF8_GET(aptr, alimit) == -1) | 
|  | switch ( ac ) | 
|  | { | 
|  | case 'Z': | 
|  | case 'B': | 
|  | case 'C': | 
|  | case 'S': | 
|  | case 'I': | 
|  | case 'J': | 
|  | case 'F': | 
|  | case 'D': | 
|  | return true; | 
|  | default: | 
|  | break; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Find out whether two _Jv_Utf8Const candidates contain the same | 
|  | // classname. | 
|  | // The method is written to handle the different formats of classnames. | 
|  | // Eg. "Ljava/lang/Class;", "Ljava.lang.Class;", "java/lang/Class" and | 
|  | // "java.lang.Class" will be seen as equal. | 
|  | // Warning: This function is not smart enough to declare "Z" and "boolean" | 
|  | // and similar cases as equal (and is not meant to be used this way)! | 
|  | jboolean | 
|  | _Jv_equalUtf8Classnames (const Utf8Const *a, const Utf8Const *b) | 
|  | { | 
|  | // If the class name's length differs by two characters | 
|  | // it is possible that we have candidates which are given | 
|  | // in the two different formats ("Lp1/p2/cn;" vs. "p1/p2/cn") | 
|  | switch (a->length - b->length) | 
|  | { | 
|  | case -2: | 
|  | case 0: | 
|  | case 2: | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  |  | 
|  | unsigned char *aptr = (unsigned char *) a->data; | 
|  | unsigned char *alimit = aptr + a->length; | 
|  | unsigned char *bptr = (unsigned char *) b->data; | 
|  | unsigned char *blimit = bptr + b->length; | 
|  |  | 
|  | if (alimit[-1] == ';') | 
|  | alimit--; | 
|  |  | 
|  | if (blimit[-1] == ';') | 
|  | blimit--; | 
|  |  | 
|  | int ac = UTF8_GET(aptr, alimit); | 
|  | int bc = UTF8_GET(bptr, blimit); | 
|  |  | 
|  | // Checks whether both strings have the same amount of leading [ characters. | 
|  | while (ac == '[') | 
|  | { | 
|  | if (bc == '[') | 
|  | { | 
|  | ac = UTF8_GET(aptr, alimit); | 
|  | bc = UTF8_GET(bptr, blimit); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Skips leading L character. | 
|  | if (ac == 'L') | 
|  | ac = UTF8_GET(aptr, alimit); | 
|  |  | 
|  | if (bc == 'L') | 
|  | bc = UTF8_GET(bptr, blimit); | 
|  |  | 
|  | // Compares the remaining characters. | 
|  | while (ac != -1 && bc != -1) | 
|  | { | 
|  | // Replaces package separating dots with slashes. | 
|  | if (ac == '.') | 
|  | ac = '/'; | 
|  |  | 
|  | if (bc == '.') | 
|  | bc = '/'; | 
|  |  | 
|  | // Now classnames differ if there is at least one non-matching | 
|  | // character. | 
|  | if (ac != bc) | 
|  | return false; | 
|  |  | 
|  | ac = UTF8_GET(aptr, alimit); | 
|  | bc = UTF8_GET(bptr, blimit); | 
|  | } | 
|  |  | 
|  | return (ac == bc); | 
|  | } | 
|  |  | 
|  | /* Count the number of Unicode chars encoded in a given Ut8 string. */ | 
|  | int | 
|  | _Jv_strLengthUtf8(const char* str, int len) | 
|  | { | 
|  | unsigned char* ptr; | 
|  | unsigned char* limit; | 
|  | int str_length; | 
|  |  | 
|  | ptr = (unsigned char*) str; | 
|  | limit = ptr + len; | 
|  | str_length = 0; | 
|  | for (; ptr < limit; str_length++) | 
|  | { | 
|  | if (UTF8_GET (ptr, limit) < 0) | 
|  | return (-1); | 
|  | } | 
|  | return (str_length); | 
|  | } | 
|  |  | 
|  | /* Calculate a hash value for a string encoded in Utf8 format. | 
|  | * This returns the same hash value as specified or java.lang.String.hashCode. | 
|  | */ | 
|  | jint | 
|  | _Jv_hashUtf8String (const char* str, int len) | 
|  | { | 
|  | unsigned char* ptr = (unsigned char*) str; | 
|  | unsigned char* limit = ptr + len; | 
|  | jint hash = 0; | 
|  |  | 
|  | for (; ptr < limit;) | 
|  | { | 
|  | int ch = UTF8_GET (ptr, limit); | 
|  | /* Updated specification from | 
|  | http://www.javasoft.com/docs/books/jls/clarify.html. */ | 
|  | hash = (31 * hash) + ch; | 
|  | } | 
|  | return hash; | 
|  | } | 
|  |  | 
|  | void | 
|  | _Jv_Utf8Const::init(const char *s, int len) | 
|  | { | 
|  | ::memcpy (data, s, len); | 
|  | data[len] = 0; | 
|  | length = len; | 
|  | hash = _Jv_hashUtf8String (s, len) & 0xFFFF; | 
|  | } | 
|  |  | 
|  | _Jv_Utf8Const * | 
|  | _Jv_makeUtf8Const (const char* s, int len) | 
|  | { | 
|  | if (len < 0) | 
|  | len = strlen (s); | 
|  | Utf8Const* m | 
|  | = (Utf8Const*) _Jv_AllocBytes (_Jv_Utf8Const::space_needed(s, len)); | 
|  | m->init(s, len); | 
|  | return m; | 
|  | } | 
|  |  | 
|  | _Jv_Utf8Const * | 
|  | _Jv_makeUtf8Const (jstring string) | 
|  | { | 
|  | jint hash = string->hashCode (); | 
|  | jint len = _Jv_GetStringUTFLength (string); | 
|  |  | 
|  | Utf8Const* m = (Utf8Const*) | 
|  | _Jv_AllocBytes (sizeof(Utf8Const) + len + 1); | 
|  |  | 
|  | m->hash = hash; | 
|  | m->length = len; | 
|  |  | 
|  | _Jv_GetStringUTFRegion (string, 0, string->length (), m->data); | 
|  | m->data[len] = 0; | 
|  |  | 
|  | return m; | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | #ifdef __GCJ_DEBUG | 
|  | void | 
|  | _Jv_Abort (const char *function, const char *file, int line, | 
|  | const char *message) | 
|  | #else | 
|  | void | 
|  | _Jv_Abort (const char *, const char *, int, const char *message) | 
|  | #endif | 
|  | { | 
|  | #ifdef __GCJ_DEBUG | 
|  | fprintf (stderr, | 
|  | "libgcj failure: %s\n   in function %s, file %s, line %d\n", | 
|  | message, function, file, line); | 
|  | #else | 
|  | fprintf (stderr, "libgcj failure: %s\n", message); | 
|  | #endif | 
|  | fflush (stderr); | 
|  | abort (); | 
|  | } | 
|  |  | 
|  | static void | 
|  | fail_on_finalization (jobject) | 
|  | { | 
|  | JvFail ("object was finalized"); | 
|  | } | 
|  |  | 
|  | void | 
|  | _Jv_GCWatch (jobject obj) | 
|  | { | 
|  | _Jv_RegisterFinalizer (obj, fail_on_finalization); | 
|  | } | 
|  |  | 
|  | void | 
|  | _Jv_ThrowBadArrayIndex(jint bad_index) | 
|  | { | 
|  | throw new java::lang::ArrayIndexOutOfBoundsException | 
|  | (java::lang::String::valueOf (bad_index)); | 
|  | } | 
|  |  | 
|  | void | 
|  | _Jv_ThrowNullPointerException () | 
|  | { | 
|  | throw new java::lang::NullPointerException; | 
|  | } | 
|  |  | 
|  | // Resolve an entry in the constant pool and return the target | 
|  | // address. | 
|  | void * | 
|  | _Jv_ResolvePoolEntry (jclass this_class, jint index) | 
|  | { | 
|  | _Jv_Constants *pool = &this_class->constants; | 
|  |  | 
|  | if ((pool->tags[index] & JV_CONSTANT_ResolvedFlag) != 0) | 
|  | return pool->data[index].field->u.addr; | 
|  |  | 
|  | JvSynchronize sync (this_class); | 
|  | return (_Jv_Linker::resolve_pool_entry (this_class, index)) | 
|  | .field->u.addr; | 
|  | } | 
|  |  | 
|  |  | 
|  | // Explicitly throw a no memory exception. | 
|  | // The collector calls this when it encounters an out-of-memory condition. | 
|  | void _Jv_ThrowNoMemory() | 
|  | { | 
|  | throw no_memory; | 
|  | } | 
|  |  | 
|  | #ifdef ENABLE_JVMPI | 
|  | # define JVMPI_NOTIFY_ALLOC(klass,size,obj) \ | 
|  | if (__builtin_expect (_Jv_JVMPI_Notify_OBJECT_ALLOC != 0, false)) \ | 
|  | jvmpi_notify_alloc(klass,size,obj); | 
|  | static void | 
|  | jvmpi_notify_alloc(jclass klass, jint size, jobject obj) | 
|  | { | 
|  | // Service JVMPI allocation request. | 
|  | JVMPI_Event event; | 
|  |  | 
|  | event.event_type = JVMPI_EVENT_OBJECT_ALLOC; | 
|  | event.env_id = NULL; | 
|  | event.u.obj_alloc.arena_id = 0; | 
|  | event.u.obj_alloc.class_id = (jobjectID) klass; | 
|  | event.u.obj_alloc.is_array = 0; | 
|  | event.u.obj_alloc.size = size; | 
|  | event.u.obj_alloc.obj_id = (jobjectID) obj; | 
|  |  | 
|  | // FIXME:  This doesn't look right for the Boehm GC.  A GC may | 
|  | // already be in progress.  _Jv_DisableGC () doesn't wait for it. | 
|  | // More importantly, I don't see the need for disabling GC, since we | 
|  | // blatantly have a pointer to obj on our stack, ensuring that the | 
|  | // object can't be collected.  Even for a nonconservative collector, | 
|  | // it appears to me that this must be true, since we are about to | 
|  | // return obj. Isn't this whole approach way too intrusive for | 
|  | // a useful profiling interface?			- HB | 
|  | _Jv_DisableGC (); | 
|  | (*_Jv_JVMPI_Notify_OBJECT_ALLOC) (&event); | 
|  | _Jv_EnableGC (); | 
|  | } | 
|  | #else /* !ENABLE_JVMPI */ | 
|  | # define JVMPI_NOTIFY_ALLOC(klass,size,obj) /* do nothing */ | 
|  | #endif | 
|  |  | 
|  | // Allocate a new object of class KLASS. | 
|  | // First a version that assumes that we have no finalizer, and that | 
|  | // the class is already initialized. | 
|  | // If we know that JVMPI is disabled, this can be replaced by a direct call | 
|  | // to the allocator for the appropriate GC. | 
|  | jobject | 
|  | _Jv_AllocObjectNoInitNoFinalizer (jclass klass) | 
|  | { | 
|  | jint size = klass->size (); | 
|  | jobject obj = (jobject) _Jv_AllocObj (size, klass); | 
|  | JVMPI_NOTIFY_ALLOC (klass, size, obj); | 
|  | return obj; | 
|  | } | 
|  |  | 
|  | // And now a version that initializes if necessary. | 
|  | jobject | 
|  | _Jv_AllocObjectNoFinalizer (jclass klass) | 
|  | { | 
|  | if (_Jv_IsPhantomClass(klass) ) | 
|  | throw new java::lang::NoClassDefFoundError(klass->getName()); | 
|  |  | 
|  | _Jv_InitClass (klass); | 
|  | jint size = klass->size (); | 
|  | jobject obj = (jobject) _Jv_AllocObj (size, klass); | 
|  | JVMPI_NOTIFY_ALLOC (klass, size, obj); | 
|  | return obj; | 
|  | } | 
|  |  | 
|  | // And now the general version that registers a finalizer if necessary. | 
|  | jobject | 
|  | _Jv_AllocObject (jclass klass) | 
|  | { | 
|  | jobject obj = _Jv_AllocObjectNoFinalizer (klass); | 
|  |  | 
|  | // We assume that the compiler only generates calls to this routine | 
|  | // if there really is an interesting finalizer. | 
|  | // Unfortunately, we still have to the dynamic test, since there may | 
|  | // be cni calls to this routine. | 
|  | // Note that on IA64 get_finalizer() returns the starting address of the | 
|  | // function, not a function pointer.  Thus this still works. | 
|  | if (klass->vtable->get_finalizer () | 
|  | != java::lang::Object::class$.vtable->get_finalizer ()) | 
|  | _Jv_RegisterFinalizer (obj, _Jv_FinalizeObject); | 
|  | return obj; | 
|  | } | 
|  |  | 
|  | // Allocate a String, including variable length storage. | 
|  | jstring | 
|  | _Jv_AllocString(jsize len) | 
|  | { | 
|  | using namespace java::lang; | 
|  |  | 
|  | jsize sz = sizeof(java::lang::String) + len * sizeof(jchar); | 
|  |  | 
|  | // We assert that for strings allocated this way, the data field | 
|  | // will always point to the object itself.  Thus there is no reason | 
|  | // for the garbage collector to scan any of it. | 
|  | // Furthermore, we're about to overwrite the string data, so | 
|  | // initialization of the object is not an issue. | 
|  |  | 
|  | // String needs no initialization, and there is no finalizer, so | 
|  | // we can go directly to the collector's allocator interface. | 
|  | jstring obj = (jstring) _Jv_AllocPtrFreeObj(sz, &String::class$); | 
|  |  | 
|  | obj->data = obj; | 
|  | obj->boffset = sizeof(java::lang::String); | 
|  | obj->count = len; | 
|  | obj->cachedHashCode = 0; | 
|  |  | 
|  | JVMPI_NOTIFY_ALLOC (&String::class$, sz, obj); | 
|  |  | 
|  | return obj; | 
|  | } | 
|  |  | 
|  | // A version of the above that assumes the object contains no pointers, | 
|  | // and requires no finalization.  This can't happen if we need pointers | 
|  | // to locks. | 
|  | #ifdef JV_HASH_SYNCHRONIZATION | 
|  | jobject | 
|  | _Jv_AllocPtrFreeObject (jclass klass) | 
|  | { | 
|  | _Jv_InitClass (klass); | 
|  | jint size = klass->size (); | 
|  |  | 
|  | jobject obj = (jobject) _Jv_AllocPtrFreeObj (size, klass); | 
|  |  | 
|  | JVMPI_NOTIFY_ALLOC (klass, size, obj); | 
|  |  | 
|  | return obj; | 
|  | } | 
|  | #endif /* JV_HASH_SYNCHRONIZATION */ | 
|  |  | 
|  |  | 
|  | // Allocate a new array of Java objects.  Each object is of type | 
|  | // `elementClass'.  `init' is used to initialize each slot in the | 
|  | // array. | 
|  | jobjectArray | 
|  | _Jv_NewObjectArray (jsize count, jclass elementClass, jobject init) | 
|  | { | 
|  | // Creating an array of an unresolved type is impossible. So we throw | 
|  | // the NoClassDefFoundError. | 
|  | if ( _Jv_IsPhantomClass(elementClass) ) | 
|  | throw new java::lang::NoClassDefFoundError(elementClass->getName()); | 
|  |  | 
|  | if (__builtin_expect (count < 0, false)) | 
|  | throw new java::lang::NegativeArraySizeException; | 
|  |  | 
|  | JvAssert (! elementClass->isPrimitive ()); | 
|  |  | 
|  | // Ensure that elements pointer is properly aligned. | 
|  | jobjectArray obj = NULL; | 
|  | size_t size = (size_t) elements (obj); | 
|  | // Check for overflow. | 
|  | if (__builtin_expect ((size_t) count > | 
|  | (MAX_OBJECT_SIZE - 1 - size) / sizeof (jobject), false)) | 
|  | throw no_memory; | 
|  |  | 
|  | size += count * sizeof (jobject); | 
|  |  | 
|  | jclass klass = _Jv_GetArrayClass (elementClass, | 
|  | elementClass->getClassLoaderInternal()); | 
|  |  | 
|  | obj = (jobjectArray) _Jv_AllocArray (size, klass); | 
|  | // Cast away const. | 
|  | jsize *lp = const_cast<jsize *> (&obj->length); | 
|  | *lp = count; | 
|  | // We know the allocator returns zeroed memory.  So don't bother | 
|  | // zeroing it again. | 
|  | if (init) | 
|  | { | 
|  | jobject *ptr = elements(obj); | 
|  | while (--count >= 0) | 
|  | *ptr++ = init; | 
|  | } | 
|  | return obj; | 
|  | } | 
|  |  | 
|  | // Allocate a new array of primitives.  ELTYPE is the type of the | 
|  | // element, COUNT is the size of the array. | 
|  | jobject | 
|  | _Jv_NewPrimArray (jclass eltype, jint count) | 
|  | { | 
|  | int elsize = eltype->size(); | 
|  | if (__builtin_expect (count < 0, false)) | 
|  | throw new java::lang::NegativeArraySizeException; | 
|  |  | 
|  | JvAssert (eltype->isPrimitive ()); | 
|  | jobject dummy = NULL; | 
|  | size_t size = (size_t) _Jv_GetArrayElementFromElementType (dummy, eltype); | 
|  |  | 
|  | // Check for overflow. | 
|  | if (__builtin_expect ((size_t) count > | 
|  | (MAX_OBJECT_SIZE - size) / elsize, false)) | 
|  | throw no_memory; | 
|  |  | 
|  | jclass klass = _Jv_GetArrayClass (eltype, 0); | 
|  |  | 
|  | # ifdef JV_HASH_SYNCHRONIZATION | 
|  | // Since the vtable is always statically allocated, | 
|  | // these are completely pointerfree!  Make sure the GC doesn't touch them. | 
|  | __JArray *arr = | 
|  | (__JArray*) _Jv_AllocPtrFreeObj (size + elsize * count, klass); | 
|  | memset((char *)arr + size, 0, elsize * count); | 
|  | # else | 
|  | __JArray *arr = (__JArray*) _Jv_AllocObj (size + elsize * count, klass); | 
|  | // Note that we assume we are given zeroed memory by the allocator. | 
|  | # endif | 
|  | // Cast away const. | 
|  | jsize *lp = const_cast<jsize *> (&arr->length); | 
|  | *lp = count; | 
|  |  | 
|  | return arr; | 
|  | } | 
|  |  | 
|  | jobject | 
|  | _Jv_NewArray (jint type, jint size) | 
|  | { | 
|  | switch (type) | 
|  | { | 
|  | case  4:  return JvNewBooleanArray (size); | 
|  | case  5:  return JvNewCharArray (size); | 
|  | case  6:  return JvNewFloatArray (size); | 
|  | case  7:  return JvNewDoubleArray (size); | 
|  | case  8:  return JvNewByteArray (size); | 
|  | case  9:  return JvNewShortArray (size); | 
|  | case 10:  return JvNewIntArray (size); | 
|  | case 11:  return JvNewLongArray (size); | 
|  | } | 
|  | throw new java::lang::InternalError | 
|  | (JvNewStringLatin1 ("invalid type code in _Jv_NewArray")); | 
|  | } | 
|  |  | 
|  | // Allocate a possibly multi-dimensional array but don't check that | 
|  | // any array length is <0. | 
|  | static jobject | 
|  | _Jv_NewMultiArrayUnchecked (jclass type, jint dimensions, jint *sizes) | 
|  | { | 
|  | JvAssert (type->isArray()); | 
|  | jclass element_type = type->getComponentType(); | 
|  | jobject result; | 
|  | if (element_type->isPrimitive()) | 
|  | result = _Jv_NewPrimArray (element_type, sizes[0]); | 
|  | else | 
|  | result = _Jv_NewObjectArray (sizes[0], element_type, NULL); | 
|  |  | 
|  | if (dimensions > 1) | 
|  | { | 
|  | JvAssert (! element_type->isPrimitive()); | 
|  | JvAssert (element_type->isArray()); | 
|  | jobject *contents = elements ((jobjectArray) result); | 
|  | for (int i = 0; i < sizes[0]; ++i) | 
|  | contents[i] = _Jv_NewMultiArrayUnchecked (element_type, dimensions - 1, | 
|  | sizes + 1); | 
|  | } | 
|  |  | 
|  | return result; | 
|  | } | 
|  |  | 
|  | jobject | 
|  | _Jv_NewMultiArray (jclass type, jint dimensions, jint *sizes) | 
|  | { | 
|  | for (int i = 0; i < dimensions; ++i) | 
|  | if (sizes[i] < 0) | 
|  | throw new java::lang::NegativeArraySizeException; | 
|  |  | 
|  | return _Jv_NewMultiArrayUnchecked (type, dimensions, sizes); | 
|  | } | 
|  |  | 
|  | jobject | 
|  | _Jv_NewMultiArray (jclass array_type, jint dimensions, ...) | 
|  | { | 
|  | // Creating an array of an unresolved type is impossible. So we throw | 
|  | // the NoClassDefFoundError. | 
|  | if (_Jv_IsPhantomClass(array_type)) | 
|  | throw new java::lang::NoClassDefFoundError(array_type->getName()); | 
|  |  | 
|  | va_list args; | 
|  | jint sizes[dimensions]; | 
|  | va_start (args, dimensions); | 
|  | for (int i = 0; i < dimensions; ++i) | 
|  | { | 
|  | jint size = va_arg (args, jint); | 
|  | if (size < 0) | 
|  | throw new java::lang::NegativeArraySizeException; | 
|  | sizes[i] = size; | 
|  | } | 
|  | va_end (args); | 
|  |  | 
|  | return _Jv_NewMultiArrayUnchecked (array_type, dimensions, sizes); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | // Ensure 8-byte alignment, for hash synchronization. | 
|  | #define DECLARE_PRIM_TYPE(NAME)			\ | 
|  | java::lang::Class _Jv_##NAME##Class __attribute__ ((aligned (8))); | 
|  |  | 
|  | DECLARE_PRIM_TYPE(byte) | 
|  | DECLARE_PRIM_TYPE(short) | 
|  | DECLARE_PRIM_TYPE(int) | 
|  | DECLARE_PRIM_TYPE(long) | 
|  | DECLARE_PRIM_TYPE(boolean) | 
|  | DECLARE_PRIM_TYPE(char) | 
|  | DECLARE_PRIM_TYPE(float) | 
|  | DECLARE_PRIM_TYPE(double) | 
|  | DECLARE_PRIM_TYPE(void) | 
|  |  | 
|  | void | 
|  | _Jv_InitPrimClass (jclass cl, const char *cname, char sig, int len) | 
|  | { | 
|  | using namespace java::lang::reflect; | 
|  |  | 
|  | // We must set the vtable for the class; the Java constructor | 
|  | // doesn't do this. | 
|  | (*(_Jv_VTable **) cl) = java::lang::Class::class$.vtable; | 
|  |  | 
|  | // Initialize the fields we care about.  We do this in the same | 
|  | // order they are declared in Class.h. | 
|  | cl->name = _Jv_makeUtf8Const ((char *) cname, -1); | 
|  | cl->accflags = Modifier::PUBLIC | Modifier::FINAL | Modifier::ABSTRACT; | 
|  | cl->method_count = sig; | 
|  | cl->size_in_bytes = len; | 
|  | cl->vtable = JV_PRIMITIVE_VTABLE; | 
|  | cl->state = JV_STATE_DONE; | 
|  | cl->depth = -1; | 
|  | } | 
|  |  | 
|  | jclass | 
|  | _Jv_FindClassFromSignature (char *sig, java::lang::ClassLoader *loader, | 
|  | char **endp) | 
|  | { | 
|  | // First count arrays. | 
|  | int array_count = 0; | 
|  | while (*sig == '[') | 
|  | { | 
|  | ++sig; | 
|  | ++array_count; | 
|  | } | 
|  |  | 
|  | jclass result = NULL; | 
|  | switch (*sig) | 
|  | { | 
|  | case 'B': | 
|  | result = JvPrimClass (byte); | 
|  | break; | 
|  | case 'S': | 
|  | result = JvPrimClass (short); | 
|  | break; | 
|  | case 'I': | 
|  | result = JvPrimClass (int); | 
|  | break; | 
|  | case 'J': | 
|  | result = JvPrimClass (long); | 
|  | break; | 
|  | case 'Z': | 
|  | result = JvPrimClass (boolean); | 
|  | break; | 
|  | case 'C': | 
|  | result = JvPrimClass (char); | 
|  | break; | 
|  | case 'F': | 
|  | result = JvPrimClass (float); | 
|  | break; | 
|  | case 'D': | 
|  | result = JvPrimClass (double); | 
|  | break; | 
|  | case 'V': | 
|  | result = JvPrimClass (void); | 
|  | break; | 
|  | case 'L': | 
|  | { | 
|  | char *save = ++sig; | 
|  | while (*sig && *sig != ';') | 
|  | ++sig; | 
|  | // Do nothing if signature appears to be malformed. | 
|  | if (*sig == ';') | 
|  | { | 
|  | _Jv_Utf8Const *name = _Jv_makeUtf8Const (save, sig - save); | 
|  | result = _Jv_FindClass (name, loader); | 
|  | } | 
|  | break; | 
|  | } | 
|  | default: | 
|  | // Do nothing -- bad signature. | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (endp) | 
|  | { | 
|  | // Not really the "end", but the last valid character that we | 
|  | // looked at. | 
|  | *endp = sig; | 
|  | } | 
|  |  | 
|  | if (! result) | 
|  | return NULL; | 
|  |  | 
|  | // Find arrays. | 
|  | while (array_count-- > 0) | 
|  | result = _Jv_GetArrayClass (result, loader); | 
|  | return result; | 
|  | } | 
|  |  | 
|  |  | 
|  | jclass | 
|  | _Jv_FindClassFromSignatureNoException (char *sig, java::lang::ClassLoader *loader, | 
|  | char **endp) | 
|  | { | 
|  | jclass klass; | 
|  |  | 
|  | try | 
|  | { | 
|  | klass = _Jv_FindClassFromSignature(sig, loader, endp); | 
|  | } | 
|  | catch (java::lang::NoClassDefFoundError *ncdfe) | 
|  | { | 
|  | return NULL; | 
|  | } | 
|  | catch (java::lang::ClassNotFoundException *cnfe) | 
|  | { | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | return klass; | 
|  | } | 
|  |  | 
|  | JArray<jstring> * | 
|  | JvConvertArgv (int argc, const char **argv) | 
|  | { | 
|  | if (argc < 0) | 
|  | argc = 0; | 
|  | jobjectArray ar = JvNewObjectArray(argc, &java::lang::String::class$, NULL); | 
|  | jobject *ptr = elements(ar); | 
|  | jbyteArray bytes = NULL; | 
|  | for (int i = 0;  i < argc;  i++) | 
|  | { | 
|  | const char *arg = argv[i]; | 
|  | int len = strlen (arg); | 
|  | if (bytes == NULL || bytes->length < len) | 
|  | bytes = JvNewByteArray (len); | 
|  | jbyte *bytePtr = elements (bytes); | 
|  | // We assume jbyte == char. | 
|  | memcpy (bytePtr, arg, len); | 
|  |  | 
|  | // Now convert using the default encoding. | 
|  | *ptr++ = new java::lang::String (bytes, 0, len); | 
|  | } | 
|  | return (JArray<jstring>*) ar; | 
|  | } | 
|  |  | 
|  | // FIXME: These variables are static so that they will be | 
|  | // automatically scanned by the Boehm collector.  This is needed | 
|  | // because with qthreads the collector won't scan the initial stack -- | 
|  | // it will only scan the qthreads stacks. | 
|  |  | 
|  | // Command line arguments. | 
|  | static JArray<jstring> *arg_vec; | 
|  |  | 
|  | // The primary thread. | 
|  | static java::lang::Thread *main_thread; | 
|  |  | 
|  | #ifndef DISABLE_GETENV_PROPERTIES | 
|  |  | 
|  | #define c_isspace(c) (memchr (" \t\n\r\v\f", c, 6) != NULL) | 
|  |  | 
|  | static char * | 
|  | next_property_key (char *s, size_t *length) | 
|  | { | 
|  | size_t l = 0; | 
|  |  | 
|  | JvAssert (s); | 
|  |  | 
|  | // Skip over whitespace | 
|  | while (c_isspace (*s)) | 
|  | s++; | 
|  |  | 
|  | // If we've reached the end, return NULL.  Also return NULL if for | 
|  | // some reason we've come across a malformed property string. | 
|  | if (*s == 0 | 
|  | || *s == ':' | 
|  | || *s == '=') | 
|  | return NULL; | 
|  |  | 
|  | // Determine the length of the property key. | 
|  | while (s[l] != 0 | 
|  | && ! c_isspace (s[l]) | 
|  | && s[l] != ':' | 
|  | && s[l] != '=') | 
|  | { | 
|  | if (s[l] == '\\' | 
|  | && s[l+1] != 0) | 
|  | l++; | 
|  | l++; | 
|  | } | 
|  |  | 
|  | *length = l; | 
|  |  | 
|  | return s; | 
|  | } | 
|  |  | 
|  | static char * | 
|  | next_property_value (char *s, size_t *length) | 
|  | { | 
|  | size_t l = 0; | 
|  |  | 
|  | JvAssert (s); | 
|  |  | 
|  | while (c_isspace (*s)) | 
|  | s++; | 
|  |  | 
|  | if (*s == ':' | 
|  | || *s == '=') | 
|  | s++; | 
|  |  | 
|  | while (c_isspace (*s)) | 
|  | s++; | 
|  |  | 
|  | // Determine the length of the property value. | 
|  | while (s[l] != 0 | 
|  | && ! c_isspace (s[l]) | 
|  | && s[l] != ':' | 
|  | && s[l] != '=') | 
|  | { | 
|  | if (s[l] == '\\' | 
|  | && s[l+1] != 0) | 
|  | l += 2; | 
|  | else | 
|  | l++; | 
|  | } | 
|  |  | 
|  | *length = l; | 
|  |  | 
|  | return s; | 
|  | } | 
|  |  | 
|  | static void | 
|  | process_gcj_properties () | 
|  | { | 
|  | char *props = getenv("GCJ_PROPERTIES"); | 
|  |  | 
|  | if (NULL == props) | 
|  | return; | 
|  |  | 
|  | // Later on we will write \0s into this string.  It is simplest to | 
|  | // just duplicate it here. | 
|  | props = strdup (props); | 
|  |  | 
|  | char *p = props; | 
|  | size_t length; | 
|  | size_t property_count = 0; | 
|  |  | 
|  | // Whip through props quickly in order to count the number of | 
|  | // property values. | 
|  | while (p && (p = next_property_key (p, &length))) | 
|  | { | 
|  | // Skip to the end of the key | 
|  | p += length; | 
|  |  | 
|  | p = next_property_value (p, &length); | 
|  | if (p) | 
|  | p += length; | 
|  |  | 
|  | property_count++; | 
|  | } | 
|  |  | 
|  | // Allocate an array of property value/key pairs. | 
|  | _Jv_Environment_Properties = | 
|  | (property_pair *) malloc (sizeof(property_pair) | 
|  | * (property_count + 1)); | 
|  |  | 
|  | // Go through the properties again, initializing _Jv_Properties | 
|  | // along the way. | 
|  | p = props; | 
|  | property_count = 0; | 
|  | while (p && (p = next_property_key (p, &length))) | 
|  | { | 
|  | _Jv_Environment_Properties[property_count].key = p; | 
|  | _Jv_Environment_Properties[property_count].key_length = length; | 
|  |  | 
|  | // Skip to the end of the key | 
|  | p += length; | 
|  |  | 
|  | p = next_property_value (p, &length); | 
|  |  | 
|  | _Jv_Environment_Properties[property_count].value = p; | 
|  | _Jv_Environment_Properties[property_count].value_length = length; | 
|  |  | 
|  | if (p) | 
|  | p += length; | 
|  |  | 
|  | property_count++; | 
|  | } | 
|  | memset ((void *) &_Jv_Environment_Properties[property_count], | 
|  | 0, sizeof (property_pair)); | 
|  |  | 
|  | // Null terminate the strings. | 
|  | for (property_pair *prop = &_Jv_Environment_Properties[0]; | 
|  | prop->key != NULL; | 
|  | prop++) | 
|  | { | 
|  | prop->key[prop->key_length] = 0; | 
|  | prop->value[prop->value_length] = 0; | 
|  | } | 
|  | } | 
|  | #endif // DISABLE_GETENV_PROPERTIES | 
|  |  | 
|  | namespace gcj | 
|  | { | 
|  | _Jv_Utf8Const *void_signature; | 
|  | _Jv_Utf8Const *clinit_name; | 
|  | _Jv_Utf8Const *init_name; | 
|  | _Jv_Utf8Const *finit_name; | 
|  |  | 
|  | bool runtimeInitialized = false; | 
|  |  | 
|  | // When true, print debugging information about class loading. | 
|  | bool verbose_class_flag; | 
|  |  | 
|  | // When true, enable the bytecode verifier and BC-ABI type verification. | 
|  | bool verifyClasses = true; | 
|  |  | 
|  | // Thread stack size specified by the -Xss runtime argument. | 
|  | size_t stack_size = 0; | 
|  |  | 
|  | // Start time of the VM | 
|  | jlong startTime = 0; | 
|  |  | 
|  | // Arguments passed to the VM | 
|  | JArray<jstring>* vmArgs; | 
|  |  | 
|  | // Currently loaded classes | 
|  | jint loadedClasses = 0; | 
|  |  | 
|  | // Unloaded classes | 
|  | jlong unloadedClasses = 0; | 
|  | } | 
|  |  | 
|  | // We accept all non-standard options accepted by Sun's java command, | 
|  | // for compatibility with existing application launch scripts. | 
|  | static jint | 
|  | parse_x_arg (char* option_string) | 
|  | { | 
|  | if (strlen (option_string) <= 0) | 
|  | return -1; | 
|  |  | 
|  | if (! strcmp (option_string, "int")) | 
|  | { | 
|  | // FIXME: this should cause the vm to never load shared objects | 
|  | } | 
|  | else if (! strcmp (option_string, "mixed")) | 
|  | { | 
|  | // FIXME: allow interpreted and native code | 
|  | } | 
|  | else if (! strcmp (option_string, "batch")) | 
|  | { | 
|  | // FIXME: disable background JIT'ing | 
|  | } | 
|  | else if (! strcmp (option_string, "debug")) | 
|  | { | 
|  | remoteDebug = true; | 
|  | } | 
|  | #ifdef INTERPRETER | 
|  | else if (! strncmp (option_string, "runjdwp:", 8)) | 
|  | { | 
|  | if (strlen (option_string) > 8) | 
|  | jdwpOptions = &option_string[8]; | 
|  | else | 
|  | { | 
|  | fprintf (stderr, | 
|  | "libgcj: argument required for JDWP options"); | 
|  | return -1; | 
|  | } | 
|  | } | 
|  | #endif // INTERPRETER | 
|  | else if (! strncmp (option_string, "bootclasspath:", 14)) | 
|  | { | 
|  | // FIXME: add a parse_bootclasspath_arg function | 
|  | } | 
|  | else if (! strncmp (option_string, "bootclasspath/a:", 16)) | 
|  | { | 
|  | } | 
|  | else if (! strncmp (option_string, "bootclasspath/p:", 16)) | 
|  | { | 
|  | } | 
|  | else if (! strcmp (option_string, "check:jni")) | 
|  | { | 
|  | // FIXME: enable strict JNI checking | 
|  | } | 
|  | else if (! strcmp (option_string, "future")) | 
|  | { | 
|  | // FIXME: enable strict class file format checks | 
|  | } | 
|  | else if (! strcmp (option_string, "noclassgc")) | 
|  | { | 
|  | // FIXME: disable garbage collection for classes | 
|  | } | 
|  | else if (! strcmp (option_string, "incgc")) | 
|  | { | 
|  | // FIXME: incremental garbage collection | 
|  | } | 
|  | else if (! strncmp (option_string, "loggc:", 6)) | 
|  | { | 
|  | if (option_string[6] == '\0') | 
|  | { | 
|  | fprintf (stderr, | 
|  | "libgcj: filename argument expected for loggc option\n"); | 
|  | return -1; | 
|  | } | 
|  | // FIXME: set gc logging filename | 
|  | } | 
|  | else if (! strncmp (option_string, "ms", 2)) | 
|  | { | 
|  | // FIXME: ignore this option until PR 20699 is fixed. | 
|  | // _Jv_SetInitialHeapSize (option_string + 2); | 
|  | } | 
|  | else if (! strncmp (option_string, "mx", 2)) | 
|  | _Jv_SetMaximumHeapSize (option_string + 2); | 
|  | else if (! strcmp (option_string, "prof")) | 
|  | { | 
|  | // FIXME: enable profiling of program running in vm | 
|  | } | 
|  | else if (! strncmp (option_string, "runhprof:", 9)) | 
|  | { | 
|  | // FIXME: enable specific type of vm profiling.  add a | 
|  | // parse_runhprof_arg function | 
|  | } | 
|  | else if (! strcmp (option_string, "rs")) | 
|  | { | 
|  | // FIXME: reduced system signal usage.  disable thread dumps, | 
|  | // only terminate in response to user-initiated calls, | 
|  | // e.g. System.exit() | 
|  | } | 
|  | else if (! strncmp (option_string, "ss", 2)) | 
|  | { | 
|  | _Jv_SetStackSize (option_string + 2); | 
|  | } | 
|  | else if (! strcmp (option_string, "X:+UseAltSigs")) | 
|  | { | 
|  | // FIXME: use signals other than SIGUSR1 and SIGUSR2 | 
|  | } | 
|  | else if (! strcmp (option_string, "share:off")) | 
|  | { | 
|  | // FIXME: don't share class data | 
|  | } | 
|  | else if (! strcmp (option_string, "share:auto")) | 
|  | { | 
|  | // FIXME: share class data where possible | 
|  | } | 
|  | else if (! strcmp (option_string, "share:on")) | 
|  | { | 
|  | // FIXME: fail if impossible to share class data | 
|  | } | 
|  | else | 
|  | { | 
|  | // Unrecognized. | 
|  | return -1; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static jint | 
|  | parse_verbose_args (char* option_string, | 
|  | bool ignore_unrecognized) | 
|  | { | 
|  | size_t len = sizeof ("-verbose") - 1; | 
|  |  | 
|  | if (strlen (option_string) < len) | 
|  | return -1; | 
|  |  | 
|  | if (option_string[len] == ':' | 
|  | && option_string[len + 1] != '\0') | 
|  | { | 
|  | char* verbose_args = option_string + len + 1; | 
|  |  | 
|  | do | 
|  | { | 
|  | if (! strncmp (verbose_args, | 
|  | "gc", sizeof ("gc") - 1)) | 
|  | { | 
|  | if (verbose_args[sizeof ("gc") - 1] == '\0' | 
|  | || verbose_args[sizeof ("gc") - 1] == ',') | 
|  | { | 
|  | // FIXME: we should add functions to boehm-gc that | 
|  | // toggle GC_print_stats, GC_PRINT_ADDRESS_MAP and | 
|  | // GC_print_back_height. | 
|  | verbose_args += sizeof ("gc") - 1; | 
|  | } | 
|  | else | 
|  | { | 
|  | verbose_arg_err: | 
|  | fprintf (stderr, "libgcj: unknown verbose option: %s\n", | 
|  | option_string); | 
|  | return -1; | 
|  | } | 
|  | } | 
|  | else if (! strncmp (verbose_args, | 
|  | "class", | 
|  | sizeof ("class") - 1)) | 
|  | { | 
|  | if (verbose_args[sizeof ("class") - 1] == '\0' | 
|  | || verbose_args[sizeof ("class") - 1] == ',') | 
|  | { | 
|  | gcj::verbose_class_flag = true; | 
|  | verbose_args += sizeof ("class") - 1; | 
|  | } | 
|  | else | 
|  | goto verbose_arg_err; | 
|  | } | 
|  | else if (! strncmp (verbose_args, "jni", | 
|  | sizeof ("jni") - 1)) | 
|  | { | 
|  | if (verbose_args[sizeof ("jni") - 1] == '\0' | 
|  | || verbose_args[sizeof ("jni") - 1] == ',') | 
|  | { | 
|  | // FIXME: enable JNI messages. | 
|  | verbose_args += sizeof ("jni") - 1; | 
|  | } | 
|  | else | 
|  | goto verbose_arg_err; | 
|  | } | 
|  | else if (ignore_unrecognized | 
|  | && verbose_args[0] == 'X') | 
|  | { | 
|  | // ignore unrecognized non-standard verbose option | 
|  | while (verbose_args[0] != '\0' | 
|  | && verbose_args[0] != ',') | 
|  | verbose_args++; | 
|  | } | 
|  | else if (verbose_args[0] == ',') | 
|  | { | 
|  | verbose_args++; | 
|  | } | 
|  | else | 
|  | goto verbose_arg_err; | 
|  |  | 
|  | if (verbose_args[0] == ',') | 
|  | verbose_args++; | 
|  | } | 
|  | while (verbose_args[0] != '\0'); | 
|  | } | 
|  | else if (option_string[len] == 'g' | 
|  | && option_string[len + 1] == 'c' | 
|  | && option_string[len + 2] == '\0') | 
|  | { | 
|  | // FIXME: we should add functions to boehm-gc that | 
|  | // toggle GC_print_stats, GC_PRINT_ADDRESS_MAP and | 
|  | // GC_print_back_height. | 
|  | return 0; | 
|  | } | 
|  | else if (option_string[len] == '\0') | 
|  | { | 
|  | gcj::verbose_class_flag = true; | 
|  | return 0; | 
|  | } | 
|  | else | 
|  | { | 
|  | // unrecognized option beginning with -verbose | 
|  | return -1; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | #ifdef INTERPRETER | 
|  | // This function loads the agent functions for JVMTI from the library indicated | 
|  | // by name.  It returns a negative value on failure, the value of which | 
|  | // indicates where ltdl failed, it also prints an error message. | 
|  | static jint | 
|  | load_jvmti_agent (const char *name) | 
|  | { | 
|  | #ifdef USE_LTDL | 
|  | if (lt_dlinit ()) | 
|  | { | 
|  | fprintf (stderr, | 
|  | "libgcj: Error in ltdl init while loading agent library.\n"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | lt_dlhandle lib = lt_dlopenext (name); | 
|  | if (!lib) | 
|  | { | 
|  | fprintf (stderr, | 
|  | "libgcj: Error opening agent library.\n"); | 
|  | return -2; | 
|  | } | 
|  |  | 
|  | if (lib) | 
|  | { | 
|  | jvmti_agentonload | 
|  | = (jvmti_agent_onload_func *) lt_dlsym (lib, "Agent_OnLoad"); | 
|  |  | 
|  | if (!jvmti_agentonload) | 
|  | { | 
|  | fprintf (stderr, | 
|  | "libgcj: Error finding agent function in library %s.\n", | 
|  | name); | 
|  | lt_dlclose (lib); | 
|  | lib = NULL; | 
|  | return -4; | 
|  | } | 
|  | else | 
|  | { | 
|  | jvmti_agentonunload | 
|  | = (jvmti_agent_onunload_func *) lt_dlsym (lib, "Agent_OnUnload"); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | fprintf (stderr, "libgcj: Library %s not found in library path.\n", name); | 
|  | return -3; | 
|  | } | 
|  |  | 
|  | #endif /* USE_LTDL */ | 
|  |  | 
|  | // If LTDL cannot be used, return an error code indicating this. | 
|  | return -99; | 
|  | } | 
|  | #endif // INTERPRETER | 
|  |  | 
|  | static jint | 
|  | parse_init_args (JvVMInitArgs* vm_args) | 
|  | { | 
|  | // if _Jv_Compiler_Properties is non-NULL then it needs to be | 
|  | // re-allocated dynamically. | 
|  | if (_Jv_Compiler_Properties) | 
|  | { | 
|  | const char** props = _Jv_Compiler_Properties; | 
|  | _Jv_Compiler_Properties = NULL; | 
|  |  | 
|  | for (int i = 0; props[i]; i++) | 
|  | { | 
|  | _Jv_Compiler_Properties = (const char**) _Jv_Realloc | 
|  | (_Jv_Compiler_Properties, | 
|  | (_Jv_Properties_Count + 1) * sizeof (const char*)); | 
|  | _Jv_Compiler_Properties[_Jv_Properties_Count++] = props[i]; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (vm_args == NULL) | 
|  | return 0; | 
|  |  | 
|  | for (int i = 0; i < vm_args->nOptions; ++i) | 
|  | { | 
|  | char* option_string = vm_args->options[i].optionString; | 
|  |  | 
|  | if (! strcmp (option_string, "vfprintf") | 
|  | || ! strcmp (option_string, "exit") | 
|  | || ! strcmp (option_string, "abort")) | 
|  | { | 
|  | // FIXME: we are required to recognize these, but for | 
|  | // now we don't handle them in any way. | 
|  | continue; | 
|  | } | 
|  | else if (! strncmp (option_string, | 
|  | "-verbose", sizeof ("-verbose") - 1)) | 
|  | { | 
|  | jint result = parse_verbose_args (option_string, | 
|  | vm_args->ignoreUnrecognized); | 
|  | if (result < 0) | 
|  | return result; | 
|  | } | 
|  | else if (! strncmp (option_string, "-D", 2)) | 
|  | { | 
|  | _Jv_Compiler_Properties = (const char**) _Jv_Realloc | 
|  | (_Jv_Compiler_Properties, | 
|  | (_Jv_Properties_Count + 1) * sizeof (char*)); | 
|  |  | 
|  | _Jv_Compiler_Properties[_Jv_Properties_Count++] = | 
|  | strdup (option_string + 2); | 
|  |  | 
|  | continue; | 
|  | } | 
|  | #ifdef INTERPRETER | 
|  | else if (! strncmp (option_string, "-agentlib", sizeof ("-agentlib") - 1)) | 
|  | { | 
|  | char *strPtr; | 
|  |  | 
|  | if (strlen(option_string) > (sizeof ("-agentlib:") - 1)) | 
|  | strPtr = &option_string[sizeof ("-agentlib:") - 1]; | 
|  | else | 
|  | { | 
|  | fprintf (stderr, | 
|  | "libgcj: Malformed agentlib argument %s: expected lib name\n", | 
|  | option_string); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | // These are optional arguments to pass to the agent library. | 
|  | jvmti_agent_opts = strchr (strPtr, '='); | 
|  |  | 
|  | if (! strncmp (strPtr, "jdwp", 4)) | 
|  | { | 
|  | // We want to run JDWP here so set the correct variables. | 
|  | remoteDebug = true; | 
|  | jdwpOptions = ++jvmti_agent_opts; | 
|  | } | 
|  | else | 
|  | { | 
|  | jint nameLength; | 
|  |  | 
|  | if (jvmti_agent_opts == NULL) | 
|  | nameLength = strlen (strPtr); | 
|  | else | 
|  | { | 
|  | nameLength = jvmti_agent_opts - strPtr; | 
|  | jvmti_agent_opts++; | 
|  | } | 
|  |  | 
|  | char lib_name[nameLength + 3 + 1]; | 
|  | strcpy (lib_name, "lib"); | 
|  | strncat (lib_name, strPtr, nameLength); | 
|  |  | 
|  | jint result = load_jvmti_agent (lib_name); | 
|  |  | 
|  | if (result < 0) | 
|  | { | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | // Mark JVMTI active | 
|  | JVMTI::enabled = true; | 
|  | } | 
|  |  | 
|  | continue; | 
|  | } | 
|  | else if (! strncmp (option_string, "-agentpath:", | 
|  | sizeof ("-agentpath:") - 1)) | 
|  | { | 
|  | char *strPtr; | 
|  |  | 
|  | if (strlen(option_string) > 10) | 
|  | strPtr = &option_string[10]; | 
|  | else | 
|  | { | 
|  | fprintf (stderr, | 
|  | "libgcj: Malformed agentlib argument %s: expected lib path\n", | 
|  | option_string); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | // These are optional arguments to pass to the agent library. | 
|  | jvmti_agent_opts = strchr (strPtr, '='); | 
|  |  | 
|  | jint nameLength; | 
|  |  | 
|  | if (jvmti_agent_opts == NULL) | 
|  | nameLength = strlen (strPtr); | 
|  | else | 
|  | { | 
|  | nameLength = jvmti_agent_opts - strPtr; | 
|  | jvmti_agent_opts++; | 
|  | } | 
|  |  | 
|  | char lib_name[nameLength + 3 + 1]; | 
|  | strcpy (lib_name, "lib"); | 
|  | strncat (lib_name, strPtr, nameLength); | 
|  | jint result = load_jvmti_agent (strPtr); | 
|  |  | 
|  | if (result < 0) | 
|  | { | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | // Mark JVMTI active | 
|  | JVMTI::enabled = true; | 
|  | continue; | 
|  | } | 
|  | #endif // INTERPRETER | 
|  | else | 
|  | { | 
|  | int r = -1; | 
|  | if (option_string[0] == '_') | 
|  | r = parse_x_arg (option_string + 1); | 
|  | else if (! strncmp (option_string, "-X", 2)) | 
|  | r = parse_x_arg (option_string + 2); | 
|  |  | 
|  | if (r == -1 && ! vm_args->ignoreUnrecognized) | 
|  | { | 
|  | fprintf (stderr, "libgcj: unknown option: %s\n", option_string); | 
|  | return -1; | 
|  | } | 
|  | } | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | jint | 
|  | _Jv_CreateJavaVM (JvVMInitArgs* vm_args) | 
|  | { | 
|  | using namespace gcj; | 
|  |  | 
|  | if (runtimeInitialized) | 
|  | return -1; | 
|  |  | 
|  | runtimeInitialized = true; | 
|  | startTime = _Jv_platform_gettimeofday(); | 
|  |  | 
|  | jint result = parse_init_args (vm_args); | 
|  | if (result < 0) | 
|  | return -1; | 
|  |  | 
|  | PROCESS_GCJ_PROPERTIES; | 
|  |  | 
|  | /* Threads must be initialized before the GC, so that it inherits the | 
|  | signal mask.  */ | 
|  | _Jv_InitThreads (); | 
|  | _Jv_InitGC (); | 
|  | _Jv_InitializeSyncMutex (); | 
|  |  | 
|  | #ifdef INTERPRETER | 
|  | _Jv_InitInterpreter (); | 
|  | #endif | 
|  |  | 
|  | #ifdef HANDLE_SEGV | 
|  | INIT_SEGV; | 
|  | #endif | 
|  |  | 
|  | #ifdef HANDLE_FPE | 
|  | INIT_FPE; | 
|  | #endif | 
|  |  | 
|  | /* Initialize Utf8 constants declared in jvm.h. */ | 
|  | void_signature = _Jv_makeUtf8Const ("()V", 3); | 
|  | clinit_name = _Jv_makeUtf8Const ("<clinit>", 8); | 
|  | init_name = _Jv_makeUtf8Const ("<init>", 6); | 
|  | finit_name = _Jv_makeUtf8Const ("finit$", 6); | 
|  |  | 
|  | /* Initialize built-in classes to represent primitive TYPEs. */ | 
|  | _Jv_InitPrimClass (&_Jv_byteClass,    "byte",    'B', 1); | 
|  | _Jv_InitPrimClass (&_Jv_shortClass,   "short",   'S', 2); | 
|  | _Jv_InitPrimClass (&_Jv_intClass,     "int",     'I', 4); | 
|  | _Jv_InitPrimClass (&_Jv_longClass,    "long",    'J', 8); | 
|  | _Jv_InitPrimClass (&_Jv_booleanClass, "boolean", 'Z', 1); | 
|  | _Jv_InitPrimClass (&_Jv_charClass,    "char",    'C', 2); | 
|  | _Jv_InitPrimClass (&_Jv_floatClass,   "float",   'F', 4); | 
|  | _Jv_InitPrimClass (&_Jv_doubleClass,  "double",  'D', 8); | 
|  | _Jv_InitPrimClass (&_Jv_voidClass,    "void",    'V', 0); | 
|  |  | 
|  | // We have to initialize this fairly early, to avoid circular class | 
|  | // initialization.  In particular we want to start the | 
|  | // initialization of ClassLoader before we start the initialization | 
|  | // of VMClassLoader. | 
|  | _Jv_InitClass (&java::lang::ClassLoader::class$); | 
|  |  | 
|  | // Set up the system class loader and the bootstrap class loader. | 
|  | gnu::gcj::runtime::ExtensionClassLoader::initialize(); | 
|  | java::lang::VMClassLoader::initialize(JvNewStringLatin1(TOOLEXECLIBDIR)); | 
|  |  | 
|  | _Jv_RegisterBootstrapPackages(); | 
|  |  | 
|  | no_memory = new java::lang::OutOfMemoryError; | 
|  |  | 
|  | #ifdef USE_LTDL | 
|  | LTDL_SET_PRELOADED_SYMBOLS (); | 
|  | #endif | 
|  |  | 
|  | _Jv_platform_initialize (); | 
|  |  | 
|  | _Jv_JNI_Init (); | 
|  |  | 
|  | #ifdef INTERPRETER | 
|  | _Jv_JVMTI_Init (); | 
|  | #endif | 
|  |  | 
|  | _Jv_GCInitializeFinalizers (&::gnu::gcj::runtime::FinalizerThread::finalizerReady); | 
|  |  | 
|  | // Start the GC finalizer thread.  A VirtualMachineError can be | 
|  | // thrown by the runtime if, say, threads aren't available. | 
|  | try | 
|  | { | 
|  | using namespace gnu::gcj::runtime; | 
|  | FinalizerThread *ft = new FinalizerThread (); | 
|  | ft->start (); | 
|  | } | 
|  | catch (java::lang::VirtualMachineError *ignore) | 
|  | { | 
|  | } | 
|  |  | 
|  | runtimeInitialized = true; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | void | 
|  | _Jv_RunMain (JvVMInitArgs *vm_args, jclass klass, const char *name, int argc, | 
|  | const char **argv, bool is_jar) | 
|  | { | 
|  | #ifndef DISABLE_MAIN_ARGS | 
|  | _Jv_SetArgs (argc, argv); | 
|  | #endif | 
|  |  | 
|  | java::lang::Runtime *runtime = NULL; | 
|  |  | 
|  | try | 
|  | { | 
|  | if (_Jv_CreateJavaVM (vm_args) < 0) | 
|  | { | 
|  | fprintf (stderr, "libgcj: couldn't create virtual machine\n"); | 
|  | exit (1); | 
|  | } | 
|  |  | 
|  | if (vm_args == NULL) | 
|  | gcj::vmArgs = JvConvertArgv(0, NULL); | 
|  | else | 
|  | { | 
|  | const char* vmArgs[vm_args->nOptions]; | 
|  | const char** vmPtr = vmArgs; | 
|  | struct _Jv_VMOption* optionPtr = vm_args->options; | 
|  | for (int i = 0; i < vm_args->nOptions; ++i) | 
|  | *vmPtr++ = (*optionPtr++).optionString; | 
|  | gcj::vmArgs = JvConvertArgv(vm_args->nOptions, vmArgs); | 
|  | } | 
|  |  | 
|  | // Get the Runtime here.  We want to initialize it before searching | 
|  | // for `main'; that way it will be set up if `main' is a JNI method. | 
|  | runtime = java::lang::Runtime::getRuntime (); | 
|  |  | 
|  | #ifdef DISABLE_MAIN_ARGS | 
|  | arg_vec = JvConvertArgv (0, 0); | 
|  | #else | 
|  | arg_vec = JvConvertArgv (argc - 1, argv + 1); | 
|  | #endif | 
|  |  | 
|  | using namespace gnu::java::lang; | 
|  | if (klass) | 
|  | main_thread = new MainThread (klass, arg_vec); | 
|  | else | 
|  | main_thread = new MainThread (JvNewStringUTF (name), | 
|  | arg_vec, is_jar); | 
|  | _Jv_AttachCurrentThread (main_thread); | 
|  |  | 
|  | #ifdef INTERPRETER | 
|  | // Start JVMTI if an agent function has been found. | 
|  | if (jvmti_agentonload) | 
|  | (*jvmti_agentonload) (_Jv_GetJavaVM (), jvmti_agent_opts, NULL); | 
|  |  | 
|  | // Start JDWP | 
|  | if (remoteDebug) | 
|  | { | 
|  | using namespace gnu::classpath::jdwp; | 
|  | VMVirtualMachine::initialize (); | 
|  | Jdwp *jdwp = new Jdwp (); | 
|  | jdwp->setDaemon (true); | 
|  | jdwp->configure (JvNewStringLatin1 (jdwpOptions)); | 
|  | jdwp->start (); | 
|  |  | 
|  | // Wait for JDWP to initialize and start | 
|  | jdwp->join (); | 
|  | } | 
|  | // Send VMInit | 
|  | if (JVMTI_REQUESTED_EVENT (VMInit)) | 
|  | _Jv_JVMTI_PostEvent (JVMTI_EVENT_VM_INIT, main_thread); | 
|  | #endif // INTERPRETER | 
|  | } | 
|  | catch (java::lang::Throwable *t) | 
|  | { | 
|  | java::lang::System::err->println (JvNewStringLatin1 | 
|  | ("Exception during runtime initialization")); | 
|  | t->printStackTrace(); | 
|  | if (runtime) | 
|  | java::lang::Runtime::exitNoChecksAccessor (1); | 
|  | // In case the runtime creation failed. | 
|  | ::exit (1); | 
|  | } | 
|  |  | 
|  | _Jv_ThreadRun (main_thread); | 
|  |  | 
|  | #ifdef INTERPRETER | 
|  | // Send VMDeath | 
|  | if (JVMTI_REQUESTED_EVENT (VMDeath)) | 
|  | { | 
|  | java::lang::Thread *thread = java::lang::Thread::currentThread (); | 
|  | JNIEnv *jni_env = _Jv_GetCurrentJNIEnv (); | 
|  | _Jv_JVMTI_PostEvent (JVMTI_EVENT_VM_DEATH, thread, jni_env); | 
|  | } | 
|  |  | 
|  | // Run JVMTI AgentOnUnload if it exists and an agent is loaded. | 
|  | if (jvmti_agentonunload) | 
|  | (*jvmti_agentonunload) (_Jv_GetJavaVM ()); | 
|  | #endif // INTERPRETER | 
|  |  | 
|  | // If we got here then something went wrong, as MainThread is not | 
|  | // supposed to terminate. | 
|  | ::exit (1); | 
|  | } | 
|  |  | 
|  | void | 
|  | _Jv_RunMain (jclass klass, const char *name, int argc, const char **argv, | 
|  | bool is_jar) | 
|  | { | 
|  | _Jv_RunMain (NULL, klass, name, argc, argv, is_jar); | 
|  | } | 
|  |  | 
|  | void | 
|  | JvRunMain (jclass klass, int argc, const char **argv) | 
|  | { | 
|  | _Jv_RunMain (klass, NULL, argc, argv, false); | 
|  | } | 
|  |  | 
|  | void | 
|  | JvRunMainName (const char *name, int argc, const char **argv) | 
|  | { | 
|  | _Jv_RunMain (NULL, name, argc, argv, false); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | // Parse a string and return a heap size. | 
|  | static size_t | 
|  | parse_memory_size (const char *spec) | 
|  | { | 
|  | char *end; | 
|  | unsigned long val = strtoul (spec, &end, 10); | 
|  | if (*end == 'k' || *end == 'K') | 
|  | val *= 1024; | 
|  | else if (*end == 'm' || *end == 'M') | 
|  | val *= 1048576; | 
|  | return (size_t) val; | 
|  | } | 
|  |  | 
|  | // Set the initial heap size.  This might be ignored by the GC layer. | 
|  | // This must be called before _Jv_RunMain. | 
|  | void | 
|  | _Jv_SetInitialHeapSize (const char *arg) | 
|  | { | 
|  | size_t size = parse_memory_size (arg); | 
|  | _Jv_GCSetInitialHeapSize (size); | 
|  | } | 
|  |  | 
|  | // Set the maximum heap size.  This might be ignored by the GC layer. | 
|  | // This must be called before _Jv_RunMain. | 
|  | void | 
|  | _Jv_SetMaximumHeapSize (const char *arg) | 
|  | { | 
|  | size_t size = parse_memory_size (arg); | 
|  | _Jv_GCSetMaximumHeapSize (size); | 
|  | } | 
|  |  | 
|  | void | 
|  | _Jv_SetStackSize (const char *arg) | 
|  | { | 
|  | size_t size = parse_memory_size (arg); | 
|  | gcj::stack_size = size; | 
|  | } | 
|  |  | 
|  | void * | 
|  | _Jv_Malloc (jsize size) | 
|  | { | 
|  | if (__builtin_expect (size == 0, false)) | 
|  | size = 1; | 
|  | void *ptr = malloc ((size_t) size); | 
|  | if (__builtin_expect (ptr == NULL, false)) | 
|  | throw no_memory; | 
|  | return ptr; | 
|  | } | 
|  |  | 
|  | void * | 
|  | _Jv_Realloc (void *ptr, jsize size) | 
|  | { | 
|  | if (__builtin_expect (size == 0, false)) | 
|  | size = 1; | 
|  | ptr = realloc (ptr, (size_t) size); | 
|  | if (__builtin_expect (ptr == NULL, false)) | 
|  | throw no_memory; | 
|  | return ptr; | 
|  | } | 
|  |  | 
|  | void * | 
|  | _Jv_MallocUnchecked (jsize size) | 
|  | { | 
|  | if (__builtin_expect (size == 0, false)) | 
|  | size = 1; | 
|  | return malloc ((size_t) size); | 
|  | } | 
|  |  | 
|  | void | 
|  | _Jv_Free (void* ptr) | 
|  | { | 
|  | return free (ptr); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | // In theory, these routines can be #ifdef'd away on machines which | 
|  | // support divide overflow signals.  However, we never know if some | 
|  | // code might have been compiled with "-fuse-divide-subroutine", so we | 
|  | // always include them in libgcj. | 
|  |  | 
|  | jint | 
|  | _Jv_divI (jint dividend, jint divisor) | 
|  | { | 
|  | if (__builtin_expect (divisor == 0, false)) | 
|  | { | 
|  | java::lang::ArithmeticException *arithexception | 
|  | = new java::lang::ArithmeticException (JvNewStringLatin1 ("/ by zero")); | 
|  | throw arithexception; | 
|  | } | 
|  |  | 
|  | if (dividend == (jint) 0x80000000L && divisor == -1) | 
|  | return dividend; | 
|  |  | 
|  | return dividend / divisor; | 
|  | } | 
|  |  | 
|  | jint | 
|  | _Jv_remI (jint dividend, jint divisor) | 
|  | { | 
|  | if (__builtin_expect (divisor == 0, false)) | 
|  | { | 
|  | java::lang::ArithmeticException *arithexception | 
|  | = new java::lang::ArithmeticException (JvNewStringLatin1 ("/ by zero")); | 
|  | throw arithexception; | 
|  | } | 
|  |  | 
|  | if (dividend == (jint) 0x80000000L && divisor == -1) | 
|  | return 0; | 
|  |  | 
|  | return dividend % divisor; | 
|  | } | 
|  |  | 
|  | jlong | 
|  | _Jv_divJ (jlong dividend, jlong divisor) | 
|  | { | 
|  | if (__builtin_expect (divisor == 0, false)) | 
|  | { | 
|  | java::lang::ArithmeticException *arithexception | 
|  | = new java::lang::ArithmeticException (JvNewStringLatin1 ("/ by zero")); | 
|  | throw arithexception; | 
|  | } | 
|  |  | 
|  | if (dividend == (jlong) 0x8000000000000000LL && divisor == -1) | 
|  | return dividend; | 
|  |  | 
|  | return dividend / divisor; | 
|  | } | 
|  |  | 
|  | jlong | 
|  | _Jv_remJ (jlong dividend, jlong divisor) | 
|  | { | 
|  | if (__builtin_expect (divisor == 0, false)) | 
|  | { | 
|  | java::lang::ArithmeticException *arithexception | 
|  | = new java::lang::ArithmeticException (JvNewStringLatin1 ("/ by zero")); | 
|  | throw arithexception; | 
|  | } | 
|  |  | 
|  | if (dividend == (jlong) 0x8000000000000000LL && divisor == -1) | 
|  | return 0; | 
|  |  | 
|  | return dividend % divisor; | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | // Return true if SELF_KLASS can access a field or method in | 
|  | // OTHER_KLASS.  The field or method's access flags are specified in | 
|  | // FLAGS. | 
|  | jboolean | 
|  | _Jv_CheckAccess (jclass self_klass, jclass other_klass, jint flags) | 
|  | { | 
|  | using namespace java::lang::reflect; | 
|  | return ((self_klass == other_klass) | 
|  | || ((flags & Modifier::PUBLIC) != 0) | 
|  | || (((flags & Modifier::PROTECTED) != 0) | 
|  | && _Jv_IsAssignableFromSlow (self_klass, other_klass)) | 
|  | || (((flags & Modifier::PRIVATE) == 0) | 
|  | && _Jv_ClassNameSamePackage (self_klass->name, | 
|  | other_klass->name))); | 
|  | } | 
|  |  | 
|  | // Prepend GCJ_VERSIONED_LIBDIR to a module search path stored in a C | 
|  | // char array, if the path is not already prefixed by | 
|  | // GCJ_VERSIONED_LIBDIR.  Return a newly JvMalloc'd char buffer.  The | 
|  | // result should be freed using JvFree. | 
|  | char* | 
|  | _Jv_PrependVersionedLibdir (char* libpath) | 
|  | { | 
|  | char* retval = 0; | 
|  |  | 
|  | if (libpath && libpath[0] != '\0') | 
|  | { | 
|  | if (! strncmp (libpath, | 
|  | GCJ_VERSIONED_LIBDIR, | 
|  | sizeof (GCJ_VERSIONED_LIBDIR) - 1)) | 
|  | { | 
|  | // LD_LIBRARY_PATH is already prefixed with | 
|  | // GCJ_VERSIONED_LIBDIR. | 
|  | retval = (char*) _Jv_Malloc (strlen (libpath) + 1); | 
|  | strcpy (retval, libpath); | 
|  | } | 
|  | else | 
|  | { | 
|  | // LD_LIBRARY_PATH is not prefixed with | 
|  | // GCJ_VERSIONED_LIBDIR. | 
|  | char path_sep[2]; | 
|  | path_sep[0] = (char) _Jv_platform_path_separator; | 
|  | path_sep[1] = '\0'; | 
|  | jsize total = ((sizeof (GCJ_VERSIONED_LIBDIR) - 1) | 
|  | + 1 /* path separator */ + strlen (libpath) + 1); | 
|  | retval = (char*) _Jv_Malloc (total); | 
|  | strcpy (retval, GCJ_VERSIONED_LIBDIR); | 
|  | strcat (retval, path_sep); | 
|  | strcat (retval, libpath); | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | // LD_LIBRARY_PATH was not specified or is empty. | 
|  | retval = (char*) _Jv_Malloc (sizeof (GCJ_VERSIONED_LIBDIR)); | 
|  | strcpy (retval, GCJ_VERSIONED_LIBDIR); | 
|  | } | 
|  |  | 
|  | return retval; | 
|  | } |