/*! Loads the memory. \param path the file containing the data dumped by syx_memory_save_image \return FALSE if an error occurred */ syx_bool syx_memory_load_image (syx_symbol path) { SyxObject *object; FILE *image; syx_int32 data; syx_int32 i; SyxMemoryLazyPointer *lazy; SYX_START_PROFILE; if (!path) { if (SYX_IS_NIL (syx_globals)) path = syx_get_image_path (); else path = SYX_OBJECT_SYMBOL (syx_globals_at ("ImageFileName")); } if (!path) return FALSE; image = fopen (path, "rb"); if (!image) return FALSE; fread (&data, sizeof (syx_int32), 1, image); data = SYX_COMPAT_SWAP_32 (data); syx_memory_init (data); fread (&data, sizeof (syx_int32), 1, image); _syx_freed_memory_top = SYX_COMPAT_SWAP_32 (data); _syx_memory_read (_syx_freed_memory, FALSE, _syx_freed_memory_top, image); _syx_scheduler_load (image); _syx_memory_read (&syx_globals, FALSE, 1, image); _syx_memory_read (&syx_symbols, FALSE, 1, image); while (!feof (image)) { if (!_syx_memory_read ((SyxOop *)&object, FALSE, 1, image)) break; _syx_memory_read (&object->klass, FALSE, 1, image); object->has_refs = fgetc (image); object->is_constant = fgetc (image); /* fetch instance variables */ fread (&data, sizeof (syx_varsize), 1, image); data = SYX_COMPAT_SWAP_32 (data); if (object->vars) syx_free (object->vars); object->vars = (SyxOop *) syx_calloc (data, sizeof (SyxOop)); _syx_memory_read (object->vars, TRUE, data, image); /* fetch data */ fread (&data, sizeof (syx_varsize), 1, image); object->data_size = SYX_COMPAT_SWAP_32 (data); if (object->data_size > 0) { if (object->data && object->data_size > 0) syx_free (object->data); if (object->has_refs) { object->data = (SyxOop *) syx_calloc (object->data_size, sizeof (SyxOop)); _syx_memory_read (object->data, TRUE, object->data_size, image); } else { object->data = (SyxOop *) syx_calloc (object->data_size, sizeof (syx_int8)); if (fgetc (image) == SYX_MEMORY_TYPE_LARGE_INTEGER) { fread (&data, sizeof (syx_int32), 1, image); data = SYX_COMPAT_SWAP_32 (data); #ifdef HAVE_LIBGMP mpz_init (SYX_OBJECT_LARGE_INTEGER ((SyxOop)object)); mpz_inp_raw (SYX_OBJECT_LARGE_INTEGER ((SyxOop)object), image); #else /* skip GMP data since we can't handle it */ fseek (image, data, SEEK_CUR); #endif } else fread (object->data, sizeof (syx_int8), object->data_size, image); } } } fclose (image); /* Fix lazy pointers */ for (i=0; i < _syx_memory_lazy_pointers_top; i++) { lazy = &_syx_memory_lazy_pointers[i]; if (lazy->stack != 0) *lazy->entry = SYX_POINTER_CAST_OOP (SYX_OBJECT_DATA (lazy->stack) + lazy->offset); else *lazy->entry = SYX_POINTER_CAST_OOP (NULL); } syx_free (_syx_memory_lazy_pointers); _syx_memory_lazy_pointers_top = 0; syx_fetch_basic (); SYX_END_PROFILE(load_image); syx_initialize_system (); return TRUE; }
/*! Print to stdout the current execution state of the interpreter and the Process traceback */ void syx_show_traceback (void) { SyxInterpState *es; SyxInterpFrame *frame, *homeframe; syx_symbol traceformat; SyxOop classname; syx_symbol extraclass; SyxOop receiver; if (!syx_memory) { puts ("Can't print the memory state"); return; } es = &_syx_interp_state; frame = es->frame; puts ("Memory state:"); printf("Memory size: %d\n", _syx_memory_size); printf("Freed memory top: %d\n", _syx_freed_memory_top); if (!_syx_memory_gc_trans_running) puts ("No GC transaction"); else printf("GC transaction top: %d\n", _syx_memory_gc_trans_top); if (!es) { puts ("Can't print the execution state"); return; } puts ("\nExecution state:"); printf("Process: %p (memory index: %ld)\n", SYX_OOP_CAST_POINTER (syx_processor_active_process), SYX_MEMORY_INDEX_OF (syx_processor_active_process)); printf("Frame: %p\n", (syx_pointer) frame); if (!frame) return; printf("Receiver: %p (memory index: %ld)\n", SYX_OOP_CAST_POINTER (frame->receiver), SYX_MEMORY_INDEX_OF (frame->receiver)); printf("Arguments: %p\n", (syx_pointer) es->arguments); printf("Temporaries: %p\n", (syx_pointer) es->temporaries); printf("Stack: %p\n", (syx_pointer) frame->stack); printf("Literals: %p\n", (syx_pointer) es->method_literals); printf("Bytecodes: %p (size: %d)\n", (syx_pointer) es->method_bytecodes, es->method_bytecodes_count); printf("Byteslice: %d\n", es->byteslice); printf("Instruction pointer: %p\n", (syx_pointer) frame->next_instruction); printf("Stack pointer: %p\n", (syx_pointer) frame->stack); printf("Message receiver: %p (memory index: %ld)\n", SYX_OOP_CAST_POINTER (es->message_receiver), SYX_MEMORY_INDEX_OF (es->message_receiver)); printf("Message arguments: %p (size: %d)\n", (syx_pointer) es->message_arguments, es->message_arguments_count); if (SYX_IS_NIL (frame->detached_frame)) printf("Process offset: %d\n", SYX_POINTERS_OFFSET (frame, SYX_OBJECT_DATA (SYX_PROCESS_STACK (_syx_interp_state.process)))); puts ("\nTraceback:"); while (frame) { if (frame->outer_frame) { homeframe = frame->outer_frame; while (homeframe->outer_frame) homeframe = homeframe->outer_frame; traceformat = "%s%s>>%s[]\n"; } else { homeframe = frame; traceformat = "%s%s>>%s\n"; } receiver = frame->receiver; classname = SYX_CLASS_NAME(syx_object_get_class(receiver)); if (SYX_IS_NIL (classname)) { classname = SYX_CLASS_NAME(SYX_METACLASS_INSTANCE_CLASS(syx_object_get_class(receiver))); extraclass = " class"; } else extraclass = ""; printf (traceformat, SYX_OBJECT_SYMBOL(classname), extraclass, SYX_OBJECT_SYMBOL(SYX_METHOD_SELECTOR(homeframe->method))); frame = frame->parent_frame; } }
/*! 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; }
/*! 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; }