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