Logo Search packages:      
Sourcecode: sablevm version File versions  Download package

gc_copying.c

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * This source file is part of SableVM.                            *
 *                                                                 *
 * See the file "LICENSE" for the copyright information and for    *
 * the terms and conditions for copying, distribution and          *
 * modification of this source file.                               *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#if defined (_SABLEVM_COPY_GC)

/*
----------------------------------------------------------------------
_svmf_heap_init_defaults
----------------------------------------------------------------------
*/

svm_static void
_svmf_heap_init_defaults (_svmt_JavaVM *vm)
{
  vm->heap.min_size = SVM_HEAP_DEFAULT_MIN_SIZE;
  vm->heap.max_size = SVM_HEAP_DEFAULT_MAX_SIZE;
  vm->heap.allocation_increment = SVM_HEAP_DEFAULT_ALLOCATION_INCREMENT;
}

/*
----------------------------------------------------------------------
_svmf_heap_init
----------------------------------------------------------------------
*/

svm_static jint
_svmf_heap_init (_svmt_JNIEnv *env)
{
  _svmt_JavaVM *vm = env->vm;

  if (_svmm_validate_min_max_increment
      (vm->heap.min_size,
       vm->heap.max_size, vm->heap.allocation_increment) != JNI_OK)
    {
      return JNI_ERR;
    }

  /* if the heap has a fixed size, allocate both semi-spaces once
     and for all, if not, allocate one semi-space */
  if (vm->heap.allocation_increment == 0 &&
      (2 * vm->heap.min_size) < vm->heap.min_size)
    {
      return JNI_ERR;
    }

  if (vm->heap.allocation_increment == 0)
    {
      if (vm->verbose_gc)
      {
        _svmf_printf (env, stderr,
                  "[verbose gc: allocating fixed size heap (2 * %d bytes)]\n",
                  vm->heap.min_size);
      }

      vm->heap.start = _svmf_malloc (2 * vm->heap.min_size);

      if (vm->heap.start == NULL)
      {
        return JNI_ERR;
      }

      vm->heap.end = ((char *) vm->heap.start) + vm->heap.min_size;
      vm->heap.alloc = vm->heap.start;
      vm->heap.hashcode_base = 0 - (size_t) vm->heap.start;
      vm->heap.next_heap = vm->heap.end;
    }
  else
    {
      if (vm->verbose_gc)
      {
        _svmf_printf (env, stderr,
                  "[verbose gc: allocating initial heap (%d bytes)]\n",
                  vm->heap.min_size);
      }

      vm->heap.start = _svmf_malloc (vm->heap.min_size);

      if (vm->heap.start == NULL)
      {
        return JNI_ERR;
      }

      vm->heap.end = ((char *) vm->heap.start) + vm->heap.min_size;
      vm->heap.alloc = vm->heap.start;
      vm->heap.hashcode_base = 0 - (size_t) vm->heap.start;
      vm->heap.suggested_next_heap_size = vm->heap.min_size;
    }

  return JNI_OK;
}

/*
----------------------------------------------------------------------
_svmf_copy_object
----------------------------------------------------------------------
*/

/* This function copies the object pointed to by obj to to_space. obj
 * may be NULL or pointing to an already copied object.  In all cases,
 * this function returns a pointer to the to_space copy (or NULL).
 */

