1(module serialize racket/base
2  (require syntax/modcollapse
3           racket/struct
4           racket/list
5           racket/flonum
6           racket/fixnum
7           "relative-path.rkt"
8           "serialize-structs.rkt")
9
10  ;; This module implements the core serializer. The syntactic
11  ;; `define-serializable-struct' layer is implemented separately
12  ;; (and differently for old-style vs. new-style `define-struct').
13
14  (provide prop:serializable
15	   make-serialize-info
16	   make-deserialize-info
17
18	   ;; Checks whether a value is serializable:
19	   serializable?
20
21	   ;; The two main routines:
22	   serialize
23	   deserialize
24
25           serialized=?
26
27           deserialize-module-guard)
28
29  ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
30  ;; serialize
31  ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
32
33  (define (serializable? v)
34    (or (serializable-struct? v)
35        (and (struct? v)
36             (prefab-struct-key v)
37             #t)
38	(boolean? v)
39	(null? v)
40	(number? v)
41	(char? v)
42	(and (symbol? v)
43             (or (symbol-interned? v)
44                 (eq? v (string->unreadable-symbol (symbol->string v)))))
45        (keyword? v)
46        (regexp? v)
47        (byte-regexp? v)
48	(string? v)
49	(path-for-some-system? v)
50	(bytes? v)
51	(vector? v)
52	(flvector? v)
53	(fxvector? v)
54	(pair? v)
55	(mpair? v)
56	(hash? v)
57	(box? v)
58	(void? v)
59	(date? v)
60	(arity-at-least? v)
61        (module-path-index? v)
62        (srcloc? v)))
63
64  ;; If a module is dynamic-required through a path,
65  ;;  then it can cause simplified module paths to be paths;
66  ;;  keep the literal path, but marshal it to bytes.
67  (define (protect-path p deser-path->relative-path)
68    (cond
69     [(path? p) (let ([rel (deser-path->relative-path p)])
70                  (if rel
71                      `(relative . ,rel)
72                      (path->bytes p)))]
73     [(and (pair? p) (eq? (car p) 'submod) (path? (cadr p)))
74      `(submod ,(protect-path (cadr p) deser-path->relative-path) . ,(cddr p))]
75     [else p]))
76  (define (unprotect-path p)
77    (cond
78     [(bytes? p) (bytes->path p)]
79     [(and (pair? p) (eq? (car p) 'submod) (or (bytes? (cadr p))
80                                               (list? (cadr p))))
81      `(submod ,(unprotect-path (cadr p)) . ,(cddr p))]
82     [(and (pair? p) (eq? (car p) 'relative))
83      (relative-path-elements->path (cdr p))]
84     [else p]))
85
86  ;; A deserialization function is provided from a `deserialize-info`
87  ;; module:
88  (define (add-submodule p)
89    (module-path-index-join '(submod "." deserialize-info)
90                            (if (resolved-module-path? p)
91                                p
92                                (module-path-index-join
93                                 p
94                                 #f))))
95
96  (define (revive-symbol s)
97    (if (string? s)
98        (string->unreadable-symbol s)
99        s))
100
101  (define deserialize-module-guard (make-parameter (lambda (mod-path sym)
102                                                     (void))
103                                                   #f
104                                                   'deserialize-module-guard))
105  (define varref (#%variable-reference varref))
106
107  (define (collapse/resolve-module-path-index mpi deser-path->relative-path)
108    (let ([v (collapse-module-path-index mpi deser-path->relative-path)])
109      (if (path? v)
110          ;; If collapsing gives a path, then we can't do any better than
111          ;; resolving --- and we must resolved, because the mpi may record
112          ;; a more accurate path inside.
113          (let ([v2 (resolved-module-path-name (module-path-index-resolve mpi))])
114            (if (symbol? v2)
115                `(quote ,v2)
116                v2))
117          v)))
118
119  (define (mod-to-id info mod-map cache deser-path->relative-path)
120    (let ([deserialize-id (serialize-info-deserialize-id info)])
121      (hash-ref
122       cache deserialize-id
123       (lambda ()
124	 (define id
125           (let ([path+name
126                  (let loop ([deserialize-id deserialize-id])
127                    (cond
128                      [(procedure? deserialize-id)
129                       (loop (deserialize-id))]
130                      [(identifier? deserialize-id)
131                       (let ([b (identifier-binding deserialize-id (variable-reference->phase varref))])
132                         (cons
133                          (and (list? b)
134                               (if (symbol? (caddr b))
135                                   (caddr b)
136                                   (protect-path
137                                    (collapse/resolve-module-path-index
138                                     (caddr b)
139                                     (build-path (serialize-info-dir info)
140                                                 "here.ss"))
141                                    deser-path->relative-path)))
142                          (syntax-e deserialize-id)))]
143                      [(symbol? deserialize-id)
144                       (cons #f deserialize-id)]
145                      [else
146                       (cons
147                        (if (symbol? (cdr deserialize-id))
148                            (cdr deserialize-id)
149                            (protect-path
150                             (collapse/resolve-module-path-index
151                              (cdr deserialize-id)
152                              (build-path (serialize-info-dir info)
153                                          "here.ss"))
154                             deser-path->relative-path))
155                        (car deserialize-id))]))])
156             (hash-ref
157              mod-map path+name
158              (lambda ()
159                (let ([id (hash-count mod-map)])
160                  (hash-set! mod-map path+name id)
161                  id)))))
162         (hash-set! cache deserialize-id id)
163         id))))
164
165  (define (is-mutable? o)
166    (or (and (or (mpair? o)
167		 (box? o)
168		 (vector? o)
169		 (hash? o))
170	     (not (immutable? o)))
171	(and (serializable-struct? o)
172             (serialize-info-can-cycle? (serializable-info o)))
173        (flvector? o)
174        (fxvector? o)
175        (let ([k (prefab-struct-key o)])
176          (and k
177               ;; Check whether all fields are mutable:
178               (pair? k)
179               (let-values ([(si skipped?) (struct-info o)])
180                 (let loop ([si si])
181                   (let*-values ([(name init auto acc mut imms super skipped?) (struct-type-info si)])
182                     (and (null? imms)
183                          (or (not super)
184                              (loop super))))))))))
185
186  ;; Finds a mutable object among those that make the
187  ;;  current cycle.
188  (define (find-mutable v cycle-stack share cycle)
189    ;; Walk back through cycle-stack to find something
190    ;;  mutable. If we get to v without anything being
191    ;;  mutable, then we're stuck.
192    (define (potentially-shared! v)
193      (unless (hash-ref share v #f)
194        (hash-set! share v (share-id share cycle))))
195    (potentially-shared! v)
196    (let loop ([cycle-stack cycle-stack])
197      (define o (car cycle-stack))
198      (cond
199       [(eq? o v)
200	(error 'serialize "cannot serialize cycle of immutable values: ~e" v)]
201       [(is-mutable? o)
202	o]
203       [else
204        (potentially-shared! o)
205	(loop (cdr cycle-stack))])))
206
207
208  (define (share-id share cycle)
209    (+ (hash-count share)
210       (hash-count cycle)))
211
212  ;; Traverses v to find cycles and sharing. Shared
213  ;;  objects go in the `shared' table, and cycle-breakers go in
214  ;;  `cycle'. In each case, the object is mapped to a number that is
215  ;;  incremented as shared/cycle objects are discovered, so
216  ;;  when the objects are deserialized, build them in reverse
217  ;;  order.
218  (define (find-cycles-and-sharing v cycle share)
219    (let ([tmp-cycle (make-hasheq)]  ;; candidates for sharing
220	  [tmp-share (make-hasheq)]  ;; candidates for cycles
221	  [cycle-stack null])      ;; same as in tmpcycle, but for finding mutable
222      (let loop ([v v])
223	(cond
224	 [(or (boolean? v)
225	      (number? v)
226	      (char? v)
227	      (symbol? v)
228	      (keyword? v)
229	      (null? v)
230	      (void? v)
231              (srcloc? v))
232	  (void)]
233	 [(hash-ref cycle v #f)
234	  ;; We already know that this value is
235	  ;;  part of a cycle
236	  (void)]
237	 [(hash-ref tmp-cycle v #f)
238	  ;; We've just learned that this value is
239	  ;;  part of a cycle.
240	  (let ([mut-v (if (is-mutable? v)
241			   v
242			   (find-mutable v cycle-stack share cycle))])
243            (unless (hash-ref cycle mut-v #f)
244              (hash-set! cycle mut-v (share-id share cycle))))]
245	 [(hash-ref share v #f)
246	  ;; We already know that this value is shared
247	  (void)]
248	 [(hash-ref tmp-share v #f)
249	  ;; We've just learned that this value is
250	  ;;  shared
251	  (hash-set! share v (share-id share cycle))]
252	 [else
253	  (hash-set! tmp-share v #t)
254	  (hash-set! tmp-cycle v #t)
255	  (set! cycle-stack (cons v cycle-stack))
256	  (cond
257	   [(serializable-struct? v)
258            (let* ([info (serializable-info v)]
259                   [vec ((serialize-info-vectorizer info) v)])
260              (for ([x (in-vector vec)])
261                (loop x)))]
262           [(and (struct? v)
263                 (prefab-struct-key v))
264            (for-each loop (struct->list v))]
265	   [(or (string? v)
266		(bytes? v)
267                (regexp? v)
268                (byte-regexp? v)
269		(path-for-some-system? v))
270	    ;; No sub-structure
271	    (void)]
272	   [(vector? v)
273            (for ([x (in-vector v)])
274              (loop x))]
275           [(flvector? v) (void)]
276           [(fxvector? v) (void)]
277	   [(pair? v)
278	    (loop (car v))
279	    (loop (cdr v))]
280	   [(mpair? v)
281	    (loop (mcar v))
282	    (loop (mcdr v))]
283	   [(box? v)
284	    (loop (unbox v))]
285	   [(date*? v)
286	    (for-each loop (take (struct->list v) 12))]
287	   [(date? v)
288	    (for-each loop (take (struct->list v) 10))]
289	   [(hash? v)
290            (for ([(k v) (in-hash v)])
291              (loop k)
292              (loop v))]
293	   [(arity-at-least? v)
294	    (loop (arity-at-least-value v))]
295	   [(module-path-index? v)
296            (let-values ([(path base) (module-path-index-split v)])
297              (loop path)
298              (loop base))]
299	   [else (raise-argument-error
300		  'serialize
301		  "serializable?"
302		  v)])
303	  ;; No more possibility for this object in
304	  ;;  a cycle:
305	  (hash-remove! tmp-cycle v)
306	  (set! cycle-stack (cdr cycle-stack))]))))
307
308  (define (quotable? v)
309    (if (pair? v)
310        (eq? (car v) 'q)
311        (or (boolean? v)
312            (number? v)
313            (char? v)
314            (null? v)
315            (string? v)
316            (symbol? v)
317            (keyword? v)
318            (regexp? v)
319            (byte-regexp? v)
320            (bytes? v))))
321
322  (define (serialize-one v share check-share? mod-map mod-map-cache path->relative-path deser-path->relative-path)
323    (define ((serial check-share?) v)
324      (cond
325       [(or (boolean? v)
326	    (number? v)
327	    (char? v)
328	    (null? v)
329            (keyword? v))
330	v]
331       [(symbol? v)
332        (if (symbol-interned? v)
333            v
334            (cons 'su (symbol->string v)))]
335       [(void? v)
336	'(void)]
337       [(and check-share?
338	     (hash-ref share v #f))
339	=> (lambda (v) (cons '? v))]
340       [(and (or (string? v)
341		 (bytes? v))
342	     (immutable? v))
343	v]
344       [(or (regexp? v)
345            (byte-regexp? v))
346        v]
347       [(serializable-struct? v)
348	(let ([info (serializable-info v)])
349	  (cons (mod-to-id info mod-map mod-map-cache deser-path->relative-path)
350                (let ([loop (serial #t)]
351                      [vec ((serialize-info-vectorizer info) v)])
352                  (for/list ([x (in-vector vec)])
353                    (loop x)))))]
354       [(and (struct? v)
355             (prefab-struct-key v))
356        => (lambda (k)
357             (cons 'f
358                   (cons
359                    k
360                    (map (serial #t) (struct->list v)))))]
361       [(or (string? v)
362	    (bytes? v))
363	(cons 'u v)]
364       [(path-for-some-system? v)
365        (let ([v-rel (and (path? v) (path->relative-path v))])
366          (if v-rel
367              (cons 'p* v-rel)
368              (list* 'p+ (path->bytes v) (path-convention-type v))))]
369       [(vector? v)
370        (define elems
371          (let ([loop (serial #t)])
372            (for/list ([x (in-vector v)])
373              (loop x))))
374        (if (and (immutable? v)
375                 (andmap quotable? elems))
376            (cons 'q v)
377            (cons (if (immutable? v) 'v 'v!) elems))]
378       [(flvector? v)
379        (cons 'vl (for/list ([i (in-flvector v)]) i))]
380       [(fxvector? v)
381        (cons 'vx (for/list ([i (in-fxvector v)]) i))]
382       [(pair? v)
383	(let ([loop (serial #t)])
384          (let ([a (loop (car v))]
385                [d (loop (cdr v))])
386            (cond
387             [(and (quotable? a) (quotable? d))
388              (cons 'q v)]
389             [else
390              (cons 'c (cons a d))])))]
391       [(mpair? v)
392	(let ([loop (serial #t)])
393	  (cons 'm
394		(cons (loop (mcar v))
395		      (loop (mcdr v)))))]
396       [(box? v)
397	(cons (if (immutable? v) 'b 'b!)
398	      ((serial #t) (unbox v)))]
399       [(hash? v)
400	(list* 'h
401	       (if (immutable? v) '- '!)
402	       (append
403		(if (hash-equal? v) '(equal) null)
404		(if (hash-eqv? v) '(eqv) null)
405		(if (hash-weak? v) '(weak) null))
406	       (let ([loop (serial #t)])
407                 (for/list ([(k v) (in-hash v)])
408                   (cons (loop k)
409                         (loop v)))))]
410       [(date*? v)
411	(cons 'date*
412	      (map (serial #t) (take (struct->list v) 12)))]
413       [(date? v)
414	(cons 'date
415	      (map (serial #t) (take (struct->list v) 10)))]
416       [(arity-at-least? v)
417	(cons 'arity-at-least
418	      ((serial #t) (arity-at-least-value v)))]
419       [(module-path-index? v)
420        (let-values ([(path base) (module-path-index-split v)])
421          (cons 'mpi
422                (cons ((serial #t) path)
423                      ((serial #t) base))))]
424       [(srcloc? v)
425        (cons 'srcloc
426              (map (serial #t) (take (struct->list v) 5)))]
427       [else (error 'serialize "shouldn't get here")]))
428    ((serial check-share?) v))
429
430  (define (serial-shell v mod-map mod-map-cache deser-path->relative-path)
431    (cond
432     [(serializable-struct? v)
433      (let ([info (serializable-info v)])
434	(mod-to-id info mod-map mod-map-cache deser-path->relative-path))]
435     [(vector? v)
436      (cons 'v (vector-length v))]
437     [(mpair? v)
438      'm]
439     [(box? v)
440      'b]
441     [(hash? v)
442      (cons 'h (append
443		(if (hash-equal? v) '(equal) null)
444		(if (hash-eqv? v) '(eqv) null)
445		(if (hash-weak? v) '(weak) null)))]
446     [else
447      ;; A mutable prefab
448      (cons 'pf (cons (prefab-struct-key v)
449                      (sub1 (vector-length (struct->vector v)))))]))
450
451  (define (serialize v
452                     #:relative-directory [rel-to #f]
453                     #:deserialize-relative-directory [deser-rel-to rel-to])
454    (let ([mod-map (make-hasheq)]
455	  [mod-map-cache (make-hash)]
456	  [share (make-hasheq)]
457	  [cycle (make-hasheq)]
458          [path->relative-path (make-path->relative-path-elements rel-to #:who 'serialize)]
459          [deser-path->relative-path (make-path->relative-path-elements deser-rel-to #:who 'serialize)])
460      ;; First, traverse V to find cycles and sharing
461      (find-cycles-and-sharing v cycle share)
462      ;; To simplify, all add the cycle records to shared.
463      ;;  (but keep cycle info, too).
464      (hash-for-each cycle
465                     (lambda (k v)
466                       (hash-set! share k v)))
467      (let ([ordered (map car (sort (hash-map share cons)
468                                    (lambda (a b) (< (cdr a) (cdr b)))))])
469	(let ([serializeds (map (lambda (v)
470				  (if (hash-ref cycle v #f)
471				      ;; Box indicates cycle record allocation
472				      ;;  followed by normal serialization
473				      (box (serial-shell v mod-map mod-map-cache deser-path->relative-path))
474				      ;; Otherwise, normal serialization
475				      (serialize-one v share #f mod-map mod-map-cache path->relative-path deser-path->relative-path)))
476				ordered)]
477	      [fixups (hash-map
478		       cycle
479		       (lambda (v n)
480			 (cons n
481			       (serialize-one v share #f mod-map mod-map-cache path->relative-path deser-path->relative-path))))]
482	      [main-serialized (serialize-one v share #t mod-map mod-map-cache path->relative-path deser-path->relative-path)]
483	      [mod-map-l (map car (sort (hash-map mod-map cons)
484                                        (lambda (a b) (< (cdr a) (cdr b)))))])
485	  (list (if (or rel-to deser-rel-to) '(4) '(3)) ;; serialization-format version
486                (hash-count mod-map)
487		(map (lambda (v) (if (symbol-interned? (cdr v))
488                                     v
489                                     (cons (car v) (symbol->string (cdr v)))))
490                     mod-map-l)
491		(length serializeds)
492		serializeds
493		fixups
494		main-serialized)))))
495
496  ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
497  ;; deserialize
498  ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
499
500  (define (make-hash/flags v)
501    (if (null? v)
502        (make-hasheq)
503        (case (car v)
504          [(equal)
505           (if (null? (cdr v))
506               (make-hash)
507               (make-weak-hash))]
508          [(eqv)
509           (if (null? (cdr v))
510               (make-hasheqv)
511               (make-weak-hasheqv))]
512          [(weak)
513           (make-weak-hasheq)])))
514
515  (define-struct not-ready (shares fixup))
516
517  (define (lookup-shared! share n mod-map module-path-index-join)
518    ;; The shared list is not necessarily in order of
519    ;;  referreds before referees. A `not-ready' object
520    ;;  indicates a reference before a value is ready,
521    ;;  so we need to recur to make it ready. Cycles
522    ;;  have been broken, though, so we don't run into
523    ;;  trouble with an infinite loop here.
524    (let ([sv (vector-ref share n)])
525      (if (not-ready? sv)
526          (let* ([v (vector-ref (not-ready-shares sv) n)]
527                 [val (if (box? v)
528                          (deserial-shell (unbox v) mod-map (not-ready-fixup sv) n)
529                          (deserialize-one v share mod-map module-path-index-join))])
530            (vector-set! share n val)
531            val)
532          sv)))
533
534  (define (deserialize-one v share mod-map module-path-index-join)
535    (let loop ([v v])
536      (cond
537       [(or (boolean? v)
538	    (number? v)
539	    (char? v)
540	    (symbol? v)
541            (keyword? v)
542            (regexp? v)
543            (byte-regexp? v)
544	    (null? v))
545	v]
546       [(string? v)
547	(string->immutable-string v)]
548       [(bytes? v)
549	(bytes->immutable-bytes v)]
550       [(number? (car v))
551	;; Struct instance:
552	(let ([info (vector-ref mod-map (car v))])
553	  (apply (deserialize-info-maker info) (map loop (cdr v))))]
554       [else
555	(case (car v)
556	  [(?) (lookup-shared! share (cdr v) mod-map module-path-index-join)]
557          [(q) (cdr v)]
558          [(f) (apply make-prefab-struct (cadr v) (map loop (cddr v)))]
559	  [(void) (void)]
560          [(su) (string->unreadable-symbol (cdr v))]
561	  [(u) (let ([x (cdr v)])
562		 (cond
563		  [(string? x) (string-copy x)]
564		  [(bytes? x) (bytes-copy x)]))]
565	  [(p) (bytes->path (cdr v))]
566	  [(p+) (bytes->path (cadr v) (cddr v))]
567	  [(p*) (relative-path-elements->path (cdr v))]
568	  [(c) (cons (loop (cadr v)) (loop (cddr v)))]
569	  [(c!) (cons (loop (cadr v)) (loop (cddr v)))]
570	  [(m) (mcons (loop (cadr v)) (loop (cddr v)))]
571	  [(v) (apply vector-immutable (map loop (cdr v)))]
572	  [(v!) (list->vector (map loop (cdr v)))]
573          [(vl) (apply flvector (map loop (cdr v)))]
574          [(vx) (apply fxvector (map loop (cdr v)))]
575	  [(b) (box-immutable (loop (cdr v)))]
576	  [(b!) (box (loop (cdr v)))]
577	  [(h) (let ([al (map (lambda (p)
578				(cons (loop (car p))
579				      (loop (cdr p))))
580			      (cdddr v))])
581		 (if (eq? '! (cadr v))
582		     (let ([ht (make-hash/flags (caddr v))])
583		       (for-each (lambda (p)
584				   (hash-set! ht (car p) (cdr p)))
585				 al)
586		       ht)
587                     (if (null? (caddr v))
588                         (make-immutable-hasheq al)
589                         (if (eq? (caaddr v) 'equal)
590                             (make-immutable-hash al)
591                             (make-immutable-hasheqv al)))))]
592	  [(date) (apply make-date (map loop (cdr v)))]
593	  [(date*) (apply make-date* (map loop (cdr v)))]
594	  [(arity-at-least) (make-arity-at-least (loop (cdr v)))]
595	  [(mpi) (module-path-index-join (loop (cadr v))
596                                         (loop (cddr v)))]
597          [(srcloc) (apply make-srcloc (map loop (cdr v)))]
598	  [else (error 'serialize "ill-formed serialization")])])))
599
600  (define (deserial-shell v mod-map fixup n)
601    (cond
602     [(number? v)
603      ;; Struct instance
604      (let* ([info (vector-ref mod-map v)])
605	(let-values ([(obj fix) ((deserialize-info-cycle-maker info))])
606	  (vector-set! fixup n fix)
607	  obj))]
608     [(pair? v)
609      (case (car v)
610	[(v)
611	 ;; Vector
612	 (let* ([m (cdr v)]
613		[v0 (make-vector m #f)])
614	   (vector-set! fixup n (lambda (v)
615				  (let loop ([i m])
616				    (unless (zero? i)
617				      (let ([i (sub1 i)])
618					(vector-set! v0 i (vector-ref v i))
619					(loop i))))))
620	   v0)]
621	[(h)
622	 ;; Hash table
623	 (let ([ht0 (make-hash/flags (cdr v))])
624	   (vector-set! fixup n (lambda (ht)
625                                  (for ([(k v) (in-hash ht)])
626                                    (hash-set! ht0 k v))))
627	   ht0)]
628        [(pf)
629         ;; Prefab
630         (let ([s (apply make-prefab-struct
631                         (cadr v)
632                         (make-list (cddr v) #f))])
633           (vector-set! fixup n (lambda (v)
634                                  (let-values ([(si skipped?) (struct-info s)])
635                                    (let loop ([si si])
636                                      (let*-values ([(name init auto acc mut imms super skipped?) (struct-type-info si)])
637                                        (let ([count (+ init auto)])
638                                          (for ([i (in-range 0 count)])
639                                            (mut s i (acc v i)))
640                                          (when super
641                                            (loop super))))))))
642           s)])]
643     [else
644      (case v
645        [(c)
646         (let ([c (cons #f #f)])
647	   (vector-set! fixup n (lambda (p)
648                                  (error 'deserialize "cannot restore pair in cycle")))
649	   c)]
650	[(m)
651	 (let ([p0 (mcons #f #f)])
652	   (vector-set! fixup n (lambda (p)
653				  (set-mcar! p0 (mcar p))
654				  (set-mcdr! p0 (mcdr p))))
655	   p0)]
656	[(b)
657	 (let ([b0 (box #f)])
658	   (vector-set! fixup n (lambda (b)
659				  (set-box! b0 (unbox b))))
660	   b0)]
661	[(date)
662         (error 'deserialize "cannot restore date in cycle")]
663	[(arity-at-least)
664         (error 'deserialize "cannot restore arity-at-least in cycle")]
665	[(mpi)
666         (error 'deserialize "cannot restore module-path-index in cycle")])]))
667
668  (define (deserialize-with-map mod-map vers l module-path-index-join)
669    (let ([share-n (list-ref l 2)]
670          [shares (list-ref l 3)]
671          [fixups (list-ref l 4)]
672          [result (list-ref l 5)])
673      ;; Create vector for sharing:
674      (let* ([fixup (make-vector share-n #f)]
675             [share (make-vector share-n (make-not-ready
676                                          (list->vector shares)
677                                          fixup))])
678        ;; Deserialize into sharing array:
679        (let loop ([n 0][l shares])
680          (unless (= n share-n)
681            (lookup-shared! share n mod-map module-path-index-join)
682            (loop (add1 n) (cdr l))))
683        ;; Fixup shell for graphs
684        (for-each (lambda (n+v)
685                    (let ([v (deserialize-one (cdr n+v) share mod-map module-path-index-join)])
686                      ((vector-ref fixup (car n+v)) v)))
687                  fixups)
688        ;; Deserialize final result. (If there's no sharing, then
689        ;;  all the work is actually here.)
690        (deserialize-one result share mod-map module-path-index-join))))
691
692  (define (extract-version l)
693    (if (pair? (car l))
694        (values (caar l) (cdr l))
695        (values 0 l)))
696
697  (define (deserialize l)
698    (let-values ([(vers l) (extract-version l)])
699      (let ([mod-map (make-vector (list-ref l 0))]
700            [mod-map-l (list-ref l 1)])
701        ;; Load constructor mapping
702        (let loop ([n 0][l mod-map-l])
703          (unless (null? l)
704            (let* ([path+name (car l)]
705                   [des (if (car path+name)
706                            (let ([serial-p (unprotect-path (car path+name))]
707                                  [serial-sym (revive-symbol (cdr path+name))])
708                              (define maybe-binding ((deserialize-module-guard) serial-p serial-sym))
709                              (define p (if (pair? maybe-binding) (car maybe-binding) serial-p))
710                              (define sym (if (pair? maybe-binding) (cdr maybe-binding) serial-sym))
711                              (let ([sub (add-submodule p)]
712                                    [fallback
713                                     (lambda ()
714                                       ;; On failure, for backward compatibility,
715                                       ;; try module instead of submodule:
716                                       (dynamic-require p sym))])
717                                (if (module-declared? sub #t)
718                                    (dynamic-require sub sym fallback)
719                                    (fallback))))
720                            (namespace-variable-value (cdr path+name)))])
721              ;; Register maker and struct type:
722              (vector-set! mod-map n des))
723            (loop (add1 n) (cdr l))))
724        (deserialize-with-map mod-map vers l module-path-index-join))))
725
726  ;; ----------------------------------------
727
728  (define (serialized=? l1 l2)
729    (let-values ([(vers1 l1) (extract-version l1)]
730                 [(vers2 l2) (extract-version l2)])
731      (let ([mod-map1 (make-vector (list-ref l1 0))]
732            [mod-map1-l (list-ref l1 1)]
733            [mod-map2 (make-vector (list-ref l2 0))]
734            [mod-map2-l (list-ref l2 1)]
735            [make-key (lambda (path+name)
736                        (if (car path+name)
737                            (let ([p (unprotect-path (car path+name))]
738                                  [sym (revive-symbol (cdr path+name))])
739                              (list p sym))
740                            (list #f (cdr path+name))))]
741            [mpi-key (gensym)])
742        (let ([keys1 (map make-key mod-map1-l)]
743              [keys2 (map make-key mod-map2-l)]
744              [ht (make-hash)]
745              [mpij (lambda (a b) (vector mpi-key a b))])
746          (for-each (lambda (key)
747                      (unless (hash-ref ht key #f)
748                        (hash-set! ht key (gensym))))
749                    (append keys1 keys2))
750          (for-each (lambda (mod-map keys)
751                      (let loop ([n 0][l keys])
752                        (unless (null? l)
753                          (let ([sym (hash-ref ht (car l))])
754                            (vector-set! mod-map n
755                                         (make-deserialize-info
756                                          (lambda args
757                                            (vector sym (list->vector args)))
758                                          (lambda ()
759                                            (let ([v (vector sym #f)])
760                                              (values v
761                                                      (lambda (vec)
762                                                        (vector-set! v 1 (vector-ref vec 1)))))))))
763                          (loop (add1 n) (cdr l)))))
764                    (list mod-map1 mod-map2)
765                    (list keys1 keys2))
766          (let ([v1 (deserialize-with-map mod-map1 vers1 l1 mpij)]
767                [v2 (deserialize-with-map mod-map2 vers2 l2 mpij)])
768            (equal? v1 v2)))))))
769