<commit_before>//! EVM Program Counter.

#[cfg(not(feature = "std"))]
use alloc::Vec;

use bigint::M256;
use util::opcode::Opcode;
#[cfg(feature = "std")] use std::cmp::min;
#[cfg(feature = "std")] use std::marker::PhantomData;
#[cfg(not(feature = "std"))] use core::cmp::min;
#[cfg(not(feature = "std"))] use core::marker::PhantomData;

use super::Patch;
use super::errors::OnChainError;

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[allow(missing_docs)]
/// Instructions for the program counter. This is the same as `Opcode`
/// except `PUSH`, which might take longer length.
pub enum Instruction {
    STOP, ADD, MUL, SUB, DIV, SDIV, MOD, SMOD, ADDMOD, MULMOD, EXP,
    SIGNEXTEND, LT, GT, SLT, SGT, EQ, ISZERO, AND, OR, XOR, NOT, BYTE,
    SHA3, ADDRESS, BALANCE, ORIGIN, CALLER, CALLVALUE, CALLDATALOAD,
    CALLDATASIZE, CALLDATACOPY, CODESIZE, CODECOPY, GASPRICE,
    EXTCODESIZE, EXTCODECOPY, BLOCKHASH, COINBASE, TIMESTAMP, NUMBER,
    DIFFICULTY, GASLIMIT, POP, MLOAD, MSTORE, MSTORE8, SLOAD, SSTORE,
    JUMP, JUMPI, PC, MSIZE, GAS, JUMPDEST, CREATE, CALL, CALLCODE,
    RETURN, DELEGATECALL, SUICIDE,

    PUSH(M256),
    DUP(usize),
    SWAP(usize),
    LOG(usize),
}

/// Represents a program counter in EVM.
pub struct PC<P: Patch> {
    position: usize,
    code: Vec<u8>,
    valids: Vec<bool>,
    _patch: PhantomData<P>,
}

impl<P: Patch> PC<P> {
    /// Create a new program counter from the given code.
    pub fn new(code: &[u8]) -> Self {
        let code: Vec<u8> = code.into();
        let mut valids: Vec<bool> = Vec::with_capacity(code.len());
        valids.resize(code.len(), false);

        let mut i = 0;
        while i < code.len() {
            let opcode: Opcode = code[i].into();
            match opcode {
                Opcode::JUMPDEST => {
                    valids[i] = true;
                    i = i + 1;
                },
                Opcode::PUSH(v) => {
                    i = i + v + 1;
                },
                _ => {
                    i = i + 1;
                }
            }
        }

        PC {
            code,
            position: 0,
            valids: valids,
            _patch: PhantomData,
        }
    }

    fn read_bytes(&self, from_position: usize, byte_count: usize) -> Result<M256, OnChainError> {
        if from_position > self.code.len() {
            return Err(OnChainError::PCOverflow);
        }
        let position = from_position;
        let max = min(position.saturating_add(byte_count), self.code.len());
        Ok(M256::from(&self.code[position..max]))
    }

    /// Get the code bytearray.
    pub fn code(&self) -> &[u8] {
        &self.code
    }

    /// Jump to a position in the code. The destination must be valid
    /// to jump.
    pub fn jump(&mut self, position: usize) -> Result<(), OnChainError> {
        if position >= self.code.len() {
            return Err(OnChainError::PCOverflow);
        }

        if !self.valids[position] {
            return Err(OnChainError::BadJumpDest);
        }

        self.position = position;<commit_msg>Set up PC at given location<commit_after>//! EVM Program Counter.

#[cfg(not(feature = "std"))]
use alloc::Vec;

use bigint::M256;
use util::opcode::Opcode;
#[cfg(feature = "std")] use std::cmp::min;
#[cfg(feature = "std")] use std::marker::PhantomData;
#[cfg(not(feature = "std"))] use core::cmp::min;
#[cfg(not(feature = "std"))] use core::marker::PhantomData;

use super::Patch;
use super::errors::OnChainError;

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[allow(missing_docs)]
/// Instructions for the program counter. This is the same as `Opcode`
/// except `PUSH`, which might take longer length.
pub enum Instruction {
    STOP, ADD, MUL, SUB, DIV, SDIV, MOD, SMOD, ADDMOD, MULMOD, EXP,
    SIGNEXTEND, LT, GT, SLT, SGT, EQ, ISZERO, AND, OR, XOR, NOT, BYTE,
    SHA3, ADDRESS, BALANCE, ORIGIN, CALLER, CALLVALUE, CALLDATALOAD,
    CALLDATASIZE, CALLDATACOPY, CODESIZE, CODECOPY, GASPRICE,
    EXTCODESIZE, EXTCODECOPY, BLOCKHASH, COINBASE, TIMESTAMP, NUMBER,
    DIFFICULTY, GASLIMIT, POP, MLOAD, MSTORE, MSTORE8, SLOAD, SSTORE,
    JUMP, JUMPI, PC, MSIZE, GAS, JUMPDEST, CREATE, CALL, CALLCODE,
    RETURN, DELEGATECALL, SUICIDE,

    PUSH(M256),
    DUP(usize),
    SWAP(usize),
    LOG(usize),
}

/// Represents a program counter in EVM.
pub struct PC<P: Patch> {
    position: usize,
    code: Vec<u8>,
    valids: Vec<bool>,
    _patch: PhantomData<P>,
}

impl<P: Patch> PC<P> {
    /// Create a new program counter from the given code.
    pub fn new(code: &[u8]) -> Self {
        let code: Vec<u8> = code.into();
        let mut valids: Vec<bool> = Vec::with_capacity(code.len());
        valids.resize(code.len(), false);

        let mut i = 0;
        while i < code.len() {
            let opcode: Opcode = code[i].into();
            match opcode {
                Opcode::JUMPDEST => {
                    valids[i] = true;
                    i = i + 1;
                },
                Opcode::PUSH(v) => {
                    i = i + v + 1;
                },
                _ => {
                    i = i + 1;
                }
            }
        }

        PC {
            code,
            position: 0,
            valids: valids,
            _patch: PhantomData,
        }
    }

    /// Create a new program counter at given position.
    pub(crate) fn with_position(code: &[u8], position: usize) -> Self {
        let mut pc = Self::new(code);
        pc.position = position;
        pc
    }

    fn read_bytes(&self, from_position: usize, byte_count: usize) -> Result<M256, OnChainError> {
        if from_position > self.code.len() {
            return Err(OnChainError::PCOverflow);
        }
        let position = from_position;
        let max = min(position.saturating_add(byte_count), self.code.len());
        Ok(M256::from(&self.code[position..max]))
    }

    /// Get the code bytearray.
    pub fn code(&self) -> &[u8] {
        &self.code
    }

    /// Jump to a position in the code. The destination must be valid
    /// to jump.
    pub fn jump(&mut self, position: usize) -> Result<(), OnChainError> {
        if position >= self.code.len() {
            return Err(OnChainError::PCOverflow);
        }

        if !self.valids[position] {
            return Err(OnChainError::BadJumpDest);
        }

        self.position = position;
{'fraction_non_alphanumeric': 0.14314896291640478, 'fraction_numerical': 0.0073852922690132, 'mean_word_length': 2.1904761904761907, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 42, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '587850', 'n_tokens_mistral': 2246, 'n_tokens_neox': 2145, 'n_words': 562}