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

feat: DYN takes a memory address instead of digest on stack #1535

Draft
wants to merge 2 commits into
base: next
Choose a base branch
from

Conversation

plafer
Copy link
Contributor

@plafer plafer commented Oct 15, 2024

Closes #1091
Closes #1478

Left to do:

  • fix docs

@bobbinth
Copy link
Contributor

This change breaks how dyncall works (i.e. dyncall compiles to call(dyn)), since after the call, the memory is wiped since we entered a new context, and hence placing the procedure hash in memory before the call doesn't work.

We might need to do #1478 before we can merge this.

Ah yes - good point! I didn't think of this. Indeed, we may need to do #1478 first.

@plafer plafer force-pushed the plafer-1091-dyn-op-rework branch 2 times, most recently from 398ec10 to b83bb5c Compare October 16, 2024 17:51
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.

Looks great! Thank you! I left some comments inline - but nothing major.

The complexity in the stack resulting from having to do a left shift and a context switch at the same time is a bit unfortunate - but I'm not seeing a better way to do it. We should probably create an issue to come back to this later and try to make the constraints a bit more uniform.

@@ -111,6 +111,7 @@ pub(super) mod opcode_constants {
pub const OPCODE_RCOMBBASE: u8 = 0b0101_1001;
pub const OPCODE_EMIT: u8 = 0b0101_1010;
pub const OPCODE_PUSH: u8 = 0b0101_1011;
pub const OPCODE_DYNCALL: u8 = 0b0101_1100;
Copy link
Contributor

Choose a reason for hiding this comment

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

Depending on where we end up in #1536 (comment), we might need to move this to a "very-high-degree" operation bucket (i.e., line 117 below).

Comment on lines +251 to +252
/// Returns the memory word at address `addr`.
pub(crate) fn read_mem_word(&mut self, addr: Felt) -> Result<Word, ExecutionError> {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: I'd maybe clarify the comment to be "Returns the memory word at address addr in the current context."

Comment on lines 31 to +34
// make sure execution context was provided for CALL and SYSCALL blocks
if block_type == BlockType::Call || block_type == BlockType::SysCall {
if block_type == BlockType::Call
|| block_type == BlockType::SysCall
|| block_type == BlockType::Dyncall
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: let's mention DYNCALL in the comment as well (may also be relevant for the comment on line 22 above).

Comment on lines 139 to 141
pub fn decoder_hasher_state_element(&self, element: usize, i: RowIndex) -> Felt {
self.columns.get_column(DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + element)[i + 1]
self.columns.get_column(DECODER_TRACE_OFFSET + HASHER_STATE_OFFSET + element)[i]
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Was this a bug previously?

@@ -77,13 +78,15 @@ pub fn enforce_stack_depth_constraints<E: FieldElement>(
let depth = frame.stack_depth();
let depth_next = frame.stack_depth_next();

let call_or_syscall = op_flag.call() + op_flag.syscall();
let call_or_syscall_end = op_flag.end() * (frame.is_call_end() + frame.is_syscall_end());
let call_or_syscall_or_dyncall = op_flag.call() + op_flag.syscall() + op_flag.dyncall();
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: I'd call it call_or_dyncall_or_syscall

Comment on lines +335 to +337
// Dyncall's effect on the trace can't be written in terms of any other operation, and
// therefore can't follow this framework. Hence, we do it "manually". It's probably worth
// refactoring the decoder though to remove this Noop execution pattern.
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's create an issue for this.

Comment on lines +418 to +423
// Note: we need to read these values before `start_dyn_node()`, since `start_dyn_node()`
// advances the clock.
let mem_addr = self.stack.get(0);
// The callee hash is stored in memory, and the address is specified on the top of the
// stack.
let callee_hash = self.read_mem_word(mem_addr)?;
Copy link
Contributor

Choose a reason for hiding this comment

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

Technically, we could move these inside start_dyn_nod() and start_dyncall_node() since we don't advance the clock until the very end of these functions - right?


let memory_req = {
let mem_addr = main_trace.stack_element(0, row);
let word = main_trace.decoder_hasher_state_first_half(row);
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: would mem_value be a better name here (instead of word)?

Comment on lines +260 to +279
match self.active_depth {
0..=MAX_TOP_IDX => unreachable!("stack underflow"),
MIN_STACK_DEPTH => {
// Shift in a ZERO, to prevent depth shrinking below the minimum stack depth.
self.trace.stack_shift_left_no_helpers(self.clk, START_POSITION, ZERO, None);
},
_ => {
// Update the stack & overflow table.
let from_overflow = self.overflow.pop(u64::from(self.clk));
self.trace.stack_shift_left_no_helpers(
self.clk,
START_POSITION,
from_overflow,
Some(self.overflow.last_row_addr()),
);

// Stack depth only decreases when it is greater than the minimum stack depth.
self.active_depth -= 1;
self.full_depth -= 1;
},
Copy link
Contributor

Choose a reason for hiding this comment

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

This code is basically the same as shift_left() function (except for lines 269 - 273). I wonder if there is a way use the same code. Though, if it complicates things too much, I'd probably just leave a comment here so that we know that these blocks of code need to be kept in sync.

Comment on lines +287 to +288
Felt::from(self.active_depth as u32),
self.overflow.last_row_addr(),
Copy link
Contributor

Choose a reason for hiding this comment

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

self.active_depth should be 16 and self.overlfow.last_row_addr() should zero here, right? Maybe worth adding a comment to mention this.

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.

2 participants