Beispiel #1
0
/* Dump the header of the object with variables */
static void
_syx_memory_write_object_with_vars (SyxObject *object, FILE *image)
{
  syx_int32 data;

  _syx_memory_write ((SyxOop *)&object, FALSE, 1, image);
  _syx_memory_write (&object->klass, FALSE, 1, image);
  fputc (object->has_refs, image);
  fputc (object->is_constant, image);

  data = syx_object_vars_size ((SyxOop)object);
  data = SYX_COMPAT_SWAP_32(data);
  fwrite (&data, sizeof (syx_int32), 1, image);

  /* store instance variables, keep an eye on special cases */
  if ((SYX_OOP_EQ (object->klass, syx_block_context_class) ||
       SYX_OOP_EQ (object->klass, syx_method_context_class))
      && !SYX_IS_NIL (object->vars[SYX_VARS_CONTEXT_PART_STACK]))
    _syx_memory_write_vars_with_fp (object, SYX_VARS_CONTEXT_PART_STACK, SYX_VARS_CONTEXT_PART_FRAME_POINTER, image);
  else if (SYX_OOP_EQ (object->klass, syx_process_class)
           && !SYX_IS_NIL (object->vars[SYX_VARS_PROCESS_STACK]))
    _syx_memory_write_vars_with_fp (object, SYX_VARS_PROCESS_STACK, SYX_VARS_PROCESS_FRAME_POINTER, image);
  else
    _syx_memory_write (object->vars, TRUE, SYX_COMPAT_SWAP_32(data), image);
}
Beispiel #2
0
/* Write the variables of a Process or of a Context, fixing the frame pointer to match a valid index
   in the stack */
