1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * This source file is part of SableVM. *
3 * *
4 * See the file "LICENSE" for the copyright information and for *
5 * the terms and conditions for copying, distribution and *
6 * modification of this source file. *
7 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8
9 #if defined (_SABLEVM_COPY_GC)
10
11 /*
12 ----------------------------------------------------------------------
13 _svmf_heap_init_defaults
14 ----------------------------------------------------------------------
15 */
16
17 svm_static void
_svmf_heap_init_defaults(_svmt_JavaVM * vm)18 _svmf_heap_init_defaults (_svmt_JavaVM *vm)
19 {
20 vm->heap.min_size = SVM_HEAP_DEFAULT_MIN_SIZE;
21 vm->heap.max_size = SVM_HEAP_DEFAULT_MAX_SIZE;
22 vm->heap.allocation_increment = SVM_HEAP_DEFAULT_ALLOCATION_INCREMENT;
23 }
24
25 /*
26 ----------------------------------------------------------------------
27 _svmf_heap_init
28 ----------------------------------------------------------------------
29 */
30
31 svm_static jint
_svmf_heap_init(_svmt_JNIEnv * env)32 _svmf_heap_init (_svmt_JNIEnv *env)
33 {
34 _svmt_JavaVM *vm = env->vm;
35
36 if (_svmm_validate_min_max_increment
37 (vm->heap.min_size,
38 vm->heap.max_size, vm->heap.allocation_increment) != JNI_OK)
39 {
40 return JNI_ERR;
41 }
42
43 /* if the heap has a fixed size, allocate both semi-spaces once
44 and for all, if not, allocate one semi-space */
45 if (vm->heap.allocation_increment == 0 &&
46 (2 * vm->heap.min_size) < vm->heap.min_size)
47 {
48 return JNI_ERR;
49 }
50
51 if (vm->heap.allocation_increment == 0)
52 {
53 if (vm->verbose_gc)
54 {
55 _svmf_printf (env, stderr,
56 "[verbose gc: allocating fixed size heap (2 * %d bytes)]\n",
57 vm->heap.min_size);
58 }
59
60 vm->heap.start = _svmf_malloc (2 * vm->heap.min_size);
61
62 if (vm->heap.start == NULL)
63 {
64 return JNI_ERR;
65 }
66
67 vm->heap.end = ((char *) vm->heap.start) + vm->heap.min_size;
68 vm->heap.alloc = vm->heap.start;
69 vm->heap.hashcode_base = 0 - (size_t) vm->heap.start;
70 vm->heap.next_heap = vm->heap.end;
71 }
72 else
73 {
74 if (vm->verbose_gc)
75 {
76 _svmf_printf (env, stderr,
77 "[verbose gc: allocating initial heap (%d bytes)]\n",
78 vm->heap.min_size);
79 }
80
81 vm->heap.start = _svmf_malloc (vm->heap.min_size);
82
83 if (vm->heap.start == NULL)
84 {
85 return JNI_ERR;
86 }
87
88 vm->heap.end = ((char *) vm->heap.start) + vm->heap.min_size;
89 vm->heap.alloc = vm->heap.start;
90 vm->heap.hashcode_base = 0 - (size_t) vm->heap.start;
91 vm->heap.suggested_next_heap_size = vm->heap.min_size;
92 }
93
94 return JNI_OK;
95 }
96
97 /*
98 ----------------------------------------------------------------------
99 _svmf_copy_object
100 ----------------------------------------------------------------------
101 */
102
103 /* This function copies the object pointed to by obj to to_space. obj
104 * may be NULL or pointing to an already copied object. In all cases,
105 * this function returns a pointer to the to_space copy (or NULL).
106 */
107
108 inline svm_static _svmt_object_instance *
_svmf_copy_object(_svmt_JNIEnv * env,_svmt_object_instance * obj,void ** pto_space_tail)109 _svmf_copy_object (_svmt_JNIEnv *env, _svmt_object_instance *obj,
110 void **pto_space_tail)
111 {
112 _svmt_word lockword;
113
114 /* NULL */
115 if (obj == NULL)
116 {
117 return NULL;
118 }
119
120 assert (((void *) obj) >= env->vm->heap.start &&
121 ((void *) obj) < env->vm->heap.alloc);
122
123 lockword = obj->lockword;
124
125 /* forward pointer */
126 if (_svmf_lockword_is_forward_reference (lockword))
127 {
128 assert (((void *) lockword) < *pto_space_tail);
129 assert (obj->vtable == ((_svmt_object_instance *) lockword)->vtable);
130
131 return (_svmt_object_instance *) lockword;
132 }
133
134 /* we must copy the object */
135 #if defined (MAGIC)
136 assert (strcmp (obj->magic, "SableVM") == 0);
137 #endif
138
139 if (_svmf_lockword_is_array (lockword))
140 {
141 /* it's actually an array */
142 _svmt_array_instance *array = (_svmt_array_instance *) obj;
143 jint size = array->size;
144 size_t instance_size =
145 _svmf_aligned_size_t (sizeof (_svmt_array_instance));
146 _svmt_word array_type = _svmf_lockword_get_array_type (array->lockword);
147 _svmt_object_instance *result;
148
149 assert (array->vtable->type->is_array);
150
151 switch (array_type)
152 {
153 case SVM_TYPE_BOOLEAN:
154 {
155 instance_size += (((size_t) size) + 7) / 8;
156 }
157 break;
158
159 case SVM_TYPE_BYTE:
160 {
161 instance_size += ((size_t) size);
162 }
163 break;
164
165 case SVM_TYPE_SHORT:
166 {
167 instance_size += ((size_t) size) * 2;
168 }
169 break;
170
171 case SVM_TYPE_CHAR:
172 {
173 instance_size += ((size_t) size) * 2;
174 }
175 break;
176
177 case SVM_TYPE_INT:
178 {
179 instance_size += ((size_t) size) * 4;
180 }
181 break;
182
183 case SVM_TYPE_LONG:
184 {
185 instance_size += ((size_t) size) * 8;
186 }
187 break;
188
189 case SVM_TYPE_FLOAT:
190 {
191 instance_size += ((size_t) size) * 4;
192 }
193 break;
194
195 case SVM_TYPE_DOUBLE:
196 {
197 instance_size += ((size_t) size) * 8;
198 }
199 break;
200
201 case SVM_TYPE_REFERENCE:
202 {
203 instance_size += ((size_t) size) * sizeof (void *);
204 }
205 break;
206
207 default:
208 {
209 _svmm_fatal_error ("impossible control flow");
210 }
211 break;
212 }
213
214 instance_size = _svmf_aligned_size_t (instance_size);
215
216 #if defined(_SABLEVM_TRADITIONAL_OBJECT_LAYOUT)
217
218 memcpy (*pto_space_tail, array, instance_size);
219 result = (_svmt_object_instance *) *pto_space_tail;
220
221 #elif defined (_SABLEVM_BIDIRECTIONAL_OBJECT_LAYOUT)
222
223 /* if elements preceed object header, adjust head pointer
224 * accordignly */
225 if (array_type == SVM_TYPE_REFERENCE)
226 {
227 size_t offset =
228 _svmf_aligned_size_t (((size_t) size) * sizeof (void *));
229
230 memcpy (*pto_space_tail, ((char *) array) - offset, instance_size);
231 result =
232 (_svmt_object_instance *) (void *) (((char *) *pto_space_tail) +
233 offset);
234 }
235 else
236 {
237 memcpy (*pto_space_tail, array, instance_size);
238 result = (_svmt_object_instance *) *pto_space_tail;
239 }
240
241 #endif /* defined (_SABLEVM_TRADITIONAL_OBJECT_LAYOUT) */
242
243 /* update to_space_tail */
244 *pto_space_tail = ((char *) *pto_space_tail) + instance_size;
245
246 /* set forward pointer */
247 *((_svmt_object_instance **) array) = result;
248
249 #if defined (MAGIC)
250 array->magic[0] = 0;
251 #endif
252
253 /* we're done */
254 return result;
255 }
256
257 /* it's a normal object */
258
259 assert (!(obj->vtable->type->is_array));
260
261 {
262 #if defined (_SABLEVM_BIDIRECTIONAL_OBJECT_LAYOUT)
263
264 size_t end_offset = _svmf_lockword_object_get_end_offset (lockword);
265 size_t start_offset = _svmf_lockword_object_get_start_offset (lockword);
266 size_t instance_size;
267 _svmt_object_instance *result;
268
269 if (end_offset == SVM_LOCKWORD_END_OVERFLOW_OFFSET)
270 {
271 end_offset = obj->vtable->next_offset_no_hashcode;
272 }
273
274 if (start_offset == SVM_LOCKWORD_START_OVERFLOW_OFFSET)
275 {
276 start_offset = obj->vtable->start_offset;
277 }
278
279 instance_size = start_offset + end_offset;
280
281 switch (_svmf_lockword_get_hashstate (lockword))
282 {
283 case SVM_HASH_NONE:
284 {
285 memcpy (*pto_space_tail, ((char *) obj) - start_offset,
286 instance_size);
287 result =
288 (_svmt_object_instance *) (void *) (((char *) *pto_space_tail) +
289 start_offset);
290 }
291 break;
292
293 case SVM_HASH_NOT_MOVED:
294 {
295 memcpy (*pto_space_tail, ((char *) obj) - start_offset,
296 instance_size);
297 result =
298 (_svmt_object_instance *) (void *) (((char *) *pto_space_tail) +
299 start_offset);
300
301 instance_size += SVM_ALIGNMENT;
302 _svmm_lockword_set_hashstate (result->lockword, SVM_HASH_MOVED);
303 _svmf_put_INT_field (result, end_offset, (jint)
304 (env->vm->heap.hashcode_base + (size_t) obj));
305 }
306 break;
307
308 case SVM_HASH_MOVED:
309 {
310 instance_size += SVM_ALIGNMENT;
311 memcpy (*pto_space_tail, ((char *) obj) - start_offset,
312 instance_size);
313 result =
314 (_svmt_object_instance *) (void *) (((char *) *pto_space_tail) +
315 start_offset);
316 }
317 break;
318
319 default:
320 {
321 result = NULL;
322 _svmm_fatal_error ("impossible control flow");
323 }
324 break;
325 }
326
327 /* update to_space_tail */
328 *pto_space_tail = ((char *) *pto_space_tail) + instance_size;
329
330 /* set forward pointer */
331 *((_svmt_object_instance **) obj) = result;
332
333 #if defined (MAGIC)
334 obj->magic[0] = 0;
335 #endif
336
337 /* we're done */
338 return result;
339
340 #elif defined (_SABLEVM_TRADITIONAL_OBJECT_LAYOUT)
341
342 size_t end_offset = _svmf_lockword_object_get_end_offset (lockword);
343 size_t instance_size;
344 _svmt_object_instance *result;
345
346 if (_svmf_lockword_object_is_info_in_header (lockword))
347 {
348 end_offset = _svmf_lockword_object_get_end_offset (lockword);
349 }
350 else
351 {
352 end_offset = obj->vtable->next_offset_no_hashcode;
353 }
354
355 instance_size = end_offset;
356
357 switch (_svmf_lockword_get_hashstate (lockword))
358 {
359 case SVM_HASH_NONE:
360 {
361 memcpy (*pto_space_tail, obj, instance_size);
362 result = (_svmt_object_instance *) *pto_space_tail;
363 }
364 break;
365
366 case SVM_HASH_NOT_MOVED:
367 {
368 memcpy (*pto_space_tail, obj, instance_size);
369 result = (_svmt_object_instance *) *pto_space_tail;
370
371 instance_size += SVM_ALIGNMENT;
372 _svmm_lockword_set_hashstate (result->lockword, SVM_HASH_MOVED);
373 _svmf_put_INT_field (result, end_offset, (jint)
374 (env->vm->heap.hashcode_base + (size_t) obj));
375 }
376 break;
377
378 case SVM_HASH_MOVED:
379 {
380 instance_size += SVM_ALIGNMENT;
381 memcpy (*pto_space_tail, obj, instance_size);
382 result = (_svmt_object_instance *) *pto_space_tail;
383 }
384 break;
385
386 default:
387 {
388 _svmm_fatal_error ("impossible control flow");
389 result = NULL; /* just to keep compiler happy (and quiet) */
390 }
391 break;
392 }
393
394 /* update to_space_tail */
395 *pto_space_tail = ((char *) *pto_space_tail) + instance_size;
396
397 /* set forward pointer */
398 *((_svmt_object_instance **) obj) = result;
399
400 #if defined (MAGIC)
401 obj->magic[0] = 0;
402 #endif
403
404 /* we're done */
405 return result;
406
407 #endif
408 }
409 }
410
411 /*
412 ----------------------------------------------------------------------
413 _svmf_trace_native_ref_list
414 ----------------------------------------------------------------------
415 */
416
417 svm_static void
_svmf_trace_native_ref_list(_svmt_JNIEnv * env,_svmt_native_ref * native_list,void ** pto_space_tail)418 _svmf_trace_native_ref_list (_svmt_JNIEnv *env, _svmt_native_ref *native_list,
419 void **pto_space_tail)
420 {
421 while (native_list != NULL)
422 {
423 native_list->ref =
424 _svmf_copy_object (env, native_list->ref, pto_space_tail);
425 native_list = native_list->next;
426 }
427 }
428
429 /*
430 ----------------------------------------------------------------------
431 _svmf_trace_stack
432 ----------------------------------------------------------------------
433 */
434
435 svm_static void
_svmf_trace_stack(_svmt_JNIEnv * env,_svmt_JNIEnv * thread,void ** pto_space_tail)436 _svmf_trace_stack (_svmt_JNIEnv *env, _svmt_JNIEnv *thread,
437 void **pto_space_tail)
438 {
439 _svmt_JavaVM *vm = env->vm;
440 _svmt_stack_frame *frame = thread->stack.current_frame;
441 _svmt_method_info *method = frame->method;
442
443 while (method != &vm->stack_bottom_method)
444 {
445 if (!_svmf_is_set_flag (method->access_flags, SVM_ACC_INTERNAL))
446 {
447 _svmt_stack_value *locals = (_svmt_stack_value *) (void *)
448 (((char *) frame) - method->frame_info->start_offset);
449 _svmt_gc_map_node *parameters_gc_map = method->parameters_gc_map;
450 jint non_parameter_ref_locals_count =
451 method->frame_info->non_parameter_ref_locals_count;
452
453 _svmt_stack_value *stack = (_svmt_stack_value *) (void *)
454 (((char *) frame) + _svmv_stack_offset);
455 jint stack_size = frame->stack_size;
456 _svmt_gc_map_node *stack_gc_map =
457 (stack_size == 0) ? NULL : (frame->pc - 1)->stack_gc_map;
458
459 /* trace pointers embeded in the stack frame */
460 frame->this = _svmf_copy_object (env, frame->this, pto_space_tail);
461 frame->stack_trace_element =
462 _svmf_copy_object (env, frame->stack_trace_element,
463 pto_space_tail);
464
465 /* method formal parameters */
466 {
467 jint i;
468 jint count = parameters_gc_map->size;
469
470 for (i = 0; i < count; i++)
471 {
472 if (_svmf_get_bit (parameters_gc_map->bits, i))
473 {
474 locals[i].reference =
475 _svmf_copy_object (env, locals[i].reference,
476 pto_space_tail);
477 }
478 }
479 }
480
481 /* other ref locals */
482 {
483 jint i;
484 jint start = method->java_args_count;
485 jint end = start + non_parameter_ref_locals_count;
486
487 for (i = start; i < end; i++)
488 {
489 locals[i].reference =
490 _svmf_copy_object (env, locals[i].reference,
491 pto_space_tail);
492 }
493 }
494
495 /* stack */
496 if (stack_size > 0)
497 {
498 jint i;
499 jint max = _svmf_min_jint (stack_size, stack_gc_map->size);
500
501 for (i = 0; i < max; i++)
502 {
503 if (_svmf_get_bit (stack_gc_map->bits, i))
504 {
505 stack[i].reference =
506 _svmf_copy_object (env, stack[i].reference,
507 pto_space_tail);
508 }
509 }
510 }
511 }
512
513 frame = (_svmt_stack_frame *) (void *)
514 (((char *) frame) - frame->previous_offset);
515 method = frame->method;
516 }
517 }
518
519 /*
520 ----------------------------------------------------------------------
521 _svmf_copy_gc_internal
522 ----------------------------------------------------------------------
523 */
524
525 /* IMPORTANT: The world must be stopped prior to calling this
526 function. */
527
528 svm_static jint
_svmf_copy_gc_internal(_svmt_JNIEnv * env,size_t requested_size)529 _svmf_copy_gc_internal (_svmt_JNIEnv *env, size_t requested_size)
530 {
531 _svmt_JavaVM *vm = env->vm;
532 size_t increment = vm->heap.allocation_increment;
533
534 void *to_space;
535 size_t to_space_size;
536
537 _svmt_word *to_space_head;
538 void *to_space_tail;
539
540 struct timeval starttime;
541 struct timeval endtime;
542
543 if (increment == 0)
544 {
545 to_space = vm->heap.next_heap;
546 to_space_size = vm->heap.min_size;
547 }
548 else
549 {
550 size_t current_heap_size =
551 ((char *) vm->heap.alloc) - ((char *) vm->heap.start);
552 size_t hash_code_size = vm->heap.hashed_notmoved * SVM_ALIGNMENT;
553
554 size_t strict_min_size = _svmf_aligned_to_increment
555 (current_heap_size + hash_code_size, increment);
556
557 size_t min_size = _svmf_aligned_to_increment
558 (current_heap_size + hash_code_size + requested_size, increment);
559
560 size_t suggested_size = vm->heap.suggested_next_heap_size;
561
562 size_t ideal_size =
563 (suggested_size > min_size) ? suggested_size : min_size;
564
565 if ((to_space = _svmf_malloc (ideal_size)) != NULL)
566 {
567 to_space_size = ideal_size;
568 }
569 else if ((to_space = _svmf_malloc (min_size)) != NULL)
570 {
571 to_space_size = min_size;
572 }
573 else if ((to_space = _svmf_malloc (strict_min_size)) != NULL)
574 {
575 to_space_size = strict_min_size;
576 }
577 else
578 {
579 return JNI_ERR;
580 }
581 }
582
583 to_space_head = to_space;
584 to_space_tail = to_space;
585
586 if (vm->verbose_gc)
587 {
588 _svmf_printf (env, stderr, "[verbose gc: ");
589 gettimeofday (&starttime, NULL);
590 }
591
592 /* trace stack & native refs */
593
594 _svmf_trace_native_ref_list (env, vm->native_globals.list, &to_space_tail);
595
596 {
597 _svmt_JNIEnv *thread;
598
599 for (thread = vm->threads.user; thread != NULL; thread = thread->next)
600 {
601 _svmf_trace_native_ref_list (env, thread->native_locals.list,
602 &to_space_tail);
603 _svmf_trace_stack (env, thread, &to_space_tail);
604 }
605
606 for (thread = vm->threads.system; thread != NULL; thread = thread->next)
607 {
608 _svmf_trace_native_ref_list (env, thread->native_locals.list,
609 &to_space_tail);
610 _svmf_trace_stack (env, thread, &to_space_tail);
611 }
612 }
613
614 /* trace tospace */
615
616 while (((void *) to_space_head) < to_space_tail)
617 {
618 _svmt_word word = *to_space_head;
619
620 #if defined (_SABLEVM_BIDIRECTIONAL_OBJECT_LAYOUT)
621
622 if (_svmf_word_is_reference (word))
623 {
624 _svmt_object_instance *obj = ((_svmt_object_instance *) word);
625 assert ((((void *) obj) == NULL) ||
626 (((void *) obj) >= vm->heap.start
627 && ((void *) obj) < vm->heap.end)
628 || (((void *) obj) >= to_space
629 && ((void *) obj) < to_space_tail));
630
631 *((_svmt_object_instance **) (to_space_head++)) =
632 _svmf_copy_object (env, obj, &to_space_tail);
633 continue;
634 }
635 #endif
636
637 /* to_space_head is pointing to an object header */
638 assert (!_svmf_word_is_reference (word));
639
640 if (_svmf_lockword_is_array (word))
641 {
642 /* it's actually an array */
643 _svmt_array_instance *array =
644 (_svmt_array_instance *) to_space_head;
645 jint size = array->size;
646 size_t instance_size =
647 _svmf_aligned_size_t (sizeof (_svmt_array_instance));
648 _svmt_word array_type = _svmf_lockword_get_array_type (word);
649
650 switch (array_type)
651 {
652 case SVM_TYPE_BOOLEAN:
653 {
654 instance_size += (((size_t) size) + 7) / 8;
655 instance_size = _svmf_aligned_size_t (instance_size);
656 }
657 break;
658
659 case SVM_TYPE_BYTE:
660 {
661 instance_size += ((size_t) size);
662 instance_size = _svmf_aligned_size_t (instance_size);
663 }
664 break;
665
666 case SVM_TYPE_SHORT:
667 {
668 instance_size += ((size_t) size) * 2;
669 instance_size = _svmf_aligned_size_t (instance_size);
670 }
671 break;
672
673 case SVM_TYPE_CHAR:
674 {
675 instance_size += ((size_t) size) * 2;
676 instance_size = _svmf_aligned_size_t (instance_size);
677 }
678 break;
679
680 case SVM_TYPE_INT:
681 {
682 instance_size += ((size_t) size) * 4;
683 instance_size = _svmf_aligned_size_t (instance_size);
684 }
685 break;
686
687 case SVM_TYPE_LONG:
688 {
689 instance_size += ((size_t) size) * 8;
690 instance_size = _svmf_aligned_size_t (instance_size);
691 }
692 break;
693
694 case SVM_TYPE_FLOAT:
695 {
696 instance_size += ((size_t) size) * 4;
697 instance_size = _svmf_aligned_size_t (instance_size);
698 }
699 break;
700
701 case SVM_TYPE_DOUBLE:
702 {
703 instance_size += ((size_t) size) * 8;
704 instance_size = _svmf_aligned_size_t (instance_size);
705 }
706 break;
707
708 case SVM_TYPE_REFERENCE:
709 {
710 #if defined(_SABLEVM_TRADITIONAL_OBJECT_LAYOUT)
711
712 instance_size += ((size_t) size) * sizeof (void *);
713 instance_size = _svmf_aligned_size_t (instance_size);
714
715 #endif
716 }
717 break;
718
719 default:
720 {
721 _svmm_fatal_error ("impossible control flow");
722 }
723 break;
724 }
725
726 #if defined(_SABLEVM_TRADITIONAL_OBJECT_LAYOUT)
727
728 if (array_type == SVM_TYPE_REFERENCE)
729 {
730 /* trace references */
731 jint i;
732 _svmt_object_instance **elements = (_svmt_object_instance **)
733 (((char *) array) +
734 _svmf_aligned_size_t (sizeof (_svmt_array_instance)));
735
736 for (i = 0; i < size; i++)
737 {
738 elements[i] =
739 _svmf_copy_object (env, elements[i], &to_space_tail);
740 }
741 }
742
743 #endif
744
745 /* skip to next object */
746 to_space_head =
747 (_svmt_word *) (void *) (((char *) array) + instance_size);
748
749 continue;
750 }
751
752 /* it's a normal object */
753 {
754 _svmt_object_instance *obj = (_svmt_object_instance *) to_space_head;
755
756 #if defined (_SABLEVM_BIDIRECTIONAL_OBJECT_LAYOUT)
757
758 size_t end_offset = _svmf_lockword_object_get_end_offset (word);
759
760 if (end_offset == SVM_LOCKWORD_END_OVERFLOW_OFFSET)
761 {
762 end_offset = obj->vtable->next_offset_no_hashcode;
763 }
764
765 switch (_svmf_lockword_get_hashstate (word))
766 {
767 case SVM_HASH_NONE:
768 {
769 /* do nothing */
770 }
771 break;
772
773 case SVM_HASH_MOVED:
774 {
775 end_offset += SVM_ALIGNMENT;
776 }
777 break;
778
779 case SVM_HASH_NOT_MOVED:
780 default:
781 {
782 _svmm_fatal_error ("impossible control flow");
783 }
784 break;
785 }
786
787 /* skip to next object */
788 to_space_head = (_svmt_word *) (void *) (((char *) obj) + end_offset);
789
790 continue;
791
792 #elif defined (_SABLEVM_TRADITIONAL_OBJECT_LAYOUT)
793
794 if (_svmf_lockword_object_is_info_in_header (word))
795 {
796 _svmt_word ref_layout =
797 _svmf_lockword_object_get_ref_layout (word);
798 size_t end_offset = _svmf_lockword_object_get_end_offset (word);
799 _svmt_object_instance **references = (_svmt_object_instance **)
800 (((char *) obj) +
801 _svmf_aligned_size_t (sizeof (_svmt_object_instance)));
802 jint i = 0;
803
804 /* trace reference fields */
805 while (ref_layout != 0)
806 {
807 if ((ref_layout & 0x01) != 0)
808 {
809 references[i] =
810 _svmf_copy_object (env, references[i], &to_space_tail);
811 }
812
813 i++;
814 ref_layout = ref_layout >> 1;
815 }
816
817 switch (_svmf_lockword_get_hashstate (word))
818 {
819 case SVM_HASH_NONE:
820 {
821 /* do nothing */
822 }
823 break;
824
825 case SVM_HASH_MOVED:
826 {
827 end_offset += SVM_ALIGNMENT;
828 }
829 break;
830
831 case SVM_HASH_NOT_MOVED:
832 default:
833 {
834 _svmm_fatal_error ("impossible control flow");
835 }
836 break;
837 }
838
839 /* skip to next object */
840 to_space_head = (_svmt_word *) (((char *) obj) + end_offset);
841
842 continue;
843 }
844
845 /* info is in vtable */
846 {
847 jint count = obj->vtable->ref_field_count;
848 size_t *offsets = obj->vtable->ref_field_offsets;
849 size_t end_offset = obj->vtable->next_offset_no_hashcode;
850 jint i;
851
852 /* trace reference fields */
853 for (i = 0; i < count; i++)
854 {
855 _svmt_object_instance **reference = (_svmt_object_instance **)
856 (((char *) obj) + offsets[i]);
857
858 *reference =
859 _svmf_copy_object (env, *reference, &to_space_tail);
860 }
861
862 switch (_svmf_lockword_get_hashstate (word))
863 {
864 case SVM_HASH_NONE:
865 {
866 /* do nothing */
867 }
868 break;
869
870 case SVM_HASH_MOVED:
871 {
872 end_offset += SVM_ALIGNMENT;
873 }
874 break;
875
876 case SVM_HASH_NOT_MOVED:
877 default:
878 {
879 _svmm_fatal_error ("impossible control flow");
880 }
881 break;
882 }
883
884 /* skip to next object */
885 to_space_head = (_svmt_word *) (((char *) obj) + end_offset);
886
887 continue;
888 }
889
890 #endif
891
892 }
893 }
894
895 if (vm->verbose_gc)
896 {
897 gettimeofday (&endtime, NULL);
898 _svmf_printf (env, stderr,
899 "previously allocated %d bytes, surviving %d bytes, ",
900 ((char *) vm->heap.alloc) - ((char *) vm->heap.start),
901 ((char *) to_space_tail) - ((char *) to_space));
902 }
903
904 assert (to_space_head == to_space_tail);
905
906 vm->heap.hashed_notmoved = 0;
907 vm->heap.hashcode_base +=
908 ((char *) vm->heap.alloc) - ((char *) vm->heap.start);
909
910 if (increment != 0)
911 {
912 size_t suggested_size;
913
914 _svmf_free (vm->heap.start);
915
916 vm->heap.start = to_space;
917 vm->heap.end = ((char *) to_space) + to_space_size;
918 vm->heap.alloc = to_space_head;
919
920 assert (to_space_tail < vm->heap.end);
921
922 /* attempt to keep the gc heap approximately 1/3 full */
923 suggested_size = _svmf_aligned_to_increment
924 (3 *
925 ((((char *) vm->heap.alloc) - ((char *) vm->heap.start)) +
926 requested_size), increment);
927
928 if (suggested_size < vm->heap.min_size)
929 {
930 suggested_size = vm->heap.min_size;
931 }
932
933 if (vm->heap.max_size != 0 && suggested_size > vm->heap.max_size)
934 {
935 suggested_size = vm->heap.max_size;
936 }
937
938 vm->heap.suggested_next_heap_size = suggested_size;
939
940
941 /* reduce new heap size if it's bigger than next suggested size */
942 {
943 char *suggestion = ((char *) vm->heap.start) + suggested_size;
944
945 if ((suggestion >= (((char *) vm->heap.alloc) + requested_size)) &&
946 (suggestion < (char *) vm->heap.end))
947 {
948 vm->heap.end = suggestion;
949 }
950 }
951 }
952 else
953 {
954 vm->heap.next_heap = vm->heap.start;
955
956 vm->heap.start = to_space;
957 vm->heap.end = ((char *) to_space) + vm->heap.min_size;
958 vm->heap.alloc = to_space_head;
959
960 assert (to_space_tail < vm->heap.end);
961 }
962
963 if (vm->verbose_gc)
964 {
965 long secs = endtime.tv_sec - starttime.tv_sec;
966 long usecs = endtime.tv_usec - starttime.tv_usec;
967
968 if (usecs < 0)
969 {
970 usecs += 1000000;
971 secs -= 1;
972 }
973
974 _svmf_printf (env, stderr,
975 "new heap is %d bytes, gc time = %ld sec %ld usec]\n",
976 ((char *) vm->heap.end) - ((char *) vm->heap.start), secs,
977 usecs);
978
979 vm->heap.total_gc_secs += secs;
980 vm->heap.total_gc_usecs += usecs;
981
982 if (vm->heap.total_gc_usecs > 999999)
983 {
984 vm->heap.total_gc_usecs -= 1000000;
985 vm->heap.total_gc_secs += 1;
986 }
987 }
988
989 if (requested_size <=
990 (size_t) (((char *) vm->heap.end) - ((char *) vm->heap.alloc)))
991 {
992 return JNI_OK;
993 }
994
995 return JNI_ERR;
996 }
997
998 /*
999 ----------------------------------------------------------------------
1000 _svmf_copy_gc
1001 ----------------------------------------------------------------------
1002 */
1003
1004 /* IMPORTANT: The calling thread should hold the lock on
1005 vm->global_mutex when calling this function. */
1006
1007 svm_static jint
_svmf_copy_gc_no_exception(_svmt_JNIEnv * env,size_t requested_size)1008 _svmf_copy_gc_no_exception (_svmt_JNIEnv *env, size_t requested_size)
1009 {
1010 _svmt_JavaVM *vm = env->vm;
1011 jint status;
1012
1013 _svmf_stop_the_world (env);
1014
1015 pthread_mutex_unlock (&vm->global_mutex);
1016
1017 status = _svmf_copy_gc_internal (env, requested_size);
1018
1019 pthread_mutex_lock (&vm->global_mutex);
1020
1021 _svmf_resume_the_world (env);
1022
1023 return status;
1024 }
1025
1026 /*
1027 ----------------------------------------------------------------------
1028 _svmf_gc_new_instance
1029 ----------------------------------------------------------------------
1030 */
1031
1032 svm_static jint
_svmf_gc_new_instance(_svmt_JNIEnv * env,size_t instance_size,void ** pinstance)1033 _svmf_gc_new_instance (_svmt_JNIEnv *env, size_t instance_size,
1034 void **pinstance)
1035 {
1036 _svmt_JavaVM *vm = env->vm;
1037 void *result = NULL;
1038 jint status = JNI_OK;
1039
1040 _svmm_mutex_lock (vm->global_mutex);
1041
1042 _svmf_halt_if_requested (env);
1043
1044 if ((instance_size <=
1045 (size_t) (((char *) vm->heap.end) - ((char *) vm->heap.alloc)))
1046 || ((status = _svmf_copy_gc_no_exception (env, instance_size)) ==
1047 JNI_OK))
1048 {
1049 result = vm->heap.alloc;
1050 vm->heap.alloc = ((char *) vm->heap.alloc) + instance_size;
1051 }
1052
1053 _svmm_mutex_unlock ();
1054
1055 if (status != JNI_OK)
1056 {
1057 _svmf_error_OutOfMemoryError (env);
1058 return JNI_ERR;
1059 }
1060
1061 memset (result, 0, instance_size);
1062
1063 *pinstance = result;
1064
1065 return JNI_OK;
1066 }
1067
1068 #endif /* defined (_SABLEVM_COPY_GC) */
1069