- MicroQuickJS(MQuickJS) 는 임베디드 시스템용으로 설계된 초경량 JavaScript 엔진으로, 약 10kB RAM과 100kB ROM만으로 실행 가능
- QuickJS와 유사한 속도를 유지하면서도 메모리 사용량을 줄이기 위해 트레이싱 가비지 컬렉터와 UTF-8 문자열 저장 방식을 채택
- 지원 언어는 ES5에 가까운 제한된 JavaScript 부분집합이며, 오류 가능성이 높은 구문을 금지하는 엄격 모드(strict mode) 만 허용
-
REPL 도구
mqjs를 통해 스크립트 실행, 바이트코드 저장 및 메모리 제한 설정이 가능하며, 생성된 바이트코드는 ROM에서 직접 실행 가능 - 전체 엔진과 표준 라이브러리가 ROM에 상주해 빠른 초기화와 낮은 메모리 소비를 실현, 임베디드 환경에서의 JavaScript 실행 효율성을 높임
소개
-
MicroQuickJS(MQuickJS) 는 임베디드 시스템을 대상으로 하는 JavaScript 엔진으로, 10kB RAM과 100kB ROM(ARM Thumb-2 코드 포함)에서 동작
- 속도는 QuickJS와 유사
- ES5에 가까운 부분집합만 지원하며, 비효율적이거나 오류 가능성이 높은 구문을 금지하는 엄격 모드(strict mode) 로만 작동
- QuickJS와 코드 일부를 공유하지만, 내부 구조는 메모리 절약을 위해 완전히 다르게 설계됨
- 트레이싱 가비지 컬렉터, CPU 스택 미사용, UTF-8 문자열 저장 방식 사용
REPL
- REPL 명령은
mqjs이며, 스크립트 실행, 평가, 인터랙티브 모드, 메모리 제한 설정, 바이트코드 저장 등을 지원- 예:
./mqjs --memory-limit 10k tests/mandelbrot.js
- 예:
-
-o옵션으로 컴파일된 바이트코드를 파일로 저장 가능- 저장된 바이트코드는
./mqjs mandelbrot.bin으로 실행 가능
- 저장된 바이트코드는
- 바이트코드는 CPU의 엔디언 및 워드 길이(32/64비트) 에 따라 다르며,
-m32옵션으로 32비트용 바이트코드 생성 가능 -
--no-column옵션으로 디버그 정보의 열 번호 제거 가능
엄격 모드
-
strict mode만 허용하며,
with키워드 사용 불가, 전역 변수는 반드시var로 선언해야 함 -
배열의 구멍(hole) 허용 안 함
- 예:
a[10] = 2는 TypeError 발생 - 구멍이 있는 배열이 필요하면 일반 객체 사용
- 예:
- 전역 eval만 지원, 지역 변수 접근 불가
-
값 박싱(value boxing) 비지원 (
new Number(1)등)
JavaScript 부분집합
- strict mode 기반, ES5 호환성 중심
- Array 객체는 구멍이 없으며, 범위를 벗어난 인덱스 접근은 오류
-
for in은 객체의 자체 속성만 순회,for of는 배열만 지원 - 글로벌 객체는 존재하지만 getter/setter 불가, 직접 생성한 속성은 전역 변수로 노출되지 않음
-
정규식(Regexp) 은 ASCII만 대소문자 구분 처리,
/./은 UTF-16 대신 유니코드 코드포인트 단위로 매칭 -
문자열 함수는 ASCII만 처리 (
toLowerCase,toUpperCase) -
Date는
Date.now()만 지원 - 추가 지원 기능:
-
for of, Typed arrays,\u{hex}문자열 리터럴 -
Math 함수:
imul,clz32,fround,trunc,log2,log10 -
지수 연산자, 정규식 플래그(s, y, u) , 문자열 함수(
replaceAll,trimStart,trimEnd), globalThis
-
C API
-
C 라이브러리 의존성 최소화,
malloc,free,printf미사용 -
메모리 버퍼를 직접 제공해야 하며, 엔진은 해당 버퍼 내에서만 메모리 할당
- 예:
ctx = JS_NewContext(mem_buf, sizeof(mem_buf), &js_stdlib)
- 예:
-
가비지 컬렉션 방식으로 인해
JS_FreeValue()호출 불필요 - 객체 주소는 할당 시마다 이동 가능하므로,
JSValue포인터 사용 권장-
JS_PushGCRef()/JS_PopGCRef()로 안전한 참조 관리
-
- 표준 라이브러리는 ROM에 저장 가능한 C 구조체로 컴파일되어, 빠른 초기화와 낮은 RAM 사용량 달성
-
바이트코드 실행은 ROM에서 가능하며,
JS_RelocateBytecode()로 재배치 후JS_LoadBytecode()와JS_Run()으로 실행 - 수학 라이브러리(libm.c) 와 부동소수점 에뮬레이터 내장
내부 구조 및 QuickJS 비교
-
가비지 컬렉션: 참조 카운팅 대신 트레이싱·압축형 GC 사용
- 메모리 단편화 방지, 객체 크기 축소
-
값 표현: CPU 워드 크기(32/64비트)에 맞춰 설계
- 31비트 정수, 유니코드 코드포인트, 부동소수점, 메모리 블록 포인터 저장 가능
- 문자열은 UTF-8로 저장, QuickJS의 8/16비트 배열 방식보다 효율적
- C 함수는 단일 값으로 저장 가능, 속성 추가 불가
- 표준 라이브러리는 ROM에 상주하며, RAM 객체 최소화로 빠른 엔진 초기화 가능
-
바이트코드는 스택 기반이며, 간접 참조 테이블을 통해 읽기 전용 처리
- Golomb 코드로 행·열 번호 압축
-
컴파일러는 QuickJS와 유사하지만 비재귀적 파서를 사용해 C 스택 사용량 제한
- 파스 트리 없이 단일 패스 바이트코드 생성
테스트 및 벤치마크
- 기본 테스트:
make test - QuickJS 마이크로 벤치마크:
make microbench -
Octane 벤치마크(엄격 모드용 수정 버전)는 별도 다운로드 가능
- 실행:
make octane
- 실행:
라이선스
- MIT 라이선스로 배포
- 소스코드 저작권은 Fabrice Bellard와 Charlie Gordon 소유