Document gc_regs and gc_regs_buckets#11437
Conversation
|
Note: my assembler-fu is pretty weak. It's easy to see where Lines 696 to 698 in 182fd48 but I would expect that the structure that is in |
Fat chance. But here is where it is used on the C side: Lines 272 to 277 in 182fd48 |
|
Thanks the pointer! I was expecting to find documentation in Lines 76 to 94 in 182fd48 I realize now that The stack-walking code that you point out (and some variants of it in backtrace_nat.c and frame_descriptors.c) mention a notion of "stack chunk" that is not explained in the documentation. I tried to piece it back together from the code but it will need another try before I can come up with a coherent description. (I think that an OCaml "stack" is made of several "chunks", one per transfer from C to OCaml, which are adjacent to each other and each start with a caml_start_program frame. But is the diagram of fiber.h the depiction of a single stack chunk, or are there implicitly several chunks in the diagram? This is all still mysterious to me.) |
|
(cc @kayceesrk who I guess worked quite a bit on this code, and could probably answer my questions above.) |
I think this comes from the OCaml 4 code. In OCaml 4 the native stack contains both OCaml function frames and C function frames. A "stack chunk" is a set of contiguous OCaml frames that can be scanned linearly. Such a chunk terminates at a C function call, and if the C code calls back into OCaml, a new chunk starts. The stack scanning code needs to jump from the end of the first chunk to the beginning of the second chunk¸ jumping over the C stack frames. In OCaml 5, OCaml frames and C frames are on different stacks. However, callbacks from C to OCaml still need special treatment when scanning the OCaml stacks. |
|
Thanks for the clarification. Here is my current understanding:
describes a "stack".
I welcome feedback if there is something very wrong in the description above. Otherwise I may send a PR later to extend the documentation comments of fiber.h to contain these details. (Let's avoid feature-creep on this one PR which should stay focused on gc_regs.) |
|
My impression of the commit is that the answer to both questions is "it's just simpler to do it that way" (to malloc instead of stack-allocating the gc_regs, to save all registers instead of having a slightly different macro to save less registers). |
|
I completely agree that it's simpler (and OK) to save and restore all registers (and not just caller-save registers) in I'd still like to be reminded the reason why |
|
I won't be able to provide a definite response to why it's If a fiber registers were saved into its stack and the fiber stack needed to grow, the whole fiber needing to be reallocated, the saved registers would also have to be moved in memory. Currently Interestingly ( |
|
Current status of the present PR:
|
xavierleroy
left a comment
There was a problem hiding this comment.
Thanks for the extra documentation, which is an improvement.
I'm still disappointed that the original authors of this code did not reply to this PR by explaining why they chose to allocate gc_regs with malloc and not on the stack, as in OCaml 4. I'm pretty sure this has to do with keeping the minimal size of a stack / a fiber small, and not having to copy the gc_regs arrays when growing the stack / the fiber.
|
Thanks! |
This PR was motivated by the discussion of #11406. cc @fabbing @Engil @Octachron @xavierleroy.
I realized while writing the documentation that there are things I don't understand.
gc_regsbuckets are now allocated on the C stack, rather than being stack-allocated as with the 4.x runtime. I don't know! I thought of the following possible explanations:realloc_stacklogic at the beginning, and it starts small at 64 words)gc_regsand why. Obviouslycaml_call_gcdoes, because the GC needs to walk the OCaml registers for roots. But if I read the assembly code correctly, the (only) other runtime function doing this iscaml_call_realloc_stack, and I don't know why. As far as I can tell, this function never transfers control back to OCaml code, and it does not call the GC (stacks are allocated by fiber.c:alloc_for_stack on the C heap).