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 | |
---|
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 | #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. |
---|
70 | static java::lang::OutOfMemoryError *no_memory; |
---|
71 | |
---|
72 | // Largest representable size_t. |
---|
73 | #define SIZE_T_MAX ((size_t) (~ (size_t) 0)) |
---|
74 | |
---|
75 | static const char *no_properties[] = { NULL }; |
---|
76 | |
---|
77 | // Properties set at compile time. |
---|
78 | const char **_Jv_Compiler_Properties = no_properties; |
---|
79 | |
---|
80 | // The JAR file to add to the beginning of java.class.path. |
---|
81 | const char *_Jv_Jar_Class_Path; |
---|
82 | |
---|
83 | #ifndef DISABLE_GETENV_PROPERTIES |
---|
84 | // Property key/value pairs. |
---|
85 | property_pair *_Jv_Environment_Properties; |
---|
86 | #endif |
---|
87 | |
---|
88 | // The name of this executable. |
---|
89 | static char *_Jv_execName; |
---|
90 | |
---|
91 | // Stash the argv pointer to benefit native libraries that need it. |
---|
92 | const char **_Jv_argv; |
---|
93 | int _Jv_argc; |
---|
94 | |
---|
95 | #ifdef ENABLE_JVMPI |
---|
96 | // Pointer to JVMPI notification functions. |
---|
97 | void (*_Jv_JVMPI_Notify_OBJECT_ALLOC) (JVMPI_Event *event); |
---|
98 | void (*_Jv_JVMPI_Notify_THREAD_START) (JVMPI_Event *event); |
---|
99 | void (*_Jv_JVMPI_Notify_THREAD_END) (JVMPI_Event *event); |
---|
100 | #endif |
---|
101 | |
---|
102 | |
---|
103 | extern "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. |
---|
108 | void |
---|
109 | _Jv_ThrowSignal (jthrowable throwable) |
---|
110 | { |
---|
111 | throwable->fillInStackTrace (); |
---|
112 | throw throwable; |
---|
113 | } |
---|
114 | |
---|
115 | #ifdef HANDLE_SEGV |
---|
116 | static java::lang::NullPointerException *nullp; |
---|
117 | |
---|
118 | SIGNAL_HANDLER (catch_segv) |
---|
119 | { |
---|
120 | MAKE_THROW_FRAME (nullp); |
---|
121 | _Jv_ThrowSignal (nullp); |
---|
122 | } |
---|
123 | #endif |
---|
124 | |
---|
125 | static java::lang::ArithmeticException *arithexception; |
---|
126 | |
---|
127 | #ifdef HANDLE_FPE |
---|
128 | SIGNAL_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 | |
---|
141 | jboolean |
---|
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 | |
---|
166 | jboolean |
---|
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. */ |
---|
188 | jboolean |
---|
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. */ |
---|
208 | int |
---|
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 | */ |
---|
229 | static jint |
---|
230 | hashUtf8String (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 |
---|
280 | void |
---|
281 | _Jv_Abort (const char *function, const char *file, int line, |
---|
282 | const char *message) |
---|
283 | #else |
---|
284 | void |
---|
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 | |
---|
298 | static void |
---|
299 | fail_on_finalization (jobject) |
---|
300 | { |
---|
301 | JvFail ("object was finalized"); |
---|
302 | } |
---|
303 | |
---|
304 | void |
---|
305 | _Jv_GCWatch (jobject obj) |
---|
306 | { |
---|
307 | _Jv_RegisterFinalizer (obj, fail_on_finalization); |
---|
308 | } |
---|
309 | |
---|
310 | void |
---|
311 | _Jv_ThrowBadArrayIndex(jint bad_index) |
---|
312 | { |
---|
313 | throw new java::lang::ArrayIndexOutOfBoundsException |
---|
314 | (java::lang::String::valueOf (bad_index)); |
---|
315 | } |
---|
316 | |
---|
317 | void |
---|
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. |
---|
325 | void _Jv_ThrowNoMemory() |
---|
326 | { |
---|
327 | throw no_memory; |
---|
328 | } |
---|
329 | |
---|
330 | #ifdef ENABLE_JVMPI |
---|
331 | static void |
---|
332 | jvmpi_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. |
---|
371 | jobject |
---|
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. |
---|
380 | jobject |
---|
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. |
---|
390 | jobject |
---|
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 |
---|
411 | jobject |
---|
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. |
---|
447 | jobjectArray |
---|
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. |
---|
480 | jobject |
---|
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 | |
---|
515 | jobject |
---|
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. |
---|
535 | static 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 | |
---|
559 | jobject |
---|
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 | |
---|
569 | jobject |
---|
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 | |
---|
594 | DECLARE_PRIM_TYPE(byte); |
---|
595 | DECLARE_PRIM_TYPE(short); |
---|
596 | DECLARE_PRIM_TYPE(int); |
---|
597 | DECLARE_PRIM_TYPE(long); |
---|
598 | DECLARE_PRIM_TYPE(boolean); |
---|
599 | DECLARE_PRIM_TYPE(char); |
---|
600 | DECLARE_PRIM_TYPE(float); |
---|
601 | DECLARE_PRIM_TYPE(double); |
---|
602 | DECLARE_PRIM_TYPE(void); |
---|
603 | |
---|
604 | void |
---|
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 | |
---|
629 | jclass |
---|
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 | |
---|
675 | JArray<jstring> * |
---|
676 | JvConvertArgv (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. |
---|
705 | static JArray<jstring> *arg_vec; |
---|
706 | |
---|
707 | // The primary thread. |
---|
708 | static java::lang::Thread *main_thread; |
---|
709 | |
---|
710 | char * |
---|
711 | _Jv_ThisExecutable (void) |
---|
712 | { |
---|
713 | return _Jv_execName; |
---|
714 | } |
---|
715 | |
---|
716 | void |
---|
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 | |
---|
728 | static char * |
---|
729 | next_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 | |
---|
763 | static char * |
---|
764 | next_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 | |
---|
802 | static void |
---|
803 | process_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 | |
---|
869 | namespace 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 | |
---|
879 | jint |
---|
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 | |
---|
954 | void |
---|
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 | |
---|
1017 | void |
---|
1018 | JvRunMain (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. |
---|
1026 | static size_t |
---|
1027 | parse_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. |
---|
1040 | void |
---|
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. |
---|
1049 | void |
---|
1050 | _Jv_SetMaximumHeapSize (const char *arg) |
---|
1051 | { |
---|
1052 | size_t size = parse_heap_size (arg); |
---|
1053 | _Jv_GCSetMaximumHeapSize (size); |
---|
1054 | } |
---|
1055 | |
---|
1056 | |
---|
1057 | |
---|
1058 | void * |
---|
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 | |
---|
1069 | void * |
---|
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 | |
---|
1080 | void * |
---|
1081 | _Jv_MallocUnchecked (jsize size) |
---|
1082 | { |
---|
1083 | if (__builtin_expect (size == 0, false)) |
---|
1084 | size = 1; |
---|
1085 | return malloc ((size_t) size); |
---|
1086 | } |
---|
1087 | |
---|
1088 | void |
---|
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 | |
---|
1101 | jint |
---|
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 | |
---|
1113 | jint |
---|
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 | |
---|
1125 | jlong |
---|
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 | |
---|
1137 | jlong |
---|
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 | } |
---|