Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,21 @@ void ControlFlow::process_finalize_with_return(FinalizeWithReturn instruction)
current_block = non_terminated_blocks.at(0);
}

void ControlFlow::process_finalize_with_revert(FinalizeWithRevert instruction)
{
if (this->current_block->terminator_type != TerminatorType::NONE) {
return;
}
current_block->finalize_with_revert(instruction.revert_options.return_size,
instruction.revert_options.return_value_tag,
instruction.revert_options.return_value_offset_index);
std::vector<ProgramBlock*> non_terminated_blocks = get_non_terminated_blocks();
if (non_terminated_blocks.size() == 0) {
return;
}
current_block = non_terminated_blocks.at(0);
}

void ControlFlow::process_switch_to_non_terminated_block(SwitchToNonTerminatedBlock instruction)
{
std::vector<ProgramBlock*> non_terminated_blocks = get_non_terminated_blocks();
Expand Down Expand Up @@ -214,6 +229,7 @@ void ControlFlow::process_cfg_instruction(CFGInstruction instruction)
[&](JumpToBlock arg) { process_jump_to_block(arg); },
[&](JumpIfToBlock arg) { process_jump_if_to_block(arg); },
[&](FinalizeWithReturn arg) { process_finalize_with_return(arg); },
[&](FinalizeWithRevert arg) { process_finalize_with_revert(arg); },
[&](SwitchToNonTerminatedBlock arg) { process_switch_to_non_terminated_block(arg); },
[&](InsertInternalCall arg) { process_insert_internal_call(arg); } },
instruction);
Expand All @@ -239,7 +255,8 @@ int predict_block_size(ProgramBlock* block)
auto bytecode_length = static_cast<int>(create_bytecode(block->get_instructions()).size());
switch (block->terminator_type) {
case TerminatorType::RETURN:
return bytecode_length; // finalized with return, already counted
case TerminatorType::REVERT:
return bytecode_length; // finalized with return/revert, already counted
case TerminatorType::JUMP:
return bytecode_length + JMP_SIZE; // finalized with jump
case TerminatorType::JUMP_IF: {
Expand All @@ -263,9 +280,9 @@ int predict_block_size(ProgramBlock* block)
return bytecode_length + JMP_IF_SIZE + JMP_SIZE; // finalized with jumpi
}
default:
throw std::runtime_error("Predict block size: Every block should be terminated with return, jump, or jumpi, "
"got " +
std::to_string(static_cast<int>(block->terminator_type)));
throw std::runtime_error(
"Predict block size: Every block should be terminated with return, revert, jump, or jumpi, got " +
std::to_string(static_cast<int>(block->terminator_type)));
}
throw std::runtime_error("Unreachable");
}
Expand Down Expand Up @@ -315,6 +332,9 @@ std::vector<uint8_t> ControlFlow::build_bytecode(const ReturnOptions& return_opt
case TerminatorType::RETURN: // finalized with return
// already terminated with return
break;
case TerminatorType::REVERT: // finalized with revert
// already terminated with revert
break;
case TerminatorType::JUMP: { // finalized with jump
ProgramBlock* target_block = block->successors.at(0);
size_t target_block_idx = find_block_idx(target_block, blocks);
Expand Down Expand Up @@ -347,7 +367,7 @@ std::vector<uint8_t> ControlFlow::build_bytecode(const ReturnOptions& return_opt
}
default:
throw std::runtime_error(
"Inject terminators: Every block should be terminated with return, jump, or jumpi");
"Inject terminators: Every block should be terminated with return, revert, jump, or jumpi");
}
block_bytecodes.push_back(create_bytecode(instructions));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ struct FinalizeWithReturn {
MSGPACK_FIELDS(return_options);
};

/// @brief finalizes the current block with Revert and switches to the first non-terminated block
struct FinalizeWithRevert {
ReturnOptions revert_options;
MSGPACK_FIELDS(revert_options);
};

