Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

부록 D: 런타임 ABI

이 부록에서는 최종 네이티브 컴파일러와 fun-rt-24를 설명합니다. 지원 호스트는 64비트 워드와 포인터를 사용하는 Apple Silicon macOS와 x86-64/AArch64 Linux입니다. 이 ABI는 이번 판의 컴파일러 내부에서만 쓰입니다. 사용자가 작성하는 FFI는 없습니다.

워드와 객체

호출 경계를 넘는 모든 소스 값은 LLVM에서는 i64, Rust에서는 u64입니다. 최하위 비트가 1이면 즉시값(immediate)을 나타냅니다. 최하위 비트가 0이면 정렬된 객체 주소를 나타냅니다. 단, 초기화 중에 임시로 쓰이는 0 자리 표시자는 예외입니다.

값인코딩
Int(n << 1) | 1, 부호 있는 63비트 2의 보수
Char왼쪽으로 1비트 시프트하고 최하위 비트를 1로 설정한 유니코드 스칼라
인자 없는 생성자(tag << 1) | 1
힙 값8바이트로 정렬된 헤더의 주소

해석은 기대 타입에 따라 정해집니다. 따라서 False, [], Nothing, ()는 모두 워드 값 1을 가질 수 있지만 서로 바꿔 쓸 수는 없습니다.

header:  [ payload size: 32 bits | constructor tag: 24 bits | kind: 8 bits ]
object:  [ header ][ payload word 0 ][ payload word 1 ] ...

크기는 페이로드 워드의 개수입니다. 생성자 태그는 각 데이터 타입 안에서만 유효하며 선언 순서를 따릅니다. 고정된 Prelude 태그는 False=0, True=1, []=0, (:)=1, Nothing=0, Just=1, ()=0, 그리고 LT=0, EQ=1, GT=2입니다.

종류ID페이로드추적 필드
CON0생성자 필드전부
CLOSURE1느린 코드 주소, 원시 항수, 캡처캡처
PAP2클로저 워드, 원시 인자 개수, 인자들클로저와 인자들
DOUBLE3Binary64 비트없음
STRING4원시 바이트 길이, 워드 단위로 패딩된 UTF-8 바이트없음
FORWARD5수집 중의 목적지 주소수집기 전용 표식

인자 없는 생성자에는 힙 할당이 없습니다. 따라서 이동 가능한 모든 객체에는 포워딩 주소를 담을 공간이 있습니다. 문자열은 저장 시에는 바이트 수를 세고, length 계열 프리미티브에서는 유니코드 스칼라 수를 셉니다.

진입점과 적용

진입점호출 규약과 시그니처
알려진 함수tailcc i64 f(i64 env, i64 a1, ..., i64 an)
느린 어댑터C: u64 slow(u64 closure, const u64 *args)
일반 적용C: u64 rt_apply(u64 closure, usize n, const u64 *args)
소규모 적용C: u64 rt_applyN(u64 closure, u64 a1, ..., u64 aN), N=1..4
PAP 생성C: u64 rt_make_pap(u64 closure, usize n, const u64 *args)
재귀 캡처 패치C: void rt_closure_set(u64 closure, usize index, u64 value)

느린 어댑터는 정확히 함수의 구문적 항수만큼 인자를 받습니다. 일반 적용 루틴은 PAP 인자를 평탄화하거나, 정확한 호출을 수행하거나, 남은 인자를 반환된 함수에 적용합니다. 네이티브 꼬리 전달이 보장되는 것은 알려진 꼬리 호출뿐입니다. C와 tailcc 사이를 넘나드는 호출은 ABI 어댑터 프레임을 유지합니다.

모든 인자는 엄격하며 이미 평가된 상태입니다. 원시 인자 배열은 호출이 진행되는 동안 읽을 수 있는 상태로 남아 있어야 합니다. 수집기는 배열의 값을 재배치할 수 있으므로, 지속되는 버퍼는 루트 소유자에게 속합니다. 느린 진입점은 어떤 할당보다도 먼저 인자를 불러오고 생성된 루트 프레임을 설정합니다.

할당과 루트

