document 'mzc --decompile'

svn: r11317
This commit is contained in:
Matthew Flatt 2008-08-19 00:50:52 +00:00
parent 08044ac0f9
commit 76cf25fc12
5 changed files with 121 additions and 28 deletions

View File

@ -115,7 +115,7 @@
,(let-values ([(globs defns) (decompile-prefix prefix)])
`(let ()
,@defns
,(decompile-expr rhs globs '(#%globals)))))]
,(decompile-form rhs globs '(#%globals)))))]
[(struct def-for-syntax (ids rhs prefix max-let-depth))
`(define-values-for-syntax ,ids
,(let-values ([(globs defns) (decompile-prefix prefix)])
@ -188,24 +188,13 @@
(if clear?
`(#%sfs-clear ,e)
e)))]
[(struct lam (name flags num-params rest? closure-map max-let-depth body))
(let ([vars (for/list ([i (in-range num-params)])
(gensym (format "arg~a-" i)))]
[rest-vars (if rest? (list (gensym 'rest)) null)]
[captures (map (lambda (v)
(list-ref/protect stack v))
(vector->list closure-map))])
`(lambda (,@vars . ,(if rest?
(car rest-vars)
null))
,@(if name
`(',name)
null)
,@(if (null? captures)
null
`('(captures: ,@captures)))
,(decompile-expr body globs (append captures
(append vars rest-vars)))))]
[(? lam?)
`(lambda . ,(decompile-lam expr globs stack))]
[(struct case-lam (name lams))
`(case-lambda
,@(map (lambda (lam)
(decompile-lam lam globs stack))
lams))]
[(struct let-one (rhs body))
(let ([id (or (extract-id rhs)
(gensym 'local))])
@ -222,7 +211,7 @@
,(decompile-expr body globs (append vars stack)))))]
[(struct let-rec (procs body))
`(begin
(set!-rec-values ,(for/list ([p (in-list procs)]
(#%set!-rec-values ,(for/list ([p (in-list procs)]
[i (in-naturals)])
(list-ref/protect stack i))
,@(map (lambda (proc)
@ -274,6 +263,27 @@
'???)]
[else `(quote ,expr)]))
(define (decompile-lam expr globs stack)
(match expr
[(struct lam (name flags num-params rest? closure-map max-let-depth body))
(let ([vars (for/list ([i (in-range num-params)])
(gensym (format "arg~a-" i)))]
[rest-vars (if rest? (list (gensym 'rest)) null)]
[captures (map (lambda (v)
(list-ref/protect stack v))
(vector->list closure-map))])
`((,@vars . ,(if rest?
(car rest-vars)
null))
,@(if (and name (not (null? name)))
`(',name)
null)
,@(if (null? captures)
null
`('(captures: ,@captures)))
,(decompile-expr body globs (append captures
(append vars rest-vars)))))]))
;; ----------------------------------------
#;

View File

@ -235,7 +235,7 @@
[(0) (read-define-values v)]
[(1) (read-define-syntax v)]
[(2) (read-set! v)]
[(3) (read-case-lambda v)]
[(3) v] ; a case-lam already
[(4) (read-begin0 v)]
[(5) (read-boxenv v)]
[(6) (read-module-wrap v)]

View File

@ -0,0 +1,81 @@
#lang scribble/doc
@(require scribble/manual
"common.ss"
(for-label scheme/base))
@title[#:tag "decompile"]{Decompiling Bytecode}
The @DFlag{decompile} mode for @|mzc| takes a bytecode file (which
usually has the file extension @filepath{.zo}) and converts it back
to an approximation of Scheme code. Decompiled bytecode is mostly
useful for checking the compiler's transformation and optimization of
the source program.
Many forms in the decompiled code, such as @scheme[module],
@scheme[define], and @scheme[lambda], have the same meanings as
always. Other forms and transformations are specific to the rendering
of bytecode, and they reflect a specific execution model:
@itemize[
@item{Top-level variables, variables defined within the module, and
variables imported from other modules are prefixed with @litchar{_},
which helps expose the difference between uses of local variables
versus other variables. Variables imported from other modules,
moreover, have a suffix that indicates the source module.
Non-local variables are always accessed indirectly though an implicit
@schemeidfont{#%globals} or @schemeidfont{#%modvars} variable that
resides on the value stack (which otherwise contains local
variables). Variable accesses are further wrapped with
@schemeidfont{#%checked} when the compiler cannot prove that the
variable will be defined before the access.
Uses of core primitives are shown without a leading @litchar{_}, and
they are never wrapped with @schemeidfont{#%checked}. Applications of
some primitives are inlined by the JIT compiler.}
@item{Local-variable access may be wrapped with
@schemeidfont{#%sfs-clear}, which indicates that the variable-stack
location holding the variable will be cleared to prevent the
variable's value from being retained by the garbage collector.
Mutable variables are converted to explicitly boxed values using
@schemeidfont{#%box}, @schemeidfont{#%unbox}, and
@schemeidfont{#%set-boxes!} (which works on multiple boxes at once).
A @schemeidfont{set!-rec-values} operation constructs
mutually-recursive closures and simultaneously updates the
corresponding variable-stack locations that bind the closures. A
@schemeidfont{set!}, @schemeidfont{set!-values}, or
@schemeidfont{set!-rec-values} form is always used on a local
variable before it is captured by a closure; that ordering reflects
how closures capture values in variable-stack locations, as opposed
to stack locations.}
@item{In a @scheme[lambda] form, if the procedure produced by the
@scheme[lambda] has a name (accessible via @scheme[object-name])
and/or source-location information, then it is shown as a quoted
constant at the start of the procedure's body. Afterward, if the
@scheme[lambda] form captures any bindings from its context, those
bindings are also shown in a quoted constant. Neither constant
corresponds to a computation when the closure is called, though the
list of captured bindings corresponds to a closure allocation when
the @scheme[lambda] form itself is evaluated.
A @scheme[lambda] form that closes over no bindings is wrapped with
@schemeidfont{#%closed} plus an identifier that is bound to the
closure. The binding's scope covers the entire decompiled output, and
it may be referenced directly in other parts of the program; the
binding corresponds to a constant closure value that is shared, and
it may even contain cyclic references to itself or other constant
closures.}
@item{A form @scheme[(#%apply-values _proc _expr)] is equivalent to
@scheme[(call-with-values (lambda () _expr) _proc)], but the run-time
system avoids allocating a closure for @scheme[_expr].}
@item{A @schemeidfont{#%decode-syntax} form corresponds to a syntax
object. Future improvements to the decompiler will convert such
syntax objects to a readable form.}
]

View File

@ -47,6 +47,9 @@ command-line flags:
@item{@as-index{@DFlag{expand}} : Pretty-prints the macro-expanded
form of a Scheme program.}
@item{@as-index{@DFlag{decompile}} : Parses a bytecode file and
prints its content as quasi-Scheme. See @secref["decompile"].}
@item{@as-index{@DFlag{zo}}, @as-index{@Flag{z}}, or
@as-index{@DFlag{collection-zo}} : Compiles Scheme code to
bytecode, without following transitive imports. See
@ -64,6 +67,7 @@ command-line flags:
@include-section["plt.scrbl"]
@include-section["cc.scrbl"]
@include-section["c-mods.scrbl"]
@include-section["decompile.scrbl"]
@include-section["zo.scrbl"]
@include-section["ext.scrbl"]
@include-section["api.scrbl"]

View File

@ -46,8 +46,6 @@
@guideintro["pairs"]{pairs and lists}
@local-table-of-contents[]
A @deftech{pair} combines exactly two values. The first value is
accessed with the @scheme[car] procedure, and the second value is
accessed with the @scheme[cdr] procedure. Pairs are not mutable (but