Skip to content

Commit

Permalink
Merge pull request #532 from maticnetwork/assembly-error
Browse files Browse the repository at this point in the history
Refactor AssemblyError and fix Miden executable
  • Loading branch information
bobbinth authored Nov 21, 2022
2 parents e8f4089 + 2d3f84b commit 8b4ecc5
Show file tree
Hide file tree
Showing 19 changed files with 237 additions and 243 deletions.
41 changes: 24 additions & 17 deletions assembly/src/assembler/context.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::{
AssemblerError, CallSet, CodeBlock, CodeBlockTable, Kernel, Procedure, ProcedureCache,
AssemblyError, CallSet, CodeBlock, CodeBlockTable, Kernel, Procedure, ProcedureCache,
ProcedureId, String, ToString, Vec,
};
use crate::MODULE_PATH_DELIM;
Expand Down Expand Up @@ -56,11 +56,7 @@ impl AssemblyContext {

/// Returns the number of memory locals allocated for the procedure currently being compiled.
pub fn num_proc_locals(&self) -> u16 {
self.module_stack
.last()
.expect("no modules")
.proc_stack
.last()
self.current_proc_context()
.expect("no procedures")
.num_locals
}
Expand All @@ -75,7 +71,7 @@ impl AssemblyContext {
///
/// # Errors
/// Returns an error if a module with the same path already exists in the module stack.
pub fn begin_module(&mut self, module_path: &str) -> Result<(), AssemblerError> {
pub fn begin_module(&mut self, module_path: &str) -> Result<(), AssemblyError> {
if self.is_kernel && self.module_stack.is_empty() {
// a kernel context must be initialized with a kernel module path
debug_assert_eq!(
Expand All @@ -92,7 +88,7 @@ impl AssemblyContext {
.iter()
.map(|m| m.path.to_string())
.collect::<Vec<_>>();
return Err(AssemblerError::circular_module_dependency(&dep_chain));
return Err(AssemblyError::circular_module_dependency(&dep_chain));
}

// push a new module context onto the module stack and return
Expand Down Expand Up @@ -140,7 +136,7 @@ impl AssemblyContext {
name: &str,
is_export: bool,
num_locals: u16,
) -> Result<(), AssemblerError> {
) -> Result<(), AssemblyError> {
self.module_stack
.last_mut()
.expect("no modules")
Expand Down Expand Up @@ -174,10 +170,11 @@ impl AssemblyContext {
&mut self,
proc_idx: u16,
inlined: bool,
) -> Result<&Procedure, AssemblerError> {
) -> Result<&Procedure, AssemblyError> {
// non-inlined calls (i.e., `call` instructions) cannot be executed in a kernel
if self.is_kernel && !inlined {
return Err(AssemblerError::call_in_kernel());
let proc_name = &self.current_proc_context().expect("no procedure").name;
return Err(AssemblyError::call_in_kernel(proc_name));
}

self.module_stack
Expand All @@ -201,10 +198,11 @@ impl AssemblyContext {
&mut self,
proc: &Procedure,
inlined: bool,
) -> Result<(), AssemblerError> {
) -> Result<(), AssemblyError> {
// non-inlined calls (i.e., `call` instructions) cannot be executed in a kernel
if self.is_kernel && !inlined {
return Err(AssemblerError::call_in_kernel());
let proc_name = &self.current_proc_context().expect("no procedure").name;
return Err(AssemblyError::call_in_kernel(proc_name));
}

self.module_stack
Expand Down Expand Up @@ -263,6 +261,15 @@ impl AssemblyContext {

cb_table
}

// HELPER METHODS
// --------------------------------------------------------------------------------------------

/// Returns the context of the procedure currently being complied, or None if module or
/// procedure stacks are empty.
fn current_proc_context(&self) -> Option<&ProcedureContext> {
self.module_stack.last().and_then(|m| m.proc_stack.last())
}
}

// MODULE CONTEXT
Expand Down Expand Up @@ -342,13 +349,13 @@ impl ModuleContext {
name: &str,
is_export: bool,
num_locals: u16,
) -> Result<(), AssemblerError> {
) -> Result<(), AssemblyError> {
// make sure a procedure with this name as not been compiled yet and is also not currently
// on the stack of procedures being compiled
if self.compiled_procs.iter().any(|p| p.label() == name)
|| self.proc_stack.iter().any(|p| p.name == name)
{
return Err(AssemblerError::duplicate_proc_name(name, &self.path));
return Err(AssemblyError::duplicate_proc_name(name, &self.path));
}

self.proc_stack
Expand Down Expand Up @@ -396,12 +403,12 @@ impl ModuleContext {
&mut self,
proc_idx: u16,
inlined: bool,
) -> Result<&Procedure, AssemblerError> {
) -> Result<&Procedure, AssemblyError> {
// get the called procedure from the listed of already compiled local procedures
let called_proc = self
.compiled_procs
.get(proc_idx as usize)
.ok_or_else(|| AssemblerError::undefined_proc(proc_idx))?;
.ok_or_else(|| AssemblyError::local_proc_not_found(proc_idx, &self.path))?;

// get the context of the procedure currently being compiled
let context = self.proc_stack.last_mut().expect("no proc context");
Expand Down
6 changes: 3 additions & 3 deletions assembly/src/assembler/instruction/adv_ops.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::{validate_param, AdviceInjector, AssemblerError, Decorator, SpanBuilder};
use super::{validate_param, AdviceInjector, AssemblyError, Decorator, SpanBuilder};
use crate::ADVICE_READ_LIMIT;
use vm_core::{code_blocks::CodeBlock, Operation::*};

Expand All @@ -12,7 +12,7 @@ use vm_core::{code_blocks::CodeBlock, Operation::*};
/// # Errors
/// Returns an error if the specified number of values to pushed is smaller than 1 or greater
/// than 16.
pub fn adv_push(span: &mut SpanBuilder, n: u8) -> Result<Option<CodeBlock>, AssemblerError> {
pub fn adv_push(span: &mut SpanBuilder, n: u8) -> Result<Option<CodeBlock>, AssemblyError> {
validate_param(n, 1, ADVICE_READ_LIMIT)?;
span.push_op_many(Read, n as usize);
Ok(None)
Expand All @@ -30,7 +30,7 @@ pub fn adv_mem(
span: &mut SpanBuilder,
start_addr: u32,
num_words: u32,
) -> Result<Option<CodeBlock>, AssemblerError> {
) -> Result<Option<CodeBlock>, AssemblyError> {
validate_param(num_words, 0, u32::MAX - start_addr)?;
span.add_decorator(Decorator::Advice(AdviceInjector::Memory(
start_addr, num_words,
Expand Down
10 changes: 5 additions & 5 deletions assembly/src/assembler/instruction/crypto_ops.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::{AssemblerError, CodeBlock, Operation::*, SpanBuilder};
use super::{AssemblyError, CodeBlock, Operation::*, SpanBuilder};
use vm_core::{AdviceInjector, Decorator, Felt};

// HASHING
Expand All @@ -24,7 +24,7 @@ const RPHASH_NUM_ELEMENTS: u64 = 8;
/// 4. Drop F and D to return our result [E, ...].
///
/// This operation takes 16 VM cycles.
pub(super) fn rphash(span: &mut SpanBuilder) -> Result<Option<CodeBlock>, AssemblerError> {
pub(super) fn rphash(span: &mut SpanBuilder) -> Result<Option<CodeBlock>, AssemblyError> {
// Add 4 elements to the stack to prepare the capacity portion for the Rescue Prime permutation
// The capacity should start at stack[8], and the number of elements to be hashed should
// be deepest in the stack at stack[11]
Expand Down Expand Up @@ -64,7 +64,7 @@ pub(super) fn rphash(span: &mut SpanBuilder) -> Result<Option<CodeBlock>, Assemb
/// - root of the tree, 4 elements.
///
/// This operation takes 9 VM cycles.
pub(super) fn mtree_get(span: &mut SpanBuilder) -> Result<Option<CodeBlock>, AssemblerError> {
pub(super) fn mtree_get(span: &mut SpanBuilder) -> Result<Option<CodeBlock>, AssemblyError> {
// stack: [d, i, R, ...]
// inject the node value we're looking for at the head of the advice tape
read_mtree_node(span);
Expand Down Expand Up @@ -96,7 +96,7 @@ pub(super) fn mtree_get(span: &mut SpanBuilder) -> Result<Option<CodeBlock>, Ass
/// - new value of the node, 4 elements
///
/// This operation takes 14 VM cycles.
pub(super) fn mtree_set(span: &mut SpanBuilder) -> Result<Option<CodeBlock>, AssemblerError> {
pub(super) fn mtree_set(span: &mut SpanBuilder) -> Result<Option<CodeBlock>, AssemblyError> {
// Inject the old node value onto the stack for the call to MRUPDATE.
// [d, i, R, V_new, ...] => [V_old, d, i, R, V_new, ...]
read_mtree_node(span);
Expand Down Expand Up @@ -136,7 +136,7 @@ pub(super) fn mtree_set(span: &mut SpanBuilder) -> Result<Option<CodeBlock>, Ass
/// - root of the old tree which was copied, 4 elements
///
/// This operation takes 12 VM cycles.
pub(super) fn mtree_cwm(span: &mut SpanBuilder) -> Result<Option<CodeBlock>, AssemblerError> {
pub(super) fn mtree_cwm(span: &mut SpanBuilder) -> Result<Option<CodeBlock>, AssemblyError> {
// Inject the old node value onto the stack for the call to MRUPDATE.
// [d, i, R, V_new, ...] => [V_old, d, i, R, V_new, ...]
read_mtree_node(span);
Expand Down
10 changes: 5 additions & 5 deletions assembly/src/assembler/instruction/env_ops.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::{
mem_ops::local_to_absolute_addr, push_felt, AssemblerError, AssemblyContext, CodeBlock, Felt,
mem_ops::local_to_absolute_addr, push_felt, AssemblyContext, AssemblyError, CodeBlock, Felt,
Operation::*, SpanBuilder,
};

Expand All @@ -25,7 +25,7 @@ use super::{
/// It will return an error if no immediate value is provided or if any of parameter formats are
/// invalid. It will also return an error if the op token is malformed or doesn't match the expected
/// instruction.
pub fn push(imms: &[Felt], span: &mut SpanBuilder) -> Result<Option<CodeBlock>, AssemblerError> {
pub fn push(imms: &[Felt], span: &mut SpanBuilder) -> Result<Option<CodeBlock>, AssemblyError> {
imms.iter().copied().for_each(|imm| push_felt(span, imm));
Ok(None)
}
Expand All @@ -42,7 +42,7 @@ pub fn locaddr(
span: &mut SpanBuilder,
index: u16,
context: &AssemblyContext,
) -> Result<Option<CodeBlock>, AssemblerError> {
) -> Result<Option<CodeBlock>, AssemblyError> {
local_to_absolute_addr(span, index, context.num_proc_locals())?;
Ok(None)
}
Expand All @@ -55,9 +55,9 @@ pub fn locaddr(
pub fn caller(
span: &mut SpanBuilder,
context: &AssemblyContext,
) -> Result<Option<CodeBlock>, AssemblerError> {
) -> Result<Option<CodeBlock>, AssemblyError> {
if !context.is_kernel() {
return Err(AssemblerError::caller_out_of_kernel());
return Err(AssemblyError::caller_out_of_kernel());
}

span.add_op(Caller)
Expand Down
30 changes: 15 additions & 15 deletions assembly/src/assembler/instruction/field_ops.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::{
validate_param, AssemblerError, CodeBlock, Felt, FieldElement, Operation::*, SpanBuilder,
validate_param, AssemblyError, CodeBlock, Felt, FieldElement, Operation::*, SpanBuilder,
StarkField, ONE, ZERO,
};
use crate::MAX_EXP_BITS;
Expand All @@ -14,7 +14,7 @@ use crate::MAX_EXP_BITS;
///
/// We do not optimize away adding 0 because it may result in a empty SPAN block and cause failures
/// later on.
pub fn add_imm(span: &mut SpanBuilder, imm: Felt) -> Result<Option<CodeBlock>, AssemblerError> {
pub fn add_imm(span: &mut SpanBuilder, imm: Felt) -> Result<Option<CodeBlock>, AssemblyError> {
if imm == ONE {
span.add_op(Incr)
} else {
Expand All @@ -30,7 +30,7 @@ pub fn add_imm(span: &mut SpanBuilder, imm: Felt) -> Result<Option<CodeBlock>, A
///
/// We do not optimize away multiplication by 1 because it may result in a empty SPAN block and
/// cause failures later on.
pub fn mul_imm(span: &mut SpanBuilder, imm: Felt) -> Result<Option<CodeBlock>, AssemblerError> {
pub fn mul_imm(span: &mut SpanBuilder, imm: Felt) -> Result<Option<CodeBlock>, AssemblyError> {
if imm == ZERO {
span.add_ops([Drop, Pad])
} else {
Expand All @@ -47,10 +47,10 @@ pub fn mul_imm(span: &mut SpanBuilder, imm: Felt) -> Result<Option<CodeBlock>, A
///
/// # Errors
/// Returns an error if the immediate value is ZERO.
pub fn div_imm(span: &mut SpanBuilder, imm: Felt) -> Result<Option<CodeBlock>, AssemblerError> {
pub fn div_imm(span: &mut SpanBuilder, imm: Felt) -> Result<Option<CodeBlock>, AssemblyError> {
// TODO: warning if imm is ONE?
if imm == ZERO {
return Err(AssemblerError::division_by_zero());
return Err(AssemblyError::division_by_zero());
}
span.add_ops([Push(imm.inv()), Mul])
}
Expand All @@ -62,7 +62,7 @@ pub fn div_imm(span: &mut SpanBuilder, imm: Felt) -> Result<Option<CodeBlock>, A
/// top of the stack.
///
/// VM cycles: 16 cycles
pub fn pow2(span: &mut SpanBuilder) -> Result<Option<CodeBlock>, AssemblerError> {
pub fn pow2(span: &mut SpanBuilder) -> Result<Option<CodeBlock>, AssemblyError> {
append_pow2_op(span);
Ok(None)
}
Expand Down Expand Up @@ -98,7 +98,7 @@ pub fn append_pow2_op(span: &mut SpanBuilder) {
///
/// # Errors
/// Returns an error if num_pow_bits is greater than 64.
pub fn exp(span: &mut SpanBuilder, num_pow_bits: u8) -> Result<Option<CodeBlock>, AssemblerError> {
pub fn exp(span: &mut SpanBuilder, num_pow_bits: u8) -> Result<Option<CodeBlock>, AssemblyError> {
validate_param(num_pow_bits, 0, MAX_EXP_BITS)?;

// arranging the stack to prepare it for expacc instruction.
Expand Down Expand Up @@ -127,7 +127,7 @@ pub fn exp(span: &mut SpanBuilder, num_pow_bits: u8) -> Result<Option<CodeBlock>
/// - pow = 6: 10 cycles
/// - pow = 7: 12 cycles
/// - pow > 7: 9 + Ceil(log2(pow))
pub fn exp_imm(span: &mut SpanBuilder, pow: Felt) -> Result<Option<CodeBlock>, AssemblerError> {
pub fn exp_imm(span: &mut SpanBuilder, pow: Felt) -> Result<Option<CodeBlock>, AssemblyError> {
if pow.as_int() <= 7 {
perform_exp_for_small_power(span, pow.as_int());
Ok(None)
Expand Down Expand Up @@ -202,7 +202,7 @@ fn perform_exp_for_small_power(span: &mut SpanBuilder, pow: u64) {
/// and the provided immediate value. Specifically, the sequences are:
/// - if imm = 0: EQZ
/// - otherwise: PUSH(imm) EQ
pub fn eq_imm(span: &mut SpanBuilder, imm: Felt) -> Result<Option<CodeBlock>, AssemblerError> {
pub fn eq_imm(span: &mut SpanBuilder, imm: Felt) -> Result<Option<CodeBlock>, AssemblyError> {
if imm == ZERO {
span.add_op(Eqz)
} else {
Expand All @@ -214,7 +214,7 @@ pub fn eq_imm(span: &mut SpanBuilder, imm: Felt) -> Result<Option<CodeBlock>, As
/// and the provided immediate value. Specifically, the sequences are:
/// - if imm = 0: EQZ NOT
/// - otherwise: PUSH(imm) EQ NOT
pub fn neq_imm(span: &mut SpanBuilder, imm: Felt) -> Result<Option<CodeBlock>, AssemblerError> {
pub fn neq_imm(span: &mut SpanBuilder, imm: Felt) -> Result<Option<CodeBlock>, AssemblyError> {
if imm == ZERO {
span.add_ops([Eqz, Not])
} else {
Expand All @@ -225,7 +225,7 @@ pub fn neq_imm(span: &mut SpanBuilder, imm: Felt) -> Result<Option<CodeBlock>, A
/// Appends a sequence of operations to check equality between two words at the top of the stack.
///
/// This operation takes 15 VM cycles.
pub fn eqw(span: &mut SpanBuilder) -> Result<Option<CodeBlock>, AssemblerError> {
pub fn eqw(span: &mut SpanBuilder) -> Result<Option<CodeBlock>, AssemblyError> {
span.add_ops([
// duplicate first pair of for comparison(4th elements of each word) in reverse order
// to avoid using dup.8 after stack shifting(dup.X where X > 7, takes more VM cycles )
Expand All @@ -240,7 +240,7 @@ pub fn eqw(span: &mut SpanBuilder) -> Result<Option<CodeBlock>, AssemblerError>
/// of 1 is pushed onto the stack if a < b. Otherwise, 0 is pushed.
///
/// This operation takes 17 VM cycles.
pub fn lt(span: &mut SpanBuilder) -> Result<Option<CodeBlock>, AssemblerError> {
pub fn lt(span: &mut SpanBuilder) -> Result<Option<CodeBlock>, AssemblyError> {
// Split both elements into high and low bits
// 3 cycles
split_elements(span);
Expand All @@ -266,7 +266,7 @@ pub fn lt(span: &mut SpanBuilder) -> Result<Option<CodeBlock>, AssemblerError> {
/// A value of 1 is pushed onto the stack if a <= b. Otherwise, 0 is pushed.
///
/// This operation takes 18 VM cycles.
pub fn lte(span: &mut SpanBuilder) -> Result<Option<CodeBlock>, AssemblerError> {
pub fn lte(span: &mut SpanBuilder) -> Result<Option<CodeBlock>, AssemblyError> {
// Split both elements into high and low bits
// 3 cycles
split_elements(span);
Expand All @@ -292,7 +292,7 @@ pub fn lte(span: &mut SpanBuilder) -> Result<Option<CodeBlock>, AssemblerError>
/// of 1 is pushed onto the stack if a > b. Otherwise, 0 is pushed.
///
/// This operation takes 18 VM cycles.
pub fn gt(span: &mut SpanBuilder) -> Result<Option<CodeBlock>, AssemblerError> {
pub fn gt(span: &mut SpanBuilder) -> Result<Option<CodeBlock>, AssemblyError> {
// Split both elements into high and low bits
// 3 cycles
split_elements(span);
Expand All @@ -318,7 +318,7 @@ pub fn gt(span: &mut SpanBuilder) -> Result<Option<CodeBlock>, AssemblerError> {
/// A value of 1 is pushed onto the stack if a >= b. Otherwise, 0 is pushed.
///
/// This operation takes 19 VM cycles.
pub fn gte(span: &mut SpanBuilder) -> Result<Option<CodeBlock>, AssemblerError> {
pub fn gte(span: &mut SpanBuilder) -> Result<Option<CodeBlock>, AssemblyError> {
// Split both elements into high and low bits
// 3 cycles
split_elements(span);
Expand Down
8 changes: 4 additions & 4 deletions assembly/src/assembler/instruction/mem_ops.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::{
push_felt, push_u32_value, validate_param, AssemblerError, AssemblyContext, CodeBlock, Felt,
push_felt, push_u32_value, validate_param, AssemblyContext, AssemblyError, CodeBlock, Felt,
Operation::*, SpanBuilder,
};

Expand All @@ -26,7 +26,7 @@ pub fn mem_read(
addr: Option<u32>,
is_local: bool,
is_single: bool,
) -> Result<Option<CodeBlock>, AssemblerError> {
) -> Result<Option<CodeBlock>, AssemblyError> {
// if the address was provided as an immediate value, put it onto the stack
if let Some(addr) = addr {
if is_local {
Expand Down Expand Up @@ -68,7 +68,7 @@ pub fn mem_write(
addr: Option<u32>,
is_local: bool,
is_single: bool,
) -> Result<Option<CodeBlock>, AssemblerError> {
) -> Result<Option<CodeBlock>, AssemblyError> {
// if the address was provided as an immediate value, put it onto the stack
if let Some(addr) = addr {
if is_local {
Expand Down Expand Up @@ -106,7 +106,7 @@ pub fn local_to_absolute_addr(
span: &mut SpanBuilder,
index: u16,
num_proc_locals: u16,
) -> Result<(), AssemblerError> {
) -> Result<(), AssemblyError> {
let max = num_proc_locals - 1;
validate_param(index, 0, max)?;

Expand Down
Loading

0 comments on commit 8b4ecc5

Please sign in to comment.