123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- ;;; WebAssembly dumper
- ;;; Copyright (C) 2023, 2024 Igalia, S.L.
- ;;; Copyright (C) 2023 David Thompson <dave@spritely.institute>
- ;;;
- ;;; Licensed under the Apache License, Version 2.0 (the "License");
- ;;; you may not use this file except in compliance with the License.
- ;;; You may obtain a copy of the License at
- ;;;
- ;;; http://www.apache.org/licenses/LICENSE-2.0
- ;;;
- ;;; Unless required by applicable law or agreed to in writing, software
- ;;; distributed under the License is distributed on an "AS IS" BASIS,
- ;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ;;; See the License for the specific language governing permissions and
- ;;; limitations under the License.
- ;;; Commentary:
- ;;;
- ;;; Print out details of WebAssembly modules.
- ;;;
- ;;; Code:
- (define-module (wasm dump)
- #:use-module (ice-9 format)
- #:use-module (ice-9 match)
- #:use-module (ice-9 pretty-print)
- #:use-module ((srfi srfi-1) #:select (count))
- #:use-module (wasm types)
- #:export (val-type-repr
- type-repr
- type-use-repr
- dump-wasm))
- (define (val-type-repr vt)
- (match vt
- (($ <ref-type> #t ht)
- `(ref null ,ht))
- (($ <ref-type> #f ht)
- `(ref ,ht))
- (_ vt)))
- (define (type-repr type)
- (define (params-repr params)
- (match params
- (() '())
- ((($ <param> #f type) ...)
- `((param ,@(map val-type-repr type))))
- ((($ <param> id type) . params)
- (cons `(param ,id ,(val-type-repr type))
- (params-repr params)))))
- (define (results-repr results)
- `((result ,@(map val-type-repr results))))
- (define (field-repr field)
- (define (wrap mutable? repr)
- (if mutable? `(mut ,repr) repr))
- (match field
- (($ <field> id mutable? type)
- (let ((repr (wrap mutable? (val-type-repr type))))
- (if id
- `(field ,id ,repr)
- repr)))))
- (match type
- (($ <func-sig> params results)
- `(func ,@(params-repr params) ,@(results-repr results)))
- (($ <sub-type> final? supers type)
- `(sub ,@(if final? '(final) '()) ,@supers ,(type-repr type)))
- (($ <struct-type> fields)
- `(struct ,@(map field-repr fields)))
- (($ <array-type> mutable? type)
- `(array ,(field-repr (make-field #f mutable? type))))))
- (define (type-use-repr type)
- (match type
- (($ <type-use> idx ($ <type> id type))
- (type-repr type))
- (($ <type-use> idx type)
- `(type ,(or idx "error: invalid type use!")))))
- (define (table-type-repr type)
- (match type
- (($ <table-type> ($ <limits> min max) elem-type)
- `(,min ,max ,(val-type-repr elem-type)))))
- (define (global-type-repr type)
- (match type
- (($ <global-type> mutable? type)
- (let ((t (val-type-repr type)))
- (if mutable? `(mut ,t) t)))))
- (define (memory-type-repr type)
- (match type
- (($ <mem-type> ($ <limits> min max))
- `(,min ,max))))
- (define* (dump-wasm mod #:key (port (current-output-port))
- (dump-func-defs? #t))
- (define (enumerate f items start)
- (let lp ((items items) (idx start))
- (match items
- (() (values))
- ((item . items)
- (f item idx)
- (lp items (1+ idx))))))
- (define* (dump-items header items #:optional (start 0))
- (unless (null? items)
- (format port "~a:\n" header)
- (enumerate (lambda (item idx)
- (format port " ~a: ~a\n" idx item))
- items start)
- (newline port)))
- (define (dump-types types)
- (define (dump-type type idx indent)
- (match type
- (($ <type> id type)
- (let ((repr (type-repr type)))
- (format port "~a~a~@[ (~a)~]: ~a\n" indent idx id repr)))))
- (unless (null? types)
- (format port "Types:\n")
- (let lp ((types types) (idx 0))
- (match types
- (() (values))
- ((($ <rec-group> rec-types) . types)
- (format port "Recursive type group:\n")
- (enumerate (lambda (type idx)
- (dump-type type idx " "))
- rec-types idx)
- (format port "Recursive type group end.\n")
- (lp types (+ idx (length rec-types))))
- ((type . types)
- (dump-type type idx " ")
- (lp types (1+ idx)))))
- (newline port)))
- (define (dump-imports imports)
- (dump-items "Imports"
- (map (match-lambda
- (($ <import> mod name 'func _ type)
- `(import ,mod ,name func ,(type-use-repr type)))
- (($ <import> mod name 'table _ type)
- `(import ,mod ,name table ,@(table-type-repr type)))
- (($ <import> mod name 'global _ type)
- `(import ,mod ,name global ,(global-type-repr type)))
- (($ <import> mod name 'memory _ type)
- `(import ,mod ,name memory ,@(memory-type-repr type))))
- imports)))
- (define (dump-func-decls funcs imported)
- (dump-items "Function declarations"
- (map (match-lambda (($ <func> id type locals body)
- (type-use-repr type)))
- funcs)
- imported))
- (define (dump-tables tables imported)
- (dump-items "Tables"
- (map (match-lambda
- (($ <table> id type init)
- `(table ,id ,@(table-type-repr type))))
- tables)
- imported))
- (define (dump-memories memories imported)
- (dump-items "Memories"
- (map (match-lambda
- (($ <memory> id type)
- `(memory ,id ,@(memory-type-repr type)))
- (type
- `(memory #f ,@(memory-type-repr type))))
- memories)))
- (define (dump-tags tags)
- (dump-items "Tags" tags))
- (define (dump-strings strings)
- (dump-items "Strings" strings))
- (define (dump-globals globals imported)
- (dump-items "Globals"
- (map (match-lambda
- (($ <global> id type init)
- (let ((t (val-type-repr type)))
- `(global ,id ,(global-type-repr type) ,init))))
- globals)
- imported))
- (define (dump-exports exports)
- (dump-items "Exports"
- (map (match-lambda
- (($ <export> name kind idx)
- `(export ,name ,kind ,idx)))
- exports)))
- (define (dump-start start)
- (when start
- (format port "Start: #~a\n\n" start)))
- (define (dump-elems elems)
- (dump-items "Elems"
- (map (match-lambda
- (($ <elem> id mode table type offset inits)
- `(elem id ,mode ,table ,(val-type-repr type)
- ,offset ,inits)))
- elems)))
- (define (dump-data datas)
- (dump-items "Datas"
- (map (match-lambda
- (($ <data> id mode mem offset init)
- `(data ,id ,mode ,mem ,offset ,init)))
- datas)))
- (define (dump-func-defs funcs imported)
- (unless (null? funcs)
- (format port "Function definitions:\n")
- (enumerate
- (match-lambda*
- ((($ <func> id type locals body) idx)
- (format port " Function #~a:\n" idx)
- (when id (format port " Id: ~a\n" id))
- (format port " Type: ~a\n" (type-use-repr type))
- (match locals
- (() #t)
- ((($ <local> id vt) ...)
- (format port " Locals:~:{ ~@[~a:~]~a~}\n"
- (map list id (map val-type-repr vt)))))
- (format port " Body:\n")
- (pretty-print body #:port port #:per-line-prefix " ")))
- funcs
- imported)))
- (match mod
- (($ <wasm> id types imports funcs tables memories globals exports start
- elems datas tags strings custom)
- (define (import-has-kind kind)
- (match-lambda
- (($ <import> mod name kind' id type) (eq? kind kind'))))
- (let ((imported-funcs (count (import-has-kind 'func) imports))
- (imported-tables (count (import-has-kind 'table) imports))
- (imported-memories (count (import-has-kind 'memory) imports))
- (imported-globals (count (import-has-kind 'global) imports)))
- (dump-types types)
- (dump-imports imports)
- (dump-func-decls funcs imported-funcs)
- (dump-tables tables imported-tables)
- (dump-memories memories imported-memories)
- (dump-tags tags)
- (dump-strings strings)
- (dump-globals globals imported-globals)
- (dump-exports exports)
- (dump-start start)
- (dump-elems elems)
- (dump-data datas)
- (when dump-func-defs?
- (dump-func-defs funcs imported-funcs))))))
|