> ## Documentation Index
> Fetch the complete documentation index at: https://voltaire.tevm.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Bytecode.getNextPc

> Get the next program counter after a given instruction

<Card title="Try it Live" icon="play" href="https://playground.tevm.sh?example=primitives/bytecode.ts">
  Run Bytecode examples in the interactive playground
</Card>

<Tabs>
  <Tab title="C">
    ## `bytecode_get_next_pc(bytecode_t bytecode, size_t current_pc, size_t *next_pc) bool`

    Calculate the next program counter position after the instruction at `current_pc`.

    **Parameters:**

    * `bytecode`: Bytecode to analyze
    * `current_pc`: Current program counter position
    * `next_pc`: Output parameter for next PC

    **Returns:** `bool` - true if next\_pc is valid, false if at end

    **Example:**

    ```c theme={null}
    #include "primitives.h"

    bytecode_t code = bytecode_from_hex("0x60016002015b00");
    size_t next_pc;

    if (bytecode_get_next_pc(code, 0, &next_pc)) {
        printf("Next PC: %zu\n", next_pc); // 2
    } else {
        printf("At end of bytecode\n");
    }

    bytecode_free(code);
    ```

    **Defined in:** [primitives.h](https://github.com/evmts/voltaire/blob/main/src/primitives.h)
  </Tab>
</Tabs>

## How It Works

`getNextPc()` handles the variable-width nature of EVM instructions:

### Regular Opcodes (1 byte)

```
ADD, MUL, STOP, JUMPDEST, etc.
└─ Next PC = Current PC + 1
```

### PUSH Instructions (1 + N bytes)

```
PUSH1:  opcode (1 byte) + data (1 byte)  = 2 bytes total
PUSH2:  opcode (1 byte) + data (2 bytes) = 3 bytes total
...
PUSH32: opcode (1 byte) + data (32 bytes) = 33 bytes total

Next PC = Current PC + 1 + N (where N = push width)
```

**Example:**

```typescript theme={null}
const code = Bytecode("0x7F" + "FF".repeat(32) + "01");
// PUSH32 (0x7F) + 32 bytes data + ADD (0x01)

console.log(code.getNextPc(0));  // 33 (skip PUSH32 + 32 bytes)
console.log(code.getNextPc(33)); // 34 (ADD is 1 byte)
```

## Usage Patterns

### Manual Iteration

```typescript theme={null}
const code = Bytecode(bytecode);

let pc = 0;
while (pc !== undefined && pc < code.size()) {
  const instruction = code.at(pc);
  console.log(`PC ${pc}: ${instruction}`);

  pc = code.getNextPc(pc);
}
```

<Note>
  For iteration, prefer using `bytecode.scan()` which handles this automatically. Use `getNextPc()` for cases requiring manual PC control.
</Note>

### Jump Target Calculation

```typescript theme={null}
// Calculate all possible next PCs from a JUMPI
function getPossibleNextPcs(
  code: BrandedBytecode,
  jumpiPc: number,
  jumpTarget: number
): number[] {
  const nextPcs: number[] = [];

  // Fallthrough path (condition false)
  const fallthrough = code.getNextPc(jumpiPc);
  if (fallthrough !== undefined) {
    nextPcs.push(fallthrough);
  }

  // Jump path (condition true)
  nextPcs.push(jumpTarget);

  return nextPcs;
}

const jumpiAt = 10;
const target = 50;
const paths = getPossibleNextPcs(code, jumpiAt, target);

console.log(`JUMPI at PC ${jumpiAt} can go to: ${paths.join(', ')}`);
```

### Instruction Boundary Validation

```typescript theme={null}
// Check if PC is at an instruction boundary (not in PUSH data)
function isInstructionStart(code: BrandedBytecode, pc: number): boolean {
  if (pc === 0) return true; // Entry point is always instruction start

  // Walk backward to find the instruction that contains or precedes this PC
  for (let checkPc = pc - 1; checkPc >= 0; checkPc--) {
    const nextPc = code.getNextPc(checkPc);
    if (nextPc === undefined) continue;

    if (nextPc === pc) {
      // Found an instruction that ends exactly at pc
      return true;
    } else if (nextPc > pc) {
      // Found an instruction that spans past pc (we're in PUSH data)
      return false;
    }
  }

  return false;
}

console.log(isInstructionStart(code, 0));  // true (entry)
console.log(isInstructionStart(code, 1));  // false (inside PUSH1 data)
console.log(isInstructionStart(code, 2));  // true (next instruction)
```

### Disassembly with PC Tracking

```typescript theme={null}
const code = Bytecode(bytecode);
const disassembly: string[] = [];

let pc = 0;
while (pc !== undefined && pc < code.size()) {
  const opcode = code.raw()[pc];
  const instruction = Opcode.getName(opcode);

  // Get PUSH data if applicable
  if (Opcode.isPush(opcode)) {
    const pushSize = opcode - 0x5F; // PUSH1 = 0x60, size = 1
    const data = code.raw().slice(pc + 1, pc + 1 + pushSize);
    const value = bytesToHex(data);
    disassembly.push(`${pc}: ${instruction} 0x${value}`);
  } else {
    disassembly.push(`${pc}: ${instruction}`);
  }

  pc = code.getNextPc(pc);
}

console.log(disassembly.join('\n'));
```

### Coverage Tracking

```typescript theme={null}
// Track which PCs were executed
const executedPcs = new Set<number>();

// Simulate execution with PC tracking
function simulateExecution(code: BrandedBytecode, startPc: number = 0) {
  let pc: number | undefined = startPc;

  while (pc !== undefined) {
    executedPcs.add(pc);

    const opcode = code.raw()[pc];

    // Handle control flow
    if (opcode === Opcode.JUMP) {
      // Would need stack to determine target
      break;
    } else if (opcode === Opcode.STOP || opcode === Opcode.RETURN) {
      break;
    }

    pc = code.getNextPc(pc);
  }
}

simulateExecution(code);

// Calculate coverage
const allPcs = new Set<number>();
let pc = 0;
while (pc !== undefined && pc < code.size()) {
  allPcs.add(pc);
  pc = code.getNextPc(pc);
}

const coverage = (executedPcs.size / allPcs.size) * 100;
console.log(`PC coverage: ${coverage.toFixed(1)}%`);
```

## Edge Cases

### At End of Bytecode

```typescript theme={null}
const code = Bytecode("0x00"); // STOP
const nextPc = code.getNextPc(0);

console.log(nextPc); // undefined (no next instruction)
```

### Invalid PC

```typescript theme={null}
const nextPc = code.getNextPc(9999);
console.log(nextPc); // undefined (PC out of bounds)
```

### Truncated PUSH

```typescript theme={null}
// Malformed bytecode: PUSH2 with only 1 byte of data
const malformed = Bytecode("0x6100"); // PUSH2 0x00 (missing 1 byte)

const nextPc = code.getNextPc(0);
// Implementation dependent: may return PC past end or undefined
```

<Warning>
  For malformed bytecode (truncated PUSH instructions), behavior is implementation-defined. Always validate bytecode before processing.
</Warning>

### PC in Middle of PUSH Data

```typescript theme={null}
// PUSH2 0x1234 at PC 0 means:
//   PC 0: PUSH2 opcode
//   PC 1: 0x12 (data byte 1)
//   PC 2: 0x34 (data byte 2)
//   PC 3: next instruction

const nextFromOpcode = code.getNextPc(0); // 3 (correct)
const nextFromData1  = code.getNextPc(1); // undefined or error (invalid PC)
const nextFromData2  = code.getNextPc(2); // undefined or error (invalid PC)
```

<Note>
  Only call `getNextPc()` from instruction start positions. Calling from within PUSH data is undefined behavior.
</Note>

## Performance

`getNextPc()` is O(1) - constant time:

* Reads single byte at current PC
* Calculates width based on opcode
* Returns PC + 1 + width

No caching or pre-analysis required.

## Comparison with scan()

| Feature         | getNextPc()           | scan()                |
| --------------- | --------------------- | --------------------- |
| **Use case**    | Manual PC control     | Automatic iteration   |
| **Returns**     | Next PC number        | Instruction object    |
| **PUSH data**   | Returns PC after data | Includes parsed value |
| **Performance** | O(1) per call         | O(1) per instruction  |
| **Ease of use** | Low-level             | High-level            |

**Use `getNextPc()` when:**

* Building custom traversal logic
* Implementing jump analysis
* Need fine-grained PC control
* Working with PC-based data structures

**Use `scan()` when:**

* Standard iteration over instructions
* Need instruction metadata (opcode, type, value)
* Want fusion detection
* Don't need manual PC manipulation

## See Also

* [scan](/primitives/bytecode/scan) - High-level iterator (recommended for most use cases)
* [getBlock](/primitives/bytecode/getBlock) - Get block containing a PC
* [parseInstructions](/primitives/bytecode/parseInstructions) - Parse all instructions to array
* [Opcode](/primitives/opcode) - Opcode utilities for determining instruction width
