INLINE void _syx_memory_gc_mark (SyxOop object) { syx_varsize i; if (!SYX_IS_OBJECT (object) || SYX_OBJECT_IS_MARKED(object) || SYX_IS_NIL(syx_object_get_class (object))) return; SYX_OBJECT_IS_MARKED(object) = TRUE; _syx_memory_gc_mark (SYX_OBJECT(object)->klass); /* Only the used stack part of the process must be marked */ if (SYX_OOP_EQ (syx_object_get_class (object), syx_process_class)) { SyxOop stack = SYX_PROCESS_STACK (object); SyxInterpFrame *frame = SYX_OOP_CAST_POINTER (SYX_PROCESS_FRAME_POINTER (object)); syx_int32 offset = SYX_POINTERS_OFFSET (frame->stack, SYX_OBJECT_DATA (stack)); SYX_OBJECT_IS_MARKED(stack) = TRUE; /* First mark variables except the process stack */ for (i=0; i < SYX_VARS_PROCESS_STACK; i++) _syx_memory_gc_mark (SYX_OBJECT_VARS(object)[i]); /* Mark detached frames */ while (frame) { _syx_memory_gc_mark (frame->detached_frame); frame = frame->parent_frame; } /* Now mark the stack */ for (i=0; i < offset; i++) _syx_memory_gc_mark (SYX_OBJECT_DATA(stack)[i]); /* Mark variables after the process stack */ for (i=SYX_VARS_PROCESS_STACK+1; i < syx_object_vars_size (object); i++) _syx_memory_gc_mark (SYX_OBJECT_VARS(object)[i]); /* Process has no data */ return; } else { for (i=0; i < syx_object_vars_size (object); i++) _syx_memory_gc_mark (SYX_OBJECT_VARS(object)[i]); } if (SYX_OBJECT_HAS_REFS (object)) { for (i=0; i < SYX_OBJECT_DATA_SIZE (object); i++) _syx_memory_gc_mark (SYX_OBJECT_DATA(object)[i]); } }
/* 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); }
/* 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); }
INLINE void _syx_memory_gc_mark (SyxOop object) { syx_varsize i; if (!SYX_IS_OBJECT (object) || SYX_OBJECT_IS_MARKED(object) || SYX_IS_NIL(syx_object_get_class (object))) return; SYX_OBJECT_IS_MARKED(object) = TRUE; _syx_memory_gc_mark (SYX_OBJECT(object)->klass); for (i=0; i < syx_object_vars_size (object); i++) _syx_memory_gc_mark (SYX_OBJECT_VARS(object)[i]); if (SYX_OBJECT_HAS_REFS (object)) { for (i=0; i < SYX_OBJECT_DATA_SIZE (object); i++) _syx_memory_gc_mark (SYX_OBJECT_DATA(object)[i]); } }
/*! 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; }