내보내는 함수계약
void rt_init()Boehm을 초기화하고 호출한 런타임 스레드를 등록
u64 *rt_alloc(usize words)헤더를 포함하여 스캔 대상 저장 공간을 확보
u8 *rt_alloc_atomic(usize bytes)포인터가 없는 저장 공간을 확보
void rt_use_copying()초기화 전에 단일 스레드 이동 힙을 선택
void rt_roots_push(u64 *slots, usize n)쓰기 가능하고 초기화된 생성 루트 범위를 등록
void rt_roots_pop()현재 생성 루트 범위를 제거
void rt_global_root(u64 *slot)프로세스 수명 동안 정적 전역 변수를 등록

할당은 반환하기 전에 수집을 수행할 수 있습니다. 호출자는 추가 할당을 하기 전에 새 객체 전체를 초기화합니다. 네이티브 시작 과정은 함수를 설치하거나 값을 평가하기 전에 전역 변수를 등록합니다. 정적 문자열 객체는 불변이며 이동하지 않습니다. Boehm 백엔드는 이들의 주소 테이블도 유지합니다.

Rust의 Roots와 GlobalRoot 소유자는 drop될 때까지 안정적인 버퍼를 등록합니다. 이동 수집기는 이들의 셀을 갱신합니다. 빌린 문자열 슬라이스와 루트로 등록되지 않은 포인터 워드의 복사본은 할당 이후까지 살아남아서는 안 됩니다. 프리미티브 익스포트는 결과를 할당하기 전에 문자열을 소유된 Rust 값으로 디코딩합니다.

프리미티브, 오류, 종료

모든 prim_* 연산에는 rt_prim_*라는 이름의 C 익스포트가 있습니다. 각 인자와 반환 값은 워드이며, unit 결과도 마찬가지입니다. Integer와 Double 산술 연산은 대신 인라인으로 생성될 수도 있습니다. 간단하지 않은 연산은 안전한 Rust 구현을 인터프리터와 공유합니다.

프리미티브 계열인자결과
intAdd/Sub/Mul/Quot/Rem/Div/ModInt 워드 두 개Int 워드
intNegIntInt
intEq/Lt/LeInt 워드 두 개Bool 즉시값
dblAdd/Sub/Mul/Div/Pow박싱된 Double 두 개박싱된 Double
dblNeg/Sqrt/Exp/Log/Sin/Cos박싱된 Double박싱된 Double
dblEq/Lt/Le박싱된 Double 두 개Bool 즉시값
intToDbl, dblFloor/Round/Truncate변환할 원본 수치 값변환된 수치 값
chrOrd, chrChr, chrEq/Lt문자/정수 피연산자정수/문자/Bool
strAppend/Length/Eq/Compare문자열 한 개 또는 두 개문자열/Int/Bool/Int
strUnpack, strPack문자열 또는 문자 리스트문자 리스트 또는 문자열
showInt/Double/Char/String이름에 해당하는 타입의 값 하나문자열
readInt문자열Maybe Int
putStr, getLine문자열 또는 unitUnit 또는 문자열
trace문자열 메시지, 임의의 값같은 값
error, exit문자열 또는 Int반환하지 않음

정수 결과는 2⁶³을 법으로 하여 순환합니다. 부동소수점 변환은 Int 범위로 포화되며, NaN은 0이 됩니다. 0으로 나누기, 잘못된 문자, getLine에서의 EOF, 매치 실패는 런타임 오류입니다.

내보내는 함수동작
rt_error(u64 string)stdout을 플러시하고 fun: MESSAGE를 출력한 뒤 1로 종료합니다
rt_pattern_fail(const char *file, u32 line, u32 col)소스 위치를 보고하고 1로 종료합니다
rt_div_zero()fun: divide by zero를 보고하고 1로 종료합니다
rt_exit(i32 code)stdout을 플러시하고 종료합니다

생성된 C main은 런타임을 초기화하고, 전역 값을 의존성 순서대로 평가하고, 소스의 main을 유닛 워드 1에 적용한 뒤, 성공적으로 종료합니다. 런타임 패닉은 생성된 코드를 거슬러 되감기(unwinding)하지 않고 즉시 중단(abort)합니다.


원문 © Stephen Diehl · Write You a Haskell · 산문 CC BY-SA 4.0 · 코드 MIT
yeokja 한국어 번역 · Anthropic 사의 claude-opus-5-5 모델을 활용하여 번역되었으며 학습을 모두 비허용한 상태로 작업하였습니다 · 이 문서는 원문을 수정한 비공식 번역본이며 산문은 같은 CC BY-SA 4.0으로 제공합니다.