inline svm_static _svmt_object_instance *
_svmf_copy_object (_svmt_JNIEnv *env, _svmt_object_instance *obj,
               void **pto_space_tail)
{
  _svmt_word lockword;

  /* NULL */
  if (obj == NULL)
    {
      return NULL;
    }

  assert (((void *) obj) >= env->vm->heap.start &&
        ((void *) obj) < env->vm->heap.alloc);

  lockword = obj->lockword;

  /* forward pointer */
  if (_svmf_lockword_is_forward_reference (lockword))
    {
      assert (((void *) lockword) < *pto_space_tail);
      assert (obj->vtable == ((_svmt_object_instance *) lockword)->vtable);

      return (_svmt_object_instance *) lockword;
    }

  /* we must copy the object */
#if defined (MAGIC)
  assert (strcmp (obj->magic, "SableVM") == 0);
#endif

  if (_svmf_lockword_is_array (lockword))
    {
      /* it's actually an array */
      _svmt_array_instance *array = (_svmt_array_instance *) obj;
      jint size = array->size;
      size_t instance_size =
      _svmf_aligned_size_t (sizeof (_svmt_array_instance));
      _svmt_word array_type = _svmf_lockword_get_array_type (array->lockword);
      _svmt_object_instance *result;

      assert (array->vtable->type->is_array);

      switch (array_type)
      {
      case SVM_TYPE_BOOLEAN:
        {
          instance_size += (((size_t) size) + 7) / 8;
        }
        break;

      case SVM_TYPE_BYTE:
        {
          instance_size += ((size_t) size);
        }
        break;

      case SVM_TYPE_SHORT:
        {
          instance_size += ((size_t) size) * 2;
        }
        break;

      case SVM_TYPE_CHAR:
        {
          instance_size += ((size_t) size) * 2;
        }
        break;

      case SVM_TYPE_INT:
        {
          instance_size += ((size_t) size) * 4;
        }
        break;

      case SVM_TYPE_LONG:
        {
          instance_size += ((size_t) size) * 8;
        }
        break;

      case SVM_TYPE_FLOAT:
        {
          instance_size += ((size_t) size) * 4;
        }
        break;

      case SVM_TYPE_DOUBLE:
        {
          instance_size += ((size_t) size) * 8;
        }
        break;

      case SVM_TYPE_REFERENCE:
        {
          instance_size += ((size_t) size) * sizeof (void *);
        }
        break;

      default:
        {
          _svmm_fatal_error ("impossible control flow");
        }
        break;
      }

      instance_size = _svmf_aligned_size_t (instance_size);

#if defined(_SABLEVM_TRADITIONAL_OBJECT_LAYOUT)

      memcpy (*pto_space_tail, array, instance_size);
      result = (_svmt_object_instance *) *pto_space_tail;

#elif defined (_SABLEVM_BIDIRECTIONAL_OBJECT_LAYOUT)

      /* if elements preceed object header, adjust head pointer
       * accordignly */
      if (array_type == SVM_TYPE_REFERENCE)
      {
        size_t offset =
          _svmf_aligned_size_t (((size_t) size) * sizeof (void *));

        memcpy (*pto_space_tail, ((char *) array) - offset, instance_size);
        result =
          (_svmt_object_instance *) (void *) (((char *) *pto_space_tail) +
                                    offset);
      }
      else
      {
        memcpy (*pto_space_tail, array, instance_size);
        result = (_svmt_object_instance *) *pto_space_tail;
      }

#endif /* defined (_SABLEVM_TRADITIONAL_OBJECT_LAYOUT) */

      /* update to_space_tail */
      *pto_space_tail = ((char *) *pto_space_tail) + instance_size;

      /* set forward pointer */
      *((_svmt_object_instance **) array) = result;

#if defined (MAGIC)
      array->magic[0] = 0;
#endif

      /* we're done */
      return result;
    }

  /* it's a normal object */

  assert (!(obj->vtable->type->is_array));

  {
#if defined (_SABLEVM_BIDIRECTIONAL_OBJECT_LAYOUT)

    size_t end_offset = _svmf_lockword_object_get_end_offset (lockword);
    size_t start_offset = _svmf_lockword_object_get_start_offset (lockword);
    size_t instance_size;
    _svmt_object_instance *result;

    if (end_offset == SVM_LOCKWORD_END_OVERFLOW_OFFSET)
      {
      end_offset = obj->vtable->next_offset_no_hashcode;
      }

    if (start_offset == SVM_LOCKWORD_START_OVERFLOW_OFFSET)
      {
      start_offset = obj->vtable->start_offset;
      }

    instance_size = start_offset + end_offset;

    switch (_svmf_lockword_get_hashstate (lockword))
      {
      case SVM_HASH_NONE:
      {
        memcpy (*pto_space_tail, ((char *) obj) - start_offset,
              instance_size);
        result =
          (_svmt_object_instance *) (void *) (((char *) *pto_space_tail) +
                                    start_offset);
      }
      break;

      case SVM_HASH_NOT_MOVED:
      {
        memcpy (*pto_space_tail, ((char *) obj) - start_offset,
              instance_size);
        result =
          (_svmt_object_instance *) (void *) (((char *) *pto_space_tail) +
                                    start_offset);

        instance_size += SVM_ALIGNMENT;
        _svmm_lockword_set_hashstate (result->lockword, SVM_HASH_MOVED);
        _svmf_put_INT_field (result, end_offset, (jint)
                         (env->vm->heap.hashcode_base + (size_t) obj));
      }
      break;

      case SVM_HASH_MOVED:
      {
        instance_size += SVM_ALIGNMENT;
        memcpy (*pto_space_tail, ((char *) obj) - start_offset,
              instance_size);
        result =
          (_svmt_object_instance *) (void *) (((char *) *pto_space_tail) +
                                    start_offset);
      }
      break;

      default:
      {
        result = NULL;
        _svmm_fatal_error ("impossible control flow");
      }
      break;
      }

    /* update to_space_tail */
    *pto_space_tail = ((char *) *pto_space_tail) + instance_size;

    /* set forward pointer */
    *((_svmt_object_instance **) obj) = result;

#if defined (MAGIC)
    obj->magic[0] = 0;
#endif

    /* we're done */
    return result;

#elif defined (_SABLEVM_TRADITIONAL_OBJECT_LAYOUT)

    size_t end_offset = _svmf_lockword_object_get_end_offset (lockword);
    size_t instance_size;
    _svmt_object_instance *result;

    if (_svmf_lockword_object_is_info_in_header (lockword))
      {
      end_offset = _svmf_lockword_object_get_end_offset (lockword);
      }
    else
      {
      end_offset = obj->vtable->next_offset_no_hashcode;
      }

    instance_size = end_offset;

    switch (_svmf_lockword_get_hashstate (lockword))
      {
      case SVM_HASH_NONE:
      {
        memcpy (*pto_space_tail, obj, instance_size);
        result = (_svmt_object_instance *) *pto_space_tail;
      }
      break;

      case SVM_HASH_NOT_MOVED:
      {
        memcpy (*pto_space_tail, obj, instance_size);
        result = (_svmt_object_instance *) *pto_space_tail;

        instance_size += SVM_ALIGNMENT;
        _svmm_lockword_set_hashstate (result->lockword, SVM_HASH_MOVED);
        _svmf_put_INT_field (result, end_offset, (jint)
                         (env->vm->heap.hashcode_base + (size_t) obj));
      }
      break;

      case SVM_HASH_MOVED:
      {
        instance_size += SVM_ALIGNMENT;
        memcpy (*pto_space_tail, obj, instance_size);
        result = (_svmt_object_instance *) *pto_space_tail;
      }
      break;

      default:
      {
        _svmm_fatal_error ("impossible control flow");
        result = NULL;  /* just to keep compiler happy (and quiet) */
      }
      break;
      }

    /* update to_space_tail */
    *pto_space_tail = ((char *) *pto_space_tail) + instance_size;

    /* set forward pointer */
    *((_svmt_object_instance **) obj) = result;

#if defined (MAGIC)
    obj->magic[0] = 0;
#endif

    /* we're done */
    return result;

#endif
  }
}

