document 'mzc --decompile'
svn: r11317
This commit is contained in:
parent
08044ac0f9
commit
76cf25fc12
|
@ -115,7 +115,7 @@
|
||||||
,(let-values ([(globs defns) (decompile-prefix prefix)])
|
,(let-values ([(globs defns) (decompile-prefix prefix)])
|
||||||
`(let ()
|
`(let ()
|
||||||
,@defns
|
,@defns
|
||||||
,(decompile-expr rhs globs '(#%globals)))))]
|
,(decompile-form rhs globs '(#%globals)))))]
|
||||||
[(struct def-for-syntax (ids rhs prefix max-let-depth))
|
[(struct def-for-syntax (ids rhs prefix max-let-depth))
|
||||||
`(define-values-for-syntax ,ids
|
`(define-values-for-syntax ,ids
|
||||||
,(let-values ([(globs defns) (decompile-prefix prefix)])
|
,(let-values ([(globs defns) (decompile-prefix prefix)])
|
||||||
|
@ -188,24 +188,13 @@
|
||||||
(if clear?
|
(if clear?
|
||||||
`(#%sfs-clear ,e)
|
`(#%sfs-clear ,e)
|
||||||
e)))]
|
e)))]
|
||||||
[(struct lam (name flags num-params rest? closure-map max-let-depth body))
|
[(? lam?)
|
||||||
(let ([vars (for/list ([i (in-range num-params)])
|
`(lambda . ,(decompile-lam expr globs stack))]
|
||||||
(gensym (format "arg~a-" i)))]
|
[(struct case-lam (name lams))
|
||||||
[rest-vars (if rest? (list (gensym 'rest)) null)]
|
`(case-lambda
|
||||||
[captures (map (lambda (v)
|
,@(map (lambda (lam)
|
||||||
(list-ref/protect stack v))
|
(decompile-lam lam globs stack))
|
||||||
(vector->list closure-map))])
|
lams))]
|
||||||
`(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)))))]
|
|
||||||
[(struct let-one (rhs body))
|
[(struct let-one (rhs body))
|
||||||
(let ([id (or (extract-id rhs)
|
(let ([id (or (extract-id rhs)
|
||||||
(gensym 'local))])
|
(gensym 'local))])
|
||||||
|
@ -222,12 +211,12 @@
|
||||||
,(decompile-expr body globs (append vars stack)))))]
|
,(decompile-expr body globs (append vars stack)))))]
|
||||||
[(struct let-rec (procs body))
|
[(struct let-rec (procs body))
|
||||||
`(begin
|
`(begin
|
||||||
(set!-rec-values ,(for/list ([p (in-list procs)]
|
(#%set!-rec-values ,(for/list ([p (in-list procs)]
|
||||||
[i (in-naturals)])
|
[i (in-naturals)])
|
||||||
(list-ref/protect stack i))
|
(list-ref/protect stack i))
|
||||||
,@(map (lambda (proc)
|
,@(map (lambda (proc)
|
||||||
(decompile-expr proc globs stack))
|
(decompile-expr proc globs stack))
|
||||||
procs))
|
procs))
|
||||||
,(decompile-expr body globs stack))]
|
,(decompile-expr body globs stack))]
|
||||||
[(struct install-value (count pos boxes? rhs body))
|
[(struct install-value (count pos boxes? rhs body))
|
||||||
`(begin
|
`(begin
|
||||||
|
@ -274,6 +263,27 @@
|
||||||
'???)]
|
'???)]
|
||||||
[else `(quote ,expr)]))
|
[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)))))]))
|
||||||
|
|
||||||
;; ----------------------------------------
|
;; ----------------------------------------
|
||||||
|
|
||||||
#;
|
#;
|
||||||
|
|
|
@ -235,7 +235,7 @@
|
||||||
[(0) (read-define-values v)]
|
[(0) (read-define-values v)]
|
||||||
[(1) (read-define-syntax v)]
|
[(1) (read-define-syntax v)]
|
||||||
[(2) (read-set! v)]
|
[(2) (read-set! v)]
|
||||||
[(3) (read-case-lambda v)]
|
[(3) v] ; a case-lam already
|
||||||
[(4) (read-begin0 v)]
|
[(4) (read-begin0 v)]
|
||||||
[(5) (read-boxenv v)]
|
[(5) (read-boxenv v)]
|
||||||
[(6) (read-module-wrap v)]
|
[(6) (read-module-wrap v)]
|
||||||
|
|
81
collects/scribblings/mzc/decompile.scrbl
Normal file
81
collects/scribblings/mzc/decompile.scrbl
Normal 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.}
|
||||||
|
|
||||||
|
]
|
|
@ -47,6 +47,9 @@ command-line flags:
|
||||||
@item{@as-index{@DFlag{expand}} : Pretty-prints the macro-expanded
|
@item{@as-index{@DFlag{expand}} : Pretty-prints the macro-expanded
|
||||||
form of a Scheme program.}
|
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
|
@item{@as-index{@DFlag{zo}}, @as-index{@Flag{z}}, or
|
||||||
@as-index{@DFlag{collection-zo}} : Compiles Scheme code to
|
@as-index{@DFlag{collection-zo}} : Compiles Scheme code to
|
||||||
bytecode, without following transitive imports. See
|
bytecode, without following transitive imports. See
|
||||||
|
@ -64,6 +67,7 @@ command-line flags:
|
||||||
@include-section["plt.scrbl"]
|
@include-section["plt.scrbl"]
|
||||||
@include-section["cc.scrbl"]
|
@include-section["cc.scrbl"]
|
||||||
@include-section["c-mods.scrbl"]
|
@include-section["c-mods.scrbl"]
|
||||||
|
@include-section["decompile.scrbl"]
|
||||||
@include-section["zo.scrbl"]
|
@include-section["zo.scrbl"]
|
||||||
@include-section["ext.scrbl"]
|
@include-section["ext.scrbl"]
|
||||||
@include-section["api.scrbl"]
|
@include-section["api.scrbl"]
|
||||||
|
|
|
@ -46,8 +46,6 @@
|
||||||
|
|
||||||
@guideintro["pairs"]{pairs and lists}
|
@guideintro["pairs"]{pairs and lists}
|
||||||
|
|
||||||
@local-table-of-contents[]
|
|
||||||
|
|
||||||
A @deftech{pair} combines exactly two values. The first value is
|
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[car] procedure, and the second value is
|
||||||
accessed with the @scheme[cdr] procedure. Pairs are not mutable (but
|
accessed with the @scheme[cdr] procedure. Pairs are not mutable (but
|
||||||
|
|
Loading…
Reference in New Issue
Block a user