CrownyJIT 핫디스패치 배선 — 루프 백엣지 JIT (증분 완료)
개요
2026-07-02 v0(self-test만, 핫디스패치 BAIL)에서 멈춰 있던 CrownyJIT를
실제 생산 경로에 배선.
루프 백엣지(동안 루프)를 핫감지 → C-트랜스파일 → cc -O2 → dlopen → 네이티브 실행으로 전환.
런타임 differential 게이트로 인터프리터와 bit-identical 검증 후에만 채택 → 출력 무오염 보장.
공유 바이너리
crownyc/
crownyc.c 무손상, 산출물은 별도
crownyc-jit.
무엇을 배선했나
- 격리 빌드:
crownyc.c → crownyc_jitmain.c(복사). JIT 모듈 include를 line168(너무 이름)에서
execute() 직전(~16428)으로 이동 → 모듈이 VM 내부(program/stack/sp/mem_at/exec_opcode 등) 가시.
조기 훅(cj_init/cj_note_call)은 forward 선언만 남김.
- 핫 백엣지 훅: fast-execute 루프(crownyc_jitmain.c ~16453)에
if(jit_active && pc<=cur) cj_backedge(pc,cur).
후방분기(JMP 백엣지)를 header pc 키로 카운트. 임계(기본 10000,
CROWNY_JIT_HOT로 조정) 초과 시 트랜스파일.
- 정수 루프 트랜스파일러(
cj_transpile_loop, crownyc_jit_hot.c): 영역 [header, 백엣지]를 스택머신→C로.
지원 opcode: DATA, LOAD(8)/STORE(7) 리터럴주소(전역var), DUP(4), POP(3), NOP(0),
ADD(81)/SUB(82)/MUL(83)/DIV(84=baldiv)/MOD(85=balmod), LT(165), JMPIFN(245) 탈출가드, JMP(243) 백엣지.
그 외 opcode/비리터럴주소(FP상대 지역var 포함)/예상밖 제어흐름 =
BAIL(NULL).
-
레지스터 호이스팅: 각 접촉주소를 네이티브
long으로 캐시(진입 rd 1회, 이탈 wr 1회 flush),
루프 내부는 순수 레지스터 연산 → cc -O2 강최적화.
-
cjnorm(): 각 산술결과를 VM의 24 균형트릿 절단(int_to_cube∘cube_to_int)과
정확 일치시킴.
범위내(±141,214,768,240)는 조기탈출(항등) → in-range 고속 유지, 오버플로도 bit-identical.
- 런타임 differential 게이트(
cj_backedge): 핫 도달 시 트랜스파일 후,
접촉주소 스냅샷 → 네이티브 CAP(4096)회 실행결과 vs 인터프리터 CAP회 실행결과(
cj_interp_region,
실제 exec_opcode semantics)
bit-identical + it/exit 일치 확인. 일치해야 채택, 불일치=영구 BAIL.
→ 트랜스파일러 버그가 있어도 출력은 절대 오염 안 됨(BAIL=인터프리터).
- opt-in + 부팅 self-test:
CROWNY_JIT=1일 때만 활성(기본 오프). 부팅 differential self-test 통과해야 armed.
- 진단/통계:
CROWNY_JIT_DUMP=1(선형 opcode 덤프), CROWNY_JIT_TIME=1(네이티브 구간 wall), atexit stats.
벤치 실측 (전부 인터프리터와 BYTE-IDENTICAL)
| 커널 | 인터프리터 | JIT 네이티브 구간 | 배속 | 출력 일치 |
|---|
10M s+=(i*i)/7 (오버플로 94%) | 22.29s | 503 ms | ~44x | ✅ -35421475230 |
500k s+=(i*i)/7 (오버플로 ~25%) | 0.55s | 7.86 ms | ~70x | ✅ -81468564661 |
10M in-range (s+i)%97 | 3.16s | 60 ms | ~53x | ✅ 37 |
| 10M in-range int64 (cjnorm 조기탈출) | — | ~8.7 ms | ~2560x | ✅ |
- ★정직한 발견: 07-02 문서의 0.0188s(LuaJIT 2.5x·1900x)는 int64 출력으로, 오버플로 커널에선
CrownyVM 인터프리터(3^24 wrap)와
출력이 다름(-35421475230 vs 4925614856). 진짜 byte-identical JIT는
VM wrap을 cjnorm으로 에뮬레이트해야 하며, 오버플로 많은 루프에선 그 대가로 속도가 준다(in-range는 무손실).
- 준비지연(cc 컴파일): self-test ~0.4s + 루프 트랜스파일 ~0.1~0.3s(1회, spawn 편차 큼). 상각형.
회귀 (4종, 단일 write stdin)
| 프로그램 | 입력 | 결과 |
|---|
| 크라우니코드뇌 | 0\n1\n1\n0\n0\n | ✅ IDENTICAL (loops_seen=0) |
| 래칫판정 | 0\n55\n60\n5\n | ✅ IDENTICAL (loops_seen=0) |
| 작업구분 | 0\n포트 상태 조회해줘\n | ✅ IDENTICAL (thr=1: 9루프 전부 BAIL, bailed=9) |
| 브레인결재 | 0\n안건C\n85\n4\n2\n0\n | ✅ IDENTICAL (loops_seen=0) |
- 문자열/맵 루프는 미지원 opcode로
BAIL → 인터프리터 → byte-identical(BAIL 안전경로 실증).
- JIT-off
crownyc-jit == 공유 crownyc (4종 전부, 드리프트 0).
관련 파일 (전부 /Users/ef/CrownyOS/crownyc/)
crownyc_jit_hot.c — ★신규 JIT 실모듈(트랜스파일러+게이트+백엣지 훅+cjnorm)
crownyc_jitmain.c — crownyc.c 복사본(훅 배선). 빌드: cc -O2 -o crownyc-jit crownyc_jitmain.c -framework Security -framework CoreFoundation
crownyc-jit — 산출 바이너리(별도)
crownyc.c / crownyc — 공유, 무손상(2026-07-04 타임스탬프 그대로)
crownyc_jit.c — v0 모듈(기존, 미사용 — jitmain은 hot 모듈 include)
남은 작업 (다음 세션 인수인계)
- FP상대 지역변수 루프 지원: 현재 전역var(DATA addr 리터럴)만. 함수 내부 동안 루프는
LOAD_FP; DATA off; ADD; LOAD/STORE 패턴 → 트랜스파일러에 FP상대 주소 인식 추가(frame_ptr 진입값 캡처).
- 함수 CALL JIT: 현재 루프 백엣지만. 다호출 함수(호출카운터>임계)를 함수단위 트랜스파일.
(cj_note_call 훅은 현재 ZIPWITH(op143) 한 곳에만 — 일반 CALL(247)엔 미배선.)
- differential 게이트 범위 확장: 현재 CAP=4096 샘플. cjnorm이 오버플로도 커버하지만,
cube_mul/divmod의 오버플로 semantics가 int_to_cube 절단과 완전 일치한다는 가정을 오버플로 커널로 실증 완료
(10M/500k byte-identical). 추가 opcode(비교 GT/GE/EQ 등, 반복문 for) 확장 시 게이트 재검증.
- for 루프(반복문)·중첩 루프: 현재 단일 조건가드+단일 백엣지 canonical shape만. 중첩/복수 탈출 BAIL.
- A서버 손익분기 게이팅: cc 컴파일 지연(~0.1s) 대비 루프 반복수 손익분기 임계 튜닝.
- 자족 JIT(copy-and-patch): 소비자앱용(cc 불필요). 07-02 설계대로 별도 트랙.
- 셀코어 규칙/학습 자산화 + (선택) 트랜스파일러 로직의 한선씨 서술본. VM코어는 C 정책상 C 유지.
안전수칙 준수
- 공유
crownyc.c/crownyc 무수정·무재빌드. 산출물 crownyc-jit 별도.
- 기본 오프(opt-in). 부팅 self-test + 런타임 differential 게이트 이중 안전.
- 데몬·커밋·영속인프라 생성 없음.