static void
_syx_memory_write_vars_with_fp (SyxObject *object, SyxVariables stack_var, SyxVariables fp_var, FILE *image)
{
  SyxInterpFrame *frame = SYX_OOP_CAST_POINTER (object->vars[fp_var]);
  SyxOop stack;
  syx_int32 offset;

  if (!SYX_IS_NIL (frame->detached_frame))
    {
      stack = frame->detached_frame;
      offset = 0;
    }
  else
    {
      stack = object->vars[stack_var];
      offset = SYX_COMPAT_SWAP_32 (SYX_POINTERS_OFFSET (frame, SYX_OBJECT_DATA (stack)));
    }

  /* Write all variables before FRAME_POINTER */
  _syx_memory_write (object->vars, TRUE, fp_var, image);
  /* Now specify our own type for frame pointers */
  fputc (SYX_MEMORY_TYPE_FRAME_POINTER, image);
  /* We have to store the stack OOP in order to point to the right stack when loading back the image */
  _syx_memory_write (&stack, FALSE, 1, image);
  fwrite (&offset, sizeof (syx_int32), 1, image);
  /* Let's store the remaining variables */
  _syx_memory_write (object->vars + fp_var + 1, TRUE,
                     syx_object_vars_size ((SyxOop)object) - fp_var - 1, image);
}
Beispiel #3
0
/* Writes a single entry of the frame that points to another frame */
static void
_syx_memory_write_lazy_pointer (SyxObject *process, SyxInterpFrame *frame, FILE *image)
{
  SyxOop stack;
  syx_int32 offset;
  if (frame && !SYX_IS_NIL (frame->detached_frame))
    stack = frame->detached_frame;
  else if (!process || !frame)
    stack = syx_nil; /* this will be encoded as 0 */
  else
    stack = process->vars[SYX_VARS_PROCESS_STACK];

  _syx_memory_write (&stack, FALSE, 1, image);
  offset = SYX_COMPAT_SWAP_32 (SYX_POINTERS_OFFSET (frame, SYX_OBJECT_DATA (stack)));

  fwrite (&offset, sizeof (syx_int32), 1, image);
}
Beispiel #4
0
/* Dump a single frame */
static void
_syx_memory_write_frame (SyxObject *process, SyxInterpFrame *frame, SyxInterpFrame *upper_frame, FILE *image)
{
  syx_int32 data;
  SyxInterpFrame *bottom_frame;

  if (!process)
    bottom_frame = NULL;
  else
    bottom_frame = (SyxInterpFrame *)SYX_OBJECT_DATA (process->vars[SYX_VARS_PROCESS_STACK]);

  _syx_memory_write (&frame->this_context, FALSE, 1, image);
  _syx_memory_write (&frame->detached_frame, FALSE, 1, image);
  _syx_memory_write_lazy_pointer (process, frame->parent_frame, image);
  _syx_memory_write_lazy_pointer (process, frame->outer_frame, image);
  _syx_memory_write_lazy_pointer (process, frame->stack_return_frame, image);
  _syx_memory_write (&frame->method, FALSE, 1, image);
  _syx_memory_write (&frame->closure, FALSE, 1, image);
  /* this is not a SmallInteger */
  data = SYX_COMPAT_SWAP_32 (frame->next_instruction);
  fwrite (&data, sizeof (syx_int32), 1, image);
  /* the stack pointer should point inside the process stack itself */
  if (process)
    _syx_memory_write (&process->vars[SYX_VARS_PROCESS_STACK], FALSE, 1, image);
  else
    {
      data = SYX_COMPAT_SWAP_32 (0);
      fwrite (&data, sizeof (syx_int32), 1, image);
    }
  data = SYX_COMPAT_SWAP_32 (SYX_POINTERS_OFFSET (frame->stack, bottom_frame));
  fwrite (&data, sizeof (syx_int32), 1, image);
  _syx_memory_write (&frame->receiver, TRUE, 1, image);
  /* Store arguments, temporaries and local stack.
     Only copy arguments and temporaries for detached frames without following the stack pointer */
  if (SYX_IS_NIL (frame->detached_frame))
    {
      /* if no upper_frame is given, this frame is the top most frame of the process stack */
      if (!upper_frame)
        data = SYX_POINTERS_OFFSET (frame->stack, &frame->local);
      else
        data = SYX_POINTERS_OFFSET (upper_frame, &frame->local);
    }
  else
    data = SYX_OBJECT_DATA_SIZE (frame->detached_frame) - SYX_POINTERS_OFFSET (&frame->local, frame);
  data = SYX_COMPAT_SWAP_32 (data);
  fwrite (&data, sizeof (syx_int32), 1, image);
  _syx_memory_write (&frame->local, TRUE, SYX_COMPAT_SWAP_32 (data), image);
}
Beispiel #5
0
/*!
  Dumps all the memory.

  \param path the file path to put all inside
  \return FALSE if an error occurred
*/
syx_bool
syx_memory_save_image (syx_symbol path)
{
  SyxObject *object;
  FILE *image;
  syx_int32 data = 0;
  SyxObject *stack;
  SyxOop process;

  if (!path)
    path = SYX_OBJECT_SYMBOL (syx_globals_at ("ImageFileName"));

  if (!path)
    return FALSE;

  image = fopen (path, "wb");
  if (!image)
    return FALSE;

  syx_memory_gc ();

  data = SYX_COMPAT_SWAP_32 (_syx_memory_size);
  fwrite (&data, sizeof (syx_int32), 1, image);
  data = SYX_COMPAT_SWAP_32 (_syx_freed_memory_top);
  fwrite (&data, sizeof (syx_int32), 1, image);
  _syx_memory_write (_syx_freed_memory, FALSE, _syx_freed_memory_top, image);

  _syx_scheduler_save (image);

  _syx_memory_write (&syx_globals, FALSE, 1, image);
  _syx_memory_write (&syx_symbols, FALSE, 1, image);

  /* First store the processes */
  process = syx_processor_active_process;
  if (!SYX_IS_NIL (process))
    {
      do
        {
          _syx_memory_write_process_stack (SYX_OBJECT (process), image);
          process = SYX_PROCESS_NEXT (process);
        } while (SYX_OOP_NE (process, syx_processor_active_process));
    }

  for (object=syx_memory; object <= SYX_MEMORY_TOP; object++)
    {
      /* the mark check is not related to the GC but means the object has been already written */
      if (SYX_IS_NIL (object->klass) || object->is_marked)
        continue;

      _syx_memory_write_object_with_vars (object, image);

      /* store data */
      data = SYX_COMPAT_SWAP_32 (object->data_size);
      fwrite (&data, sizeof (syx_varsize), 1, image);
      if (object->data_size > 0)
        {
          if (object->has_refs)
            _syx_memory_write (object->data, TRUE, object->data_size, image);
          else
            {
#ifdef HAVE_LIBGMP
              if (SYX_OBJECT_IS_LARGE_INTEGER ((SyxOop)object))
                {
                  /* This algorithm is used to store large integers.
                     We need to specify how many bytes GMP wrote to the image,
                     for systems that don't support GMP */

                  syx_int32 offset = 0;
                  syx_nint start, end;
                  /* specify that's a large integer */
                  fputc (SYX_MEMORY_TYPE_LARGE_INTEGER, image);
                  /* make space to hold the offset */
                  fwrite (&offset, sizeof (syx_int32), 1, image);
                  start = ftell (image);
                  mpz_out_raw (image, SYX_OBJECT_LARGE_INTEGER ((SyxOop)object));
                  end = ftell (image);
                  offset = end - start;
                  /* go back to the offset */
                  fseek (image, - offset - sizeof (syx_int32), SEEK_CUR);
                  /* now write the length of the data written by mpz_out_raw () */
                  data = SYX_COMPAT_SWAP_32 (offset);
                  fwrite (&data, sizeof (syx_int32), 1, image);
                  /* return again to continue normal writing */
                  fseek (image, offset, SEEK_CUR);
                }
              else
#endif /* HAVE_LIBGMP */
                {
                  /* it's not a large integer */
                  fputc (SYX_MEMORY_TYPE_NORMAL, image);
                  fwrite (object->data, sizeof (syx_int8), object->data_size, image);
                }
            }
        }

      /* Check for block closures that are not attached to any process */
      if (SYX_OOP_EQ (object->klass, syx_block_closure_class))
        {
          stack = SYX_OBJECT (object->vars[SYX_VARS_BLOCK_CLOSURE_OUTER_FRAME]);
          /* Check if the stack has been collected or written to the image */
          if (SYX_IS_NIL (SYX_POINTER_CAST_OOP (stack)) || stack->is_marked)
            continue;

          _syx_memory_write_object_with_vars (stack, image);

          data = SYX_COMPAT_SWAP_32 (stack->data_size);
          fwrite (&data, sizeof (syx_varsize), 1, image);
          /* Store the index of this frame */
          fputc (SYX_MEMORY_TYPE_BOF, image);
          data = SYX_COMPAT_SWAP_32 (0);
          fwrite (&data, sizeof (syx_varsize), 1, image);
          /* Outer frames have only one frame */
          _syx_memory_write_frame (NULL, (SyxInterpFrame *)stack->data, NULL, image);
          fputc (SYX_MEMORY_TYPE_EOS, image);
          fwrite (&data, sizeof (syx_varsize), 1, image);
          
          stack->is_marked = TRUE;
        }
    }

  fclose (image);

  /* be sure all objects are unmarked */
  for (object=syx_memory; object <= SYX_MEMORY_TOP; object++)
    object->is_marked = FALSE;

  return TRUE;
}
Beispiel #6
0
/* Dump the whole stack of the process.
   This will also dump relative objects containing stack, like block closure outerFrames. */
