source: trunk/third/gcc/libjava/prims.cc @ 18474

Revision 18474, 27.8 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18473, which included commits to RCS files with non-trunk default branches.
Line 
1// prims.cc - Code for core of runtime environment.
2
3/* Copyright (C) 1998, 1999, 2000, 2001, 2002  Free Software Foundation
4
5   This file is part of libgcj.
6
7This software is copyrighted work licensed under the terms of the
8Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
9details.  */
10
11#include <config.h>
12#include <platform.h>
13
14#include <stdlib.h>
15#include <stdarg.h>
16#include <stdio.h>
17#include <string.h>
18#include <signal.h>
19
20#ifdef HAVE_UNISTD_H
21#include <unistd.h>
22#endif
23
24#include <gcj/cni.h>
25#include <jvm.h>
26#include <java-signal.h>
27#include <java-threads.h>
28
29#ifdef ENABLE_JVMPI
30#include <jvmpi.h>
31#include <java/lang/ThreadGroup.h>
32#endif
33
34#ifndef DISABLE_GETENV_PROPERTIES
35#include <ctype.h>
36#include <java-props.h>
37#define PROCESS_GCJ_PROPERTIES process_gcj_properties()
38#else
39#define PROCESS_GCJ_PROPERTIES
40#endif // DISABLE_GETENV_PROPERTIES
41
42#include <java/lang/Class.h>
43#include <java/lang/ClassLoader.h>
44#include <java/lang/Runtime.h>
45#include <java/lang/String.h>
46#include <java/lang/Thread.h>
47#include <java/lang/ThreadGroup.h>
48#include <java/lang/ArrayIndexOutOfBoundsException.h>
49#include <java/lang/ArithmeticException.h>
50#include <java/lang/ClassFormatError.h>
51#include <java/lang/InternalError.h>
52#include <java/lang/NegativeArraySizeException.h>
53#include <java/lang/NullPointerException.h>
54#include <java/lang/OutOfMemoryError.h>
55#include <java/lang/System.h>
56#include <java/lang/reflect/Modifier.h>
57#include <java/io/PrintStream.h>
58#include <java/lang/UnsatisfiedLinkError.h>
59#include <java/lang/VirtualMachineError.h>
60#include <gnu/gcj/runtime/VMClassLoader.h>
61#include <gnu/gcj/runtime/FinalizerThread.h>
62#include <gnu/gcj/runtime/FirstThread.h>
63
64#ifdef USE_LTDL
65#include <ltdl.h>
66#endif
67
68// We allocate a single OutOfMemoryError exception which we keep
69// around for use if we run out of memory.
70static java::lang::OutOfMemoryError *no_memory;
71
72// Largest representable size_t.
73#define SIZE_T_MAX ((size_t) (~ (size_t) 0))
74
75static const char *no_properties[] = { NULL };
76
77// Properties set at compile time.
78const char **_Jv_Compiler_Properties = no_properties;
79
80// The JAR file to add to the beginning of java.class.path.
81const char *_Jv_Jar_Class_Path;
82
83#ifndef DISABLE_GETENV_PROPERTIES
84// Property key/value pairs.
85property_pair *_Jv_Environment_Properties;
86#endif
87
88// The name of this executable.
89static char *_Jv_execName;
90
91// Stash the argv pointer to benefit native libraries that need it.
92const char **_Jv_argv;
93int _Jv_argc;
94
95#ifdef ENABLE_JVMPI
96// Pointer to JVMPI notification functions.
97void (*_Jv_JVMPI_Notify_OBJECT_ALLOC) (JVMPI_Event *event);
98void (*_Jv_JVMPI_Notify_THREAD_START) (JVMPI_Event *event);
99void (*_Jv_JVMPI_Notify_THREAD_END) (JVMPI_Event *event);
100#endif
101
102
103extern "C" void _Jv_ThrowSignal (jthrowable) __attribute ((noreturn));
104
105// Just like _Jv_Throw, but fill in the stack trace first.  Although
106// this is declared extern in order that its name not be mangled, it
107// is not intended to be used outside this file.
108void
109_Jv_ThrowSignal (jthrowable throwable)
110{
111  throwable->fillInStackTrace ();
112  throw throwable;
113}
114 
115#ifdef HANDLE_SEGV
116static java::lang::NullPointerException *nullp;
117
118SIGNAL_HANDLER (catch_segv)
119{
120  MAKE_THROW_FRAME (nullp);
121  _Jv_ThrowSignal (nullp);
122}
123#endif
124
125static java::lang::ArithmeticException *arithexception;
126
127#ifdef HANDLE_FPE
128SIGNAL_HANDLER (catch_fpe)
129{
130#ifdef HANDLE_DIVIDE_OVERFLOW
131  HANDLE_DIVIDE_OVERFLOW;
132#else
133  MAKE_THROW_FRAME (arithexception);
134#endif
135  _Jv_ThrowSignal (arithexception);
136}
137#endif
138
139
140
141jboolean
142_Jv_equalUtf8Consts (Utf8Const* a, Utf8Const *b)
143{
144  int len;
145  _Jv_ushort *aptr, *bptr;
146  if (a == b)
147    return true;
148  if (a->hash != b->hash)
149    return false;
150  len = a->length;
151  if (b->length != len)
152    return false;
153  aptr = (_Jv_ushort *)a->data;
154  bptr = (_Jv_ushort *)b->data;
155  len = (len + 1) >> 1;
156  while (--len >= 0)
157    if (*aptr++ != *bptr++)
158      return false;
159  return true;
160}
161
162/* True iff A is equal to STR.
163   HASH is STR->hashCode(). 
164*/
165
166jboolean
167_Jv_equal (Utf8Const* a, jstring str, jint hash)
168{
169  if (a->hash != (_Jv_ushort) hash)
170    return false;
171  jint len = str->length();
172  jint i = 0;
173  jchar *sptr = _Jv_GetStringChars (str);
174  unsigned char* ptr = (unsigned char*) a->data;
175  unsigned char* limit = ptr + a->length;
176  for (;; i++, sptr++)
177    {
178      int ch = UTF8_GET (ptr, limit);
179      if (i == len)
180        return ch < 0;
181      if (ch != *sptr)
182        return false;
183    }
184  return true;
185}
186
187/* Like _Jv_equal, but stop after N characters.  */
188jboolean
189_Jv_equaln (Utf8Const *a, jstring str, jint n)
190{
191  jint len = str->length();
192  jint i = 0;
193  jchar *sptr = _Jv_GetStringChars (str);
194  unsigned char* ptr = (unsigned char*) a->data;
195  unsigned char* limit = ptr + a->length;
196  for (; n-- > 0; i++, sptr++)
197    {
198      int ch = UTF8_GET (ptr, limit);
199      if (i == len)
200        return ch < 0;
201      if (ch != *sptr)
202        return false;
203    }
204  return true;
205}
206
207/* Count the number of Unicode chars encoded in a given Ut8 string. */
208int
209_Jv_strLengthUtf8(char* str, int len)
210{
211  unsigned char* ptr;
212  unsigned char* limit;
213  int str_length;
214
215  ptr = (unsigned char*) str;
216  limit = ptr + len;
217  str_length = 0;
218  for (; ptr < limit; str_length++)
219    {
220      if (UTF8_GET (ptr, limit) < 0)
221        return (-1);
222    }
223  return (str_length);
224}
225
226/* Calculate a hash value for a string encoded in Utf8 format.
227 * This returns the same hash value as specified or java.lang.String.hashCode.
228 */
229static jint
230hashUtf8String (char* str, int len)
231{
232  unsigned char* ptr = (unsigned char*) str;
233  unsigned char* limit = ptr + len;
234  jint hash = 0;
235
236  for (; ptr < limit;)
237    {
238      int ch = UTF8_GET (ptr, limit);
239      /* Updated specification from
240         http://www.javasoft.com/docs/books/jls/clarify.html. */
241      hash = (31 * hash) + ch;
242    }
243  return hash;
244}
245
246_Jv_Utf8Const *
247_Jv_makeUtf8Const (char* s, int len)
248{
249  if (len < 0)
250    len = strlen (s);
251  Utf8Const* m = (Utf8Const*) _Jv_AllocBytes (sizeof(Utf8Const) + len + 1);
252  memcpy (m->data, s, len);
253  m->data[len] = 0;
254  m->length = len;
255  m->hash = hashUtf8String (s, len) & 0xFFFF;
256  return (m);
257}
258
259_Jv_Utf8Const *
260_Jv_makeUtf8Const (jstring string)
261{
262  jint hash = string->hashCode ();
263  jint len = _Jv_GetStringUTFLength (string);
264
265  Utf8Const* m = (Utf8Const*)
266    _Jv_AllocBytes (sizeof(Utf8Const) + len + 1);
267
268  m->hash = hash;
269  m->length = len;
270
271  _Jv_GetStringUTFRegion (string, 0, string->length (), m->data);
272  m->data[len] = 0;
273 
274  return m;
275}
276
277
278
279#ifdef DEBUG
280void
281_Jv_Abort (const char *function, const char *file, int line,
282           const char *message)
283#else
284void
285_Jv_Abort (const char *, const char *, int, const char *message)
286#endif
287{
288#ifdef DEBUG
289  fprintf (stderr,
290           "libgcj failure: %s\n   in function %s, file %s, line %d\n",
291           message, function, file, line);
292#else
293  fprintf (stderr, "libgcj failure: %s\n", message);
294#endif
295  abort ();
296}
297
298static void
299fail_on_finalization (jobject)
300{
301  JvFail ("object was finalized");
302}
303
304void
305_Jv_GCWatch (jobject obj)
306{
307  _Jv_RegisterFinalizer (obj, fail_on_finalization);
308}
309
310void
311_Jv_ThrowBadArrayIndex(jint bad_index)
312{
313  throw new java::lang::ArrayIndexOutOfBoundsException
314    (java::lang::String::valueOf (bad_index));
315}
316
317void
318_Jv_ThrowNullPointerException ()
319{
320  throw new java::lang::NullPointerException;
321}
322
323// Explicitly throw a no memory exception.
324// The collector calls this when it encounters an out-of-memory condition.
325void _Jv_ThrowNoMemory()
326{
327  throw no_memory;
328}
329
330#ifdef ENABLE_JVMPI
331static void
332jvmpi_notify_alloc(jclass klass, jint size, jobject obj)
333{
334  // Service JVMPI allocation request.
335  if (__builtin_expect (_Jv_JVMPI_Notify_OBJECT_ALLOC != 0, false))
336    {
337      JVMPI_Event event;
338
339      event.event_type = JVMPI_EVENT_OBJECT_ALLOC;
340      event.env_id = NULL;
341      event.u.obj_alloc.arena_id = 0;
342      event.u.obj_alloc.class_id = (jobjectID) klass;
343      event.u.obj_alloc.is_array = 0;
344      event.u.obj_alloc.size = size;
345      event.u.obj_alloc.obj_id = (jobjectID) obj;
346
347      // FIXME:  This doesn't look right for the Boehm GC.  A GC may
348      // already be in progress.  _Jv_DisableGC () doesn't wait for it.
349      // More importantly, I don't see the need for disabling GC, since we
350      // blatantly have a pointer to obj on our stack, ensuring that the
351      // object can't be collected.  Even for a nonconservative collector,
352      // it appears to me that this must be true, since we are about to
353      // return obj. Isn't this whole approach way too intrusive for
354      // a useful profiling interface?                  - HB
355      _Jv_DisableGC ();
356      (*_Jv_JVMPI_Notify_OBJECT_ALLOC) (&event);
357      _Jv_EnableGC ();
358    }
359}
360#else /* !ENABLE_JVMPI */
361# define jvmpi_notify_alloc(klass,size,obj) /* do nothing */
362#endif
363
364// Allocate a new object of class KLASS.  SIZE is the size of the object
365// to allocate.  You might think this is redundant, but it isn't; some
366// classes, such as String, aren't of fixed size.
367// First a version that assumes that we have no finalizer, and that
368// the class is already initialized.
369// If we know that JVMPI is disabled, this can be replaced by a direct call
370// to the allocator for the appropriate GC.
371jobject
372_Jv_AllocObjectNoInitNoFinalizer (jclass klass, jint size)
373{
374  jobject obj = (jobject) _Jv_AllocObj (size, klass);
375  jvmpi_notify_alloc (klass, size, obj);
376  return obj;
377}
378
379// And now a version that initializes if necessary.
380jobject
381_Jv_AllocObjectNoFinalizer (jclass klass, jint size)
382{
383  _Jv_InitClass (klass);
384  jobject obj = (jobject) _Jv_AllocObj (size, klass);
385  jvmpi_notify_alloc (klass, size, obj);
386  return obj;
387}
388
389// And now the general version that registers a finalizer if necessary.
390jobject
391_Jv_AllocObject (jclass klass, jint size)
392{
393  jobject obj = _Jv_AllocObjectNoFinalizer (klass, size);
394
395  // We assume that the compiler only generates calls to this routine
396  // if there really is an interesting finalizer.
397  // Unfortunately, we still have to the dynamic test, since there may
398  // be cni calls to this routine.
399  // Nore that on IA64 get_finalizer() returns the starting address of the
400  // function, not a function pointer.  Thus this still works.
401  if (klass->vtable->get_finalizer ()
402      != java::lang::Object::class$.vtable->get_finalizer ())
403    _Jv_RegisterFinalizer (obj, _Jv_FinalizeObject);
404  return obj;
405}
406
407// A version of the above that assumes the object contains no pointers,
408// and requires no finalization.  This can't happen if we need pointers
409// to locks.
410#ifdef JV_HASH_SYNCHRONIZATION
411jobject
412_Jv_AllocPtrFreeObject (jclass klass, jint size)
413{
414  _Jv_InitClass (klass);
415
416  jobject obj = (jobject) _Jv_AllocPtrFreeObj (size, klass);
417
418#ifdef ENABLE_JVMPI
419  // Service JVMPI request.
420
421  if (__builtin_expect (_Jv_JVMPI_Notify_OBJECT_ALLOC != 0, false))
422    {
423      JVMPI_Event event;
424
425      event.event_type = JVMPI_EVENT_OBJECT_ALLOC;
426      event.env_id = NULL;
427      event.u.obj_alloc.arena_id = 0;
428      event.u.obj_alloc.class_id = (jobjectID) klass;
429      event.u.obj_alloc.is_array = 0;
430      event.u.obj_alloc.size = size;
431      event.u.obj_alloc.obj_id = (jobjectID) obj;
432
433      _Jv_DisableGC ();
434      (*_Jv_JVMPI_Notify_OBJECT_ALLOC) (&event);
435      _Jv_EnableGC ();
436    }
437#endif
438
439  return obj;
440}
441#endif /* JV_HASH_SYNCHRONIZATION */
442
443
444// Allocate a new array of Java objects.  Each object is of type
445// `elementClass'.  `init' is used to initialize each slot in the
446// array.
447jobjectArray
448_Jv_NewObjectArray (jsize count, jclass elementClass, jobject init)
449{
450  if (__builtin_expect (count < 0, false))
451    throw new java::lang::NegativeArraySizeException;
452
453  JvAssert (! elementClass->isPrimitive ());
454
455  // Ensure that elements pointer is properly aligned.
456  jobjectArray obj = NULL;
457  size_t size = (size_t) elements (obj);
458  size += count * sizeof (jobject);
459
460  // FIXME: second argument should be "current loader"
461  jclass klass = _Jv_GetArrayClass (elementClass, 0);
462
463  obj = (jobjectArray) _Jv_AllocArray (size, klass);
464  // Cast away const.
465  jsize *lp = const_cast<jsize *> (&obj->length);
466  *lp = count;
467  // We know the allocator returns zeroed memory.  So don't bother
468  // zeroing it again.
469  if (init)
470    {
471      jobject *ptr = elements(obj);
472      while (--count >= 0)
473        *ptr++ = init;
474    }
475  return obj;
476}
477
478// Allocate a new array of primitives.  ELTYPE is the type of the
479// element, COUNT is the size of the array.
480jobject
481_Jv_NewPrimArray (jclass eltype, jint count)
482{
483  int elsize = eltype->size();
484  if (__builtin_expect (count < 0, false))
485    throw new java::lang::NegativeArraySizeException;
486
487  JvAssert (eltype->isPrimitive ());
488  jobject dummy = NULL;
489  size_t size = (size_t) _Jv_GetArrayElementFromElementType (dummy, eltype);
490
491  // Check for overflow.
492  if (__builtin_expect ((size_t) count >
493                        (SIZE_T_MAX - size) / elsize, false))
494    throw no_memory;
495
496  jclass klass = _Jv_GetArrayClass (eltype, 0);
497
498# ifdef JV_HASH_SYNCHRONIZATION
499  // Since the vtable is always statically allocated,
500  // these are completely pointerfree!  Make sure the GC doesn't touch them.
501  __JArray *arr =
502    (__JArray*) _Jv_AllocPtrFreeObj (size + elsize * count, klass);
503  memset((char *)arr + size, 0, elsize * count);
504# else
505  __JArray *arr = (__JArray*) _Jv_AllocObj (size + elsize * count, klass);
506  // Note that we assume we are given zeroed memory by the allocator.
507# endif
508  // Cast away const.
509  jsize *lp = const_cast<jsize *> (&arr->length);
510  *lp = count;
511
512  return arr;
513}
514
515jobject
516_Jv_NewArray (jint type, jint size)
517{
518  switch (type)
519    {
520      case  4:  return JvNewBooleanArray (size);
521      case  5:  return JvNewCharArray (size);
522      case  6:  return JvNewFloatArray (size);
523      case  7:  return JvNewDoubleArray (size);
524      case  8:  return JvNewByteArray (size);
525      case  9:  return JvNewShortArray (size);
526      case 10:  return JvNewIntArray (size);
527      case 11:  return JvNewLongArray (size);
528    }
529  throw new java::lang::InternalError
530    (JvNewStringLatin1 ("invalid type code in _Jv_NewArray"));
531}
532
533// Allocate a possibly multi-dimensional array but don't check that
534// any array length is <0.
535static jobject
536_Jv_NewMultiArrayUnchecked (jclass type, jint dimensions, jint *sizes)
537{
538  JvAssert (type->isArray());
539  jclass element_type = type->getComponentType();
540  jobject result;
541  if (element_type->isPrimitive())
542    result = _Jv_NewPrimArray (element_type, sizes[0]);
543  else
544    result = _Jv_NewObjectArray (sizes[0], element_type, NULL);
545
546  if (dimensions > 1)
547    {
548      JvAssert (! element_type->isPrimitive());
549      JvAssert (element_type->isArray());
550      jobject *contents = elements ((jobjectArray) result);
551      for (int i = 0; i < sizes[0]; ++i)
552        contents[i] = _Jv_NewMultiArrayUnchecked (element_type, dimensions - 1,
553                                                  sizes + 1);
554    }
555
556  return result;
557}
558
559jobject
560_Jv_NewMultiArray (jclass type, jint dimensions, jint *sizes)
561{
562  for (int i = 0; i < dimensions; ++i)
563    if (sizes[i] < 0)
564      throw new java::lang::NegativeArraySizeException;
565
566  return _Jv_NewMultiArrayUnchecked (type, dimensions, sizes);
567}
568
569jobject
570_Jv_NewMultiArray (jclass array_type, jint dimensions, ...)
571{
572  va_list args;
573  jint sizes[dimensions];
574  va_start (args, dimensions);
575  for (int i = 0; i < dimensions; ++i)
576    {
577      jint size = va_arg (args, jint);
578      if (size < 0)
579        throw new java::lang::NegativeArraySizeException;
580      sizes[i] = size;
581    }
582  va_end (args);
583
584  return _Jv_NewMultiArrayUnchecked (array_type, dimensions, sizes);
585}
586
587
588
589// Ensure 8-byte alignment, for hash synchronization.
590#define DECLARE_PRIM_TYPE(NAME)                 \
591  _Jv_ArrayVTable _Jv_##NAME##VTable;           \
592  java::lang::Class _Jv_##NAME##Class __attribute__ ((aligned (8)));
593
594DECLARE_PRIM_TYPE(byte);
595DECLARE_PRIM_TYPE(short);
596DECLARE_PRIM_TYPE(int);
597DECLARE_PRIM_TYPE(long);
598DECLARE_PRIM_TYPE(boolean);
599DECLARE_PRIM_TYPE(char);
600DECLARE_PRIM_TYPE(float);
601DECLARE_PRIM_TYPE(double);
602DECLARE_PRIM_TYPE(void);
603
604void
605_Jv_InitPrimClass (jclass cl, char *cname, char sig, int len,
606                   _Jv_ArrayVTable *array_vtable)
607{   
608  using namespace java::lang::reflect;
609
610  _Jv_InitNewClassFields (cl);
611
612  // We must set the vtable for the class; the Java constructor
613  // doesn't do this.
614  (*(_Jv_VTable **) cl) = java::lang::Class::class$.vtable;
615
616  // Initialize the fields we care about.  We do this in the same
617  // order they are declared in Class.h.
618  cl->name = _Jv_makeUtf8Const ((char *) cname, -1);
619  cl->accflags = Modifier::PUBLIC | Modifier::FINAL | Modifier::ABSTRACT;
620  cl->method_count = sig;
621  cl->size_in_bytes = len;
622  cl->vtable = JV_PRIMITIVE_VTABLE;
623  cl->state = JV_STATE_DONE;
624  cl->depth = -1;
625  if (sig != 'V')
626    _Jv_NewArrayClass (cl, NULL, (_Jv_VTable *) array_vtable);
627}
628
629jclass
630_Jv_FindClassFromSignature (char *sig, java::lang::ClassLoader *loader)
631{
632  switch (*sig)
633    {
634    case 'B':
635      return JvPrimClass (byte);
636    case 'S':
637      return JvPrimClass (short);
638    case 'I':
639      return JvPrimClass (int);
640    case 'J':
641      return JvPrimClass (long);
642    case 'Z':
643      return JvPrimClass (boolean);
644    case 'C':
645      return JvPrimClass (char);
646    case 'F':
647      return JvPrimClass (float);
648    case 'D':
649      return JvPrimClass (double);
650    case 'V':
651      return JvPrimClass (void);
652    case 'L':
653      {
654        int i;
655        for (i = 1; sig[i] && sig[i] != ';'; ++i)
656          ;
657        _Jv_Utf8Const *name = _Jv_makeUtf8Const (&sig[1], i - 1);
658        return _Jv_FindClass (name, loader);
659
660      }
661    case '[':
662      {
663        jclass klass = _Jv_FindClassFromSignature (&sig[1], loader);
664        if (! klass)
665          return NULL;
666        return _Jv_GetArrayClass (klass, loader);
667      }
668    }
669
670  return NULL;                  // Placate compiler.
671}
672
673
674
675JArray<jstring> *
676JvConvertArgv (int argc, const char **argv)
677{
678  if (argc < 0)
679    argc = 0;
680  jobjectArray ar = JvNewObjectArray(argc, &StringClass, NULL);
681  jobject *ptr = elements(ar);
682  jbyteArray bytes = NULL;
683  for (int i = 0;  i < argc;  i++)
684    {
685      const char *arg = argv[i];
686      int len = strlen (arg);
687      if (bytes == NULL || bytes->length < len)
688        bytes = JvNewByteArray (len);
689      jbyte *bytePtr = elements (bytes);
690      // We assume jbyte == char.
691      memcpy (bytePtr, arg, len);
692
693      // Now convert using the default encoding.
694      *ptr++ = new java::lang::String (bytes, 0, len);
695    }
696  return (JArray<jstring>*) ar;
697}
698
699// FIXME: These variables are static so that they will be
700// automatically scanned by the Boehm collector.  This is needed
701// because with qthreads the collector won't scan the initial stack --
702// it will only scan the qthreads stacks.
703
704// Command line arguments.
705static JArray<jstring> *arg_vec;
706
707// The primary thread.
708static java::lang::Thread *main_thread;
709
710char *
711_Jv_ThisExecutable (void)
712{
713  return _Jv_execName;
714}
715
716void
717_Jv_ThisExecutable (const char *name)
718{
719  if (name)
720    {
721      _Jv_execName = (char *) _Jv_Malloc (strlen (name) + 1);
722      strcpy (_Jv_execName, name);
723    }
724}
725
726#ifndef DISABLE_GETENV_PROPERTIES
727
728static char *
729next_property_key (char *s, size_t *length)
730{
731  size_t l = 0;
732
733  JvAssert (s);
734
735  // Skip over whitespace
736  while (isspace (*s))
737    s++;
738
739  // If we've reached the end, return NULL.  Also return NULL if for
740  // some reason we've come across a malformed property string.
741  if (*s == 0
742      || *s == ':'
743      || *s == '=')
744    return NULL;
745
746  // Determine the length of the property key.
747  while (s[l] != 0
748         && ! isspace (s[l])
749         && s[l] != ':'
750         && s[l] != '=')
751    {
752      if (s[l] == '\\'
753          && s[l+1] != 0)
754        l++;
755      l++;
756    }
757
758  *length = l;
759
760  return s;
761}
762
763static char *
764next_property_value (char *s, size_t *length)
765{
766  size_t l = 0;
767
768  JvAssert (s);
769
770  while (isspace (*s))
771    s++;
772
773  if (*s == ':'
774      || *s == '=')
775    s++;
776
777  while (isspace (*s))
778    s++;
779
780  // If we've reached the end, return NULL.
781  if (*s == 0)
782    return NULL;
783
784  // Determine the length of the property value.
785  while (s[l] != 0
786         && ! isspace (s[l])
787         && s[l] != ':'
788         && s[l] != '=')
789    {
790      if (s[l] == '\\'
791          && s[l+1] != 0)
792        l += 2;
793      else
794        l++;
795    }
796
797  *length = l;
798
799  return s;
800}
801
802static void
803process_gcj_properties ()
804{
805  char *props = getenv("GCJ_PROPERTIES");
806  char *p = props;
807  size_t length;
808  size_t property_count = 0;
809
810  if (NULL == props)
811    return;
812
813  // Whip through props quickly in order to count the number of
814  // property values.
815  while (p && (p = next_property_key (p, &length)))
816    {
817      // Skip to the end of the key
818      p += length;
819
820      p = next_property_value (p, &length);
821      if (p)
822        p += length;
823     
824      property_count++;
825    }
826
827  // Allocate an array of property value/key pairs.
828  _Jv_Environment_Properties =
829    (property_pair *) malloc (sizeof(property_pair)
830                              * (property_count + 1));
831
832  // Go through the properties again, initializing _Jv_Properties
833  // along the way.
834  p = props;
835  property_count = 0;
836  while (p && (p = next_property_key (p, &length)))
837    {
838      _Jv_Environment_Properties[property_count].key = p;
839      _Jv_Environment_Properties[property_count].key_length = length;
840
841      // Skip to the end of the key
842      p += length;
843
844      p = next_property_value (p, &length);
845     
846      _Jv_Environment_Properties[property_count].value = p;
847      _Jv_Environment_Properties[property_count].value_length = length;
848
849      if (p)
850        p += length;
851
852      property_count++;
853    }
854  memset ((void *) &_Jv_Environment_Properties[property_count],
855          0, sizeof (property_pair));
856  {
857    size_t i = 0;
858
859    // Null terminate the strings.
860    while (_Jv_Environment_Properties[i].key)
861      {
862        _Jv_Environment_Properties[i].key[_Jv_Environment_Properties[i].key_length] = 0;
863        _Jv_Environment_Properties[i++].value[_Jv_Environment_Properties[i].value_length] = 0;
864      }
865  }
866}
867#endif // DISABLE_GETENV_PROPERTIES
868
869namespace gcj
870{
871  _Jv_Utf8Const *void_signature;
872  _Jv_Utf8Const *clinit_name;
873  _Jv_Utf8Const *init_name;
874  _Jv_Utf8Const *finit_name;
875 
876  bool runtimeInitialized = false;
877}
878
879jint
880_Jv_CreateJavaVM (void* /*vm_args*/)
881{
882  using namespace gcj;
883 
884  if (runtimeInitialized)
885    return -1;
886
887  runtimeInitialized = true;
888
889  PROCESS_GCJ_PROPERTIES;
890
891  _Jv_InitThreads ();
892  _Jv_InitGC ();
893  _Jv_InitializeSyncMutex ();
894
895  /* Initialize Utf8 constants declared in jvm.h. */
896  void_signature = _Jv_makeUtf8Const ("()V", 3);
897  clinit_name = _Jv_makeUtf8Const ("<clinit>", 8);
898  init_name = _Jv_makeUtf8Const ("<init>", 6);
899  finit_name = _Jv_makeUtf8Const ("finit$", 6);
900
901  /* Initialize built-in classes to represent primitive TYPEs. */
902  _Jv_InitPrimClass (&_Jv_byteClass,    "byte",    'B', 1, &_Jv_byteVTable);
903  _Jv_InitPrimClass (&_Jv_shortClass,   "short",   'S', 2, &_Jv_shortVTable);
904  _Jv_InitPrimClass (&_Jv_intClass,     "int",     'I', 4, &_Jv_intVTable);
905  _Jv_InitPrimClass (&_Jv_longClass,    "long",    'J', 8, &_Jv_longVTable);
906  _Jv_InitPrimClass (&_Jv_booleanClass, "boolean", 'Z', 1, &_Jv_booleanVTable);
907  _Jv_InitPrimClass (&_Jv_charClass,    "char",    'C', 2, &_Jv_charVTable);
908  _Jv_InitPrimClass (&_Jv_floatClass,   "float",   'F', 4, &_Jv_floatVTable);
909  _Jv_InitPrimClass (&_Jv_doubleClass,  "double",  'D', 8, &_Jv_doubleVTable);
910  _Jv_InitPrimClass (&_Jv_voidClass,    "void",    'V', 0, &_Jv_voidVTable);
911
912  // Turn stack trace generation off while creating exception objects.
913  _Jv_InitClass (&java::lang::Throwable::class$);
914  java::lang::Throwable::trace_enabled = 0;
915 
916  INIT_SEGV;
917#ifdef HANDLE_FPE
918  INIT_FPE;
919#else
920  arithexception = new java::lang::ArithmeticException
921    (JvNewStringLatin1 ("/ by zero"));
922#endif
923
924  no_memory = new java::lang::OutOfMemoryError;
925
926  java::lang::Throwable::trace_enabled = 1;
927
928#ifdef USE_LTDL
929  LTDL_SET_PRELOADED_SYMBOLS ();
930#endif
931
932  _Jv_platform_initialize ();
933
934  _Jv_JNI_Init ();
935
936  _Jv_GCInitializeFinalizers (&::gnu::gcj::runtime::FinalizerThread::finalizerReady);
937
938  // Start the GC finalizer thread.  A VirtualMachineError can be
939  // thrown by the runtime if, say, threads aren't available.  In this
940  // case finalizers simply won't run.
941  try
942    {
943      using namespace gnu::gcj::runtime;
944      FinalizerThread *ft = new FinalizerThread ();
945      ft->start ();
946    }
947  catch (java::lang::VirtualMachineError *ignore)
948    {
949    }
950
951  return 0;
952}
953
954void
955_Jv_RunMain (jclass klass, const char *name, int argc, const char **argv,
956             bool is_jar)
957{
958  _Jv_argv = argv;
959  _Jv_argc = argc;
960
961  java::lang::Runtime *runtime = NULL;
962
963
964#ifdef DISABLE_MAIN_ARGS
965  _Jv_ThisExecutable ("[Embedded App]");
966#else
967#ifdef HAVE_PROC_SELF_EXE
968  char exec_name[20];
969  sprintf (exec_name, "/proc/%d/exe", getpid ());
970  _Jv_ThisExecutable (exec_name);
971#else
972  _Jv_ThisExecutable (argv[0]);
973#endif /* HAVE_PROC_SELF_EXE */
974#endif /* DISABLE_MAIN_ARGS */
975
976  try
977    {
978      // Set this very early so that it is seen when java.lang.System
979      // is initialized.
980      if (is_jar)
981        _Jv_Jar_Class_Path = strdup (name);
982      _Jv_CreateJavaVM (NULL);
983
984      // Get the Runtime here.  We want to initialize it before searching
985      // for `main'; that way it will be set up if `main' is a JNI method.
986      runtime = java::lang::Runtime::getRuntime ();
987
988#ifdef DISABLE_MAIN_ARGS
989      arg_vec = JvConvertArgv (0, 0);
990#else     
991      arg_vec = JvConvertArgv (argc - 1, argv + 1);
992#endif
993
994      using namespace gnu::gcj::runtime;
995      if (klass)
996        main_thread = new FirstThread (klass, arg_vec);
997      else
998        main_thread = new FirstThread (JvNewStringLatin1 (name),
999                                       arg_vec, is_jar);
1000    }
1001  catch (java::lang::Throwable *t)
1002    {
1003      java::lang::System::err->println (JvNewStringLatin1
1004        ("Exception during runtime initialization"));
1005      t->printStackTrace();
1006      runtime->exit (1);
1007    }
1008
1009  _Jv_AttachCurrentThread (main_thread);
1010  _Jv_ThreadRun (main_thread);
1011  _Jv_ThreadWait ();
1012
1013  int status = (int) java::lang::ThreadGroup::had_uncaught_exception;
1014  runtime->exit (status);
1015}
1016
1017void
1018JvRunMain (jclass klass, int argc, const char **argv)
1019{
1020  _Jv_RunMain (klass, NULL, argc, argv, false);
1021}
1022
1023
1024
1025// Parse a string and return a heap size.
1026static size_t
1027parse_heap_size (const char *spec)
1028{
1029  char *end;
1030  unsigned long val = strtoul (spec, &end, 10);
1031  if (*end == 'k' || *end == 'K')
1032    val *= 1024;
1033  else if (*end == 'm' || *end == 'M')
1034    val *= 1048576;
1035  return (size_t) val;
1036}
1037
1038// Set the initial heap size.  This might be ignored by the GC layer.
1039// This must be called before _Jv_RunMain.
1040void
1041_Jv_SetInitialHeapSize (const char *arg)
1042{
1043  size_t size = parse_heap_size (arg);
1044  _Jv_GCSetInitialHeapSize (size);
1045}
1046
1047// Set the maximum heap size.  This might be ignored by the GC layer.
1048// This must be called before _Jv_RunMain.
1049void
1050_Jv_SetMaximumHeapSize (const char *arg)
1051{
1052  size_t size = parse_heap_size (arg);
1053  _Jv_GCSetMaximumHeapSize (size);
1054}
1055
1056
1057
1058void *
1059_Jv_Malloc (jsize size)
1060{
1061  if (__builtin_expect (size == 0, false))
1062    size = 1;
1063  void *ptr = malloc ((size_t) size);
1064  if (__builtin_expect (ptr == NULL, false))
1065    throw no_memory;
1066  return ptr;
1067}
1068
1069void *
1070_Jv_Realloc (void *ptr, jsize size)
1071{
1072  if (__builtin_expect (size == 0, false))
1073    size = 1;
1074  ptr = realloc (ptr, (size_t) size);
1075  if (__builtin_expect (ptr == NULL, false))
1076    throw no_memory;
1077  return ptr;
1078}
1079
1080void *
1081_Jv_MallocUnchecked (jsize size)
1082{
1083  if (__builtin_expect (size == 0, false))
1084    size = 1;
1085  return malloc ((size_t) size);
1086}
1087
1088void
1089_Jv_Free (void* ptr)
1090{
1091  return free (ptr);
1092}
1093
1094
1095
1096// In theory, these routines can be #ifdef'd away on machines which
1097// support divide overflow signals.  However, we never know if some
1098// code might have been compiled with "-fuse-divide-subroutine", so we
1099// always include them in libgcj.
1100
1101jint
1102_Jv_divI (jint dividend, jint divisor)
1103{
1104  if (__builtin_expect (divisor == 0, false))
1105    _Jv_ThrowSignal (arithexception);
1106 
1107  if (dividend == (jint) 0x80000000L && divisor == -1)
1108    return dividend;
1109
1110  return dividend / divisor;
1111}
1112
1113jint
1114_Jv_remI (jint dividend, jint divisor)
1115{
1116  if (__builtin_expect (divisor == 0, false))
1117    _Jv_ThrowSignal (arithexception);
1118 
1119  if (dividend == (jint) 0x80000000L && divisor == -1)
1120    return 0;
1121
1122  return dividend % divisor;
1123}
1124
1125jlong
1126_Jv_divJ (jlong dividend, jlong divisor)
1127{
1128  if (__builtin_expect (divisor == 0, false))
1129    _Jv_ThrowSignal (arithexception);
1130 
1131  if (dividend == (jlong) 0x8000000000000000LL && divisor == -1)
1132    return dividend;
1133
1134  return dividend / divisor;
1135}
1136
1137jlong
1138_Jv_remJ (jlong dividend, jlong divisor)
1139{
1140  if (__builtin_expect (divisor == 0, false))
1141    _Jv_ThrowSignal (arithexception);
1142 
1143  if (dividend == (jlong) 0x8000000000000000LL && divisor == -1)
1144    return 0;
1145
1146  return dividend % divisor;
1147}
Note: See TracBrowser for help on using the repository browser.