-
Notifications
You must be signed in to change notification settings - Fork 141
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add reference-barrier to (srfi 124) #796
Conversation
An example program where you need it is given here: https://srfi-email.schemers.org/srfi-124/msg/4181743/ (Please excuse the partly broken code indentation.) |
For the record, I haven't been following the SRFI discussion but it seems to me that if something like |
(import (srfi 124)) gives: Please fix the imports (at least Independently, consider the following code:
It must return Does Chibi under any circumstance and under any optimization settings happen to inline the call to
and thus potentially equivalent to
which can, in principle, evaluate to If on the other side, the call to |
Can you clarify? For sure, it would be nicer if we need fewer primitives. It has been consensus on the SRFI 124 mailing list that What do you exactly mean by that the design is
calling But I am not sure whether you would consider such a primitive less broken. |
Grumblegrumblegrumble. (Yes, sorry, I didn’t test this before merging. I consider myself fired. I had to do a |
Since I now somewhat understand the need for it, it seems to me that the issue which If the design needs to be fixed at all, it might be by providing syntax which evaluates a body and automatically uses |
Yes, it is the same situation for (ordinary) weak pairs.
Do you mean something like my |
Yes, I hadn’t seen your reply yet when I started typing mine. |
My general complaint is that this violates the first sentence of the introduction to the standard. Instead of making ephemerons "just work," we're introducing a confusing and error prone construct. I haven't dug into how difficult it is to fix the root problem, but ephemerons already require special GC support. If nothing else, adding a Failing that, if we really need a stopgap solution for practical implementations now, then we can just unify the API into a single construct that avoids this problem:
optionally with some syntactic sugar:
|
I agree that using SRFI 124's API correctly, which is basically a stripped-down version of MIT/GNU Scheme's API, can somewhat be as delicate as writing a multi-threaded program correctly. Let me cite the example from SRFI 124 here: ;; Return the datum component of the ephemeron if its key component is
KEY. Return #f otherwise.
(define (ephemeron-ref ephemeron key)
(let ((k (ephemeron-key ephemeron))
(d (ephemeron-datum ephemeron)))
(and (not (ephemeron-broken? ephemeron))
(eq? key k)
(reference-barrier k)
d))) Here, an optimizing compiler can reorder the side-effect free This suggests redefining (define-syntax volatile
(syntax-rules ()
((volatile var)
(let ((val var))
(reference-barrier val)
val)))) But such is just a reformulation of the current API so does not really address your point. The (syntactic) construct you suggest as an alternative is possibly implemented (modulo some syntactic variations) as (define-syntax ephemeron-case
(syntax-rules (ephemeron else)
((ephemeron-case eph-expr
((ephemeron key datum) . body1)
(else . body2))
(let ((eph eph-expr))
(let ((k (ephemeron-key eph)) (d (ephemeron-datum eph)))
(let ((broken? (ephemeron-broken? eph)))
(reference-barrier k)
(if broken?
(let* () . body2)
(let ((key k) (datum d)) . body1)))))))) With it, the example of (define (ephemeron-ref eph key)
(ephemeron-case eph
((ephemeron k d)
(and (eq? key k) d))
(else #f))) It expands to (modulo irrelevant simplifications) (define (ephemeron-ref eph key)
(let ((k (ephemeron-key eph))
(d (ephemeron-key eph)))
(let ((broken? (ephemeron-broken? eph)))
(reference-barrier k)
(and (not broken?)
(eq? key k) d)))) This looks correct but isn't. An implementation would be free to rewrite this to (define (ephemeron-ref eph key)
(define key-eq? <one-argument procedure that checks whether the argument is eq? to key>)
(let ((k (ephemeron-key eph))
(d (ephemeron-key eph)))
(let ((broken? (ephemeron-broken? eph)))
(reference-barrier k)
(and (not broken?)
(key-eq? k) d)))) The "one-argument procedure" doesn't necessarily have to keep a (strong) reference to In fact, |
The compiler could internally (transparently to the user) treat ephemeron accessors as volatile/unreorderable. That doesn't disable code reordering in general, and doesn't preclude future compiler optimizations from figuring out when it actually could reorder the ephemeron accessors. But failing that, combining all of the ephemeron operations into a single primitive could be built on top of existing systems (using reference-barrier under the hood if needed), without exposing any of the details to the user. The
|
Can you explain what you mean by the accessors being "unreorderable"? Unreordable with respect to what? If we insert "every other expression" for "what", it would be far too strong.
See the second part of my post why this would still not be correct. (As I wrote: dealing with ephemerons can be as tricky as getting multi-threaded code right). |
The compiler argument is just a vague handwavy way of saying "it should be possible." As one example I was suggesting to prevent code reordering of ephemeron operations where they happen locally (because code reordering only happens locally, modulo inlining). Transitive calls to ephemeron operations are possible, if pathological, and may defeat this, which is perhaps an argument not to separate the ephemeron operations to begin with. Sorry I missed your ephemeron-case example. I of course meant Anyway, I'm just grumbling that we're piling on features and making things more complicated rather than simpler, but I don't have time to spend on the simpler solution. Please don't take that as an argument that the simpler solution doesn't exist. |
The root problem is not the separation of the ephemeron operations but the requirement that the inconspicuously looking expression
I get it. I would also like to see a simpler solution but so far it seems to me that a solution without explicit reference barriers is not possible without making ephemeron trivial (and without implicitly inserting a reference barrier at every value reference for every value). What I mean by this: For ephemerons (or, more generally, weak references) to make any sense, the notion of strongly reachable must be defined in the language semantics. SRFI 124 (implicitly) does this through |
According to a post-finalization note in SRFI 124, this procedure is now mandatory. Its purpose is not entirely clear to me (nor was it to Vyzo when I implemented SRFI 124 for Gerbil), but I think this should be an acceptable implementation for Chibi’s GC.