핵심 요약
- Rust로 JS 파서를 리팩터링하던 개발자가 불리언 캐스팅 최적화 후 알 수 없는 파싱 에러를 겪었습니다.
- 'if-else'로 되돌리면 멀쩡히 작동해, 의심 끝에 어셈블리를 까보며 실제 컴파일러 문제를 확인하게 되었습니다.
- 평소엔 99% 개발자 착각이지만 이번만큼은 진짜 '컴파일러 탓'이었던 드문 케이스입니다.
요약 Rust로 자체 JavaScript 엔진 파서를 리팩터링하던 개발자가 실제로 컴파일러 버그를 마주친 드문 경험을 공유했습니다.
개발자는 렉서의 소비 함수인 `consume_test`를 리팩터링하면서 분기문(`if-else`)을 제거하고 코드 미학 및 생성되는 어셈블리 바이트를 줄이기 위해 `self.0 += x as u32;` 형태로 불리언을 정수로 캐스팅하는 최적화를 시도했습니다. 개별 어셈블리를 확인했을 때 분기 없이 깔끔하게 동작할 것으로 기대했으나, 막상 단순한 `for` 루프 파싱 명령을 실행하자 곧바로 파싱 에러(E079)가 발생했습니다.
놀란 개발자가 `if x { 1 } else { 0 }` 형태의 명시적 분기 코드로 되돌리자 코드는 다시 정상 작동했습니다. 평소 수백 번 작성했던 `bool as u32` 캐스팅 문법 자체에 문제가 없음을 확신한 개발자는, 모든 프로그래머가 버그를 만났을 때 속으로 외치지만 대개는 착각인 그 말—"내 잘못이 아니라 컴파일러 탓이다!"를 떠올리며 어셈블리 디컴파일 분석에 돌입했습니다.
작성자는 Cargo 대신 TypeScript와 Deno로 직접 구축한 빌드 시스템의 분석 도구를 활용해 최적화 플래그(-Copt-level=3, LTO 등)와 함께 컴파일된 바이너리의 실제 어셈블리 코드를 추출해 어디서 컴파일러의 최적화 오동작이 발생했는지 원인을 추적했습니다.
Sponsored · 광고