/// @brief switches to the non-terminated block with the chosen index
struct SwitchToNonTerminatedBlock {
uint16_t non_terminated_block_idx;
Expand All @@ -83,6 +89,7 @@ using CFGInstruction = std::variant<InsertSimpleInstructionBlock,
JumpToBlock,
JumpIfToBlock,
FinalizeWithReturn,
FinalizeWithRevert,
SwitchToNonTerminatedBlock,
InsertInternalCall>;
template <class... Ts> struct overloaded_cfg_instruction : Ts... {
Expand Down Expand Up @@ -111,6 +118,10 @@ inline std::ostream& operator<<(std::ostream& os, const CFGInstruction& instruct
os << "FinalizeWithReturn " << arg.return_options.return_size << " "
<< arg.return_options.return_value_tag << " " << arg.return_options.return_value_offset_index;
},
[&](FinalizeWithRevert arg) {
os << "FinalizeWithRevert " << arg.revert_options.return_size << " "
<< arg.revert_options.return_value_tag << " " << arg.revert_options.return_value_offset_index;
},
[&](SwitchToNonTerminatedBlock arg) {
os << "SwitchToNonTerminatedBlock " << arg.non_terminated_block_idx;
},
Expand Down Expand Up @@ -160,6 +171,10 @@ class ControlFlow {
/// @param instruction the instruction to process
void process_finalize_with_return(FinalizeWithReturn instruction);

/// @brief terminates the current block with Revert and switches to the first non-terminated block
/// @param instruction the instruction to process
void process_finalize_with_revert(FinalizeWithRevert instruction);

/// @brief switches to the non-terminated block with the chosen index
/// @param instruction the instruction to process
void process_switch_to_non_terminated_block(SwitchToNonTerminatedBlock instruction);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1586,6 +1586,34 @@ void ProgramBlock::finalize_with_return(uint8_t return_size,
instructions.push_back(return_instruction);
}

void ProgramBlock::finalize_with_revert(uint8_t revert_size,
MemoryTagWrapper revert_value_tag,
uint16_t revert_value_offset_index)
{
this->terminator_type = TerminatorType::REVERT;

auto revert_addr = memory_manager.get_memory_offset_16(revert_value_tag.value, revert_value_offset_index);
if (!revert_addr.has_value()) {
revert_addr = std::optional<uint32_t>(0);
}

// Once we do more of the randomness in Instruction selection, revert_size_offset we shouldnt need to hardcode
uint16_t revert_size_offset = 5U;
// Ensure operands are created as U16 to match wire format (UINT16)
auto set_size_instruction = bb::avm2::testing::InstructionBuilder(bb::avm2::WireOpCode::SET_16)
.operand(revert_size_offset)
.operand(bb::avm2::MemoryTag::U32)
.operand(static_cast<uint16_t>(revert_size))
.build();
instructions.push_back(set_size_instruction);
// REVERT_16 expects UINT16 operands, ensure we cast to uint16_t explicitly
auto revert_instruction = bb::avm2::testing::InstructionBuilder(bb::avm2::WireOpCode::REVERT_16)
.operand(static_cast<uint16_t>(revert_size_offset))
.operand(revert_addr.value())
.build();
instructions.push_back(revert_instruction);
}

void ProgramBlock::finalize_with_jump(ProgramBlock* target_block, bool copy_memory_manager)
{
this->terminator_type = TerminatorType::JUMP;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

enum class TerminatorType {
RETURN,
REVERT,
JUMP,
JUMP_IF,
NONE,
Expand Down Expand Up @@ -139,6 +140,13 @@ class ProgramBlock {
MemoryTagWrapper return_value_tag,
uint16_t return_value_offset_index);

/// @brief finalize the program block with a revert instruction
/// Similar to finalize_with_return but uses REVERT opcode instead.
/// Sets the terminator type to REVERT.
void finalize_with_revert(uint8_t revert_size,
MemoryTagWrapper revert_value_tag,
uint16_t revert_value_offset_index);

/// @brief finalize the block with a jump
/// Sets the terminator type to JUMP, adds the target block to the successors and the current block to the
/// predecessors.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -555,11 +555,12 @@ enum class CFGInstructionGenerationOptions {
JumpToBlock,
JumpIfToBlock,
FinalizeWithReturn,
FinalizeWithRevert,
SwitchToNonTerminatedBlock,
InsertInternalCall,
};

using CFGInstructionGenerationConfig = WeightedSelectionConfig<CFGInstructionGenerationOptions, 8>;
using CFGInstructionGenerationConfig = WeightedSelectionConfig<CFGInstructionGenerationOptions, 9>;

constexpr CFGInstructionGenerationConfig BASIC_CFG_INSTRUCTION_GENERATION_CONFIGURATION =
CFGInstructionGenerationConfig({
Expand All @@ -569,6 +570,7 @@ constexpr CFGInstructionGenerationConfig BASIC_CFG_INSTRUCTION_GENERATION_CONFIG
{ CFGInstructionGenerationOptions::JumpToBlock, 15 },
{ CFGInstructionGenerationOptions::JumpIfToBlock, 15 },
{ CFGInstructionGenerationOptions::FinalizeWithReturn, 7 },
{ CFGInstructionGenerationOptions::FinalizeWithRevert, 3 },
{ CFGInstructionGenerationOptions::SwitchToNonTerminatedBlock, 8 },
{ CFGInstructionGenerationOptions::InsertInternalCall, 3 },
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ void mutate_finalize_with_return(FinalizeWithReturn& instr, std::mt19937_64& rng
mutate_return_options(instr.return_options, rng, BASIC_RETURN_OPTIONS_MUTATION_CONFIGURATION);
}

void mutate_finalize_with_revert(FinalizeWithRevert& instr, std::mt19937_64& rng)
{
mutate_return_options(instr.revert_options, rng, BASIC_RETURN_OPTIONS_MUTATION_CONFIGURATION);
}

void mutate_switch_to_non_terminated_block(SwitchToNonTerminatedBlock& instr, std::mt19937_64& rng)
{
mutate_uint16_t(instr.non_terminated_block_idx, rng, BASIC_UINT16_T_MUTATION_CONFIGURATION);
Expand Down Expand Up @@ -86,6 +91,10 @@ CFGInstruction generate_cfg_instruction(std::mt19937_64& rng)
return FinalizeWithReturn(ReturnOptions(generate_random_uint8(rng),
generate_memory_tag(rng, BASIC_MEMORY_TAG_GENERATION_CONFIGURATION),
generate_random_uint16(rng)));
case CFGInstructionGenerationOptions::FinalizeWithRevert:
return FinalizeWithRevert(ReturnOptions(generate_random_uint8(rng),
generate_memory_tag(rng, BASIC_MEMORY_TAG_GENERATION_CONFIGURATION),
generate_random_uint16(rng)));
case CFGInstructionGenerationOptions::SwitchToNonTerminatedBlock:
return SwitchToNonTerminatedBlock(generate_random_uint16(rng));
case CFGInstructionGenerationOptions::InsertInternalCall:
Expand All @@ -102,6 +111,7 @@ void mutate_cfg_instruction(CFGInstruction& cfg_instruction, std::mt19937_64& rn
[&](JumpToBlock& instr) { mutate_jump_to_block(instr, rng); },
[&](JumpIfToBlock& instr) { mutate_jump_if_to_block(instr, rng); },
[&](FinalizeWithReturn& instr) { mutate_finalize_with_return(instr, rng); },
[&](FinalizeWithRevert& instr) { mutate_finalize_with_revert(instr, rng); },
[&](SwitchToNonTerminatedBlock& instr) { mutate_switch_to_non_terminated_block(instr, rng); },
[&](InsertInternalCall& instr) { mutate_insert_internal_call(instr, rng); } },
cfg_instruction);
Expand Down
Loading