/*
----------------------------------------------------------------------
_svmf_trace_native_ref_list
----------------------------------------------------------------------
*/

svm_static void
_svmf_trace_native_ref_list (_svmt_JNIEnv *env, _svmt_native_ref *native_list,
                       void **pto_space_tail)
{
  while (native_list != NULL)
    {
      native_list->ref =
      _svmf_copy_object (env, native_list->ref, pto_space_tail);
      native_list = native_list->next;
    }
}

/*
----------------------------------------------------------------------
_svmf_trace_stack
----------------------------------------------------------------------
*/

svm_static void
_svmf_trace_stack (_svmt_JNIEnv *env, _svmt_JNIEnv *thread,
               void **pto_space_tail)
{
  _svmt_JavaVM *vm = env->vm;
  _svmt_stack_frame *frame = thread->stack.current_frame;
  _svmt_method_info *method = frame->method;

  while (method != &vm->stack_bottom_method)
    {
      if (!_svmf_is_set_flag (method->access_flags, SVM_ACC_INTERNAL))
      {
        _svmt_stack_value *locals = (_svmt_stack_value *) (void *)
          (((char *) frame) - method->frame_info->start_offset);
        _svmt_gc_map_node *parameters_gc_map = method->parameters_gc_map;
        jint non_parameter_ref_locals_count =
          method->frame_info->non_parameter_ref_locals_count;

        _svmt_stack_value *stack = (_svmt_stack_value *) (void *)
          (((char *) frame) + _svmv_stack_offset);
        jint stack_size = frame->stack_size;
        _svmt_gc_map_node *stack_gc_map =
          (stack_size == 0) ? NULL : (frame->pc - 1)->stack_gc_map;

        /* trace pointers embeded in the stack frame */
        frame->this = _svmf_copy_object (env, frame->this, pto_space_tail);
        frame->stack_trace_element =
          _svmf_copy_object (env, frame->stack_trace_element,
                         pto_space_tail);

        /* method formal parameters */
        {
          jint i;
          jint count = parameters_gc_map->size;

          for (i = 0; i < count; i++)
            {
            if (_svmf_get_bit (parameters_gc_map->bits, i))
              {
                locals[i].reference =
                  _svmf_copy_object (env, locals[i].reference,
                               pto_space_tail);
              }
            }
        }

        /* other ref locals */
        {
          jint i;
          jint start = method->java_args_count;
          jint end = start + non_parameter_ref_locals_count;

          for (i = start; i < end; i++)
            {
            locals[i].reference =
              _svmf_copy_object (env, locals[i].reference,
                             pto_space_tail);
            }
        }

        /* stack */
        if (stack_size > 0)
          {
            jint i;
            jint max = _svmf_min_jint (stack_size, stack_gc_map->size);

            for (i = 0; i < max; i++)
            {
              if (_svmf_get_bit (stack_gc_map->bits, i))
                {
                  stack[i].reference =
                  _svmf_copy_object (env, stack[i].reference,
                                 pto_space_tail);
                }
            }
          }
      }

      frame = (_svmt_stack_frame *) (void *)
      (((char *) frame) - frame->previous_offset);
      method = frame->method;
    }
}

