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
Remove use of C variable length arrays (VLAs) #11693
Conversation
I can see how the current implementation of |
My understanding is that CAMLlocalN is part of the public API so it should itself be fixed, so that it never uses a VLA. How about replacing both uses of VLAs in (In a second time we can look at the generated code to see if it generates better code after the transformation into a macro, but this is a priori not needed for correctness.) |
It's the use of |
The previous |
I tried doing this here: trunk...smuenzel:ocaml:no-vla |
It does indeed look equivalent, thanks @smuenzel (I think it needs a slight tweak to use I haven't checked, but given that |
I didn't notice that I'm in favor of removing |
We're still just at the point with 5.0 release cycle where |
This sounds like a good idea to me. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Following the discussion, this looks essentially good. Both this approach with a macro and the alternative suggested by Garbiel (inlining DO_ALLOC_SMALL) sounds equally good to me.
Changes
Outdated
@@ -21,6 +21,10 @@ Working version | |||
- #11691, #11706: use __asm__ instead of asm for strict ISO C conformance | |||
(Xavier Leroy, report by Gregg Reynolds , review by Sadiq Jaffer) | |||
|
|||
* #11693: Remove use of C99 Variable Length Arrays (VLAs) and therefore the | |||
caml_alloc_N function. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This description needs to be updated now that caml_alloc_N never made it into OCaml 5 (esp. no breaking change).
runtime/alloc.c
Outdated
Field(v, i) = vals[i]; | ||
} | ||
return v; | ||
#define DO_ALLOC_SMALL(wosize, tag, vals) \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit-pick. I'd write Do_alloc_small
and use parentheses around the occurrences of the arguments, e.g. (tag) < 256
.
Can you please add one comment line here to explain to future readers why you had to use a macro?
@gasche This looks ready. I am also convinced now that it is better to have a macro than to duplicate code. (Please credit other reviewers who helped come up with the best version.) |
Actually, it's not quite there - the name |
Naming suggestion for that version of the macro: Edit: or maybe: |
Use a macro to build them instead of a VLA.
Prevent VLAs being accidentally used in future.
I went with "preserve" - so |
runtime/alloc.c
Outdated
value v[3] = {a, b, c}; | ||
return do_alloc_small(3, tag, v); | ||
value vals[3] = {a, b, c}; | ||
Do_alloc_small(3, tag); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, could this be just
CAMLexport value caml_alloc_3 (tag_t tag, value a, value b, value c)
{
Do_alloc_small(3, tag, {a, b, c});
}
?
With this form we can bind vals
in Do_alloc_small
itself, and thus reduce the scope of the code that has to reason about vals
as a magical/fixed name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it can work - the { ... }
is an initialiser syntax and it doesn't work as a bracket for the macro (that gets seen by the preprocessor as a 5-argument macro call)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just add parentheses! Do_alloc_small(3, tag, ({a, b, c}))
should pass the preprocessor. But then you could just omit the braces and add them back in the macro.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd tried that - but then you end up with value vals[3] = ({a, b, c})
which is a syntax error. I hadn't considered passing them as (a, b, c)
and then restoring the braces in the macro, but that doesn't appear to work either ("left-hand operand of comma expression has no effect" presumably arising from `value vals[3] = {(a, b, c)}).
It does "work" with __VA_ARGS__
, - what do you think??
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like a sophisticated monster born out of the best intentions, I love it. Approved.
OCaml 5 adds
caml_alloc_1
..caml_alloc_9
and the generalcaml_alloc_N
tocaml/alloc.h
(seeocaml-multicore/ocaml-multicore#72). These are implemented using C99 variable length arrays (VLAs). VLAs are (if I understand correctly) deprecated in C11 and they're not supported in our favourite MS C compiler (and they have no intention of adding them as part of their C11 and C17 support).
This PR is intended mainly to start discussion - at this stage I've removed
caml_alloc_N
, but it may be possible to reintroduce it as a macro (cf.CAMLlocalN
) if we wanted?I've reimplemented the 9 allocation functions with the inlined function as a macro, but this needs checking to ensure that the generated code is still correct (cf. the discussion in the original PR and cc @stedolan and @gadmm).