OSDN Git Service

* prims.cc (_Jv_MallocUnchecked): New function.
[pf3gnuchains/gcc-fork.git] / libjava / prims.cc
1 // prims.cc - Code for core of runtime environment.
2
3 /* Copyright (C) 1998, 1999, 2000  Red Hat, Inc.
4
5    This file is part of libgcj.
6
7 This software is copyrighted work licensed under the terms of the
8 Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
9 details.  */
10
11 #include <config.h>
12
13 #include <stdlib.h>
14 #include <stdarg.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <signal.h>
18
19 #ifdef HAVE_UNISTD_H
20 #include <unistd.h>
21 #endif
22
23 #include <gcj/cni.h>
24 #include <jvm.h>
25 #include <java-signal.h>
26 #include <java-threads.h>
27
28 #ifndef DISABLE_GETENV_PROPERTIES
29 #include <ctype.h>
30 #include <java-props.h>
31 #define PROCESS_GCJ_PROPERTIES process_gcj_properties()
32 #else
33 #define PROCESS_GCJ_PROPERTIES
34 #endif // DISABLE_GETENV_PROPERTIES
35
36 #include <java/lang/Class.h>
37 #include <java/lang/Runtime.h>
38 #include <java/lang/String.h>
39 #include <java/lang/Thread.h>
40 #include <java/lang/ThreadGroup.h>
41 #include <java/lang/FirstThread.h>
42 #include <java/lang/ArrayIndexOutOfBoundsException.h>
43 #include <java/lang/ArithmeticException.h>
44 #include <java/lang/ClassFormatError.h>
45 #include <java/lang/ClassCastException.h>
46 #include <java/lang/NegativeArraySizeException.h>
47 #include <java/lang/NullPointerException.h>
48 #include <java/lang/OutOfMemoryError.h>
49 #include <java/lang/ArrayStoreException.h>
50 #include <java/lang/System.h>
51 #include <java/lang/reflect/Modifier.h>
52 #include <java/io/PrintStream.h>
53
54 #ifdef USE_LTDL
55 #include <ltdl.h>
56 #endif
57
58 #define ObjectClass _CL_Q34java4lang6Object
59 extern java::lang::Class ObjectClass;
60
61 // We allocate a single OutOfMemoryError exception which we keep
62 // around for use if we run out of memory.
63 static java::lang::OutOfMemoryError *no_memory;
64
65 // Largest representable size_t.
66 #define SIZE_T_MAX ((size_t) (~ (size_t) 0))
67
68 // Properties set at compile time.
69 const char **_Jv_Compiler_Properties;
70
71 #ifndef DISABLE_GETENV_PROPERTIES
72 // Property key/value pairs.
73 property_pair *_Jv_Environment_Properties;
74 #endif
75
76 // The name of this executable.
77 static char * _Jv_execName;
78
79 \f
80
81 #ifdef HANDLE_SEGV
82 static java::lang::NullPointerException *nullp;
83 SIGNAL_HANDLER (catch_segv)
84 {
85   MAKE_THROW_FRAME;
86   nullp->fillInStackTrace ();
87   _Jv_Throw (nullp);
88 }
89 #endif
90
91 static java::lang::ArithmeticException *arithexception;
92
93 #ifdef HANDLE_FPE
94 SIGNAL_HANDLER (catch_fpe)
95 {
96 #ifdef HANDLE_DIVIDE_OVERFLOW
97   HANDLE_DIVIDE_OVERFLOW;
98 #else
99   MAKE_THROW_FRAME;
100 #endif
101   arithexception->fillInStackTrace ();
102   _Jv_Throw (arithexception);
103 }
104 #endif
105
106 \f
107
108 jboolean
109 _Jv_equalUtf8Consts (Utf8Const* a, Utf8Const *b)
110 {
111   register int len;
112   register _Jv_ushort *aptr, *bptr;
113   if (a == b)
114     return true;
115   if (a->hash != b->hash)
116     return false;
117   len = a->length;
118   if (b->length != len)
119     return false;
120   aptr = (_Jv_ushort *)a->data;
121   bptr = (_Jv_ushort *)b->data;
122   len = (len + 1) >> 1;
123   while (--len >= 0)
124     if (*aptr++ != *bptr++)
125       return false;
126   return true;
127 }
128
129 /* True iff A is equal to STR.
130    HASH is STR->hashCode().  
131 */
132
133 jboolean
134 _Jv_equal (Utf8Const* a, jstring str, jint hash)
135 {
136   if (a->hash != (_Jv_ushort) hash)
137     return false;
138   jint len = str->length();
139   jint i = 0;
140   jchar *sptr = _Jv_GetStringChars (str);
141   register unsigned char* ptr = (unsigned char*) a->data;
142   register unsigned char* limit = ptr + a->length;
143   for (;; i++, sptr++)
144     {
145       int ch = UTF8_GET (ptr, limit);
146       if (i == len)
147         return ch < 0;
148       if (ch != *sptr)
149         return false;
150     }
151   return true;
152 }
153
154 /* Like _Jv_equal, but stop after N characters.  */
155 jboolean
156 _Jv_equaln (Utf8Const *a, jstring str, jint n)
157 {
158   jint len = str->length();
159   jint i = 0;
160   jchar *sptr = _Jv_GetStringChars (str);
161   register unsigned char* ptr = (unsigned char*) a->data;
162   register unsigned char* limit = ptr + a->length;
163   for (; n-- > 0; i++, sptr++)
164     {
165       int ch = UTF8_GET (ptr, limit);
166       if (i == len)
167         return ch < 0;
168       if (ch != *sptr)
169         return false;
170     }
171   return true;
172 }
173
174 /* Count the number of Unicode chars encoded in a given Ut8 string. */
175 int
176 _Jv_strLengthUtf8(char* str, int len)
177 {
178   register unsigned char* ptr;
179   register unsigned char* limit;
180   int str_length;
181
182   ptr = (unsigned char*) str;
183   limit = ptr + len;
184   str_length = 0;
185   for (; ptr < limit; str_length++) {
186     if (UTF8_GET (ptr, limit) < 0) {
187       return (-1);
188     }
189   }
190   return (str_length);
191 }
192
193 /* Calculate a hash value for a string encoded in Utf8 format.
194  * This returns the same hash value as specified or java.lang.String.hashCode.
195  */
196 static jint
197 hashUtf8String (char* str, int len)
198 {
199   register unsigned char* ptr = (unsigned char*) str;
200   register unsigned char* limit = ptr + len;
201   jint hash = 0;
202
203   for (; ptr < limit;)
204     {
205       int ch = UTF8_GET (ptr, limit);
206       /* Updated specification from
207          http://www.javasoft.com/docs/books/jls/clarify.html. */
208       hash = (31 * hash) + ch;
209     }
210   return hash;
211 }
212
213 _Jv_Utf8Const *
214 _Jv_makeUtf8Const (char* s, int len)
215 {
216   if (len < 0)
217     len = strlen (s);
218   Utf8Const* m = (Utf8Const*) _Jv_AllocBytes (sizeof(Utf8Const) + len + 1);
219   if (! m)
220     JvThrow (no_memory);
221   memcpy (m->data, s, len);
222   m->data[len] = 0;
223   m->length = len;
224   m->hash = hashUtf8String (s, len) & 0xFFFF;
225   return (m);
226 }
227
228 _Jv_Utf8Const *
229 _Jv_makeUtf8Const (jstring string)
230 {
231   jint hash = string->hashCode ();
232   jint len = _Jv_GetStringUTFLength (string);
233
234   Utf8Const* m = (Utf8Const*)
235     _Jv_AllocBytesChecked (sizeof(Utf8Const) + len + 1);
236
237   m->hash = hash;
238   m->length = len;
239
240   _Jv_GetStringUTFRegion (string, 0, string->length (), m->data);
241   m->data[len] = 0;
242   
243   return m;
244 }
245
246 \f
247
248 #ifdef DEBUG
249 void
250 _Jv_Abort (const char *function, const char *file, int line,
251            const char *message)
252 #else
253 void
254 _Jv_Abort (const char *, const char *, int, const char *message)
255 #endif
256 {
257 #ifdef DEBUG
258   fprintf (stderr,
259            "libgcj failure: %s\n   in function %s, file %s, line %d\n",
260            message, function, file, line);
261 #else
262   java::io::PrintStream *err = java::lang::System::err;
263   err->print(JvNewStringLatin1 ("libgcj failure: "));
264   err->println(JvNewStringLatin1 (message));
265   err->flush();
266 #endif
267   abort ();
268 }
269
270 static void
271 fail_on_finalization (jobject)
272 {
273   JvFail ("object was finalized");
274 }
275
276 void
277 _Jv_GCWatch (jobject obj)
278 {
279   _Jv_RegisterFinalizer (obj, fail_on_finalization);
280 }
281
282 void
283 _Jv_ThrowBadArrayIndex(jint bad_index)
284 {
285   JvThrow (new java::lang::ArrayIndexOutOfBoundsException
286            (java::lang::String::valueOf(bad_index)));
287 }
288
289 void*
290 _Jv_CheckCast (jclass c, jobject obj)
291 {
292   if (obj != NULL && ! c->isAssignableFrom(obj->getClass()))
293     JvThrow (new java::lang::ClassCastException);
294   return obj;
295 }
296
297 void
298 _Jv_CheckArrayStore (jobject arr, jobject obj)
299 {
300   if (obj)
301     {
302       JvAssert (arr != NULL);
303       jclass arr_class = arr->getClass();
304       JvAssert (arr_class->isArray());
305       jclass elt_class = arr_class->getComponentType();
306       jclass obj_class = obj->getClass();
307       if (! elt_class->isAssignableFrom(obj_class))
308         JvThrow (new java::lang::ArrayStoreException);
309     }
310 }
311
312 \f
313
314 // Allocate some unscanned memory and throw an exception if no memory.
315 void *
316 _Jv_AllocBytesChecked (jsize size)
317 {
318   void *r = _Jv_AllocBytes (size);
319   if (! r)
320     _Jv_Throw (no_memory);
321   return r;
322 }
323
324 // Allocate a new object of class C.  SIZE is the size of the object
325 // to allocate.  You might think this is redundant, but it isn't; some
326 // classes, such as String, aren't of fixed size.
327 jobject
328 _Jv_AllocObject (jclass c, jint size)
329 {
330   _Jv_InitClass (c);
331
332   jobject obj = (jobject) _Jv_AllocObj (size);
333   if (! obj)
334     JvThrow (no_memory);
335   *((_Jv_VTable **) obj) = c->vtable;
336
337   // If this class has inherited finalize from Object, then don't
338   // bother registering a finalizer.  We know that finalize() is the
339   // very first method after the dummy entry.  If this turns out to be
340   // unreliable, a more robust implementation can be written.  Such an
341   // implementation would look for Object.finalize in Object's method
342   // table at startup, and then use that information to find the
343   // appropriate index in the method vector.
344   if (c->vtable->method[1] != ObjectClass.vtable->method[1])
345     _Jv_RegisterFinalizer (obj, _Jv_FinalizeObject);
346
347   return obj;
348 }
349
350 // Allocate a new array of Java objects.  Each object is of type
351 // `elementClass'.  `init' is used to initialize each slot in the
352 // array.
353 jobjectArray
354 _Jv_NewObjectArray (jsize count, jclass elementClass, jobject init)
355 {
356   if (count < 0)
357     JvThrow (new java::lang::NegativeArraySizeException);
358
359   JvAssert (! elementClass->isPrimitive ());
360
361   jobjectArray obj = NULL;
362   size_t size = (size_t) _Jv_GetArrayElementFromElementType (obj,
363                                                              elementClass);
364
365   // Check for overflow.
366   if ((size_t) count > (SIZE_T_MAX - size) / sizeof (jobject))
367     JvThrow (no_memory);
368
369   size += count * sizeof (jobject);
370
371   // FIXME: second argument should be "current loader" //
372   jclass clas = _Jv_FindArrayClass (elementClass, 0);
373
374   obj = (jobjectArray) _Jv_AllocArray (size);
375   if (! obj)
376     JvThrow (no_memory);
377   obj->length = count;
378   jobject* ptr = elements(obj);
379   // We know the allocator returns zeroed memory.  So don't bother
380   // zeroing it again.
381   if (init)
382     {
383       while (--count >= 0)
384         *ptr++ = init;
385     }
386   // Set the vtbl last to avoid problems if the GC happens during the
387   // window in this function between the allocation and this
388   // assignment.
389   *((_Jv_VTable **) obj) = clas->vtable;
390   return obj;
391 }
392
393 // Allocate a new array of primitives.  ELTYPE is the type of the
394 // element, COUNT is the size of the array.
395 jobject
396 _Jv_NewPrimArray (jclass eltype, jint count)
397 {
398   int elsize = eltype->size();
399   if (count < 0)
400     JvThrow (new java::lang::NegativeArraySizeException ());
401
402   JvAssert (eltype->isPrimitive ());
403   jobject dummy = NULL;
404   size_t size = (size_t) _Jv_GetArrayElementFromElementType (dummy, eltype);
405
406   // Check for overflow.
407   if ((size_t) count > (SIZE_T_MAX - size) / elsize)
408     JvThrow (no_memory);
409
410   __JArray *arr = (__JArray*) _Jv_AllocObj (size + elsize * count);
411   if (! arr)
412     JvThrow (no_memory);
413   arr->length = count;
414   // Note that we assume we are given zeroed memory by the allocator.
415
416   jclass klass = _Jv_FindArrayClass (eltype, 0);
417   // Set the vtbl last to avoid problems if the GC happens during the
418   // window in this function between the allocation and this
419   // assignment.
420   *((_Jv_VTable **) arr) = klass->vtable;
421   return arr;
422 }
423
424 jcharArray
425 JvNewCharArray (jint length)
426 {
427   return (jcharArray) _Jv_NewPrimArray (JvPrimClass (char), length);
428 }
429
430 jbooleanArray
431 JvNewBooleanArray (jint length)
432 {
433   return (jbooleanArray) _Jv_NewPrimArray (JvPrimClass (boolean), length);
434 }
435
436 jbyteArray
437 JvNewByteArray (jint length)
438 {
439   return (jbyteArray) _Jv_NewPrimArray (JvPrimClass (byte), length);
440 }
441
442 jshortArray
443 JvNewShortArray (jint length)
444 {
445   return (jshortArray) _Jv_NewPrimArray (JvPrimClass (short), length);
446 }
447
448 jintArray
449 JvNewIntArray (jint length)
450 {
451   return (jintArray) _Jv_NewPrimArray (JvPrimClass (int), length);
452 }
453
454 jlongArray
455 JvNewLongArray (jint length)
456 {
457   return (jlongArray) _Jv_NewPrimArray (JvPrimClass (long), length);
458 }
459
460 jfloatArray
461 JvNewFloatArray (jint length)
462 {
463   return (jfloatArray) _Jv_NewPrimArray (JvPrimClass (float), length);
464 }
465
466 jdoubleArray
467 JvNewDoubleArray (jint length)
468 {
469   return (jdoubleArray) _Jv_NewPrimArray (JvPrimClass (double), length);
470 }
471
472 jobject
473 _Jv_NewArray (jint type, jint size)
474 {
475   switch (type)
476     {
477       case  4:  return JvNewBooleanArray (size);
478       case  5:  return JvNewCharArray (size);
479       case  6:  return JvNewFloatArray (size);
480       case  7:  return JvNewDoubleArray (size);
481       case  8:  return JvNewByteArray (size);
482       case  9:  return JvNewShortArray (size);
483       case 10:  return JvNewIntArray (size);
484       case 11:  return JvNewLongArray (size);
485     }
486   JvFail ("newarray - bad type code");
487   return NULL;                  // Placate compiler.
488 }
489
490 jobject
491 _Jv_NewMultiArray (jclass type, jint dimensions, jint *sizes)
492 {
493   JvAssert (type->isArray());
494   jclass element_type = type->getComponentType();
495   jobject result;
496   if (element_type->isPrimitive())
497     result = _Jv_NewPrimArray (element_type, sizes[0]);
498   else
499     result = _Jv_NewObjectArray (sizes[0], element_type, NULL);
500
501   if (dimensions > 1)
502     {
503       JvAssert (! element_type->isPrimitive());
504       JvAssert (element_type->isArray());
505       jobject *contents = elements ((jobjectArray) result);
506       for (int i = 0; i < sizes[0]; ++i)
507         contents[i] = _Jv_NewMultiArray (element_type, dimensions - 1,
508                                          sizes + 1);
509     }
510
511   return result;
512 }
513
514 jobject
515 _Jv_NewMultiArray (jclass array_type, jint dimensions, ...)
516 {
517   va_list args;
518   jint sizes[dimensions];
519   va_start (args, dimensions);
520   for (int i = 0; i < dimensions; ++i)
521     {
522       jint size = va_arg (args, jint);
523       sizes[i] = size;
524     }
525   va_end (args);
526
527   return _Jv_NewMultiArray (array_type, dimensions, sizes);
528 }
529
530 \f
531
532 class _Jv_PrimClass : public java::lang::Class
533 {
534 public:
535   // FIXME: calling convention is weird.  If we use the natural types
536   // then the compiler will complain because they aren't Java types.
537   _Jv_PrimClass (jobject cname, jbyte sig, jint len)
538     {
539       using namespace java::lang::reflect;
540
541       // We must initialize every field of the class.  We do this in
542       // the same order they are declared in Class.h.
543       next = NULL;
544       name = _Jv_makeUtf8Const ((char *) cname, -1);
545       accflags = Modifier::PUBLIC | Modifier::FINAL;
546       superclass = NULL;
547       constants.size = 0;
548       constants.tags = NULL;
549       constants.data = NULL;
550       methods = NULL;
551       method_count = sig;
552       vtable_method_count = 0;
553       fields = NULL;
554       size_in_bytes = len;
555       field_count = 0;
556       static_field_count = 0;
557       vtable = JV_PRIMITIVE_VTABLE;
558       interfaces = NULL;
559       loader = NULL;
560       interface_count = 0;
561       state = JV_STATE_NOTHING;
562       thread = NULL;
563     }
564 };
565
566 #define DECLARE_PRIM_TYPE(NAME, SIG, LEN) \
567   _Jv_PrimClass _Jv_##NAME##Class((jobject) #NAME, (jbyte) SIG, (jint) LEN)
568
569 DECLARE_PRIM_TYPE(byte, 'B', 1);
570 DECLARE_PRIM_TYPE(short, 'S', 2);
571 DECLARE_PRIM_TYPE(int, 'I', 4);
572 DECLARE_PRIM_TYPE(long, 'J', 8);
573 DECLARE_PRIM_TYPE(boolean, 'Z', 1);
574 DECLARE_PRIM_TYPE(char, 'C', 2);
575 DECLARE_PRIM_TYPE(float, 'F', 4);
576 DECLARE_PRIM_TYPE(double, 'D', 8);
577 DECLARE_PRIM_TYPE(void, 'V', 0);
578
579 jclass
580 _Jv_FindClassFromSignature (char *sig, java::lang::ClassLoader *loader)
581 {
582   switch (*sig)
583     {
584     case 'B':
585       return JvPrimClass (byte);
586     case 'S':
587       return JvPrimClass (short);
588     case 'I':
589       return JvPrimClass (int);
590     case 'J':
591       return JvPrimClass (long);
592     case 'Z':
593       return JvPrimClass (boolean);
594     case 'C':
595       return JvPrimClass (char);
596     case 'F':
597       return JvPrimClass (float);
598     case 'D':
599       return JvPrimClass (double);
600     case 'V':
601       return JvPrimClass (void);
602     case 'L':
603       {
604         int i;
605         for (i = 1; sig[i] && sig[i] != ';'; ++i)
606           ;
607         _Jv_Utf8Const *name = _Jv_makeUtf8Const (&sig[1], i - 1);
608         return _Jv_FindClass (name, loader);
609
610       }
611     case '[':
612       return _Jv_FindArrayClass (_Jv_FindClassFromSignature (&sig[1], loader),
613                                  loader);
614     }
615   JvFail ("couldn't understand class signature");
616   return NULL;                  // Placate compiler.
617 }
618
619 \f
620
621 JArray<jstring> *
622 JvConvertArgv (int argc, const char **argv)
623 {
624   if (argc < 0)
625     argc = 0;
626   jobjectArray ar = JvNewObjectArray(argc, &StringClass, NULL);
627   jobject* ptr = elements(ar);
628   for (int i = 0;  i < argc;  i++)
629     {
630       const char *arg = argv[i];
631       // FIXME - should probably use JvNewStringUTF.
632       *ptr++ = JvNewStringLatin1(arg, strlen(arg));
633     }
634   return (JArray<jstring>*) ar;
635 }
636
637 // FIXME: These variables are static so that they will be
638 // automatically scanned by the Boehm collector.  This is needed
639 // because with qthreads the collector won't scan the initial stack --
640 // it will only scan the qthreads stacks.
641
642 // Command line arguments.
643 static jobject arg_vec;
644
645 // The primary threadgroup.
646 static java::lang::ThreadGroup *main_group;
647
648 // The primary thread.
649 static java::lang::Thread *main_thread;
650
651 char *
652 _Jv_ThisExecutable (void)
653 {
654   return _Jv_execName;
655 }
656
657 void
658 _Jv_ThisExecutable (const char *name)
659 {
660   if (name)
661     {
662       _Jv_execName = new char[strlen (name) + 1];
663       strcpy (_Jv_execName, name);
664     }
665 }
666
667 static void
668 main_init ()
669 {
670   INIT_SEGV;
671 #ifdef HANDLE_FPE
672   INIT_FPE;
673 #else
674   arithexception = new java::lang::ArithmeticException
675     (JvNewStringLatin1 ("/ by zero"));
676 #endif
677
678   no_memory = new java::lang::OutOfMemoryError;
679
680 #ifdef USE_LTDL
681   LTDL_SET_PRELOADED_SYMBOLS ();
682 #endif
683
684   // FIXME: we only want this on POSIX systems.
685   struct sigaction act;
686   act.sa_handler = SIG_IGN;
687   sigemptyset (&act.sa_mask);
688   act.sa_flags = 0;
689   sigaction (SIGPIPE, &act, NULL);
690
691   _Jv_JNI_Init ();
692 }
693
694 #ifndef DISABLE_GETENV_PROPERTIES
695
696 static char *
697 next_property_key (char *s, size_t *length)
698 {
699   size_t l = 0;
700
701   JvAssert (s);
702
703   // Skip over whitespace
704   while (isspace (*s))
705     s++;
706
707   // If we've reached the end, return NULL.  Also return NULL if for
708   // some reason we've come across a malformed property string.
709   if (*s == 0
710       || *s == ':'
711       || *s == '=')
712     return NULL;
713
714   // Determine the length of the property key.
715   while (s[l] != 0
716          && ! isspace (s[l])
717          && s[l] != ':'
718          && s[l] != '=')
719     {
720       if (s[l] == '\\'
721           && s[l+1] != 0)
722         l++;
723       l++;
724     }
725
726   *length = l;
727
728   return s;
729 }
730
731 static char *
732 next_property_value (char *s, size_t *length)
733 {
734   size_t l = 0;
735
736   JvAssert (s);
737
738   while (isspace (*s))
739     s++;
740
741   if (*s == ':'
742       || *s == '=')
743     s++;
744
745   while (isspace (*s))
746     s++;
747
748   // If we've reached the end, return NULL.
749   if (*s == 0)
750     return NULL;
751
752   // Determine the length of the property value.
753   while (s[l] != 0
754          && ! isspace (s[l])
755          && s[l] != ':'
756          && s[l] != '=')
757     {
758       if (s[l] == '\\'
759           && s[l+1] != 0)
760         l += 2;
761       else
762         l++;
763     }
764
765   *length = l;
766
767   return s;
768 }
769
770 static void
771 process_gcj_properties ()
772 {
773   char *props = getenv("GCJ_PROPERTIES");
774   char *p = props;
775   size_t length;
776   size_t property_count = 0;
777
778   if (NULL == props)
779     return;
780
781   // Whip through props quickly in order to count the number of
782   // property values.
783   while (p && (p = next_property_key (p, &length)))
784     {
785       // Skip to the end of the key
786       p += length;
787
788       p = next_property_value (p, &length);
789       if (p)
790         p += length;
791       
792       property_count++;
793     }
794
795   // Allocate an array of property value/key pairs.
796   _Jv_Environment_Properties = 
797     (property_pair *) malloc (sizeof(property_pair) 
798                               * (property_count + 1));
799
800   // Go through the properties again, initializing _Jv_Properties
801   // along the way.
802   p = props;
803   property_count = 0;
804   while (p && (p = next_property_key (p, &length)))
805     {
806       _Jv_Environment_Properties[property_count].key = p;
807       _Jv_Environment_Properties[property_count].key_length = length;
808
809       // Skip to the end of the key
810       p += length;
811
812       p = next_property_value (p, &length);
813       
814       _Jv_Environment_Properties[property_count].value = p;
815       _Jv_Environment_Properties[property_count].value_length = length;
816
817       if (p)
818         p += length;
819
820       property_count++;
821     }
822   memset ((void *) &_Jv_Environment_Properties[property_count], 
823           0, sizeof (property_pair));
824   {
825     size_t i = 0;
826
827     // Null terminate the strings.
828     while (_Jv_Environment_Properties[i].key)
829       {
830         _Jv_Environment_Properties[i].key[_Jv_Environment_Properties[i].key_length] = 0;
831         _Jv_Environment_Properties[i++].value[_Jv_Environment_Properties[i].value_length] = 0;
832       }
833   }
834 }
835 #endif // DISABLE_GETENV_PROPERTIES
836
837 void
838 JvRunMain (jclass klass, int argc, const char **argv)
839 {
840   PROCESS_GCJ_PROPERTIES;
841
842   main_init ();
843 #ifdef HAVE_PROC_SELF_EXE
844   char exec_name[20];
845   sprintf (exec_name, "/proc/%d/exe", getpid ());
846   _Jv_ThisExecutable (exec_name);
847 #else
848   _Jv_ThisExecutable (argv[0]);
849 #endif
850
851   arg_vec = JvConvertArgv (argc - 1, argv + 1);
852   main_group = new java::lang::ThreadGroup (23);
853   main_thread = new java::lang::FirstThread (main_group, klass, arg_vec);
854
855   main_thread->start();
856   _Jv_ThreadWait ();
857
858   java::lang::Runtime::getRuntime ()->exit (0);
859 }
860
861 void
862 _Jv_RunMain (const char *class_name, int argc, const char **argv)
863 {
864   PROCESS_GCJ_PROPERTIES;
865
866   main_init ();
867
868 #ifdef HAVE_PROC_SELF_EXE
869   char exec_name[20];
870   sprintf (exec_name, "/proc/%d/exe", getpid ());
871   _Jv_ThisExecutable (exec_name);
872 #endif
873
874   arg_vec = JvConvertArgv (argc - 1, argv + 1);
875   main_group = new java::lang::ThreadGroup (23);
876   main_thread = new java::lang::FirstThread (main_group,
877                                              JvNewStringLatin1 (class_name),
878                                              arg_vec);
879   main_thread->start();
880   _Jv_ThreadWait ();
881
882   java::lang::Runtime::getRuntime ()->exit (0);
883 }
884
885 \f
886
887 // Parse a string and return a heap size.
888 static size_t
889 parse_heap_size (const char *spec)
890 {
891   char *end;
892   unsigned long val = strtoul (spec, &end, 10);
893   if (*end == 'k' || *end == 'K')
894     val *= 1024;
895   else if (*end == 'm' || *end == 'M')
896     val *= 1048576;
897   return (size_t) val;
898 }
899
900 // Set the initial heap size.  This might be ignored by the GC layer.
901 // This must be called before _Jv_RunMain.
902 void
903 _Jv_SetInitialHeapSize (const char *arg)
904 {
905   size_t size = parse_heap_size (arg);
906   _Jv_GCSetInitialHeapSize (size);
907 }
908
909 // Set the maximum heap size.  This might be ignored by the GC layer.
910 // This must be called before _Jv_RunMain.
911 void
912 _Jv_SetMaximumHeapSize (const char *arg)
913 {
914   size_t size = parse_heap_size (arg);
915   _Jv_GCSetMaximumHeapSize (size);
916 }
917
918 \f
919
920 void *
921 _Jv_MallocUnchecked (jsize size)
922 {
923   if (size == 0)
924     size = 1;
925   return malloc ((size_t) size);
926 }
927
928 void *
929 _Jv_Malloc (jsize size)
930 {
931   if (size == 0)
932     size = 1;
933   void *ptr = malloc ((size_t) size);
934   if (ptr == NULL)
935     JvThrow (no_memory);
936   return ptr;
937 }
938
939 void
940 _Jv_Free (void* ptr)
941 {
942   return free (ptr);
943 }
944
945 \f
946
947 // In theory, these routines can be #ifdef'd away on machines which
948 // support divide overflow signals.  However, we never know if some
949 // code might have been compiled with "-fuse-divide-subroutine", so we
950 // always include them in libgcj.
951
952 jint
953 _Jv_divI (jint dividend, jint divisor)
954 {
955   if (divisor == 0)
956     _Jv_Throw (arithexception);
957   
958   if (dividend == (jint) 0x80000000L && divisor == -1)
959     return dividend;
960
961   return dividend / divisor;
962 }
963
964 jint
965 _Jv_remI (jint dividend, jint divisor)
966 {
967   if (divisor == 0)
968     _Jv_Throw (arithexception);
969   
970   if (dividend == (jint) 0x80000000L && divisor == -1)
971     return 0;
972
973   return dividend % divisor;
974 }
975
976 jlong
977 _Jv_divJ (jlong dividend, jlong divisor)
978 {
979   if (divisor == 0)
980     _Jv_Throw (arithexception);
981   
982   if (dividend == (jlong) 0x8000000000000000LL && divisor == -1)
983     return dividend;
984
985   return dividend / divisor;
986 }
987
988 jlong
989 _Jv_remJ (jlong dividend, jlong divisor)
990 {
991   if (divisor == 0)
992     _Jv_Throw (arithexception);
993   
994   if (dividend == (jlong) 0x8000000000000000LL && divisor == -1)
995     return 0;
996
997   return dividend % divisor;
998 }