IRC channel logs

2025-04-11.log

back to list of logs

<old>does Guile have optimization passes on the bytecode?
<old>Something like peephole optimization
<mwette> lechner: you should be able to initialize conv using a guile pointer (to a C function) or a lamda, if I read it correctly. I've been off of nyacc for a bit
<mwette>old: check modules/language/cps/
<lechner>mwette / okay, thanks!
<lechner>mwette / Hi, to get my callbacks to work I have to first re-enter Guile in a small C wrapper. The callback is called from a dynamically loaded, shared ELF object. Is that something that could be fixed in Guile?
<lechner>without it, i get inconsistent errors. they indicate I'm still in libguile, showing a variety of Guile-like error messages, but things are not resolved properly
<lechner>it seems like a small bug in procedure->pointer to me, near where the closure is calculated
<lechner>Hi, do both procedure->pointer and foreign-library-pointer return boxed pointer objects?
<lilyp>procedure->pointer should return a raw pointer
<lilyp>foreign-library-pointer idk
<lechner>lilyp / what is a raw pointer? procedure->pointer in foreign.c returns an SCM object, I think pointer = scm_from_pointer (executable, ffi_closure_free);
<lechner>and is pointer-address the way to unbox it?
<lechner>I always forget about the REPL. Both return boxed pointers
<old>mwette: my understanding of CPS is that this is similar to optimization applied to AST no? Peephole optimization are directly applied on the generate bytecode. There's no control flow involve
<mwette>you said "something like"; I pointed you to the optimization I have seen; you could look at the assembler in system/vm but I don't recall seeing anything there; didn't know where peephole goes
<mwette>I think procedure->pointer returns a boxed pointer object, indicated by <pointer xxxx>, you use pointer-address to get the integer address value
<lechner>mwette / thanks so much! my issue may have been garbage collection
<lechner>mwette / yes, that was it
<lechner>Hi, can a parameter be a good strategy to avoid garbage collection when one loses scope of a variable?
<old>lechner: what are you trying to achieve? Protecting a procedure sent to C?
<lechner>old / yes, across shared library calls but i don't want to expose this low level handler in the API. instead my low-level handler calls a higher-level handler given by the caller
<old>I see. This happen often with lambda procedures
<old>for example, callbacks in C
<old>IIRC, taking the pointer of the procedure does not protect it from GC
<old>so you need to box the procedure in a hashtable
<old>so say you are adding callback to some C library. You add the procedure in the hashtable first then pass it to C. You can then return something to remove the callback if necessary
<old>Could be a symbol, a cookie or a thunk wathever
<lechner>old / okay, thanks!
<lechner>Hi, what do I do when an argument to my callback appears as <pointer 0x1> instead of the integer 1, please?
<old>What's the signature of the C function?
<lechner>old / int (*conv)(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) from here https://linux.die.net/man/3/pam_conv
<lechner>and the two pointers in the middle are passed as int!
<old>so you have something like: (procedure->pointer int my-conv (list int '* '* '*)) ?
<old>And it's the C library that is calling this procedure?
<old>so I assume you have a procedure like: (lambda (num-msg msg resp appdata-ptr) ...)
<old>so which argument is <pointer 0x1>?
<lechner>yes, on all. num_msg is <pointer 0x1>
<lechner>old / ^
<lechner>and msg and resp are int. appdata_ptr is always correct, namely a null #<pointer 0x0>
<old>hmm that's weird. I suppose these pointer are structure allocated by the C library
<old>this looks like a ABI mismatch
<lechner>old / i can use pointer-address and make-pointer to convert, but Guile has them wrong
<old>but you would end it with the same pointer if do that
<lechner>?
<old>you are saying that in your procedure callback, you have <pointer 0x1> as an argument?
<old>as a paremter directly received from C
<lechner>no, convert the int with (pointer-address #<pointer 0x1>) and get the pointers in the middle with make-pointer
<lechner>yes, i have #<pointer 0x1> as an argument
<old>okay
<old>that's look like a problem from the library side then
<old>or ABI mismatch. If your callback is not the same signature as the library expected
<old>I see that struct pam_conv is expecting a void *appdata_ptr;
<lechner>it is, i think. isn't the convention that ints are passed directly and pointers to everything else? why does Guile think the first one is a pointer?
<old>can you set appdata_ptr to something like (make-pointer #xdeadbeef) and see if you get the same pointer in your callback?
<old>num-msg should be a number if the signature is (list int '* '* '*)
<old>do you mind sharing your code so I can have a quick peek?
<lechner>yes, i will
<lechner>the deadbeef pointer works but that value comes from guile
<lechner>bit of a mess but i can help you find your way https://bpa.st/U47A
<lechner>this is the handler https://bpa.st/U47A#1L197-L241
<lechner>this is the foreign function pointer https://bpa.st/U47A#1L259-L262
<lechner>actually, here is the foreign function pointer, and just below the value is used via nyacc's cdata https://bpa.st/U47A#1L259-L265
<lechner>I'm not even sure how Guile know what each parameter is
<lechner>knows
<old>okay
<old>well regarding the gc, you should be fine since this procedure is globally defined
<old>for the num-msg argument
<old>it really should be a number, no need anything else
<old>(pk fake_num_msg) should print: ;; (1)
<lechner>how does Guile know what type it is being passed?
<old>it does not. It respect the ABI as defined by (list int '* '* '*)
<old>internally, Guile use libffi
<old>which understand the calling convention of the architecture you are on. I assume x86-64
<lechner>pk prints ;;; (#<pointer 0x1>)
<old>so it knows that the first argument will be in register %rdi, the second in %rsi and so on
<lechner>yes, but it cannot know the type? the signature is not part of conversation-function
<old>then Guile receive these values as raw integer and will convert them to a object representation
<old>yes it it. (list int '* '* '*)
<old>it tells guile to interpret the first argument as an integer. Actually it tells libffi that and then Guile will interpret the result as a number
<old>so really the first argument should be number. But the other pointers because that's what you expect
<old>you could for example replace the '* with uintptr_t
<old>then you will only receive number
<old>you can then interpret these numbers as address by invoking make-pointer
<lechner>okay, don't know much about libffi. procedure->pointer registers the callback somewhere with that signature so Guile (or libffi) knows types when the call comes in?
<old>yes
<lechner>well, that's obviously not working here
<old>actually the pointer returned by Guile is some kind of wrapper trampoline that will jump to your procedure
<old>with the arguments decoded for you, respecting the ABI specifies
<lechner>okay
<old>try changing all the '* for uintptr_t
<old>if you see any <pointer> in one of your argument that would be _very_ strange
<lechner>no change
<old>it seems like the callback in C is still pointing to the same pointer?
<old>Did you try in a fresh process to see if there's change?
<lechner>it's an executable that runs anew each time I change something
<old>okay
<lechner>well, the trampoline never got it right in the first place, so perhaps you are asking too much!
<old>I don't really understand. Looking at your code, it should work
<old>at least you should have a plain integer as fake_num_msg
<old>I see that you're using nyacc, which I'm not familiar with
<old>so perhaps there's something there, but I doubt
<lechner>old / yesterday I called a custom C routine with the procedure pointer and then used the appdata_ptr to transfer the trampoline pointer. same problem, I think, but i will try again https://bpa.st/PDBA
<lechner>old / same problem when I go that route.
<lechner>is there anything interesting i can do with the trampoline pointer from C?
<lechner>ACTION reads up libffi
<old>SCM scm_entry_point = scm_pointer_to_procedure (scm_int_type, scm_appdata_ptr, scm_parameter_types);
<old>this does not make sens
<old>scm_appdata_ptr should be scm_entrypoint_ptr
<old>eh sorry
<old>no
<old>but the procedure you want to call
<lechner>old / it is. that's the trampoline pointer. i changed the guile code
<old>or are you passing the procedure pointer in appdata_ptr?
<old>ahh
<lechner> https://bpa.st/YA6Q
<lechner>the procedure pointer and the trampoline pointer are the same thing, right?
<old>are you on x86-64?
<lechner>yes
<old>no they are not the same
<old>(program-code procedure) != (procedure->pointe procedure)
<lechner>okay, i have never used program-code
<old>procedure->pointer generate a proxy function that will be able to translate C things to Guile thing and call your proecedure
<lechner>i did verify that the address is the same in C and Guile, but I think I only deal with the trampoline pointer
<lechner>does the trampoline pointer allow any inspection from C?
<old>You can probably disassemble it in GDB
<old>given the pointer, do (gdb) disassemble pointer
<lechner>I'm not sure how to do that. there may be too many layers
<old>can you print the address of procedure->pointer before packing it with nyacc and then print the address you have in C?
<lechner>yes, it's the same
<lechner> https://bpa.st/JWFQ
<old>in GDB, break in pam_conv_entry_point
<old>dans do
<old>dissasemble appdata_ptr
<lechner>i don't know how to start gdb on a guile program
<old>hhaha okay
<old>but what's the value print here: (pk (procedure->pointer int conversation-function ;; (make-conversation-function message-handler) (list int uintptr_t uintptr_t uintptr_t)))
<old>before packing it with cdata-set!
<lechner>also, the same https://bpa.st/3IDQ
<old>eh weird
<old>I can't see what is problematic
<old>sorry :/
<lechner>okay, thanks! it's either nyacc or my weird shared library library stuff. the callback is called by an ELF module (pam_unix.so) that was dynamically loaded by Guile-PAM (the thing we are debugging) which was loaded by an ELF module that starts libguile (pam_guile.so) which is called by a shared library (libpam.so) that was loaded by my test program
<lechner>could the nested call to libguile mess things up or does it simply stand down when the executable is already in Guile mode?
<ArneBab>dthompson: that’s also true (code assignment, and it’s ok for me if you use that to get it into Guile) for everything I have in the wisp repo. In the examples there are a few things I’d love to contribute, but I have a hard time contributing them. https://hg.sr.ht/~arnebab/wisp/browse/examples/
<lechner>ArneBab / thanks for waiting, and sorry we took up so much space
<mwette>lechner: one BIG issue with cdata is that it uses bytevectors. Guile's GC does not scan bytevectors for pointers :(. I wish Guile had a make-bytevector/pointers.
<mwette>^ the issue is not bytevectors per se but the fact that c data structures contain pointer that point to, e.g., callbacks
<mwette>i have thought about how to fix, but make-bytevector/pointers would be better
<lechner>mwette / thanks! i think my issues are probably unrelated to Nyacc at this point
<ArneBab>lechner: no problem: this channel is for talking, not for saving space ☺
<lechner>mwette / Hi, does cdata* dereference a cpointer while staying in <cdata>?
<lechner>Hi, how may I convert, for experimental purposes, a signed int to an unsigned int, please? It's pointer value that was mistakenly delivered as a signed int
<lechner>nvm, i subtracted from 4294967294 for my arch
<ieure>oh no lol
<lechner>yeah, it's bad
<rlb>Is print-set! broken in 3.0 atm, or am I just missing something?
<rlb>scheme@(guile-user)> (print-set! r7rs-symbols #t)
<rlb>While compiling expression:
<rlb>In procedure print-options-interface: Unknown option name: #t
<rlb>And putting an fprintf of name in change_option_setting() prints "nothing" for each name.
<rlb>...yeah, something is clobbering the scm_print_opts names (at least).
<rlb>ohh, hmm, it's more complicated than I realized, we're hiding an SCM in a char* -- I wonder how the gc knows about that.
<singpolyma>Very conservative gc
<rlb>We might have a marking function somewhere I suppose...
<rlb>oh, it's probably interned
<rlb>maybe nvm
<rlb>Ohh, right, I think I've hit this before -- that interface is just surprising (to me), i.e. it sounds like you're only supposed to provide values for booleans, e.g. (print-set! highlight-prefix "..." r7rs-symbols), but if that's so, then how could you *unset* a boolean value, and why do the docs mention (print-set! quote-keywordish-symbols #f)?
<rlb>s/docs/NEWS/
<lechner>mwette / okay, i have something that works. just to confirm, please: (make-cdata type) allocates space for an instance of that type, right?
<old>ArneBab: are wisp module compatible with Scheme module?
<old>for example, IIRC, the Javascript language was just not usable because you could not reference symbol, thus module, that have a hyphen in it
<old>So, can I import a wisp module and use it in Scheme and vice-versa?
<mwette>lechner: yes
<lechner>mwette / thank you! great software, and great support! please have a good weekend!
<lilyp>more generally, wisp treats hyphens just like scheme does