From b47e95950bfcca1870e50736bf48c3f15d3f2ef5 Mon Sep 17 00:00:00 2001
From: Matthew Flatt <mflatt@racket-lang.org>
Date: Thu, 4 Sep 2014 08:21:53 +0200
Subject: [PATCH] scribble/eval: change handling of serializable convertible
 results

When an evaluation result from a sandboxed computation is convertible
(so that it should be preserved for rendering) and serializable, then
serialize the value from transfer from the sandboxed environment to
the rendering environment.

This change complements the one that makes `pict`s serializable.
Serializing a pict result avoids retaining the sandboxed environment,
including its instance of the `pict` and `racket/draw` modules,
when a sandbox-created pict is part of the generated document.
For example, the memory use of the result of "math.scrbl" is about
20% smaller with this change.

original commit: c9a11c4ee4dff8e099e30d8c5040b087dae4a42b
---
 .../scribblings/scribble/eval.scrbl            | 17 +++++++++++++++--
 .../scribble-lib/scribble/eval.rkt             | 15 ++++++++++++---
 .../scribble/private/serialize.rkt             | 18 ++++++++++++++++++
 3 files changed, 45 insertions(+), 5 deletions(-)
 create mode 100644 pkgs/scribble-pkgs/scribble-lib/scribble/private/serialize.rkt

diff --git a/pkgs/scribble-pkgs/scribble-doc/scribblings/scribble/eval.scrbl b/pkgs/scribble-pkgs/scribble-doc/scribblings/scribble/eval.scrbl
index 0411aea2..b3aea23e 100644
--- a/pkgs/scribble-pkgs/scribble-doc/scribblings/scribble/eval.scrbl
+++ b/pkgs/scribble-pkgs/scribble-doc/scribblings/scribble/eval.scrbl
@@ -1,5 +1,10 @@
 #lang scribble/doc
-@(require scribble/manual "utils.rkt" (for-label racket/sandbox racket/pretty))
+@(require scribble/manual
+          "utils.rkt"
+          (for-label racket/sandbox
+                     racket/pretty
+                     file/convertible
+                     racket/serialize))
 
 @title[#:tag "eval"]{Evaluation and Examples}
 
@@ -169,7 +174,15 @@ setting sandbox parameters to disable limits, setting the outputs to
 @racket['string], and not adding extra security guards.
 
 If @racket[pretty-print?] is true, the sandbox's printer is set to
-@racket[pretty-print-handler].}
+@racket[pretty-print-handler]. In that case, values that are convertible
+in the sense of @racket[convertible?] are printed using @racket[write-special],
+except that values that are serializable in the sense of @racket[serializable?]
+are serialized for tranfers from inside the sandbox to outside (which can avoid
+pulling code and support from the sandboxed environment into the document-rendering
+environment).
+
+@history[#:changed "1.6" @elem{Changed treatment of convertible values that are
+                               serializable.}]}
 
 
 @defproc[(make-base-eval-factory [mod-paths (listof module-path?)]
diff --git a/pkgs/scribble-pkgs/scribble-lib/scribble/eval.rkt b/pkgs/scribble-pkgs/scribble-lib/scribble/eval.rkt
index 5031d536..79253c71 100644
--- a/pkgs/scribble-pkgs/scribble-lib/scribble/eval.rkt
+++ b/pkgs/scribble-pkgs/scribble-lib/scribble/eval.rkt
@@ -4,7 +4,9 @@
          (only-in "core.rkt" content?)
          racket/list
          file/convertible ;; attached into new namespace via anchor
+         racket/serialize ;; attached into new namespace via anchor
          racket/pretty ;; attached into new namespace via anchor
+         scribble/private/serialize ;; attached into new namespace via anchor
          racket/sandbox racket/promise racket/port
          racket/gui/dynamic
          (for-syntax racket/base syntax/srcloc unstable/struct)
@@ -241,7 +243,11 @@
                                        (and (convertible? obj) 1)))
                                     (pretty-print-print-hook
                                      (lambda (obj _mode out)
-                                       (write-special obj out))))
+                                       (write-special (if (serializable? obj)
+                                                          (make-serialized-convertible
+                                                           (serialize obj))
+                                                          obj)
+                                                      out))))
                        (map (current-print) v))
                      (close-output-port out)
                      in)))])))
@@ -346,8 +352,11 @@
                     [sandbox-namespace-specs
                      (append (sandbox-namespace-specs)
                              (if pretty-print?
-                                 '(racket/pretty file/convertible)
-                                 '(file/convertible)))])
+                                 '(racket/pretty)
+                                 '())
+                             '(file/convertible
+                               racket/serialize
+                               scribble/private/serialize))])
        (let ([e (apply make-evaluator lang ips)])
          (when pretty-print?
            (call-in-sandbox-context e
diff --git a/pkgs/scribble-pkgs/scribble-lib/scribble/private/serialize.rkt b/pkgs/scribble-pkgs/scribble-lib/scribble/private/serialize.rkt
new file mode 100644
index 00000000..cc3f26f1
--- /dev/null
+++ b/pkgs/scribble-pkgs/scribble-lib/scribble/private/serialize.rkt
@@ -0,0 +1,18 @@
+#lang racket/base
+(require racket/serialize
+         file/convertible)
+
+(provide make-serialized-convertible)
+
+(struct serialized-convertible (ser [deser #:mutable])
+  #:property prop:convertible (lambda (v mode default)
+                                (unless (serialized-convertible-deser v)
+                                  (set-serialized-convertible-deser!
+                                   v
+                                   (deserialize (serialized-convertible-ser v))))
+                                (convert (serialized-convertible-deser v) mode default)))
+
+(define (make-serialized-convertible ser)
+  (serialized-convertible ser #f))
+
+