/*
----------------------------------------------------------------------
_svmf_copy_gc_internal
----------------------------------------------------------------------
*/

/* IMPORTANT: The world must be stopped prior to calling this
   function. */

svm_static jint
_svmf_copy_gc_internal (_svmt_JNIEnv *env, size_t requested_size)
{
  _svmt_JavaVM *vm = env->vm;
  size_t increment = vm->heap.allocation_increment;

  void *to_space;
  size_t to_space_size;

  _svmt_word *to_space_head;
  void *to_space_tail;

  struct timeval starttime;
  struct timeval endtime;

  if (increment == 0)
    {
      to_space = vm->heap.next_heap;
      to_space_size = vm->heap.min_size;
    }
  else
    {
      size_t current_heap_size =
      ((char *) vm->heap.alloc) - ((char *) vm->heap.start);
      size_t hash_code_size = vm->heap.hashed_notmoved * SVM_ALIGNMENT;

      size_t strict_min_size = _svmf_aligned_to_increment
      (current_heap_size + hash_code_size, increment);

      size_t min_size = _svmf_aligned_to_increment
      (current_heap_size + hash_code_size + requested_size, increment);

      size_t suggested_size = vm->heap.suggested_next_heap_size;

      size_t ideal_size =
      (suggested_size > min_size) ? suggested_size : min_size;

      if ((to_space = _svmf_malloc (ideal_size)) != NULL)
      {
        to_space_size = ideal_size;
      }
      else if ((to_space = _svmf_malloc (min_size)) != NULL)
      {
        to_space_size = min_size;
      }
      else if ((to_space = _svmf_malloc (strict_min_size)) != NULL)
      {
        to_space_size = strict_min_size;
      }
      else
      {
        return JNI_ERR;
      }
    }

  to_space_head = to_space;
  to_space_tail = to_space;

  if (vm->verbose_gc)
    {
      _svmf_printf (env, stderr, "[verbose gc: ");
      gettimeofday (&starttime, NULL);
    }

  /* trace stack & native refs */

  _svmf_trace_native_ref_list (env, vm->native_globals.list, &to_space_tail);

  {
    _svmt_JNIEnv *thread;

    for (thread = vm->threads.user; thread != NULL; thread = thread->next)
      {
      _svmf_trace_native_ref_list (env, thread->native_locals.list,
                             &to_space_tail);
      _svmf_trace_stack (env, thread, &to_space_tail);
      }

    for (thread = vm->threads.system; thread != NULL; thread = thread->next)
      {
      _svmf_trace_native_ref_list (env, thread->native_locals.list,
                             &to_space_tail);
      _svmf_trace_stack (env, thread, &to_space_tail);
      }
  }

  /* trace tospace */

  while (((void *) to_space_head) < to_space_tail)
    {
      _svmt_word word = *to_space_head;

#if defined (_SABLEVM_BIDIRECTIONAL_OBJECT_LAYOUT)

      if (_svmf_word_is_reference (word))
      {
        _svmt_object_instance *obj = ((_svmt_object_instance *) word);
        assert ((((void *) obj) == NULL) ||
              (((void *) obj) >= vm->heap.start
               && ((void *) obj) < vm->heap.end)
              || (((void *) obj) >= to_space
                  && ((void *) obj) < to_space_tail));

        *((_svmt_object_instance **) (to_space_head++)) =
          _svmf_copy_object (env, obj, &to_space_tail);
        continue;
      }
#endif

      /* to_space_head is pointing to an object header */
      assert (!_svmf_word_is_reference (word));

      if (_svmf_lockword_is_array (word))
      {
        /* it's actually an array */
        _svmt_array_instance *array =
          (_svmt_array_instance *) to_space_head;
        jint size = array->size;
        size_t instance_size =
          _svmf_aligned_size_t (sizeof (_svmt_array_instance));
        _svmt_word array_type = _svmf_lockword_get_array_type (word);

        switch (array_type)
          {
          case SVM_TYPE_BOOLEAN:
            {
            instance_size += (((size_t) size) + 7) / 8;
            instance_size = _svmf_aligned_size_t (instance_size);
            }
            break;

          case SVM_TYPE_BYTE:
            {
            instance_size += ((size_t) size);
            instance_size = _svmf_aligned_size_t (instance_size);
            }
            break;

          case SVM_TYPE_SHORT:
            {
            instance_size += ((size_t) size) * 2;
            instance_size = _svmf_aligned_size_t (instance_size);
            }
            break;

          case SVM_TYPE_CHAR:
            {
            instance_size += ((size_t) size) * 2;
            instance_size = _svmf_aligned_size_t (instance_size);
            }
            break;

          case SVM_TYPE_INT:
            {
            instance_size += ((size_t) size) * 4;
            instance_size = _svmf_aligned_size_t (instance_size);
            }
            break;

          case SVM_TYPE_LONG:
            {
            instance_size += ((size_t) size) * 8;
            instance_size = _svmf_aligned_size_t (instance_size);
            }
            break;

          case SVM_TYPE_FLOAT:
            {
            instance_size += ((size_t) size) * 4;
            instance_size = _svmf_aligned_size_t (instance_size);
            }
            break;

          case SVM_TYPE_DOUBLE:
            {
            instance_size += ((size_t) size) * 8;
            instance_size = _svmf_aligned_size_t (instance_size);
            }
            break;

          case SVM_TYPE_REFERENCE:
            {
#if defined(_SABLEVM_TRADITIONAL_OBJECT_LAYOUT)

            instance_size += ((size_t) size) * sizeof (void *);
            instance_size = _svmf_aligned_size_t (instance_size);

#endif
            }
            break;

          default:
            {
            _svmm_fatal_error ("impossible control flow");
            }
            break;
          }

#if defined(_SABLEVM_TRADITIONAL_OBJECT_LAYOUT)

        if (array_type == SVM_TYPE_REFERENCE)
          {
            /* trace references */
            jint i;
            _svmt_object_instance **elements = (_svmt_object_instance **)
            (((char *) array) +
             _svmf_aligned_size_t (sizeof (_svmt_array_instance)));

            for (i = 0; i < size; i++)
            {
              elements[i] =
                _svmf_copy_object (env, elements[i], &to_space_tail);
            }
          }

#endif

        /* skip to next object */
        to_space_head =
          (_svmt_word *) (void *) (((char *) array) + instance_size);

        continue;
      }

      /* it's a normal object */
      {
      _svmt_object_instance *obj = (_svmt_object_instance *) to_space_head;

#if defined (_SABLEVM_BIDIRECTIONAL_OBJECT_LAYOUT)

      size_t end_offset = _svmf_lockword_object_get_end_offset (word);

      if (end_offset == SVM_LOCKWORD_END_OVERFLOW_OFFSET)
        {
          end_offset = obj->vtable->next_offset_no_hashcode;
        }

      switch (_svmf_lockword_get_hashstate (word))
        {
        case SVM_HASH_NONE:
          {
            /* do nothing */
          }
          break;

        case SVM_HASH_MOVED:
          {
            end_offset += SVM_ALIGNMENT;
          }
          break;

        case SVM_HASH_NOT_MOVED:
        default:
          {
            _svmm_fatal_error ("impossible control flow");
          }
          break;
        }

      /* skip to next object */
      to_space_head = (_svmt_word *) (void *) (((char *) obj) + end_offset);

      continue;

#elif defined (_SABLEVM_TRADITIONAL_OBJECT_LAYOUT)

      if (_svmf_lockword_object_is_info_in_header (word))
        {
          _svmt_word ref_layout =
            _svmf_lockword_object_get_ref_layout (word);
          size_t end_offset = _svmf_lockword_object_get_end_offset (word);
          _svmt_object_instance **references = (_svmt_object_instance **)
            (((char *) obj) +
             _svmf_aligned_size_t (sizeof (_svmt_object_instance)));
          jint i = 0;

          /* trace reference fields */
          while (ref_layout != 0)
            {
            if ((ref_layout & 0x01) != 0)
              {
                references[i] =
                  _svmf_copy_object (env, references[i], &to_space_tail);
              }

            i++;
            ref_layout = ref_layout >> 1;
            }

          switch (_svmf_lockword_get_hashstate (word))
            {
            case SVM_HASH_NONE:
            {
              /* do nothing */
            }
            break;

            case SVM_HASH_MOVED:
            {
              end_offset += SVM_ALIGNMENT;
            }
            break;

            case SVM_HASH_NOT_MOVED:
            default:
            {
              _svmm_fatal_error ("impossible control flow");
            }
            break;
            }

          /* skip to next object */
          to_space_head = (_svmt_word *) (((char *) obj) + end_offset);

          continue;
        }

      /* info is in vtable */
      {
        jint count = obj->vtable->ref_field_count;
        size_t *offsets = obj->vtable->ref_field_offsets;
        size_t end_offset = obj->vtable->next_offset_no_hashcode;
        jint i;

        /* trace reference fields */
        for (i = 0; i < count; i++)
          {
            _svmt_object_instance **reference = (_svmt_object_instance **)
            (((char *) obj) + offsets[i]);

            *reference =
            _svmf_copy_object (env, *reference, &to_space_tail);
          }

        switch (_svmf_lockword_get_hashstate (word))
          {
          case SVM_HASH_NONE:
            {
            /* do nothing */
            }
            break;

          case SVM_HASH_MOVED:
            {
            end_offset += SVM_ALIGNMENT;
            }
            break;

          case SVM_HASH_NOT_MOVED:
          default:
            {
            _svmm_fatal_error ("impossible control flow");
            }
            break;
          }

        /* skip to next object */
        to_space_head = (_svmt_word *) (((char *) obj) + end_offset);

        continue;
      }

#endif

      }
    }

  if (vm->verbose_gc)
    {
      gettimeofday (&endtime, NULL);
      _svmf_printf (env, stderr,
                "previously allocated %d bytes, surviving %d bytes, ",
                ((char *) vm->heap.alloc) - ((char *) vm->heap.start),
                ((char *) to_space_tail) - ((char *) to_space));
    }

  assert (to_space_head == to_space_tail);

  vm->heap.hashed_notmoved = 0;
  vm->heap.hashcode_base +=
    ((char *) vm->heap.alloc) - ((char *) vm->heap.start);

  if (increment != 0)
    {
      size_t suggested_size;

      _svmf_free (vm->heap.start);

      vm->heap.start = to_space;
      vm->heap.end = ((char *) to_space) + to_space_size;
      vm->heap.alloc = to_space_head;

      assert (to_space_tail < vm->heap.end);

      /* attempt to keep the gc heap approximately 1/3 full */
      suggested_size = _svmf_aligned_to_increment
      (3 *
       ((((char *) vm->heap.alloc) - ((char *) vm->heap.start)) +
        requested_size), increment);

      if (suggested_size < vm->heap.min_size)
      {
        suggested_size = vm->heap.min_size;
      }

      if (vm->heap.max_size != 0 && suggested_size > vm->heap.max_size)
      {
        suggested_size = vm->heap.max_size;
      }

      vm->heap.suggested_next_heap_size = suggested_size;


      /* reduce new heap size if it's bigger than next suggested size */
      {
      char *suggestion = ((char *) vm->heap.start) + suggested_size;

      if ((suggestion >= (((char *) vm->heap.alloc) + requested_size)) &&
          (suggestion < (char *) vm->heap.end))
        {
          vm->heap.end = suggestion;
        }
      }
    }
  else
    {
      vm->heap.next_heap = vm->heap.start;

      vm->heap.start = to_space;
      vm->heap.end = ((char *) to_space) + vm->heap.min_size;
      vm->heap.alloc = to_space_head;

      assert (to_space_tail < vm->heap.end);
    }

  if (vm->verbose_gc)
    {
      long secs = endtime.tv_sec - starttime.tv_sec;
      long usecs = endtime.tv_usec - starttime.tv_usec;

      if (usecs < 0)
      {
        usecs += 1000000;
        secs -= 1;
      }

      _svmf_printf (env, stderr,
                "new heap is %d bytes, gc time = %ld sec %ld usec]\n",
                ((char *) vm->heap.end) - ((char *) vm->heap.start), secs,
                usecs);

      vm->heap.total_gc_secs += secs;
      vm->heap.total_gc_usecs += usecs;

      if (vm->heap.total_gc_usecs > 999999)
      {
        vm->heap.total_gc_usecs -= 1000000;
        vm->heap.total_gc_secs += 1;
      }
    }

  if (requested_size <=
      (size_t) (((char *) vm->heap.end) - ((char *) vm->heap.alloc)))
    {
      return JNI_OK;
    }

  return JNI_ERR;
}

