Skip to content
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

Plafer 1122 fix decorators #1466

Merged
merged 44 commits into from
Sep 11, 2024
Merged

Plafer 1122 fix decorators #1466

merged 44 commits into from
Sep 11, 2024

Conversation

plafer
Copy link
Contributor

@plafer plafer commented Aug 26, 2024

Closes #1122

Based on #1473

Note that I didn't left DecoratorList in a similar format as it was (instead of the proposed DecoratorSpan) initially to change fewer things in this PR. But then it's not clear to me that we would gain much by using DecoratorSpan, since IIUC, it is useful when there are a lot of decorators sit next to each other. Especially after #1457, I don't think this would be very frequent.

@plafer plafer marked this pull request as ready for review August 30, 2024 18:47
@plafer plafer requested review from bobbinth and bitwalker August 30, 2024 18:47
@bobbinth
Copy link
Contributor

bobbinth commented Sep 8, 2024

One thing we may need to add to this PR (or to a follow-up PR) is related to #1457 (comment). Basically, when we compute eq_hash of a basic block, we should include error codes attached to assert operations into it. This is actually causing some real issues in miden-base as sometimes error codes don't get reported properly.

* Move strings data to its own buffer

* move StringTableBuilder out of BasicBlockDataBuilder

* Create `StringTable` type

* Encode decorators separately

* fix strings table

* Introduce Operation iterator in BasicBlockNode

* Document use of `MAX_DECORATORS` value

* fix typo

* merge `basic_block_data_decoder` and `basic_block_data_builder` modules

* Use `DecoratorId::from_u32_safe` in deserialization

* serialization failing test

* serialize before_enter/after_exit maps

* Document serialization format

* rename `BasicBlockNode::operation_iter`

* `MastNodeInfo::new()`: soft enforce 0 values for non-basic block nodes

* update docstring for `BasicBlockDataDecoder`

* decorator id deserializing meaningful errors

* move `basic_block_data_decoder` var

* Don't use maps for before enter/after exit decorators
@plafer
Copy link
Contributor Author

plafer commented Sep 10, 2024

One thing we may need to add to this PR (or to a follow-up PR) is related to #1457 (comment). Basically, when we compute eq_hash of a basic block, we should include error codes attached to assert operations into it. This is actually causing some real issues in miden-base as sometimes error codes don't get reported properly.

The u32 argument to Assert and U32assert2 are now incorporated into the eq_hash computation (see 20446b7).

@plafer plafer requested a review from bobbinth September 10, 2024 18:13
@bobbinth
Copy link
Contributor

The u32 argument to Assert and U32assert2 are now incorporated into the eq_hash computation (see 20446b7).

Nice! There is one other operation which has carries an error code: MpVerify. Could we include it as well?

@plafer plafer force-pushed the plafer-1122-fix-decorators branch from 20446b7 to adbfe9a Compare September 10, 2024 19:18
@plafer
Copy link
Contributor Author

plafer commented Sep 10, 2024

Nice! There is one other operation which has carries an error code: MpVerify. Could we include it as well?

Ah yes - done (adbfe9a)

Copy link
Contributor

@bobbinth bobbinth left a comment

Choose a reason for hiding this comment

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

All looks good! Thank you! I left one comment for the future inline.

Comment on lines +630 to +635
let then_blk = self.compile_body(
then_blk.iter(),
proc_ctx,
None,
block_builder.mast_forest_builder_mut(),
)?;
Copy link
Contributor

Choose a reason for hiding this comment

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

Not for this PR, but in the future we could move wrapper into ProcedureContext and then we won't need to pass None here and in other similar places.

@bobbinth
Copy link
Contributor

btw, as a result of this PR we should also be able to close #832. I think the resolution is that we don't allow procedures with just decorators.

};

let procedure_body_id = if body_node_ids.is_empty() {
// We cannot allow only decorators in a procedure body, since decorators don't change
Copy link
Contributor

Choose a reason for hiding this comment

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

This should probably be documented in the Miden documentation, specifically which instructions are decorators, and the fact that they cannot appear in a procedure by themselves.

I'm not sure how likely it is in practice, but I imagine the error would be pretty confusing.

Copy link
Contributor

Choose a reason for hiding this comment

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

This can probably go into the Procedures section. And we can refer to the a advice injectors as well as list emit, debug, and trace instructions (so that we don't have to list all advice injectors).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated the docs 2e8481e. With #1457 we can fix it more holistically - the "decorators" name could be removed in favor of "debug instructions" or whatnot, and here in the "debug instructions" section we can state that these do not modify the MAST root, can be stripped away without affecting the behavior of the program, and cannot be the only instructions in a procedure

#[error("invalid procedure: body must contain at least one instruction if it has decorators")]
#[diagnostic()]
EmptyProcedureBodyWithDecorators {
span: SourceSpan,
Copy link
Contributor

Choose a reason for hiding this comment

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

This is an example of an error where using Report and ad-hoc diagnostics works better than a concrete error type like AssemblyError. This error sets the stage for what is wrong, but is sort of incomplete from the user perspective. Ideally, you'd have the primary label span the procedure body, with a secondary label spanning the first decorator, with a message like '<opcode>' is a decorator, which cannot appear in a procedure body without at least one non-decorator instruction, with help text attached to the diagnostic like try adding a 'nop' instruction at the end of the procedure body to anchor the decorators.

By using AssemblyError for things like this, we make it difficult (if not impossible) to construct these kind of helpful diagnostics, which is why most APIs are designed to return Report rather than AssemblyError.

Your call on whether you want to make the change, but we should try to get in the habit of thinking about how these errors will be seen and acted on by users, particularly those that don't have as strong a familiarity with Miden Assembly, and may not understand the difference between things like decorators and instructions, since they appear the same way in the source code.

Copy link
Contributor

Choose a reason for hiding this comment

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

I echoed this comment in #1431 so that we can address it when removing AssemblyError.

@@ -231,7 +296,7 @@ impl PrettyPrint for BasicBlockNode {
}
}

impl fmt::Display for BasicBlockNode {
impl<'a> fmt::Display for BasicBlockNodePrettyPrint<'a> {
Copy link
Contributor

Choose a reason for hiding this comment

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

FYI Display is implemented for dyn PrettyPrint, so a reference to any PrettyPrint impl automatically implements Display. Can still be convenient to impl Display explicitly, like done here, but figured it's useful info to have on hand anyway.

@@ -18,6 +19,8 @@ use crate::{
pub struct JoinNode {
children: [MastNodeId; 2],
digest: RpoDigest,
before_enter: Vec<DecoratorId>,
Copy link
Contributor

Choose a reason for hiding this comment

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

Looks like most places where we are using Vec<DecoratorId> here could use Box<[DecoratorId]> instead, and shave off 8 bytes per field (on 64-bit systems). Doesn't look like we ever mutate them in-place, just create/replace. AFAIK Box::from([]) as Box<[DecoratorId]> won't actually allocate anything.

Not something we need to change in this PR necessarily, but that'd be the first thing I'd do to reduce the size of MastNode when we start trying to trim down the size.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah good point. I won't address it now, since these might or might not go away when we investigate reducing the size of MastNode - but good to keep in mind.

Copy link
Contributor

@bitwalker bitwalker left a comment

Choose a reason for hiding this comment

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

Looks good! Left a few notes/suggestions, but nothing that needs to block merging this. Nice work!

@plafer plafer merged commit 4ba0c53 into next Sep 11, 2024
9 checks passed
@plafer plafer deleted the plafer-1122-fix-decorators branch September 11, 2024 20:35
This was referenced Sep 11, 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.

3 participants