-
Notifications
You must be signed in to change notification settings - Fork 9
Ephemeron references #303
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
Comments
Can you suggest a signature for this? Perhaps it should be a Basis Library enhancement? |
Here is one potential modification to the current
Example:
|
I think that this mechanism (if implemented) should be a separate structure and type from the existing signature EPHEMERON =
sig
(* `ephemeron (k, v)` constructs a weak pointer with key `k` and value `v`.
* This maintains a reference to `v` so long as `k` remains alive. Note that `k`
* is not considered alive if the only reference to `k` comes through this
* ephemeron's reference to `v`.
*)
val ephemeron : 'k * 'v -> 'v ephemeron
(* `broken eph` returns `true` if the key that was used to create `eph` has been garbage collected and `false`
* otherwise.
*)
val broken : 'v ephemeron -> bool
(* `get eph` returns `NONE` if the key that was used to construct `eph` has been garbage collected.
* It returns `SOME v` if the key used to construct `eph` is alive, where `v` was the value used to
* construct `eph`.
*)
val get : 'v ephemeron -> 'v option
end SRFI 124 includes an operation for getting the key value, which would mean that the type constructor for an ephemeron would have to have two type arguments. It also have a "barrier" operation for pinning down a key until after the barrier is executed. I assume that this is a mechanism that guarantees that the compiler is not allowed to optimize away the reference to the key. Such a mechanism might be generally useful independent of ephemerons. |
I would avoid functions such as Allowing key access is not explicitly necessary from an API perspective, since you can always implement The reference barrier could be useful as a primitive. I know it exists in MLton in the MLtonFinalizable module as |
I think that Also, I am interpreting the statement
as
Furthermore, the notion that signature EPHEMERON =
sig
type 'a key
type 'v ephemeron
val broken : 'v ephemeron -> bool
val ephemeron : 'k key * 'v -> 'v ephemeron
val getValue : 'v ephemeron -> 'v option
val key : 'k -> 'k key
val getKey : 'k key -> 'k
val sameKey : 'k key * 'k key -> bool
end |
This seems backwards: if That signature may have a better notion of "object identity", but I don't think it matters for usability, and it will have performance impact (an additional allocation). |
W.r.t Weak references themselves have object identity, so it is not the same situation. What would it mean to have a |
Apologies, I misread your comment regarding With respect to the keys, having an
Also, the Haskell description of their
The GHC implementation of ephemerons is something like the following since they don't have weak pointers, only ephemerons (I removed finalizers for this pseudocode example): struct ephemeron {
header_t header;
value_t *key;
value_t *value;
struct ephemeron *_next;
};
void gc() {
// ...
struct ephemeron *ephemerons = NULL;
vector<value_t *> worklist;
// Keep looping until we have no more values to visit and have processed every ephemeron
while (worklist.len() > 0 || ephemerons != NULL) {
value_t *v = worlist.pop();
// ...
// Phase 1: mark everything as reachable, putting reachable ephemerons in a list for later.
// ...
if (is_ephemeron(v)) {
((struct ephemeron *)v)->_next = ephemerons;
ephemerons = v;
}
// ...
// Phase 2: Handle ephemerons
for (struct ephemeron *e = ephemerons; e->_next != NULL; e = e->_next) {
if (is_alive(e->key)) {
visit(e->value); // copy/mark value as alive/visit the value
} // else the ephemeron doesn't get copied and it dies if it isn't resurrected by the end of the main loop
}
// keep going so long as there are values in the work list or ephemerons in the linked list.
} // end main loop
} |
Regarding the semantics of weak references in SML/NJ, I think "non-deterministic" is a better characterization than "ambiguous." Also, the issues are more to do with the semantics of the language and what that allows compilers to do than the semantics of the GC (although the language semantics does allow for replication by the GC). - fun f (x : (int * int)) = SMLofNJ.Weak.weak x;
val f = fn : int * int -> (int * int) ?.Weak.weak
- val y = (17, 42);
val y = (17,42) : int * int
- val z = f y;
val z = - : (int * int) ?.Weak.weak
- SMLofNJ.Internals.GC.doGC 5;
val it = () : unit
- SMLofNJ.Weak.strong z;
val it = NONE : (int * int) option
- y;
val it = (17,42) : int * int So even though There was a paper in ISSM'06 by Donnelly et al that defines a formal semantics for weak references. The paper claims that it can handle GHC's weak references, so perhaps that work could form a basis for specifying ephemerons. |
To make sure I fully understand, the issue you describe could also occur if |
I believe that you are correct. If it has type |
Description
From SRFI 124:
These kinds of references are invaluable for memoization libraries, or any kind of library which builds and maintains a table of all objects in the library.
Ephemerons are implemented in the following languages/implementations, for ideas on naming and features:
The text was updated successfully, but these errors were encountered: