Zig로 만든 파서, 메모리 레이아웃 최적화로 10배 성능 향상!
Zig 언어 기반 파서 'Yuku'가 npm 대안 대비 3~10배 빠른 성능을 달성함
데이터 지향 설계(Data-Oriented Design)를 통해 메모리 접근 최적화 및 포인터 대신 인덱스 사용을 핵심으로 함
AST 노드 표현 방식을 개선하여 캐시 효율성을 높이고, 단일 할당 및 해제로 오버헤드를 줄임
문자열 및 유니코드 처리에서 제로 카피(Zero-copy)와 압축된 테이블을 활용하여 성능 저하 요인을 제거함
포인터 대신 인덱스를 활용한 AST 메모리 레이아웃
전통적인 AST 구조는 별도의 메모리 할당(Separate Allocations)과 포인터 추적(Pointer Chasing)으로 인해 캐시 효율성이 낮습니다. Yuku는 이를 개선하기 위해 모든 포인터를 정수 인덱스(Integer Index)로 대체하고, AST 노드를 평탄한 배열(Flat Arrays) 형태로 저장합니다. 이 데이터 격리 아키텍처(Data Isolation Architecture)는 메모리 할당/해제 오버헤드를 크게 줄이고, 선형 스캔(Linear Scans)을 통해 캐시 친화적인 접근을 가능하게 합니다. 또한, 단일 할당 및 해제(Single Allocation and Free)로 전체 트리 메모리를 관리하여 효율성을 극대화합니다.
가변 길이 자식 노드 처리를 위한 스크래치 버퍼 활용
블록(Block)과 같이 가변적인 수의 자식 노드를 갖는 경우, 각 노드마다 동적 할당을 피하기 위해 스크래치 버퍼(Scratch Buffer)를 사용합니다. 파서는 각 구문 처리 시 스크래치 버퍼의 시작점을 기록하고, 완료 후 해당 지점으로 되돌려 재사용합니다. 이는 중첩된 재귀 호출(Nested Recursive Calls)에서도 효율적으로 작동하며, 한 번의 대량 복사(Bulk Copy)로 트리에 반영됩니다. 이러한 메모리 풀링(Memory Pooling) 기법은 파싱 과정에서 발생하는 메모리 파편화를 방지하고 성능을 향상시킵니다.
제로 카피(Zero-copy) 문자열 처리 및 효율적인 유니코드 식별자 검증
Yuku는 식별자나 문자열 리터럴을 파싱할 때 원본 소스 코드의 바이트 범위(Byte Range)를 문자열로 사용합니다. 이는 제로 카피(Zero-copy) 방식으로, 불필요한 문자열 복사를 방지합니다. 예외적인 경우(예: 이스케이프 시퀀스)에만 별도의 인터닝 풀(Interning Pool)을 사용하며, 이 역시 해시맵을 통해 중복을 제거합니다. 유니코드 식별자 검증 시에는 압축된 비트 테이블(Compressed Bit Tables)을 사용하여 메모리 사용량을 512KB에서 29KB로 줄였고, ASCII 문자의 경우 별도의 컴파일 타임 테이블(Compile-time Table)을 사용하여 유니코드 경로를 완전히 우회합니다.
직렬화 불필요: AST 버퍼를 와이어 포맷으로 활용
Yuku의 가장 큰 장점 중 하나는 평탄한 배열 기반 AST 구조가 위치 독립적인 바이트 버퍼(Position-Independent Byte Buffer) 형태라는 점입니다. 이는 별도의 직렬화 과정 없이 해당 버퍼를 그대로 JavaScript로 전달할 수 있게 합니다. JavaScript 측에서는 타입 배열 뷰(Typed Array Views)를 사용하여 버퍼에서 직접 데이터를 읽어오므로, JSON 파싱과 같은 디시리얼라이제이션 오버헤드(Deserialization Overhead)가 발생하지 않습니다. 이 구조는 데이터 격리 아키텍처(Data Isolation Architecture)를 통해 디스크 저장, 프로세스 간 공유 등 다양한 활용 가능성을 제공합니다.