1 /* Copyright (C) 2001 Free Software Foundation, Inc.
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
21 * The exception is that, if you link the GUILE library with other files
22 * to produce an executable, this does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * Your use of that executable is in no way restricted on account of
25 * linking the GUILE library code into it.
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
30 * This exception applies only to the code released by the
31 * Free Software Foundation under the name GUILE. If you copy
32 * code from other Free Software Foundation releases into a copy of
33 * GUILE, as the General Public License permits, the exception does
34 * not apply to the code that you add in this way. To avoid misleading
35 * anyone as to the status of such modified files, you must delete
36 * this exception notice from them.
38 * If you write modifications of your own for GUILE, it is your choice
39 * whether to permit this exception to apply to your modifications.
40 * If you do not wish that, delete this exception notice. */
48 #include <sys/types.h>
50 #include "libguile/_scm.h"
51 #include "libguile/tags.h"
52 #include "libguile/root.h"
53 #include "libguile/alist.h"
54 #include "libguile/smob.h"
55 #include "libguile/ports.h"
56 #include "libguile/fports.h"
57 #include "libguile/strings.h"
58 #include "libguile/hashtab.h"
59 #include "libguile/vectors.h"
60 #include "libguile/validate.h"
61 #include "libguile/dump.h"
63 #define SCM_DUMP_COOKIE "\x7fGBF-0.1"
65 #define SCM_DUMP_HASH_SIZE 151
66 #define SCM_DUMP_IMAGE_SIZE 4096
68 #define SCM_DUMP_INDEX_TO_WORD(x) ((scm_bits_t) ((x) << 3))
69 #define SCM_DUMP_WORD_TO_INDEX(x) ((long) ((x) >> 3))
71 struct scm_dump_header
{
72 scm_bits_t cookie
; /* cookie string */
73 scm_bits_t version
; /* version string */
74 scm_bits_t nobjs
; /* the number of objects */
75 /* or immediate value */
78 struct scm_dump_object_update
{
79 scm_bits_t id
; /* object identifier */
80 scm_bits_t
*addr
; /* object address */
81 struct scm_dump_object_update
*next
; /* next update */
84 struct scm_dump_cell_update
{
85 scm_bits_t id
; /* object identifier */
88 struct scm_dump_cell_update
*next
; /* next update */
96 static scm_bits_t scm_tc16_dstate
;
101 scm_sizet image_size
;
109 /* Update schedule */
110 struct scm_dump_object_update
*object_updates
;
111 struct scm_dump_cell_update
*cell_updates
;
114 #define SCM_DSTATE_DATA(d) ((struct scm_dstate *) SCM_SMOB_DATA (d))
115 #define SCM_DSTATE_TABLE(d) (SCM_DSTATE_DATA (d)->table)
116 #define SCM_DSTATE_TABLE_REF(d,i) (SCM_VELTS (SCM_DSTATE_TABLE (d))[i])
117 #define SCM_DSTATE_TABLE_SET(d,i,x) (SCM_VELTS (SCM_DSTATE_TABLE (d))[i] = (x))
118 #define SCM_DSTATE_OBJECT_UPDATES(d)(SCM_DSTATE_DATA (d)->object_updates)
119 #define SCM_DSTATE_CELL_UPDATES(d) (SCM_DSTATE_DATA (d)->cell_updates)
123 #define FUNC_NAME "make_dstate"
125 struct scm_dstate
*p
= SCM_MUST_MALLOC (sizeof (struct scm_dstate
));
127 p
->image_size
= SCM_DUMP_IMAGE_SIZE
;
129 p
->image_base
= SCM_MUST_MALLOC (p
->image_size
);
131 p
->table
= SCM_BOOL_F
;
132 p
->object_updates
= 0;
134 SCM_RETURN_NEWSMOB (scm_tc16_dstate
, p
);
139 make_dstate_by_mmap (int fd
)
140 #define FUNC_NAME "make_dstate_by_mmap"
145 struct scm_dstate
*p
= SCM_MUST_MALLOC (sizeof (struct scm_dstate
));
147 SCM_SYSCALL (ret
= fstat (fd
, &st
));
151 SCM_SYSCALL (addr
= mmap (0, st
.st_size
, PROT_READ
, MAP_SHARED
, fd
, 0));
152 if (addr
== MAP_FAILED
)
156 p
->image_size
= st
.st_size
;
158 p
->image_base
= addr
;
160 p
->table
= SCM_BOOL_F
;
161 p
->object_updates
= 0;
163 SCM_RETURN_NEWSMOB (scm_tc16_dstate
, p
);
168 dstate_mark (SCM obj
)
170 return SCM_DSTATE_TABLE (obj
);
174 dstate_free (SCM obj
)
175 #define FUNC_NAME "dstate_free"
177 int size
= sizeof (struct scm_dstate
);
178 struct scm_dstate
*p
= SCM_DSTATE_DATA (obj
);
180 /* Free dump image */
184 SCM_SYSCALL (rv
= munmap (p
->image_base
, p
->image_size
));
190 size
+= p
->image_size
;
192 scm_must_free (p
->image_base
);
195 /* Free update schedules */
196 while (p
->object_updates
)
198 struct scm_dump_object_update
*next
= p
->object_updates
->next
;
199 scm_must_free (p
->object_updates
);
200 size
+= sizeof (struct scm_dump_object_update
);
201 p
->object_updates
= next
;
203 while (p
->cell_updates
)
205 struct scm_dump_cell_update
*next
= p
->cell_updates
->next
;
206 scm_must_free (p
->cell_updates
);
207 size
+= sizeof (struct scm_dump_cell_update
);
208 p
->cell_updates
= next
;
217 dstate_extend (struct scm_dstate
*p
)
219 scm_sizet old_size
= p
->image_size
;
221 p
->image_base
= scm_must_realloc (p
->image_base
,
233 scm_object_indicator (SCM obj
, SCM dstate
)
237 return SCM_UNPACK (obj
);
241 SCM id
= scm_hashq_ref (SCM_DSTATE_TABLE (dstate
), obj
, SCM_BOOL_F
);
245 return SCM_DUMP_INDEX_TO_WORD (SCM_INUM (id
));
250 scm_indicator_object (scm_bits_t word
, SCM dstate
)
252 if (SCM_IMP (SCM_PACK (word
)))
253 return SCM_PACK (word
);
255 return SCM_DSTATE_TABLE_REF (dstate
, SCM_DUMP_WORD_TO_INDEX (word
));
263 /* store functions */
266 scm_store_pad (SCM dstate
)
268 struct scm_dstate
*p
= SCM_DSTATE_DATA (dstate
);
269 while (p
->image_index
+ sizeof (scm_bits_t
) >= p
->image_size
)
271 while (p
->image_index
% sizeof (scm_bits_t
) != 0)
272 p
->image_base
[p
->image_index
++] = '\0';
276 scm_store_string (const char *addr
, scm_sizet size
, SCM dstate
)
278 struct scm_dstate
*p
= SCM_DSTATE_DATA (dstate
);
279 while (p
->image_index
+ size
+ 1 >= p
->image_size
)
281 memcpy (p
->image_base
+ p
->image_index
, addr
, size
);
282 memcpy (p
->image_base
+ p
->image_index
+ size
, "\0", 1);
283 p
->image_index
+= size
+ 1;
284 scm_store_pad (dstate
);
288 scm_store_bytes (const void *addr
, scm_sizet size
, SCM dstate
)
290 struct scm_dstate
*p
= SCM_DSTATE_DATA (dstate
);
291 while (p
->image_index
+ size
>= p
->image_size
)
293 memcpy (p
->image_base
+ p
->image_index
, addr
, size
);
294 p
->image_index
+= size
;
295 scm_store_pad (dstate
);
299 scm_store_word (const scm_bits_t word
, SCM dstate
)
301 scm_store_bytes (&word
, sizeof (scm_bits_t
), dstate
);
305 scm_store_object (SCM obj
, SCM dstate
)
307 scm_bits_t id
= scm_object_indicator (obj
, dstate
);
310 /* OBJ is not stored yet. Do it later */
311 struct scm_dstate
*p
= SCM_DSTATE_DATA (dstate
);
312 struct scm_dump_object_update
*update
=
313 scm_must_malloc (sizeof (struct scm_dump_object_update
),
315 update
->id
= SCM_UNPACK (obj
);
316 update
->addr
= (scm_bits_t
*) p
->image_index
;
317 update
->next
= p
->object_updates
;
318 p
->object_updates
= update
;
320 scm_store_word (id
, dstate
);
324 scm_store_cell_object (SCM cell
, int n
, SCM dstate
)
326 scm_store_object (SCM_CELL_OBJECT (cell
, n
), dstate
);
329 /* restore functions */
332 scm_restore_pad (SCM dstate
)
334 struct scm_dstate
*p
= SCM_DSTATE_DATA (dstate
);
335 while (p
->image_index
% sizeof (scm_bits_t
) != 0)
340 scm_restore_string (scm_sizet
*sizep
, SCM dstate
)
342 struct scm_dstate
*p
= SCM_DSTATE_DATA (dstate
);
343 const char *addr
= p
->image_base
+ p
->image_index
;
344 *sizep
= strlen (addr
);
345 p
->image_index
+= *sizep
+ 1;
346 scm_restore_pad (dstate
);
351 scm_restore_bytes (scm_sizet size
, SCM dstate
)
353 struct scm_dstate
*p
= SCM_DSTATE_DATA (dstate
);
354 const void *addr
= p
->image_base
+ p
->image_index
;
355 p
->image_index
+= size
;
356 scm_restore_pad (dstate
);
361 scm_restore_word (SCM dstate
)
363 struct scm_dstate
*p
= SCM_DSTATE_DATA (dstate
);
364 scm_bits_t word
= *(scm_bits_t
*) (p
->image_base
+ p
->image_index
);
365 p
->image_index
+= sizeof (scm_bits_t
);
370 scm_restore_object (SCM
*objp
, SCM dstate
)
372 scm_bits_t id
= scm_restore_word (dstate
);
373 *objp
= scm_indicator_object (id
, dstate
);
375 if (SCM_UNBNDP (*objp
))
377 struct scm_dump_object_update
*update
=
378 scm_must_malloc (sizeof (struct scm_dump_object_update
),
379 "scm_restore_object");
381 update
->addr
= (scm_bits_t
*) objp
;
382 update
->next
= SCM_DSTATE_OBJECT_UPDATES (dstate
);
383 SCM_DSTATE_OBJECT_UPDATES (dstate
) = update
;
388 scm_restore_cell_object (SCM cell
, int n
, SCM dstate
)
390 scm_bits_t id
= scm_restore_word (dstate
);
391 SCM obj
= scm_indicator_object (id
, dstate
);
392 SCM_SET_CELL_OBJECT (cell
, n
, obj
);
394 if (SCM_UNBNDP (obj
))
396 struct scm_dump_cell_update
*update
=
397 scm_must_malloc (sizeof (struct scm_dump_cell_update
),
398 "scm_restore_cell_object");
402 update
->next
= SCM_DSTATE_CELL_UPDATES (dstate
);
403 SCM_DSTATE_CELL_UPDATES (dstate
) = update
;
413 scm_dump (SCM obj
, SCM dstate
)
415 struct scm_dstate
*p
= SCM_DSTATE_DATA (dstate
);
417 /* Check if immediate or already dumpped */
418 if (scm_object_indicator (obj
, dstate
) != -1)
422 scm_hashq_set_x (p
->table
, obj
, SCM_MAKINUM (p
->table_index
));
425 if (SCM_SLOPPY_CONSP (obj
))
427 scm_store_word (scm_tc3_cons
, dstate
);
428 /* Store cdr first in order to avoid a possible deep recursion
429 * with a long list */
430 scm_store_cell_object (obj
, 1, dstate
);
431 scm_store_cell_object (obj
, 0, dstate
);
434 switch (SCM_TYP7 (obj
))
438 scm_store_word (scm_tc7_symbol
, dstate
);
439 scm_store_string (SCM_SYMBOL_CHARS (obj
),
440 SCM_SYMBOL_LENGTH (obj
),
444 case scm_tc7_substring
:
447 scm_store_word (scm_tc7_string
, dstate
);
448 scm_store_string (SCM_STRING_CHARS (obj
),
449 SCM_STRING_LENGTH (obj
),
456 int len
= SCM_VECTOR_LENGTH (obj
);
457 SCM
*base
= SCM_VELTS (obj
);
458 scm_store_word (scm_tc7_vector
, dstate
);
459 scm_store_word (len
, dstate
);
460 for (i
= 0; i
< len
; i
++)
461 scm_store_object (base
[i
], dstate
);
466 void (*dump
) () = SCM_SMOB_DESCRIPTOR (obj
).dump
;
470 /* FIXME: SCM_CELL_TYPE may change when undump!! */
471 scm_store_word (SCM_CELL_TYPE (obj
), dstate
);
477 scm_misc_error ("scm_dump_mark", "Cannot dump: ~A", SCM_LIST1 (obj
));
481 while (p
->object_updates
)
483 struct scm_dump_object_update
*update
= p
->object_updates
;
484 p
->object_updates
= update
->next
;
485 scm_dump (SCM_PACK (update
->id
), dstate
);
486 *(scm_bits_t
*) (p
->image_base
+ (int) update
->addr
) =
487 scm_object_indicator (SCM_PACK (update
->id
), dstate
);
488 scm_must_free (update
);
493 scm_undump (SCM dstate
)
495 struct scm_dstate
*p
= SCM_DSTATE_DATA (dstate
);
496 scm_bits_t tc
= scm_restore_word (dstate
);
499 if (SCM_ITAG3 (SCM_PACK (tc
)) == scm_tc3_cons
)
502 /* cdr was stored first */
503 scm_restore_cell_object (obj
, 1, dstate
);
504 scm_restore_cell_object (obj
, 0, dstate
);
508 switch (SCM_ITAG7 (SCM_PACK (tc
)))
513 const char *mem
= scm_restore_string (&len
, dstate
);
514 obj
= scm_mem2symbol (mem
, len
);
520 const char *mem
= scm_restore_string (&len
, dstate
);
521 obj
= scm_makfromstr (mem
, len
, 0);
527 int len
= scm_restore_word (dstate
);
529 obj
= scm_c_make_vector (len
, SCM_BOOL_F
);
530 base
= SCM_VELTS (obj
);
531 for (i
= 0; i
< len
; i
++)
532 scm_restore_object (&base
[i
], dstate
);
537 SCM (*undump
) () = scm_smobs
[SCM_TC2SMOBNUM (tc
)].undump
;
540 obj
= undump (dstate
);
545 scm_misc_error ("scm_undump", "Cannot undump", SCM_EOL
);
549 SCM_DSTATE_TABLE_SET (dstate
, p
->table_index
, obj
);
558 SCM_DEFINE (scm_binary_write
, "binary-write", 1, 1, 0,
560 "Write OBJ to PORT in a binary format.")
561 #define FUNC_NAME s_scm_binary_write
563 struct scm_dstate
*p
;
564 struct scm_dump_header header
;
568 if (SCM_UNBNDP (port
))
571 SCM_VALIDATE_OUTPUT_PORT (2, port
);
574 dstate
= make_dstate ();
575 p
= SCM_DSTATE_DATA (dstate
);
576 p
->table
= scm_c_make_hash_table (SCM_DUMP_HASH_SIZE
);
577 scm_dump (obj
, dstate
);
580 header
.cookie
= ((scm_bits_t
*) SCM_DUMP_COOKIE
)[0];
581 header
.version
= ((scm_bits_t
*) SCM_DUMP_COOKIE
)[1];
582 header
.nobjs
= (p
->table_index
583 ? SCM_DUMP_INDEX_TO_WORD (p
->table_index
)
585 scm_lfwrite ((const char *) &header
, sizeof (struct scm_dump_header
), port
);
587 scm_lfwrite (p
->image_base
, p
->image_index
, port
);
589 return SCM_UNSPECIFIED
;
593 SCM_DEFINE (scm_binary_read
, "binary-read", 0, 1, 0,
595 "Read an object from PORT in a binary format.")
596 #define FUNC_NAME s_scm_binary_read
599 struct scm_dstate
*p
;
600 struct scm_dump_header
*header
;
604 if (SCM_UNBNDP (port
))
607 SCM_VALIDATE_INPUT_PORT (1, port
);
610 if (SCM_FPORTP (port
))
611 /* Undump with mmap */
612 dstate
= make_dstate_by_mmap (SCM_FPORT_FDES (port
));
614 /* Undump with malloc */
615 SCM_MISC_ERROR ("Not supported yet", SCM_EOL
);
616 p
= SCM_DSTATE_DATA (dstate
);
619 header
= (struct scm_dump_header
*) p
->image_base
;
620 p
->image_index
+= sizeof (struct scm_dump_header
);
621 if (p
->image_size
< sizeof (*header
))
622 SCM_MISC_ERROR ("Invalid binary format: ~A", SCM_LIST1 (port
));
623 if (header
->cookie
!= ((scm_bits_t
*) SCM_DUMP_COOKIE
)[0])
624 SCM_MISC_ERROR ("Invalid binary format: ~A", SCM_LIST1 (port
));
625 if (header
->version
!= ((scm_bits_t
*) SCM_DUMP_COOKIE
)[1])
626 SCM_MISC_ERROR ("Unsupported binary version: ~A", SCM_LIST1 (port
));
628 /* Check for immediate */
629 if (SCM_IMP (SCM_PACK (header
->nobjs
)))
630 return SCM_PACK (header
->nobjs
);
632 /* Create object table */
633 nobjs
= SCM_DUMP_WORD_TO_INDEX (header
->nobjs
);
634 p
->table
= scm_c_make_vector (nobjs
, SCM_UNDEFINED
);
637 for (i
= 0; i
< nobjs
; i
++)
640 /* Update references */
641 while (p
->object_updates
)
643 struct scm_dump_object_update
*update
= p
->object_updates
;
644 p
->object_updates
= update
->next
;
645 *(update
->addr
) = SCM_UNPACK (scm_indicator_object (update
->id
, dstate
));
646 scm_must_free (update
);
649 while (p
->cell_updates
)
651 struct scm_dump_cell_update
*update
= p
->cell_updates
;
652 p
->cell_updates
= update
->next
;
653 SCM_SET_CELL_OBJECT (update
->cell
,
655 scm_indicator_object (update
->id
, dstate
));
656 scm_must_free (update
);
661 SCM obj
= SCM_DSTATE_TABLE_REF (dstate
, 0);
662 p
->table
= SCM_BOOL_F
;
672 scm_tc16_dstate
= scm_make_smob_type ("dstate", 0);
673 scm_set_smob_mark (scm_tc16_dstate
, dstate_mark
);
674 scm_set_smob_free (scm_tc16_dstate
, dstate_free
);
675 #ifndef SCM_MAGIC_SNARFER
676 #include "libguile/dump.x"