Use when explaining System V AMD64, ARM AAPCS, RISC-V psABI, stack frames, variadic calls, or FFI register rules. Not for the Rust FFI binding layer: use rust-ffi.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when designing bytecode dispatch loops, choosing stack or register VM shapes, adding inline caches, or building a first JIT with mmap. Not for a language toolchain: use compiler-frontend.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
설치 방법 보기설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.
An interpreter's speed is decided by its dispatch loop and its value representation. Pick those two first; everything else is negotiable.
| Field | Bound contract |
|---|---|
| Trigger | The task implements or speeds up a bytecode interpreter, chooses dispatch strategy, designs value tagging, adds inline caches, or writes a small JIT. |
| Authority | Reversible local: writes only the interpreter source, build files, and scratch benchmark files the user names; rollback is version control. No remote mutation. |
| Side effect | Local writes to source and build outputs. JIT pages are created with mmap and mprotect inside the program under development. |
| Done | The interpreter runs the benchmark workload end to end, and a measured comparison backs every performance claim made about it. |
| Style | Trade |
|---|---|
| Stack based | Compact code, simple compiler, more dispatches per expression. CPython and Wasm sit here. |
| Register based | Fewer dispatches, better for complex expressions, needs register allocation. Lua 5 sits here. |
switch; it is correct and portable. Then compare computed goto, which gives each opcode its own indirect branch so the predictor trains per opcode. Done when: the benchmark runs and the dispatch strategy is chosen from its measurement, not from habit.// switch form: one indirect branch serves every opcode
while (1) {
uint8_t op = *ip++;
switch (op) {
case OP_ADD: { Value b = pop(); Value a = pop(); push(a + b); } break;
case OP_HALT: return;
}
}
// computed goto: one indirect branch per opcode, GCC and Clang only
static const void *dispatch_table[] = {
[OP_ADD] = &&op_add,
[OP_HALT] = &&op_halt,
};
#define DISPATCH() goto *dispatch_table[*ip++]
op_add: { Value b = pop(); Value a = pop(); push(a + b); DISPATCH(); }
op_halt: return;
Guard the goto form with #ifdef __GNUC__ and keep the switch as the fallback for other compilers.
typedef uintptr_t Value;
#define TAG_MASK 0x3u
#define MAKE_INT(x) ((((uint64_t)(int64_t)(x)) << 2) | 0x0)
#define IS_INT(v) (((v) & TAG_MASK) == 0x0)
#define INT_VAL(v) ((int64_t)(v) >> 2) // sign-extends through the tag bits
#define STACK_SIZE 4096
Value stack[STACK_SIZE];
Value *sp = stack;
#define PUSH(v) do { if (sp >= stack + STACK_SIZE) vm_error("stack overflow"); *sp++ = (v); } while (0)
#define POP() (*--sp)
struct call_site {
uint32_t cached_type; // last observed receiver type
void (*cached_method)(VM *);
uint32_t miss_count;
};
void invoke(VM *vm, struct call_site *cs, Value receiver) {
uint32_t t = value_type(receiver);
if (t == cs->cached_type) {
cs->cached_method(vm);
return;
}
cs->cached_method = lookup_method(t);
cs->cached_type = t;
cs->miss_count++;
cs->cached_method(vm);
}
Extend to a polymorphic cache of a few type and method pairs when profiling shows a site serving several stable types.
PROT_READ|PROT_WRITE memory, then switch the page to PROT_READ|PROT_EXEC before calling it. On Apple silicon, MAP_JIT plus pthread_jit_write_protect_np replaces the switch. Done when: the compiled function runs and returns the expected value.#include <sys/mman.h>
#include <string.h>
typedef int (*jit_fn)(int, int);
jit_fn compile_add(void) {
// add edi, esi ; mov eax, edi ; ret in System V argument order
static const uint8_t code[] = {
0x01, 0xF7, // add %esi, %edi
0x89, 0xF8, // mov %edi, %eax
0xC3, // ret
};
void *mem = mmap(NULL, sizeof(code), PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (mem == MAP_FAILED) return NULL;
memcpy(mem, code, sizeof(code));
mprotect(mem, sizeof(code), PROT_READ | PROT_EXEC); // W^X: never write and exec at once
return (jit_fn)mem;
}
lookup means the caches are missing. Done when: the next change on the list is justified by a profile line, not by folklore.perf record -g ./my_interp bench.bytecode
perf report --no-children
sp and ip first in the VM struct. Keeping sp in a fixed register through a global register variable is a GCC and Clang trick that costs an otherwise usable register; measure it before keeping it. Done when: the struct layout matches the access frequency.| Failure class | Behavior |
|---|---|
| Computed goto fails to compile | The compiler is not GCC or Clang, or the guard is missing. Use the switch fallback. |
| JIT page crashes on execute | The page stayed PROT_WRITE or the W^X switch ran after the call. Apply mprotect before invoking. |
| JIT code corrupts state | The emitted code broke the ABI, usually a missing save of a callee-saved register or bad alignment before call. Check the emission against the ABI. |
| Inline cache never hits | The receiver type alternates every call. Widen to a polymorphic cache or fall back to the generic path. |
| Stack overflow reported late | The push macro checked after writing. Reorder the check before the store. |
| Benchmark says the rewrite is slower | Revert. The dispatch strategy interacts with branch predictor state that the microbenchmark may not reproduce. |
A working interpreter with the chosen dispatch, value representation, and caching, plus a measured before and after for each performance change. The relative dispatch strategy figures and tiering notes are in references/benchmarks.md.
아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.
로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.
아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.
Use when explaining System V AMD64, ARM AAPCS, RISC-V psABI, stack frames, variadic calls, or FFI register rules. Not for the Rust FFI binding layer: use rust-ffi.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when configuring ADC sampling time, DMA-driven ADC, calibration, or DAC channel setup on bare-metal MCUs. Not for the DMA stream itself: use dma-baremetal.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when creating AF_XDP sockets, configuring UMEM and XSK rings, writing an XDP redirect program, or choosing copy versus zero-copy mode. Not for full kernel bypass: use dpdk.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when a completed session needs an agent-environment retrospective. Not for an engineering retrospective from telemetry: use engineering-retrospective.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when a redacted, trimmed agent transcript must be appended to a GitHub PR or issue body, with human approval and preview. Not for automated or model-initiated insertion.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when a repo needs agent setup, AGENTS.md added or made lean, CLAUDE.md audited, or agent instructions scored or pruned. Not for remote, credential, publish, deploy, or irreversible changes.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.