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 */
83 static scm_bits_t scm_tc16_dstate
;
89 char *image_base
; /* Memory image */
91 SCM table
; /* Object table */
92 SCM task
; /* Update task */
95 #define SCM_DSTATE_DATA(d) ((struct scm_dstate *) SCM_SMOB_DATA (d))
96 #define SCM_DSTATE_TABLE(d) (SCM_DSTATE_DATA (d)->table)
97 #define SCM_DSTATE_TABLE_REF(d,i) (SCM_VELTS (SCM_DSTATE_TABLE (d))[i])
98 #define SCM_DSTATE_TABLE_SET(d,i,x) (SCM_VELTS (SCM_DSTATE_TABLE (d))[i] = (x))
99 #define SCM_DSTATE_TASK(d) (SCM_DSTATE_DATA (d)->task)
101 #define SCM_DTASK_ID(t) ((scm_bits_t) SCM_CELL_WORD_1 (t))
102 #define SCM_DTASK_ADDR(t) ((scm_bits_t *) SCM_CELL_WORD_2 (t))
103 #define SCM_DTASK_NEXT(t) (SCM_CELL_OBJECT_3 (t))
104 #define SCM_SET_DTASK_ID(t,x) SCM_SET_CELL_WORD_1 (t, x)
105 #define SCM_SET_DTASK_ADDR(t,x) SCM_SET_CELL_WORD_2 (t, x)
106 #define SCM_SET_DTASK_NEXT(t,x) SCM_SET_CELL_OBJECT_3 (t, x)
110 #define FUNC_NAME "make_dstate"
112 struct scm_dstate
*p
= SCM_MUST_MALLOC (sizeof (struct scm_dstate
));
114 p
->image_size
= SCM_DUMP_IMAGE_SIZE
;
116 p
->image_base
= SCM_MUST_MALLOC (p
->image_size
);
118 p
->table
= SCM_BOOL_F
;
120 SCM_RETURN_NEWSMOB (scm_tc16_dstate
, p
);
125 make_dstate_by_mmap (int fd
)
126 #define FUNC_NAME "make_dstate_by_mmap"
131 struct scm_dstate
*p
= SCM_MUST_MALLOC (sizeof (struct scm_dstate
));
133 SCM_SYSCALL (ret
= fstat (fd
, &st
));
137 SCM_SYSCALL (addr
= mmap (0, st
.st_size
, PROT_READ
, MAP_SHARED
, fd
, 0));
138 if (addr
== MAP_FAILED
)
142 p
->image_size
= st
.st_size
;
144 p
->image_base
= addr
;
146 p
->table
= SCM_BOOL_F
;
148 SCM_RETURN_NEWSMOB (scm_tc16_dstate
, p
);
153 dstate_mark (SCM obj
)
156 struct scm_dstate
*p
= SCM_DSTATE_DATA (obj
);
157 for (task
= p
->task
; !SCM_NULLP (task
); task
= SCM_DTASK_NEXT (task
))
163 dstate_free (SCM obj
)
164 #define FUNC_NAME "dstate_free"
166 int size
= sizeof (struct scm_dstate
);
167 struct scm_dstate
*p
= SCM_DSTATE_DATA (obj
);
169 /* Free dump image */
173 SCM_SYSCALL (rv
= munmap (p
->image_base
, p
->image_size
));
179 size
+= p
->image_size
;
181 scm_must_free (p
->image_base
);
190 dstate_extend (struct scm_dstate
*p
)
192 scm_sizet old_size
= p
->image_size
;
194 p
->image_base
= scm_must_realloc (p
->image_base
,
206 scm_object_indicator (SCM obj
, SCM dstate
)
210 return SCM_UNPACK (obj
);
214 SCM id
= scm_hashq_ref (SCM_DSTATE_TABLE (dstate
), obj
, SCM_BOOL_F
);
218 return SCM_DUMP_INDEX_TO_WORD (SCM_INUM (id
));
223 scm_indicator_object (scm_bits_t word
, SCM dstate
)
225 if (SCM_IMP (SCM_PACK (word
)))
226 return SCM_PACK (word
);
228 return SCM_DSTATE_TABLE_REF (dstate
, SCM_DUMP_WORD_TO_INDEX (word
));
236 /* store functions */
239 scm_store_pad (SCM dstate
)
241 struct scm_dstate
*p
= SCM_DSTATE_DATA (dstate
);
242 while (p
->image_index
+ sizeof (scm_bits_t
) >= p
->image_size
)
244 while (p
->image_index
% sizeof (scm_bits_t
) != 0)
245 p
->image_base
[p
->image_index
++] = '\0';
249 scm_store_word (const scm_bits_t word
, SCM dstate
)
251 struct scm_dstate
*p
= SCM_DSTATE_DATA (dstate
);
252 while (p
->image_index
+ sizeof (scm_bits_t
) >= p
->image_size
)
254 memcpy (p
->image_base
+ p
->image_index
, &word
, sizeof (scm_bits_t
));
255 p
->image_index
+= sizeof (scm_bits_t
);
259 scm_store_bytes (const void *addr
, scm_sizet size
, SCM dstate
)
261 struct scm_dstate
*p
= SCM_DSTATE_DATA (dstate
);
262 scm_store_word (size
, dstate
);
263 while (p
->image_index
+ size
+ sizeof (scm_bits_t
) >= p
->image_size
)
265 memcpy (p
->image_base
+ p
->image_index
, addr
, size
);
266 p
->image_index
+= size
;
267 scm_store_pad (dstate
);
271 scm_store_string (const char *addr
, scm_sizet size
, SCM dstate
)
273 struct scm_dstate
*p
= SCM_DSTATE_DATA (dstate
);
274 while (p
->image_index
+ size
+ 1 >= p
->image_size
)
276 memcpy (p
->image_base
+ p
->image_index
, addr
, size
);
277 memcpy (p
->image_base
+ p
->image_index
+ size
, "\0", 1);
278 p
->image_index
+= size
+ 1;
279 scm_store_pad (dstate
);
283 scm_store_object (SCM obj
, SCM dstate
)
285 scm_bits_t id
= scm_object_indicator (obj
, dstate
);
288 /* OBJ is not stored yet. Do it later */
289 struct scm_dstate
*p
= SCM_DSTATE_DATA (dstate
);
292 SCM_SET_DTASK_ID (task
, SCM_UNPACK (obj
));
293 SCM_SET_DTASK_ADDR (task
, p
->image_index
);
294 SCM_SET_DTASK_NEXT (task
, p
->task
);
297 scm_store_word (id
, dstate
);
300 /* restore functions */
303 scm_restore_pad (struct scm_dstate
*p
)
305 while (p
->image_index
% sizeof (scm_bits_t
) != 0)
310 scm_restore_word (scm_bits_t
*wordp
, SCM dstate
)
312 struct scm_dstate
*p
= SCM_DSTATE_DATA (dstate
);
313 *wordp
= *(scm_bits_t
*) (p
->image_base
+ p
->image_index
);
314 p
->image_index
+= sizeof (scm_bits_t
);
318 scm_restore_bytes (const void **pp
, scm_sizet
*sizep
, SCM dstate
)
321 struct scm_dstate
*p
= SCM_DSTATE_DATA (dstate
);
322 scm_restore_word (&size
, dstate
);
325 *pp
= p
->image_base
+ p
->image_index
;
326 p
->image_index
+= size
;
331 scm_restore_string (const char **pp
, scm_sizet
*sizep
, SCM dstate
)
334 struct scm_dstate
*p
= SCM_DSTATE_DATA (dstate
);
335 *pp
= p
->image_base
+ p
->image_index
;
339 p
->image_index
+= len
+ 1;
344 scm_restore_object (SCM
*objp
, SCM dstate
)
347 scm_restore_word (&id
, dstate
);
348 *objp
= scm_indicator_object (id
, dstate
);
350 if (SCM_UNBNDP (*objp
))
352 struct scm_dstate
*p
= SCM_DSTATE_DATA (dstate
);
355 SCM_SET_DTASK_ID (task
, id
);
356 SCM_SET_DTASK_ADDR (task
, objp
);
357 SCM_SET_DTASK_NEXT (task
, p
->task
);
368 scm_dump (SCM obj
, SCM dstate
)
370 struct scm_dstate
*p
= SCM_DSTATE_DATA (dstate
);
372 /* Check if immediate or already dumpped */
373 if (scm_object_indicator (obj
, dstate
) != -1)
377 scm_hashq_set_x (p
->table
, obj
, SCM_MAKINUM (p
->table_index
));
380 if (SCM_SLOPPY_CONSP (obj
))
382 scm_store_word (scm_tc3_cons
, dstate
);
383 /* Store cdr first in order to avoid a possible deep recursion
384 * with a long list */
385 scm_store_object (SCM_CDR (obj
), dstate
);
386 scm_store_object (SCM_CAR (obj
), dstate
);
389 switch (SCM_TYP7 (obj
))
393 scm_store_word (scm_tc7_symbol
, dstate
);
394 scm_store_string (SCM_SYMBOL_CHARS (obj
),
395 SCM_SYMBOL_LENGTH (obj
),
399 case scm_tc7_substring
:
402 scm_store_word (scm_tc7_string
, dstate
);
403 scm_store_string (SCM_STRING_CHARS (obj
),
404 SCM_STRING_LENGTH (obj
),
411 scm_bits_t len
= SCM_VECTOR_LENGTH (obj
);
412 SCM
*base
= SCM_VELTS (obj
);
413 scm_store_word (scm_tc7_vector
, dstate
);
414 scm_store_word (len
, dstate
);
415 for (i
= 0; i
< len
; i
++)
416 scm_store_object (base
[i
], dstate
);
421 void (*dump
) () = SCM_SMOB_DESCRIPTOR (obj
).dump
;
425 /* FIXME: SCM_CELL_TYPE may change when undump!! */
426 scm_store_word (SCM_CELL_TYPE (obj
), dstate
);
432 scm_misc_error ("scm_dump_mark", "Cannot dump: ~A", SCM_LIST1 (obj
));
438 for (task
= p
->task
; !SCM_NULLP (task
); task
= SCM_DTASK_NEXT (task
))
440 SCM obj
= SCM_PACK (SCM_DTASK_ID (task
));
441 scm_dump (obj
, dstate
);
442 *(scm_bits_t
*) (p
->image_base
+ (int) SCM_DTASK_ADDR (task
)) =
443 scm_object_indicator (obj
, dstate
);
449 scm_undump (SCM dstate
)
451 struct scm_dstate
*p
= SCM_DSTATE_DATA (dstate
);
455 scm_restore_word (&tc
, dstate
);
457 if (SCM_ITAG3 (SCM_PACK (tc
)) == scm_tc3_cons
)
460 /* cdr was stored first */
461 scm_restore_object (SCM_CDRLOC (obj
), dstate
);
462 scm_restore_object (SCM_CARLOC (obj
), dstate
);
466 switch (SCM_ITAG7 (SCM_PACK (tc
)))
472 scm_restore_string (&mem
, &len
, dstate
);
473 obj
= scm_mem2symbol (mem
, len
);
480 scm_restore_string (&mem
, &len
, dstate
);
481 obj
= scm_makfromstr (mem
, len
, 0);
489 scm_restore_word (&len
, dstate
);
490 obj
= scm_c_make_vector (len
, SCM_BOOL_F
);
491 base
= SCM_VELTS (obj
);
492 for (i
= 0; i
< len
; i
++)
493 scm_restore_object (&base
[i
], dstate
);
498 SCM (*undump
) () = scm_smobs
[SCM_TC2SMOBNUM (tc
)].undump
;
501 obj
= undump (dstate
);
506 scm_misc_error ("scm_undump", "Cannot undump", SCM_EOL
);
510 SCM_DSTATE_TABLE_SET (dstate
, p
->table_index
, obj
);
519 SCM_DEFINE (scm_binary_write
, "binary-write", 1, 1, 0,
521 "Write OBJ to PORT in a binary format.")
522 #define FUNC_NAME s_scm_binary_write
524 struct scm_dstate
*p
;
525 struct scm_dump_header header
;
529 if (SCM_UNBNDP (port
))
532 SCM_VALIDATE_OUTPUT_PORT (2, port
);
535 dstate
= make_dstate ();
536 p
= SCM_DSTATE_DATA (dstate
);
537 p
->table
= scm_c_make_hash_table (SCM_DUMP_HASH_SIZE
);
538 scm_dump (obj
, dstate
);
541 header
.cookie
= ((scm_bits_t
*) SCM_DUMP_COOKIE
)[0];
542 header
.version
= ((scm_bits_t
*) SCM_DUMP_COOKIE
)[1];
543 header
.nobjs
= (p
->table_index
544 ? SCM_DUMP_INDEX_TO_WORD (p
->table_index
)
546 scm_lfwrite ((const char *) &header
, sizeof (struct scm_dump_header
), port
);
548 scm_lfwrite (p
->image_base
, p
->image_index
, port
);
550 return SCM_UNSPECIFIED
;
554 SCM_DEFINE (scm_binary_read
, "binary-read", 0, 1, 0,
556 "Read an object from PORT in a binary format.")
557 #define FUNC_NAME s_scm_binary_read
560 struct scm_dstate
*p
;
561 struct scm_dump_header
*header
;
565 if (SCM_UNBNDP (port
))
568 SCM_VALIDATE_INPUT_PORT (1, port
);
571 if (SCM_FPORTP (port
))
572 /* Undump with mmap */
573 dstate
= make_dstate_by_mmap (SCM_FPORT_FDES (port
));
575 /* Undump with malloc */
576 SCM_MISC_ERROR ("Not supported yet", SCM_EOL
);
577 p
= SCM_DSTATE_DATA (dstate
);
580 header
= (struct scm_dump_header
*) p
->image_base
;
581 p
->image_index
+= sizeof (struct scm_dump_header
);
582 if (p
->image_size
< sizeof (*header
))
583 SCM_MISC_ERROR ("Invalid binary format: ~A", SCM_LIST1 (port
));
584 if (header
->cookie
!= ((scm_bits_t
*) SCM_DUMP_COOKIE
)[0])
585 SCM_MISC_ERROR ("Invalid binary format: ~A", SCM_LIST1 (port
));
586 if (header
->version
!= ((scm_bits_t
*) SCM_DUMP_COOKIE
)[1])
587 SCM_MISC_ERROR ("Unsupported binary version: ~A", SCM_LIST1 (port
));
589 /* Check for immediate */
590 if (SCM_IMP (SCM_PACK (header
->nobjs
)))
591 return SCM_PACK (header
->nobjs
);
593 /* Create object table */
594 nobjs
= SCM_DUMP_WORD_TO_INDEX (header
->nobjs
);
595 p
->table
= scm_c_make_vector (nobjs
, SCM_UNDEFINED
);
598 for (i
= 0; i
< nobjs
; i
++)
601 /* Update references */
604 for (task
= p
->task
; !SCM_NULLP (task
); task
= SCM_DTASK_NEXT (task
))
606 *SCM_DTASK_ADDR (task
) =
607 SCM_UNPACK (scm_indicator_object (SCM_DTASK_ID (task
), dstate
));
613 SCM obj
= SCM_DSTATE_TABLE_REF (dstate
, 0);
614 p
->table
= SCM_BOOL_F
;
624 scm_tc16_dstate
= scm_make_smob_type ("dstate", 0);
625 scm_set_smob_mark (scm_tc16_dstate
, dstate_mark
);
626 scm_set_smob_free (scm_tc16_dstate
, dstate_free
);
627 #ifndef SCM_MAGIC_SNARFER
628 #include "libguile/dump.x"