-
Notifications
You must be signed in to change notification settings - Fork 7
Explicit Unsized Metadata & Unified DST Handling #259
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
Conversation
|
Your plan seems good. I'm hoping to merge #252 shortly as soon as I confirm no breakages. Thanks. |
|
Thanks! Let us progress on this! |
|
I'm implementing the step 1, i.e. turning The problem is also similar -- the macro implementations about slices in Currently we are planning to implement these functions using abstract syntax in |
|
This is a good plan. I think I mentioned this earlier, but I wonder if it's worth extending the cremepat PPX rewriter to allow you to write concrete syntax for expressions (not just patterns). The idea is that if we end up writing a lot of deeply embedded syntax, things are going to get very hard to maintain. You could image doing something like: What do you think? I don't have a good sense of the amount of work involved. Maybe all the functions that operate on slices are small and this won't be a problem. |
|
I shall first try to see the amount of work and do we need the cremepat PPX rewriter :) |
…en in abstract syntax when they are not needed
|
Hi @msprotz , we think this PR should be quite ready and also the Charon is now ready for this. Would you please have a look on this? |
|
This appears to have conflicts with the |
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.
Here's a preliminary review -- I'll do a more in-depth review once this is rebased and I have some answers to my questions.
- Why are some functions eliminated from the glue, and why are some other functions still written using macros? (like slice_split_at_mut?) -- I expected all of these to be in abstract syntax now. Is there a reason for that?
- Can you please write high-level summaries of the new functions? What does
vtable_typ_of_dyn_preddo? Do I understand correctly that this PR now generates struct declarations for vtables? (If so, that's great!) - As always, commented-out code should go, since we can see quite well in the diff what went away (I'm thinking of eurydice_glue.h right now)
I feel like I'm seeing changes related to the array PR in there, too, so I'm going to stop for now until you merge main into this branch. Overall, it looks quite good, and I'm very pleased with the amount of ad-hoc code for DST support that is going away. Good work!
edit: also please make sure that you have good test coverage -- does test-unsize also cover vtable metadata?
| match List.rev @@ ty_decl_ref.generics.types with | ||
| (* This is `()`, which has metadata `()` *) | ||
| | [] -> None | ||
| (* For tuple, the type of metadata is the last element *) |
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.
can you say more about that? this seems weird
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 is written by me. For a tuple type (X, Y, Z), the ptr-metadata is the same as Z as the last field, but if the tuple is empty, which means it is the unit type (), then there is surely no ptr-metadata.
| decl.item_meta.lang_item = Some "sized" | ||
| in | ||
| let var_is_sized = | ||
| true |
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 presume this is work in progress?
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.
OK, this is a tough issue. If we use the correct impl (which is a line below), it causes many errors in the tests -- this suggests that the original treatments to the references are not correct, especially when handling std libraries like the call_mut functions. To get this truly right, we will need a monomorphization procedure that supports the PtrMetadata-type-level computation, but this is not that realistic especially considering that we are now migrating to mono LLBC, which should resolve the problem. So we simply leave a true here to restore the current behavior.
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.
In a more precise tone, in those cases (like call_mut's assoc-types), the generic params can actually be substituted by some non-sized types. As we are working with the references, so there will be a need to compute PtrMetadata(T) from the type parameter T.
lib/AstOfLlbc.ml
Outdated
| match !*sub_e.K.typ with | ||
| | TBuf (t_pointee, _) | TArray (t_pointee, _) -> | ||
| Krml.Helpers.(mk_deref t_pointee !*sub_e.K.node) | ||
| | TArray (_, _) -> assert false |
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.
if there's no comment explaining why, I usually like to put failwith followed by a reason why this shouldn't happen
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've removed this line cuz it can be covered by the following case for error info. Actually this is a cleanup for the array PR we missed before.
| mk_deep_copy e (expression_of_const_generic env cg) | ||
| | _ -> e | ||
| end | ||
| | Copy p -> expression_of_place env p |
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.
ok this should have been in the array PR already, no?
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.
Yes.
| | C.TAdt { id = TBuiltin TBox; _ } -> true | ||
| | _ -> false | ||
|
|
||
| let mk_reference (e : K.expr) (metadata : K.expr) : K.expr = |
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.
also a comment like "returns either a regular naked C pointer, or a fat pointer in the case of DSTs" would help here I 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.
Updated the comments for this function :)
| (K.ETApp (Builtin.(expr_of_builtin empty_array), [], [], [ ty ])) | ||
| in | ||
| K.with_type typ_arr (K.EApp (empty_array, [ K.with_type ty K.EAny ])) | ||
| (* a dummy arg is needed to pass the checker *) |
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.
can you remind me about the empty array issue? was the upstream bug ever fixed?
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.
The previous discussion of empty array ended here: #252 (comment). The current situation is that we use a builtin function to initialize the empty array as (t_dst) {.data = {}}. The existence of empty array is still an open issue i think.
lib/AstOfLlbc.ml
Outdated
| (TArray (typ_of_ty env t, constant_of_scalar_value (assert_cg_scalar cg))) | ||
| (K.EBufCreateL (Stack, List.map (expression_of_operand env) ops)) | ||
| in | ||
| K.with_type typ_arr (expression_of_struct_Arr array_expr) |
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 -- this function does not follow the naming convention... maybe mk_arr_struct?
…-better-unsize
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.
Ok I read the rest (thanks for merging main in!) and it looks like this all makes sense. Some general comments:
- I need a few more high-level explanations to finish the review (see detailed remarks)
- let's try to understand why you need to reimplement a reachability analysis
- I think some cleanup phases from Cleanup3 should no longer be necessary, correct? like
add_extra_type_to_slice_index
| | _ -> super#visit_expr env e | ||
| end | ||
|
|
||
| (** Comes from [drop_unused] in Inlining.ml, we use it to remove the builtin function defined using |
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.
why do you not do what was done before, and mark these as private, so that they are automatically eliminated by the reachability analysis?
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.
These functions are marked as private. This is kind of a quick fix cuz we need to remove these functions in precleanup to pass the following check while directly using Krml.Inlining.drop_unused after precleanup causes some other errors. I will try to directly reuse it by looking further into these errors.
| | CgConst n -> Krml.Helpers.mk_sizet (int_of_string (snd n)) | ||
| | CgVar _ -> failwith "non-const length in the Arr<T,C>" | ||
|
|
||
| let expand_slice_to_array = |
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.
can you describe what this function does, to help me understand a little bit better?
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.
First of all, this should be a part of the array PR. But try_into() was not included in the test cases. Now it is added in slice_array.rs.
The difference is that the previous implementation of slice_to_array and slice_to_ref_array are based on that array was transalted into pointer T*. So we basically just do the memcpy. However, now arrays are translated into structs, so we need to first allocate the array struct and do the memcpy to its data field.
This is exactly what this function does for slice_to_array (the first case). For slice_to_ref_array, it allocates the struct and call slice_to_ref_array2 defiend in glue.h to finish the possible core_result_Err . See slice_array_f3 in out/test-slice_array/slice_array.c for the translation result.
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.
Can you split this into a separate PR? That would make it much easier to review. Thanks.
No special reason. I just found that some macros can still work after a little bit changes (e.g. from |
I've removed some of these code in
As mentioned in the reply, I'll try to reuse the Edit: I've found that applying a general On the other hand, why we need to eliminate these new builtin functions early? Because they are functions with implementation and actually use the It seems quite tricky for me. Maybe we have to reimplement and “fine-tune” this reachability analysis to eliminate some of the unused functions.
Yes! After the array PR and the implementation of other builtin functions, I've removed it successfully. |
|
Thank @Lin23299 for helping refining the PR! I'm mainly working on adapting the vtable support in Eurydice. For the vtable, now charon should be quite ready for that with some minor issues:
Yet, there is still a bug in the vtable support in Charon. Now the stuff has been fixed in AeneasVerif/charon#842 . After merging that, we will have pretty nice vtable support: typedef struct dyn_trait_struct_type_Trait__vtable__s
{
size_t size;
size_t align;
void (*drop)(Eurydice_dst_ref_06 x0);
void (*method_method)(Eurydice_dst_ref_06 x0);
core_marker_MetaSized__vtable_ *super_trait_0;
}
dyn_trait_struct_type_Trait__vtable_;
typedef struct Eurydice_dst_ref_06_s
{
Eurydice_c_void_t *ptr;
dyn_trait_struct_type_Trait__vtable_ *meta;
}
Eurydice_dst_ref_06;
void dyn_trait_struct_type_use_trait(Eurydice_dst_ref_06 t)
{
Eurydice_dst_ref_06 uu____0 = t;
uu____0.meta->method_method(uu____0);
}For the Rust code: trait Trait {
fn method(&self);
}
fn use_trait(t: &dyn Trait) {
t.method();
} |
1. metadata of dyn from struct to pointer; 2. new example added; 3. Eurydice_c_void_t defined;
|
Ok I am traveling for a couple conferences right now, so the best way to get this moving is to split the changes that are only about arrays into a separate PR, merge that, and come back to this one. I think it'll make the process easier for all of us... thanks! (And very excited about vtable support -- this is great!) |
Yes, maybe some functions can only be eliminated later. I agree that it is tricky and I've had similar issues in the past. Let me think about this... |
|
@Lin23299 can you merge main into this branch to make sure we don't have any commits left behind? thank you! |
|
Ok there's only this one left -- please merge main into this branch to make sure there's nothing important left on this branch. @Lin23299 congratulations on a super nice piece of work! |
…-better-unsize
|
@protz I've merged Btw, I have no idea why the output of |
|
@Lin23299: @Nadrieril updated the README.md so perhaps there is some useful information in there. In the meanwhile:
Please note that the Cargo.lock file should not be modified (insofar as I understand); you may want to do Let me know how it goes! |
|
(I did this for you in the interest of cleaning up PRs.) |
|
Thank you very much! These instructions works for me and everything is pretty clean now. :) |
I've implemented on the Charon side (AeneasVerif/charon#797) a functionality of making the pointer-metadata explicit in Charon. This reflects in that both
RawPtrandRvRefin thervaluetype now will take an additional operand, which stores the metadata. So that, now, codes like:Now will have the RHS represented as:
This is a part of the full DST (dynamically sized types) support plan. A new type
struct Eurydice::DstRef<Pointee, Meta> { Pointee *ptr, Meta meta }is also added as the ultimate representation of such types. A functionmk_referenceis added, this function judges if the given metadata is(), the default case indicating no metadata is required (Thinpointer), otherwise, wrap the whole value withEurydice::DstRef.This has 3 major implications:
&[T]is now simplyEurydice::DstRef<T, usize>, we may add an abbreviation astype Eurydice::Slice<T> = Eurydice::DstRef<T, usize>for better readability, though. This involves also the casting part inAstOfLlbcand many Cleanups.strtype should now simplyEurydice::DstRef<char, usize>.Type<U : ?Sized>) can be now more generally handled. This should also make the codes more structured & clean.Let us merge #252 first to partly alleviate the situation!
Of course, if we are simply to adapt to the new AST from Charon, we can ignore the final Operand for metadata, and everything will remain exactly the same as before.