aboutsummaryrefslogtreecommitdiff
path: root/libjava/prims.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/prims.cc')
-rw-r--r--libjava/prims.cc602
1 files changed, 602 insertions, 0 deletions
diff --git a/libjava/prims.cc b/libjava/prims.cc
new file mode 100644
index 0000000..265e281
--- /dev/null
+++ b/libjava/prims.cc
@@ -0,0 +1,602 @@
+// prims.cc - Code for core of runtime environment.
+
+/* Copyright (C) 1998, 1999 Cygnus Solutions
+
+ 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 <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef HANDLE_SEGV
+#include <signal.h>
+#endif
+
+#pragma implementation "java-array.h"
+
+#include <cni.h>
+#include <jvm.h>
+
+#include <java/lang/Class.h>
+#include <java/lang/Runtime.h>
+#include <java/lang/String.h>
+#include <java/lang/Thread.h>
+#include <java/lang/ThreadGroup.h>
+#include <java/lang/FirstThread.h>
+#include <java/lang/ArrayIndexOutOfBoundsException.h>
+#include <java/lang/ClassFormatError.h>
+#include <java/lang/ClassCastException.h>
+#include <java/lang/NegativeArraySizeException.h>
+#include <java/lang/NullPointerException.h>
+#include <java/lang/OutOfMemoryError.h>
+#include <java/lang/ArrayStoreException.h>
+#include <java/lang/System.h>
+#include <java/lang/reflect/Modifier.h>
+#include <java/io/PrintStream.h>
+
+#define ObjectClass _CL_Q34java4lang6Object
+extern java::lang::Class ObjectClass;
+
+// We allocate a single OutOfMemoryError exception which we keep
+// around for use if we run out of memory.
+static java::lang::OutOfMemoryError *no_memory;
+
+// Largest representable size_t.
+#define SIZE_T_MAX ((size_t) (~ (size_t) 0))
+
+
+
+jboolean
+_Jv_equalUtf8Consts (Utf8Const* a, Utf8Const *b)
+{
+ register int len;
+ register _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 = (_Jv_ushort *)a->data;
+ bptr = (_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);
+ register unsigned char* ptr = (unsigned char*) a->data;
+ register 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;
+}
+
+/* Count the number of Unicode chars encoded in a given Ut8 string. */
+int
+_Jv_strLengthUtf8(char* str, int len)
+{
+ register unsigned char* ptr;
+ register 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.
+ */
+static jint
+hashUtf8String (char* str, int len)
+{
+ register unsigned char* ptr = (unsigned char*) str;
+ register 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;
+}
+
+_Jv_Utf8Const *
+_Jv_makeUtf8Const (char* s, int len)
+{
+ if (len < 0)
+ len = strlen (s);
+ Utf8Const* m = (Utf8Const*) _Jv_AllocBytes (sizeof(Utf8Const) + len + 1);
+ if (! m)
+ JvThrow (no_memory);
+ memcpy (m->data, s, len);
+ m->data[len] = 0;
+ m->length = len;
+ m->hash = hashUtf8String (s, len) & 0xFFFF;
+ return (m);
+}
+
+
+
+#ifdef 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 DEBUG
+ fprintf (stderr,
+ "libgcj failure: %s\n in function %s, file %s, line %d\n",
+ message, function, file, line);
+#else
+ java::io::PrintStream *err = java::lang::System::err;
+ err->print(JvNewStringLatin1 ("libgcj failure: "));
+ err->println(JvNewStringLatin1 (message));
+ err->flush();
+#endif
+ 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)
+{
+ JvThrow (new java::lang::ArrayIndexOutOfBoundsException
+ (java::lang::String::valueOf(bad_index)));
+}
+
+void*
+_Jv_CheckCast (jclass c, jobject obj)
+{
+ if (obj != NULL && ! c->isAssignableFrom(obj->getClass()))
+ JvThrow (new java::lang::ClassCastException);
+ return obj;
+}
+
+void
+_Jv_CheckArrayStore (jobject arr, jobject obj)
+{
+ if (obj)
+ {
+ JvAssert (arr != NULL);
+ jclass arr_class = arr->getClass();
+ JvAssert (arr_class->isArray());
+ jclass elt_class = arr_class->getComponentType();
+ jclass obj_class = obj->getClass();
+ if (! elt_class->isAssignableFrom(obj_class))
+ JvThrow (new java::lang::ArrayStoreException);
+ }
+}
+
+
+
+// Allocate some unscanned memory and throw an exception if no memory.
+void *
+_Jv_AllocBytesChecked (jsize size)
+{
+ void *r = _Jv_AllocBytes (size);
+ if (! r)
+ _Jv_Throw (no_memory);
+ return r;
+}
+
+// Allocate a new object of class C. SIZE is the size of the object
+// to allocate. You might think this is redundant, but it isn't; some
+// classes, such as String, aren't of fixed size.
+jobject
+_Jv_AllocObject (jclass c, jint size)
+{
+ _Jv_InitClass (c);
+
+ jobject obj = (jobject) _Jv_AllocObj (size);
+ if (! obj)
+ JvThrow (no_memory);
+ *((_Jv_VTable **) obj) = c->vtable;
+
+ // If this class has inherited finalize from Object, then don't
+ // bother registering a finalizer. We know that finalize() is the
+ // very first method after the dummy entry. If this turns out to be
+ // unreliable, a more robust implementation can be written. Such an
+ // implementation would look for Object.finalize in Object's method
+ // table at startup, and then use that information to find the
+ // appropriate index in the method vector.
+ if (c->vtable->method[1] != ObjectClass.vtable->method[1])
+ _Jv_RegisterFinalizer (obj, _Jv_FinalizeObject);
+
+ return obj;
+}
+
+// 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)
+{
+ if (count < 0)
+ JvThrow (new java::lang::NegativeArraySizeException);
+
+ // Check for overflow.
+ if ((size_t) count > (SIZE_T_MAX - sizeof (__JArray)) / sizeof (jobject))
+ JvThrow (no_memory);
+
+ size_t size = count * sizeof (jobject) + sizeof (__JArray);
+ jclass clas = _Jv_FindArrayClass (elementClass);
+ jobjectArray obj = (jobjectArray) _Jv_AllocArray (size);
+ if (! obj)
+ JvThrow (no_memory);
+ obj->length = count;
+ jobject* ptr = elements(obj);
+ // We know the allocator returns zeroed memory. So don't bother
+ // zeroing it again.
+ if (init)
+ {
+ while (--count >= 0)
+ *ptr++ = init;
+ }
+ // Set the vtbl last to avoid problems if the GC happens during the
+ // window in this function between the allocation and this
+ // assignment.
+ *((_Jv_VTable **) obj) = clas->vtable;
+ 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 (count < 0)
+ JvThrow (new java::lang::NegativeArraySizeException ());
+
+ // Check for overflow.
+ if ((size_t) count > (SIZE_T_MAX - sizeof (__JArray)) / elsize)
+ JvThrow (no_memory);
+
+ __JArray *arr = (__JArray*) _Jv_AllocObj (sizeof (__JArray)
+ + elsize * count);
+ if (! arr)
+ JvThrow (no_memory);
+ arr->length = count;
+ // Note that we assume we are given zeroed memory by the allocator.
+
+ jclass klass = _Jv_FindArrayClass (eltype);
+ // Set the vtbl last to avoid problems if the GC happens during the
+ // window in this function between the allocation and this
+ // assignment.
+ *((_Jv_VTable **) arr) = klass->vtable;
+ return arr;
+}
+
+jcharArray
+JvNewCharArray (jint length)
+{
+ return (jcharArray) _Jv_NewPrimArray (JvPrimClass (char), length);
+}
+
+jbooleanArray
+JvNewBooleanArray (jint length)
+{
+ return (jbooleanArray) _Jv_NewPrimArray (JvPrimClass (boolean), length);
+}
+
+jbyteArray
+JvNewByteArray (jint length)
+{
+ return (jbyteArray) _Jv_NewPrimArray (JvPrimClass (byte), length);
+}
+
+jshortArray
+JvNewShortArray (jint length)
+{
+ return (jshortArray) _Jv_NewPrimArray (JvPrimClass (short), length);
+}
+
+jintArray
+JvNewIntArray (jint length)
+{
+ return (jintArray) _Jv_NewPrimArray (JvPrimClass (int), length);
+}
+
+jlongArray
+JvNewLongArray (jint length)
+{
+ return (jlongArray) _Jv_NewPrimArray (JvPrimClass (long), length);
+}
+
+jfloatArray
+JvNewFloatArray (jint length)
+{
+ return (jfloatArray) _Jv_NewPrimArray (JvPrimClass (float), length);
+}
+
+jdoubleArray
+JvNewDoubleArray (jint length)
+{
+ return (jdoubleArray) _Jv_NewPrimArray (JvPrimClass (double), length);
+}
+
+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);
+ }
+ JvFail ("newarray - bad type code");
+ return NULL; // Placate compiler.
+}
+
+jobject
+_Jv_NewMultiArray (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_NewMultiArray (element_type, dimensions - 1,
+ sizes + 1);
+ }
+
+ return result;
+}
+
+jobject
+_Jv_NewMultiArray (jclass array_type, jint dimensions, ...)
+{
+ va_list args;
+ jint sizes[dimensions];
+ va_start (args, dimensions);
+ for (int i = 0; i < dimensions; ++i)
+ {
+ jint size = va_arg (args, jint);
+ sizes[i] = size;
+ }
+ va_end (args);
+
+ return _Jv_NewMultiArray (array_type, dimensions, sizes);
+}
+
+
+
+#ifdef HANDLE_SEGV
+
+static java::lang::NullPointerException *nullp;
+
+static void
+catch_segv (int)
+{
+ // Don't run `new' in a signal handler, so we always throw the same
+ // null pointer exception.
+ _Jv_Throw (nullp);
+}
+
+#endif /* HANDLE_SEGV */
+
+class _Jv_PrimClass : public java::lang::Class
+{
+public:
+ // FIXME: calling convention is weird. If we use the natural types
+ // then the compiler will complain because they aren't Java types.
+ _Jv_PrimClass (jobject cname, jbyte sig, jint len)
+ {
+ using namespace java::lang::reflect;
+
+ // We must initialize every field of the class. We do this in
+ // the same order they are declared in Class.h.
+ next = NULL;
+ name = _Jv_makeUtf8Const ((char *) cname, -1);
+ accflags = Modifier::PUBLIC | Modifier::FINAL;
+ superclass = NULL;
+ constants.size = 0;
+ constants.tags = NULL;
+ constants.data = NULL;
+ methods = NULL;
+ method_count = sig;
+ vtable_method_count = 0;
+ fields = NULL;
+ size_in_bytes = len;
+ field_count = 0;
+ static_field_count = 0;
+ vtable = JV_PRIMITIVE_VTABLE;
+ interfaces = NULL;
+ loader = NULL;
+ interface_count = 0;
+ state = 0; // FIXME.
+ thread = NULL;
+ }
+};
+
+#define DECLARE_PRIM_TYPE(NAME, SIG, LEN) \
+ _Jv_PrimClass _Jv_##NAME##Class((jobject) #NAME, (jbyte) SIG, (jint) LEN)
+
+DECLARE_PRIM_TYPE(byte, 'B', 1);
+DECLARE_PRIM_TYPE(short, 'S', 2);
+DECLARE_PRIM_TYPE(int, 'I', 4);
+DECLARE_PRIM_TYPE(long, 'J', 8);
+DECLARE_PRIM_TYPE(boolean, 'Z', 1);
+DECLARE_PRIM_TYPE(char, 'C', 2);
+DECLARE_PRIM_TYPE(float, 'F', 4);
+DECLARE_PRIM_TYPE(double, 'D', 8);
+DECLARE_PRIM_TYPE(void, 'V', 0);
+
+jclass
+_Jv_FindClassFromSignature (char *sig, java::lang::ClassLoader *loader)
+{
+ switch (*sig)
+ {
+ case 'B':
+ return JvPrimClass (byte);
+ case 'S':
+ return JvPrimClass (short);
+ case 'I':
+ return JvPrimClass (int);
+ case 'J':
+ return JvPrimClass (long);
+ case 'Z':
+ return JvPrimClass (boolean);
+ case 'C':
+ return JvPrimClass (char);
+ case 'F':
+ return JvPrimClass (float);
+ case 'D':
+ return JvPrimClass (double);
+ case 'V':
+ return JvPrimClass (void);
+ case 'L':
+ {
+ int i;
+ for (i = 1; sig[i] && sig[i] != ';'; ++i)
+ ;
+ _Jv_Utf8Const *name = _Jv_makeUtf8Const (&sig[1], i - 1);
+ return _Jv_FindClass (name, loader);
+ }
+ case '[':
+ return _Jv_FindArrayClass (_Jv_FindClassFromSignature (&sig[1], loader));
+ }
+ JvFail ("couldn't understand class signature");
+ return NULL; // Placate compiler.
+}
+
+
+
+JArray<jstring> *
+JvConvertArgv (int argc, const char **argv)
+{
+ if (argc < 0)
+ argc = 0;
+ jobjectArray ar = JvNewObjectArray(argc, &StringClass, NULL);
+ jobject* ptr = elements(ar);
+ for (int i = 0; i < argc; i++)
+ {
+ const char *arg = argv[i];
+ // FIXME - should probably use JvNewStringUTF.
+ *ptr++ = JvNewStringLatin1(arg, strlen(arg));
+ }
+ 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 jobject arg_vec;
+
+// The primary threadgroup.
+static java::lang::ThreadGroup *main_group;
+
+// The primary thread.
+static java::lang::Thread *main_thread;
+
+void
+JvRunMain (jclass klass, int argc, const char **argv)
+{
+#ifdef HANDLE_SEGV
+ nullp = new java::lang::NullPointerException ();
+
+ struct sigaction act;
+ act.sa_handler = catch_segv;
+ sigemptyset (&act.sa_mask);
+ act.sa_flags = 0;
+ sigaction (SIGSEGV, &act, NULL);
+#endif
+
+ no_memory = new java::lang::OutOfMemoryError;
+
+ arg_vec = JvConvertArgv (argc - 1, argv + 1);
+ main_group = new java::lang::ThreadGroup (23);
+ main_thread = new java::lang::FirstThread (main_group, klass, arg_vec);
+
+ main_thread->start();
+ _Jv_ThreadWait ();
+
+ java::lang::Runtime::getRuntime ()->exit (0);
+}
+
+
+
+void *
+_Jv_Malloc (jsize size)
+{
+ if (size == 0)
+ size = 1;
+ void *ptr = malloc ((size_t) size);
+ if (ptr == NULL)
+ JvThrow (no_memory);
+ return ptr;
+}
+
+void
+_Jv_Free (void* ptr)
+{
+ return free (ptr);
+}