unofficial mirror of guix-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: Andy Wingo <wingo@igalia.com>
To: "Ludovic Courtès" <ludo@gnu.org>
Cc: Ricardo Wurmus <rekado@elephly.net>, guix-devel@gnu.org
Subject: Re: better error messages through assertions
Date: Wed, 30 Mar 2022 15:28:03 +0200	[thread overview]
Message-ID: <87bkxny3h8.fsf@igalia.com> (raw)
In-Reply-To: <87lewrwzll.fsf@gnu.org> ("Ludovic Courtès"'s message of "Wed, 30 Mar 2022 11:37:10 +0200")

On Wed 30 Mar 2022 11:37, Ludovic Courtès <ludo@gnu.org> writes:

>> scheme@(guile-user)> (container-contents '())
>> ice-9/boot-9.scm:1685:16: In procedure raise-exception:
>> In procedure struct-vtable: Wrong type argument in position 1
> scheme@(guile-user)> ,use(srfi srfi-9)
> scheme@(guile-user)> (define-record-type <foo>
> 		       (make-foo x)
> 		       foo?
> 		       (x foo-x))
> scheme@(guile-user)> ,optimize (foo-x '())
> $9 = (if (eq? (struct-vtable '()) <foo>)
>   (struct-ref '() 0)
>   (throw 'wrong-type-arg
>          'foo-x
>          "Wrong type argument: ~S"
>          (list '())
>          (list '())))
>
> With Guile 3, it might be that adding an extra ‘struct?’ test would have
> little effect on performance; we’d need to check.

Would have no effect.

Incidentally, you might want to use ,optimize-cps;

  scheme@(guile-user)> ,optimize (foo-x '())
  $9 = (if (eq? (struct-vtable '()) <foo>)
    (struct-ref '() 0)
    (throw 'wrong-type-arg
           'foo-x
           "Wrong type argument: ~S"
           (list '())
           (list '())))
  scheme@(guile-user)> ,optimize-cps (foo-x '())
  L0:                                           ;               at <unknown>:15:14
    v0 := self
    L1(...)
  L1:
    receive()
    v1 := const ()                              ; arg           at <unknown>:15:21
    throw throw/value+data[#(wrong-type-arg "struct-vtable" "Wrong type argument in position 1 (expecting struct): ~S")](v1) ;  at <unknown>:15:14

L1(...) means, pass all values to L1.  In this case because there are
varargs on the stack from the procedure call.  L1 parses them with the
receive().  Anyway, here we see that with respect to the immediate '(),
that all the tests folded.  If we instead lift to a procedure:

  scheme@(guile-user)> ,optimize-cps (lambda (x) (foo-x x))
  L0:                                           ;               at <unknown>:16:14
    v0 := self
    L1(...)
  L1:
    receive()
    v1 := current-module()                      ; module        at <unknown>:16:14
    cache-set![0](v1)                           ;               at <unknown>:16:14
    v2 := const-fun L7                          ; _ 
    return v2                                   ;               at <unknown>:16:14

  L7:                                           ;               at <unknown>:16:14
    v3 := self
    L8(...)
  L8:
    v4 := receive(x)                            ; x 
    heap-object?(v4) ? L10() : L38()            ;               at <unknown>:16:26
  L10():
    struct?(v4) ? L11() : L38()                 ;               at <unknown>:16:26
  L38():
    throw throw/value+data[#(wrong-type-arg "struct-vtable" "Wrong type argument in position 1 (expecting struct): ~S")](v4) ;  at <unknown>:16:26
  L11():
    v5 := scm-ref/tag[struct](v4)               ; vtable        at <unknown>:16:26
    v6 := cache-ref[(0 . <foo>)]()              ; cached        at <unknown>:10:20
    heap-object?(v6) ? L19() : L14()            ;               at <unknown>:10:20
  L19():
    L20(v6)                                     ;               at <unknown>:10:20
  L14():
    v7 := cache-ref[0]()                        ; mod           at <unknown>:10:20
    v8 := const <foo>                           ; name          at <unknown>:10:20
    v9 := lookup-bound(v7, v8)                  ; var           at <unknown>:10:20
    cache-set![(0 . <foo>)](v9)                 ;               at <unknown>:10:20
    L20(v9)                                     ;               at <unknown>:10:20
  L20(v10):                                     ; box 
    v11 := scm-ref/immediate[(box . 1)](v10)    ; arg           at <unknown>:10:20
    eq?(v5, v11) ? L22() : L37()                ;               at <unknown>:16:26
  L37():
    throw throw/value+data[#(wrong-type-arg foo-x "Wrong type argument: ~S")](v4) ;  at <unknown>:16:26
  L22():
    v12 := word-ref/immediate[(struct . 6)](v5) ; rfields       at <unknown>:16:26
    v13 := v12                                  ; nfields       at <unknown>:16:26
    imm-u64-<[0](v13) ? L25() : L35()           ;               at <unknown>:16:26
  L35():
    v21 := const 0                              ; _             at <unknown>:16:26
    throw throw/value+data[#(out-of-range "struct-ref/immediate" "Argument 2 out of range: ~S")](v21) ;  at <unknown>:16:26
  L25():
    v14 := pointer-ref/immediate[(struct . 7)](v5) ; ptr        at <unknown>:16:26
    v15 := load-u64[0]()                        ; word          at <unknown>:16:26
    v16 := u32-ref[bitmask](v5, v14, v15)       ; bits          at <unknown>:16:26
    v17 := load-u64[1]()                        ; mask          at <unknown>:16:26
    v18 := ulogand(v17, v16)                    ; res           at <unknown>:16:26
    u64-imm-=[0](v18) ? L31() : L33()           ;               at <unknown>:16:26
  L33():
    v20 := const 0                              ; _             at <unknown>:16:26
    throw throw/value+data[#(wrong-type-arg "struct-ref/immediate" "Wrong type argument in position 2 (expecting boxed field): ~S")](v20) ;  at <unknown>:16:26
  L31():
    v19 := scm-ref/immediate[(struct . 1)](v4)  ; val           at <unknown>:16:26
    return v19                                  ;               at <unknown>:16:26

Here we see the first procedure which is the thunk that wraps the
expression.  Then in the beginning of the procedure at L7 you can see
there is a check for struct?, which has to be dominated by a true
heap-object? check.  Duplicate checks are elided.  So if SRFI-9 added a
`struct?` check it wouldn't be more code; rather it would be less,
actually, because instead of branching to L38, you'd branch to L37.

Too bad about all that other crap about checking whether the index is in
range and the field is boxed or not, though :-/  Probably there is a
better design...

Andy


  reply	other threads:[~2022-03-30 13:42 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-02-14 22:32 better error messages through assertions Ricardo Wurmus
2022-02-15  8:48 ` Maxime Devos
2022-02-15 21:45 ` Philip McGrath
2022-02-15 22:15   ` Ricardo Wurmus
2022-02-28 12:59     ` Ludovic Courtès
2022-02-28 16:18       ` Philip McGrath
2022-03-07 10:13         ` Ludovic Courtès
2022-03-28 20:25           ` Philip McGrath
2022-03-30  9:37             ` Ludovic Courtès
2022-03-30 13:28               ` Andy Wingo [this message]
2022-04-01  8:47                 ` Ludovic Courtès
2022-04-01 19:28                 ` Philip McGrath
2022-04-05 12:04                   ` Ludovic Courtès
2022-04-01 19:47               ` Philip McGrath
2022-02-22  4:31 ` Arun Isaac
2022-02-25 18:55 ` Maxim Cournoyer
2022-02-26 13:33   ` Ricardo Wurmus
2022-02-26 13:51     ` Maxim Cournoyer
2022-02-28 13:02     ` Ludovic Courtès
2022-02-28 16:00       ` Maxim Cournoyer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://guix.gnu.org/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87bkxny3h8.fsf@igalia.com \
    --to=wingo@igalia.com \
    --cc=guix-devel@gnu.org \
    --cc=ludo@gnu.org \
    --cc=rekado@elephly.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/guix.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).