Every instruction is a sequence of ints in the bytecode stream: one opcode int, followed by zero or more operand ints. “Size” below is the total instruction length (opcode + operands), i.e. what getOpCodeOffset() returns and how far PC advances by default.
All arithmetic opcodes are size 1 (no operands) — they pop two int64 values off the stack, combine them, and push an int64 result. Operand order: the value pushed second (b) is popped first, so a OP b is computed correctly for non-commutative operators.
Size 2 — operand is the offset to jump to if the comparison is false. All pop two values, compare as int64, and either fall through (true) or jump to the operand (false). This is exactly how if blocks compile.
There is no dedicated float arithmetic opcode set yet — TAG_FLOAT exists in the type system (see Bytecode Format) but the current arithmetic opcodes operate on int64_t only.
Unrecognized opcodes cause the VM to print Invalid opcode and halt with an error.