Page MenuHomePhorge

bytecode.h
No OneTemporary

Size
13 KB
Referenced Files
None
Subscribers
None

bytecode.h

#ifndef ANT_BYTECODE_H
#define ANT_BYTECODE_H
#include "ant.h"
#include <stdint.h>
#include <stdbool.h>
// Bytecode instruction format:
// [opcode:8] [operand:24] for most instructions
// Some instructions use immediate values in following slots
typedef uint32_t bc_inst_t;
#define BC_OP(inst) ((uint8_t)((inst) >> 24))
#define BC_ARG(inst) ((inst) & 0x00FFFFFF)
#define BC_SARG(inst) ((int32_t)((inst) << 8) >> 8) // sign-extended 24-bit
#define BC_MAKE(op, arg) (((uint32_t)(op) << 24) | ((arg) & 0x00FFFFFF))
// ============================================================================
// Opcode definitions
// ============================================================================
typedef enum {
// Stack operations (0x00-0x0F)
OP_NOP = 0x00, // no-op
OP_POP = 0x01, // pop TOS
OP_DUP = 0x02, // duplicate TOS
OP_SWAP = 0x03, // swap TOS and TOS-1
OP_ROT3 = 0x04, // rotate top 3: [a,b,c] -> [b,c,a]
OP_DUP2 = 0x05, // duplicate TOS and TOS-1
OP_POPN = 0x06, // pop arg items from stack
// Constants (0x10-0x1F)
OP_CONST = 0x10, // push constant pool[arg]
OP_UNDEF = 0x11, // push undefined
OP_NULL = 0x12, // push null
OP_TRUE = 0x13, // push true
OP_FALSE = 0x14, // push false
OP_ZERO = 0x15, // push 0
OP_ONE = 0x16, // push 1
OP_IMM_I8 = 0x17, // push signed 8-bit immediate (in arg)
OP_IMM_I24 = 0x18, // push signed 24-bit immediate
OP_GLOBAL_THIS= 0x19, // push globalThis
// Arithmetic (0x20-0x2F)
OP_ADD = 0x20, // TOS = TOS-1 + TOS
OP_SUB = 0x21, // TOS = TOS-1 - TOS
OP_MUL = 0x22, // TOS = TOS-1 * TOS
OP_DIV = 0x23, // TOS = TOS-1 / TOS
OP_MOD = 0x24, // TOS = TOS-1 % TOS
OP_EXP = 0x25, // TOS = TOS-1 ** TOS
OP_NEG = 0x26, // TOS = -TOS
OP_POS = 0x27, // TOS = +TOS (to number)
OP_INC = 0x28, // TOS = TOS + 1
OP_DEC = 0x29, // TOS = TOS - 1
OP_INC_LOCAL = 0x2A, // ++locals[arg], push result
OP_DEC_LOCAL = 0x2B, // --locals[arg], push result
OP_POST_INC_LOCAL = 0x2C, // locals[arg]++, push old value
OP_POST_DEC_LOCAL = 0x2D, // locals[arg]--, push old value
// Bitwise (0x30-0x3F)
OP_BITOR = 0x30, // TOS = TOS-1 | TOS
OP_BITAND = 0x31, // TOS = TOS-1 & TOS
OP_BITXOR = 0x32, // TOS = TOS-1 ^ TOS
OP_BITNOT = 0x33, // TOS = ~TOS
OP_SHL = 0x34, // TOS = TOS-1 << TOS
OP_SHR = 0x35, // TOS = TOS-1 >> TOS (signed)
OP_USHR = 0x36, // TOS = TOS-1 >>> TOS (unsigned)
// Comparison (0x40-0x4F)
OP_EQ = 0x40, // TOS = TOS-1 == TOS
OP_NE = 0x41, // TOS = TOS-1 != TOS
OP_SEQ = 0x42, // TOS = TOS-1 === TOS
OP_SNE = 0x43, // TOS = TOS-1 !== TOS
OP_LT = 0x44, // TOS = TOS-1 < TOS
OP_LE = 0x45, // TOS = TOS-1 <= TOS
OP_GT = 0x46, // TOS = TOS-1 > TOS
OP_GE = 0x47, // TOS = TOS-1 >= TOS
// Logical (0x50-0x5F)
OP_NOT = 0x50, // TOS = !TOS
OP_TYPEOF = 0x51, // TOS = typeof TOS
OP_INSTANCEOF = 0x52, // TOS = TOS-1 instanceof TOS
OP_IN = 0x53, // TOS = TOS-1 in TOS
OP_VOID = 0x54, // TOS = void TOS (always undefined)
OP_DELETE = 0x55, // TOS = delete TOS (for delete identifier)
// Control flow (0x60-0x6F)
OP_JMP = 0x60, // pc = arg (absolute)
OP_JMP_REL = 0x61, // pc += sarg (relative, signed)
OP_JT = 0x62, // if (TOS) pc = arg; pop
OP_JF = 0x63, // if (!TOS) pc = arg; pop
OP_JT_REL = 0x64, // if (TOS) pc += sarg; pop
OP_JF_REL = 0x65, // if (!TOS) pc += sarg; pop
OP_JNULLISH = 0x66, // if (TOS === null || TOS === undefined) pc = arg; NO pop
OP_LOOP = 0x67, // backward jump (for loop optimization hints)
OP_JT_KEEP = 0x68, // if (TOS) pc = arg; keep TOS (for ||)
OP_JF_KEEP = 0x69, // if (!TOS) pc = arg; keep TOS (for &&)
OP_CASE = 0x6A, // switch case: if TOS-1 === TOS, pop & jump, else pop TOS only
OP_JNULLISH_POP = 0x6B, // if (TOS === null || TOS === undefined) pc = arg; pop
// Variables (0x70-0x7F)
OP_LOAD_LOCAL = 0x70, // push locals[arg]
OP_STORE_LOCAL= 0x71, // locals[arg] = TOS; pop
OP_LOAD_GLOBAL= 0x72, // push global[names[arg]]
OP_STORE_GLOBAL=0x73, // global[names[arg]] = TOS; pop
OP_LOAD_UPVAL = 0x74, // push upvalues[arg]
OP_STORE_UPVAL= 0x75, // upvalues[arg] = TOS; pop
OP_LOAD_NAME = 0x76, // push scope lookup names[arg]
OP_STORE_NAME = 0x77, // scope[names[arg]] = TOS; pop
OP_DEF_VAR = 0x78, // define var in current scope (for hoisting)
OP_DEF_LET = 0x79, // define let in current block scope
OP_DEF_CONST = 0x7A, // define const in current block scope
OP_DEL_NAME = 0x7B, // delete names[arg] from scope
OP_STORE_LOCAL_KEEP = 0x7C, // locals[arg] = TOS; keep TOS
OP_STORE_NAME_KEEP = 0x7D, // scope[names[arg]] = TOS; keep TOS
// Objects & Arrays (0x80-0x8F)
OP_NEW_OBJ = 0x80, // push {}
OP_NEW_ARR = 0x81, // push []
OP_GET_PROP = 0x82, // TOS = TOS[names[arg]]; (replaces TOS)
OP_SET_PROP = 0x83, // TOS-1[names[arg]] = TOS; pop 2, push TOS
OP_GET_ELEM = 0x84, // TOS = TOS-1[TOS]; pop 1
OP_SET_ELEM = 0x85, // TOS-2[TOS-1] = TOS; pop 2, push TOS
OP_DEL_PROP = 0x86, // TOS = delete TOS[names[arg]]
OP_DEL_ELEM = 0x87, // TOS = delete TOS-1[TOS]
OP_INIT_PROP = 0x88, // obj init: TOS-1[names[arg]] = TOS, pop value keep obj
OP_INIT_ELEM = 0x89, // arr init: TOS-1.push(TOS), pop value keep arr
OP_SPREAD = 0x8A, // spread TOS into array/object on TOS-1
OP_GET_SUPER = 0x8B, // TOS = super[names[arg]]
OP_SET_SUPER = 0x8C, // super[names[arg]] = TOS; pop, push TOS
OP_GET_PROP_OPT = 0x8D, // TOS = TOS?.[names[arg]] (optional chain)
OP_GET_ELEM_OPT = 0x8E, // TOS = TOS-1?.[TOS] (optional chain)
OP_INIT_COMPUTED = 0x8F, // obj[TOS-1] = TOS; for computed property names
// Functions (0x90-0x9F)
OP_CALL = 0x90, // call TOS-arg-1 with arg arguments
OP_CALL_METHOD= 0x91, // obj.method(args): TOS-arg-1=obj, TOS-arg=method, args on stack
OP_NEW = 0x92, // new TOS-arg with arg arguments
OP_RET = 0x93, // return TOS
OP_RET_UNDEF = 0x94, // return undefined
OP_CLOSURE = 0x95, // create closure from func_pool[arg]
OP_THIS = 0x96, // push this
OP_ARGS = 0x97, // push arguments object
OP_REST = 0x98, // collect rest params starting at arg
OP_SUPER = 0x99, // push super
OP_NEW_TARGET = 0x9A, // push new.target
OP_CALL_OPT = 0x9B, // func?.(...args) optional call
OP_SUPER_CALL = 0x9C, // super(...args) with arg arguments
OP_SPREAD_ARG = 0x9D, // mark TOS as spread argument for next call
// Iterators & Generators (0xA0-0xAF)
OP_GET_ITER = 0xA0, // TOS = TOS[Symbol.iterator]()
OP_ITER_NEXT = 0xA1, // push {value, done} = TOS.next()
OP_FOR_IN = 0xA2, // setup for-in iteration
OP_FOR_OF = 0xA3, // setup for-of iteration
OP_YIELD = 0xA4, // yield TOS
OP_YIELD_STAR = 0xA5, // yield* TOS
OP_AWAIT = 0xA6, // await TOS
OP_ITER_CLOSE = 0xA7, // close iterator (for break/return in for-of)
OP_ASYNC_ITER = 0xA8, // TOS = TOS[Symbol.asyncIterator]()
// Exception handling (0xB0-0xBF)
OP_THROW = 0xB0, // throw TOS
OP_TRY_START = 0xB1, // arg = catch handler offset
OP_TRY_END = 0xB2, // end try block
OP_CATCH = 0xB3, // catch handler (binds exception to local)
OP_FINALLY = 0xB4, // finally handler
OP_RETHROW = 0xB5, // rethrow current exception
OP_EXCEPTION = 0xB6, // push current exception value
// Scope (0xC0-0xCF)
OP_PUSH_SCOPE = 0xC0, // create new block scope
OP_POP_SCOPE = 0xC1, // exit block scope
OP_PUSH_WITH = 0xC2, // enter with(TOS) scope
OP_POP_WITH = 0xC3, // exit with scope
// Classes (0xD0-0xDF)
OP_CLASS = 0xD0, // create class from constructor func[arg]
OP_CLASS_EXTEND = 0xD1, // set TOS as superclass for class on TOS-1
OP_INIT_METHOD = 0xD2, // add method TOS to class TOS-1, name=names[arg]
OP_INIT_GETTER = 0xD3, // add getter TOS to class TOS-1, name=names[arg]
OP_INIT_SETTER = 0xD4, // add setter TOS to class TOS-1, name=names[arg]
OP_INIT_STATIC = 0xD5, // add static method TOS to class TOS-1
OP_INIT_STATIC_GET = 0xD6, // add static getter
OP_INIT_STATIC_SET = 0xD7, // add static setter
OP_INIT_FIELD = 0xD8, // initialize instance field
OP_INIT_PRIVATE = 0xD9, // initialize private field/method
// Template literals (0xE0-0xEF)
OP_TEMPLATE = 0xE0, // build template literal, arg = num parts
OP_TAGGED_TEMPLATE = 0xE1, // tagged template call
// Destructuring (0xE8-0xEF)
OP_UNPACK_ARR = 0xE8, // unpack array: TOS = iterable, pushes elements
OP_UNPACK_OBJ = 0xE9, // unpack object: TOS = object, uses names for keys
OP_UNPACK_REST = 0xEA, // collect remaining elements into array/object
// Misc (0xF0-0xFF)
OP_DEBUG = 0xF0, // debugger statement
OP_LINE = 0xF1, // source line number for debugging
OP_COL = 0xF2, // source column for debugging
OP_FILENAME = 0xF3, // source filename index
OP_HALT = 0xFF, // stop execution
} bc_opcode_t;
// ============================================================================
// Bytecode function prototype
// ============================================================================
typedef struct bc_func {
bc_inst_t *code; // instruction array
uint32_t code_len; // number of instructions
uint32_t code_cap; // allocated capacity
jsval_t *constants; // constant pool
uint32_t const_len;
uint32_t const_cap;
char **names; // name table for variables/properties
uint32_t names_len;
uint32_t names_cap;
uint8_t arity; // number of parameters
uint8_t nlocals; // number of local variables (including params)
const char *name; // function name (for debugging)
} bc_func_t;
// ============================================================================
// Bytecode chunk - a compiled unit of code (module/script level)
// ============================================================================
typedef struct {
bc_inst_t *code; // instruction array
uint32_t code_len; // number of instructions
uint32_t code_cap; // allocated capacity
jsval_t *constants; // constant pool
uint32_t const_len; // number of constants
uint32_t const_cap; // allocated capacity
char **names; // name table for variables/properties
uint32_t names_len;
uint32_t names_cap;
bc_func_t **functions; // function table
uint32_t func_len;
uint32_t func_cap;
uint16_t *lines; // line number table (1:1 with code)
const char *filename;
uint8_t nlocals; // number of top-level locals
} bc_chunk_t;
// ============================================================================
// VM state
// ============================================================================
#define BC_STACK_MAX 4096
#define BC_CALL_MAX 256
#define BC_LOCALS_MAX 256
typedef struct bc_frame {
bc_func_t *func; // function being executed (NULL for top-level)
bc_chunk_t *chunk; // chunk (for top-level or constants access)
uint32_t ip; // instruction pointer
uint32_t bp; // base pointer (stack frame start)
jsval_t locals[BC_LOCALS_MAX]; // local variables
uint8_t nlocals;
} bc_frame_t;
typedef struct bc_vm {
struct js *js; // reference to JS runtime (for value ops)
jsval_t stack[BC_STACK_MAX];
uint32_t sp; // stack pointer
bc_frame_t frames[BC_CALL_MAX];
uint32_t fp; // frame pointer
jsval_t globals[BC_LOCALS_MAX]; // global variables
uint8_t nglobals;
bool has_error;
jsval_t error;
} bc_vm_t;
// ============================================================================
// API
// ============================================================================
// Chunk operations
bc_chunk_t *bc_chunk_new(void);
void bc_chunk_free(bc_chunk_t *chunk);
uint32_t bc_emit(bc_chunk_t *chunk, bc_inst_t inst);
uint32_t bc_emit_op(bc_chunk_t *chunk, bc_opcode_t op);
uint32_t bc_add_const(bc_chunk_t *chunk, jsval_t val);
uint32_t bc_add_name(bc_chunk_t *chunk, const char *name);
void bc_patch(bc_chunk_t *chunk, uint32_t offset, bc_inst_t inst);
// Function operations
bc_func_t *bc_func_new(const char *name, uint8_t arity);
void bc_func_free(bc_func_t *func);
uint32_t bc_func_emit(bc_func_t *func, bc_inst_t inst);
uint32_t bc_func_emit_op(bc_func_t *func, bc_opcode_t op);
uint32_t bc_func_add_const(bc_func_t *func, jsval_t val);
uint32_t bc_func_add_name(bc_func_t *func, const char *name);
uint32_t bc_add_func(bc_chunk_t *chunk, bc_func_t *func);
// VM operations
bc_vm_t *bc_vm_new(struct js *js);
void bc_vm_free(bc_vm_t *vm);
void bc_vm_reset(bc_vm_t *vm);
jsval_t bc_vm_run(bc_vm_t *vm, bc_chunk_t *chunk);
jsval_t bc_vm_call(bc_vm_t *vm, bc_func_t *func, jsval_t *args, int nargs);
void bc_vm_push(bc_vm_t *vm, jsval_t val);
jsval_t bc_vm_pop(bc_vm_t *vm);
jsval_t bc_vm_peek(bc_vm_t *vm, int distance);
void bc_vm_set_global(bc_vm_t *vm, uint8_t slot, jsval_t val);
jsval_t bc_vm_get_global(bc_vm_t *vm, uint8_t slot);
// Compiler
bc_chunk_t *bc_compile(struct js *js, const char *code, size_t len);
bc_chunk_t *bc_compile_program(struct js *js, const char *code, size_t len);
void bc_compile_debug(struct js *js, const char *code, size_t len);
jsval_t bc_compile_run(struct js *js, const char *code, size_t len);
jsval_t bc_run_program(struct js *js, const char *code, size_t len);
// Debug
void bc_disassemble(bc_chunk_t *chunk, const char *name);
void bc_disassemble_func(bc_func_t *func);
void bc_disassemble_inst(bc_chunk_t *chunk, uint32_t offset);
void bc_disassemble_func_inst(bc_func_t *func, uint32_t offset);
const char *bc_opcode_name(bc_opcode_t op);
#endif // ANT_BYTECODE_H

File Metadata

Mime Type
text/x-c
Expires
Thu, Mar 26, 9:12 PM (1 d, 22 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
512251
Default Alt Text
bytecode.h (13 KB)

Event Timeline