static void
_syx_memory_write_process_stack (SyxObject *process, FILE *image)
{
  syx_int32 data;
  SyxObject *stack = SYX_OBJECT (process->vars[SYX_VARS_PROCESS_STACK]);
  SyxInterpFrame *bottom_frame = (SyxInterpFrame *)stack->data;
  SyxInterpFrame *frame = SYX_OOP_CAST_POINTER (process->vars[SYX_VARS_PROCESS_FRAME_POINTER]);
  SyxInterpFrame *upper_frame = NULL;
  SyxOop *oop;

  if (SYX_IS_NIL (SYX_POINTER_CAST_OOP (stack)))
    return;

  _syx_memory_write_object_with_vars (stack, image);

  /* store data size */
  data = SYX_COMPAT_SWAP_32 (stack->data_size);
  fwrite (&data, sizeof (syx_varsize), 1, image);
  /* We have to do things in reverse order because the stack is such a reverse single linked list,
     each frame connected by parent frames */
  while (frame)
    {
      /* We store detached frames later */
      if (!SYX_IS_NIL (frame->detached_frame))
        {
          frame = frame->parent_frame;
          continue;
        }

      /* Store the index of this frame */
      fputc (SYX_MEMORY_TYPE_BOF, image);
      data = SYX_COMPAT_SWAP_32 (SYX_POINTERS_OFFSET (frame, bottom_frame));
      fwrite (&data, sizeof (syx_varsize), 1, image);
      _syx_memory_write_frame (process, frame, NULL, image);
      upper_frame = frame;
      frame = frame->parent_frame;
    }
  fputc (SYX_MEMORY_TYPE_EOS, image);
  /* We have to store the rest of objects, for detached frames, up to the upper frame.
     What we need is only the local stacks, but we don't know where they begin, so just skip C pointers */
  if (upper_frame)
    {
      data = SYX_COMPAT_SWAP_32 (SYX_POINTERS_OFFSET (upper_frame, bottom_frame));
      fwrite (&data, sizeof (syx_int32), 1, image);
      for (oop = (SyxOop *)bottom_frame; oop != (SyxOop *)upper_frame; oop++)
        {
          if (SYX_IS_CPOINTER (*oop))
            _syx_memory_write (&syx_nil, TRUE, 1, image);
          else
            _syx_memory_write (oop, TRUE, 1, image);
        }
    }
  else
    {
      data = SYX_COMPAT_SWAP_32 (0);
      fwrite (&data, sizeof (syx_int32), 1, image);
    }
  stack->is_marked = TRUE;

  /* Let's store all detached frames until they have a reference to this process */
  frame = SYX_OOP_CAST_POINTER (process->vars[SYX_VARS_PROCESS_FRAME_POINTER]);
  while (frame)
    {
      stack = SYX_OBJECT (frame->detached_frame);
      /* Also check if the stack has been collected */
      if (SYX_IS_NIL (SYX_POINTER_CAST_OOP (stack)) || stack->is_marked)
        {
          frame = frame->parent_frame;
          continue;
        }

      _syx_memory_write_object_with_vars (stack, image);

      data = SYX_COMPAT_SWAP_32 (stack->data_size);
      fwrite (&data, sizeof (syx_varsize), 1, image);    
      /* Store the index of this frame */
      fputc (SYX_MEMORY_TYPE_BOF, image);
      data = SYX_COMPAT_SWAP_32 (0);
      fwrite (&data, sizeof (syx_varsize), 1, image);
      _syx_memory_write_frame (process, frame, NULL, image);
      fputc (SYX_MEMORY_TYPE_EOS, image);
      fwrite (&data, sizeof (syx_varsize), 1, image);

      stack->is_marked = TRUE;
      frame = frame->parent_frame;
    }
}
Beispiel #7
0
/*!
  Dumps all the memory.

  \param path the file path to put all inside
  \return FALSE if an error occurred
*/
syx_bool
syx_memory_save_image (syx_symbol path)
{
  SyxObject *object;
  FILE *image;
  syx_int32 data;

  if (!path)
    path = SYX_OBJECT_SYMBOL (syx_globals_at ("ImageFileName"));

  if (!path)
    return FALSE;

  image = fopen (path, "wb");
  if (!image)
    return FALSE;

  syx_memory_gc ();

  data = SYX_COMPAT_SWAP_32 (_syx_memory_size);
  fwrite (&data, sizeof (syx_int32), 1, image);
  data = SYX_COMPAT_SWAP_32 (_syx_freed_memory_top);
  fwrite (&data, sizeof (syx_int32), 1, image);
  _syx_memory_write (_syx_freed_memory, FALSE, _syx_freed_memory_top, image);

  _syx_scheduler_save (image);

  _syx_memory_write (&syx_globals, FALSE, 1, image);
  _syx_memory_write (&syx_symbols, FALSE, 1, image);

  for (object=syx_memory; object <= SYX_MEMORY_TOP; object++)
    {
      if (SYX_IS_NIL (object->klass))
        continue;

      _syx_memory_write ((SyxOop *)&object, FALSE, 1, image);
      _syx_memory_write (&object->klass, FALSE, 1, image);
      fputc (object->has_refs, image);
      fputc (object->is_constant, image);

      /* store instance variables */
      data = syx_object_vars_size ((SyxOop)object);
      data = SYX_COMPAT_SWAP_32(data);
      fwrite (&data, sizeof (syx_varsize), 1, image);
      _syx_memory_write (object->vars, TRUE, SYX_COMPAT_SWAP_32(data), image);

      /* store data */
      data = SYX_COMPAT_SWAP_32 (object->data_size);
      fwrite (&data, sizeof (syx_varsize), 1, image);
      if (object->data_size > 0)
        {
          if (object->has_refs)
            _syx_memory_write (object->data, TRUE, object->data_size, image);
          else
            {
#ifdef HAVE_LIBGMP
              if (SYX_OBJECT_IS_LARGE_INTEGER ((SyxOop)object))
                {
                  /* This algorithm is used to store large integers.
                     We need to specify how many bytes GMP wrote to the image,
                     for systems that doesn't support GMP */

                  syx_int32 offset = 0;
                  syx_nint start, end;
                  /* specify that's a large integer */
                  fputc (1, image);
                  /* make space to hold the offset */
                  fwrite (&offset, sizeof (syx_int32), 1, image);
                  start = ftell (image);
                  mpz_out_raw (image, SYX_OBJECT_LARGE_INTEGER ((SyxOop)object));
                  end = ftell (image);
                  offset = end - start;
                  /* go back to the offset */
                  fseek (image, - offset - sizeof (syx_int32), SEEK_CUR);
                  data = SYX_COMPAT_SWAP_32 (offset);
                  fwrite (&data, sizeof (syx_int32), 1, image);
                  /* return again to continue normal writing */
                  fseek (image, offset, SEEK_CUR);
                }
              else
#endif
                {
                  /* it's not a large integer */
                  fputc (0, image);
                  fwrite (object->data, sizeof (syx_int8), object->data_size, image);
                }
            }
        }
    }

  fclose (image);

  return TRUE;
}