Skip to content

Add a kind of finalisation function called without argument#562

Merged
damiendoligez merged 12 commits intoocaml:trunkfrom
bobot:finalise_unit
Aug 1, 2016
Merged

Add a kind of finalisation function called without argument#562
damiendoligez merged 12 commits intoocaml:trunkfrom
bobot:finalise_unit

Conversation

@bobot
Copy link
Contributor

@bobot bobot commented Apr 27, 2016

The advantage is that this kind of finalization functions are called after the value being unreachable for the last time instead of the first time (GC.finalise). MPR#7210

Gc.finalise_unit: (unit -> unit) -> 'a -> unit

Tests are not provided because there are no tests for GC.finalise and I must understand which kind of tests should be done.

@bobot bobot force-pushed the finalise_unit branch 2 times, most recently from ab504e5 to 4f423bb Compare April 27, 2016 13:45
Assert (Is_in_heap (final_table[i].val));
if (Is_white_val (final_table[i].val)) ++ todo_count;
if (final_table[i].flags == flags &&
Is_white_val (final_table[i].val)) ++ todo_count;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add braces and put the statement on a separate line.

@damiendoligez
Copy link
Member

I don't like the function name. You should change it, probably to finalise_last or something like that. Does anyone have a good idea?

As for the documentation, I find it confusing because it speaks about "unreachable for the first time" and "unreachable for the last time", notions that are non-obvious and not used anywhere else. Moreover, you absolutely need to mention ephemerons here, because that's the whole point.

@lpw25
Copy link
Contributor

lpw25 commented May 2, 2016

I see that these finalisers still cause their associated values to be marked during minor collections. Instead couldn't we only mark the values associated with "traditional" finalisers, and move the finalisers whose values are not promoted directly into the finalising set?

@lpw25
Copy link
Contributor

lpw25 commented May 2, 2016

Does anyone have a good idea?

I don't have a specific good idea, but it might be good to just call these by some other name than "finaliser" ("destructor", "cleaner", ...).

Moreover, you absolutely need to mention ephemerons here, because that's the whole point.

I agree. The documentation should include a guarantee that these new finalisers run after any weak pointers to the object have been cleared.

@bobot
Copy link
Contributor Author

bobot commented May 2, 2016

@lpw25 Indeed it is a good idea. I can modify caml_final_do_young_roots to not mark these values and move the finalisers into the todo set. Moreover your remark shows that there is a bug in the current patch caml_final_do_strong_roots should not mark values that have the FINAL_CALLED_WITHOUT_VALUE flag. I will fix that.

The documentation should include a guarantee that these new finalisers run after any weak pointers to the object have been cleared.

Just to be clear, when the finalisers run, the weak pointers could have not yet been cleared, but the accessors behave as if it is already done (during the clean phase accessors verify if the weak pointer is going to be cleared in this phase).

@damiendoligez

As for the documentation, I find it confusing because it speaks about "unreachable for the first time" and "unreachable for the last time", notions that are non-obvious and not used anywhere else.

In the current documentation of GC.finalize the notion of "unreachable for the first time" is used:

  [f] will be called with [v] as
   argument at some point between the first time [v] becomes unreachable
   (including through weak pointers) and the time [v] is collected by
   the GC.

In any case I'm going to add something about weak pointers and ephemerons.

@bobot
Copy link
Contributor Author

bobot commented May 3, 2016

@damiendoligez Could you please check the comments I added in cfa8a1d before I try to implement @lpw25 idea?

When the branch will be stable, I will stash the commits, but for now I think it can help the review.

@bobot bobot force-pushed the finalise_unit branch from cfa8a1d to b519847 Compare May 3, 2016 11:35
@bobot
Copy link
Contributor Author

bobot commented May 3, 2016

@damiendoligez I don't understand why there is a finalisable set and a recent set, they both appear at the same time in 0a2021e. Why can't we just check if the value is young or not? Thank you for your help.

@damiendoligez
Copy link
Member

The comment in cfa8a1d looks OK.

The recent set is used when scanning roots for minor collection. We don't want to go through all the finalized values at each minor GC, so we isolate a subset that is guaranteed to contain all young finalized values.

@damiendoligez damiendoligez added this to the 4.04 milestone Jun 7, 2016
This is called by the minor GC through [caml_oldify_local_roots].
*/
void caml_final_do_young_roots (scanning_action f)
void caml_final_do_young_roots ()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We decided this function (and any others without the "f") should be renamed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We decided this function (and any others without the "f") should be renamed.

Done. That was the only function like that.

@bobot
Copy link
Contributor Author

bobot commented Jul 7, 2016

@lpw25 idea have been implemented: don't mark value with finalisation_last` during minor collection. It was trickier than what I though.

The implementation have been simplified, by keeping the two datastructures separate.

The added tests doesn't contain any oracle but with the debug runtime it found an error. It is hard to have deterministic (ocamlc/ocamlopt) oracle for this problems.