/*
----------------------------------------------------------------------
_svmf_copy_gc
----------------------------------------------------------------------
*/

/* IMPORTANT: The calling thread should hold the lock on
   vm->global_mutex when calling this function. */

svm_static jint
_svmf_copy_gc_no_exception (_svmt_JNIEnv *env, size_t requested_size)
{
  _svmt_JavaVM *vm = env->vm;
  jint status;

  _svmf_stop_the_world (env);

  pthread_mutex_unlock (&vm->global_mutex);

  status = _svmf_copy_gc_internal (env, requested_size);

  pthread_mutex_lock (&vm->global_mutex);

  _svmf_resume_the_world (env);

  return status;
}

/*
----------------------------------------------------------------------
_svmf_gc_new_instance
----------------------------------------------------------------------
*/

svm_static jint
_svmf_gc_new_instance (_svmt_JNIEnv *env, size_t instance_size,
                   void **pinstance)
{
  _svmt_JavaVM *vm = env->vm;
  void *result = NULL;
  jint status = JNI_OK;

  _svmm_mutex_lock (vm->global_mutex);

  _svmf_halt_if_requested (env);

  if ((instance_size <=
       (size_t) (((char *) vm->heap.end) - ((char *) vm->heap.alloc)))
      || ((status = _svmf_copy_gc_no_exception (env, instance_size)) ==
        JNI_OK))
    {
      result = vm->heap.alloc;
      vm->heap.alloc = ((char *) vm->heap.alloc) + instance_size;
    }

  _svmm_mutex_unlock ();

  if (status != JNI_OK)
    {
      _svmf_error_OutOfMemoryError (env);
      return JNI_ERR;
    }

  memset (result, 0, instance_size);

  *pinstance = result;

  return JNI_OK;
}

#endif /* defined (_SABLEVM_COPY_GC) */

Generated by  Doxygen 1.6.0   Back to index