@damiendoligez Something strange: for executing all the finaliser, sometime two Gc.full_major () are needed. I though that after a Gc.full_major () another one was always useless. So perhaps a problem remains. An example can be seen by replacing in testsuite/test/misc/finalise.ml let debug = false by true. The output is finaliser.log.txt.

bobot added 11 commits July 9, 2016 21:02
       and rename it to caml_final_invert_finalizable_values
       into caml_final_do_roots because there is no other place where
       roots are called strong roots, and the weak roots function have
       already been renamed.
       into caml_final_oldify_young_root
   Values with finalize_last could be garbage collected immediately
   during minor collection, they don't have to pass by the major heap.

   No change for finalize(_first) values since the value is needed for
   running the finalization function.
    But there is no unit test or oracles.
    When no finalisation function need to be run, the young values where not
    updated with their new location in major heap.

    Also add a check for some invariants
@bobot
Copy link
Contributor Author

bobot commented Jul 9, 2016

@damiendoligez Something strange: for executing all the finaliser, sometime two Gc.full_major () are needed. I though that after a Gc.full_major () another one was always useless.

It was just because I attached a Gc.finaliser(_first) and a Gc.finaliser_last on the same object. In fact if there is some Gc.finaliser(_first), the documentation of Gc.full_major is misleading:

external full_major : unit -> unit = "caml_gc_full_major"
(** Do a minor collection, finish the current major collection cycle,
   and perform a complete new cycle.  This will collect all currently
   unreachable blocks. *)

Edit: substitute first and last

@damiendoligez
Copy link
Member

Maybe it should say "this will collect and finalize all currently unreachable blocks".

@lpw25
Copy link
Contributor

lpw25 commented Jul 28, 2016

@bobot What is the status of this? I'm rather hoping to use these in 4.04.

@bobot
Copy link
Contributor Author

bobot commented Jul 28, 2016

On my side it is finished (the modification of the documentation of full_major can wait). But it needs a review, there were a lot of change since the last review for integrating your idea.

@damiendoligez
Copy link
Member

Reviewed, rebased, merged.

@bobot
Copy link
Contributor Author

bobot commented Aug 1, 2016

@damiendoligez Thank you!

camlspotter pushed a commit to camlspotter/ocaml that referenced this pull request Oct 17, 2017
EduardoRFS pushed a commit to esy-ocaml/ocaml that referenced this pull request Jul 23, 2021
Import fixes to the minor heap allocation code from DLABs.
chambart pushed a commit to Gbury/ocaml that referenced this pull request Aug 5, 2021
When resolving a symbol projection to some simple `s`, we then
recursively try and resolve `s` as a symbol projection. If `s` carries a
coercion, we need to apply that coercion to the final result.

Unfortunately, I don't have a test case for this, because I'm not sure
it's currently possible to trip it: one would need a symbol that gets
set to a recursive occurrence, and yet that recursive occurrence needs
to be an alias to some other symbol projection. You'd want to do
something like

    let foo = Sys.opaque_identity 42

    let rec waste b = if b then waste false else bar [@@inline]
    and bar = foo

but the `and bar = foo` part is not valid OCaml.

At any rate, I ran tests with the shortcut in
`create_coerced_singleton_let` removed, so the basic functionality of
wrapping a `Named.t` in a coercion is working.
stedolan pushed a commit to stedolan/ocaml that referenced this pull request May 24, 2022
stedolan pushed a commit to stedolan/ocaml that referenced this pull request May 24, 2022
fe8a98b flambda-backend: Save Mach as Cfg after Selection (ocaml#624)
2b205d8 flambda-backend: Clean up algorithms (ocaml#611)
524f0b4 flambda-backend: Initial refactoring of To_cmm (ocaml#619)
0bf75de flambda-backend: Refactor and correct the "is pure" and "can raise" (port upstream PR#10354 and PR#10387) (ocaml#555)
d234bfd flambda-backend: Cpp mangling is now a configuration option (ocaml#614)
20fc614 flambda-backend: Check that stack frames are not too large (ocaml#10085) (ocaml#561)
5fc2e95 flambda-backend: Allow CSE of immutable loads across stores (port upstream PR#9562) (ocaml#562)
2a650de flambda-backend: Backport commit fc95347 from trunk (ocaml#584)
31651b8 flambda-backend: Improved ARM64 code generation (port upstream PR#9937) (ocaml#556)
f0b6d68 flambda-backend: Simplify processing and remove dead code (error paths) in asmlink (port upstream PR#9943) (ocaml#557)
90c6746 flambda-backend: Improve code-generation for inlined comparisons (port upstream PR#10228) (ocaml#563)

git-subtree-dir: ocaml
git-subtree-split: fe8a98b
lpw25 pushed a commit to lpw25/ocaml that referenced this pull request Jun 21, 2022
EmileTrotignon pushed a commit to EmileTrotignon/ocaml that referenced this pull request Jan 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants