diff options
| author | eunhhu <[email protected]> | 2026-09-24 17:14:54 +0100 |
|---|---|---|
| committer | eunhhu <[email protected]> | 2026-09-24 17:14:54 +0100 |
| commit | b1ce1927022d374198441afafeb27199fc8a052a (patch) | |
| tree | 6021f175f4c67ed03b44240eaa2f90d846f12f6f /docs/design/003-module-contract.md | |
| parent | d34f9426d5317a1948f12f229439946728bc342a (diff) | |
| download | pure-b1ce1927022d374198441afafeb27199fc8a052a.tar.gz pure-b1ce1927022d374198441afafeb27199fc8a052a.zip | |
Establish native micro runtime checkpoint
Diffstat (limited to 'docs/design/003-module-contract.md')
| -rw-r--r-- | docs/design/003-module-contract.md | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/docs/design/003-module-contract.md b/docs/design/003-module-contract.md new file mode 100644 index 0000000..1fcdb76 --- /dev/null +++ b/docs/design/003-module-contract.md @@ -0,0 +1,119 @@ +# 모듈 계약 초안 0.1 + +상태: **제안**. 이 문서는 논리적 호출·수명·호환 조건과 데이터 레코드를 정한다. +동적 로더·네이티브 함수 테이블·Wasm 모듈 연결은 아직 구현하지 않았다. +[C17 레코드 헤더](abi-v0.h)는 데이터 표현을 검토·컴파일하기 위한 초안이며 실행 가능한 모듈 SDK가 아니다. + +## 1. 세 가지 경계 + +| 경계 | 첫 방침 | +|---|---| +| Pure 내부 연산·모듈 | 값 종류, 버퍼 접근, 길이, 예산, 진행·오류·완료 의미를 명시 | +| 플랫폼의 네이티브 함수 호출 | 해당 타깃의 기존 C 호출 규약을 사용. 레지스터·스택 규약을 새로 발명하지 않음 | +| 저장·전송 형식 | 별도 버전·필드 폭·바이트 순서·검증·호환 규칙을 설계한 뒤 도입 | + +구조체·포인터를 파일로 덤프하는 것을 영속 형식으로 삼지 않는다. 반대로 같은 프로세스에서 +모듈을 호출할 때마다 데이터 전체를 직렬화할 필요도 없다. +Arm의 호출 규약도 데이터 모델·포인터·정렬·패딩을 다룬다. 이것이 Apple을 포함한 모든 +플랫폼의 호출 차이를 없애주는 것은 아니므로 타깃별 경계를 검증해야 한다. +[AAPCS64 고정 원문](https://github.com/ARM-software/abi-aa/blob/0948ccc42ed2ea6f1ae88a3cbd5438d904709112/aapcs64/aapcs64.rst#L635-L695) + +Wasm 선형 메모리의 숫자 저장은 little-endian이다. Wasm 어댑터는 그 규칙을 따르며, +네이티브 레코드를 포인터 그대로 다른 인스턴스나 프로세스에 넘기지 않는다. +[WebAssembly 숫자 저장](https://webassembly.github.io/spec/core/exec/numerics.html#storage) + +## 2. 프로파일과 버전 + +모듈마다 다음 정보를 로드 전에 확인한다. + +- 연산 계약 버전과 프로파일 ID. 첫 제안은 `0.1 / byte_stream=1`이다. +- 모듈 구현 식별자·빌드 해시·설정, 상태 스키마 식별자. 실행·재생 기록에 보관한다. +- 입력·출력 종류와 개수, 구간 최대 크기, 정렬, 문맥·임시 공간 예산. +- 동기/비동기 지원, 종료·취소 동작, 모듈 내부 외부 할당의 계측 가능 여부. + +`0.x` 동안 호환성은 정확한 버전 일치로만 허용한다. 임의로 더 높은 minor를 받아들이지 않는다. +기능 필드·상태·플래그를 알 수 없으면 작업 시작 전에 `UNSUPPORTED`로 거절한다. +이후 호환 확장을 도입하려면 필수·선택 기능의 구분과 구버전 검사를 별도로 정한다. + +현재 Workbench의 `revision`은 순환하는 적용 횟수다. ABI 버전·상태 스키마·비동기 티켓의 +대체물로 사용하지 않는다. 현재 중간 명령 번호나 Zig `Program` 메모리 배치를 모듈 파일 형식으로 고정하지 않는다. + +## 3. 첫 바이트 프로파일의 데이터 레코드 + +모든 필드는 고정 폭 정수다. 네이티브에서는 native-endian이며 C의 기본 정렬을 사용한다. +패킹 속성·C enum·bool·플랫폼별 `long`·포인터를 레코드에 넣지 않는다. +동일한 숫자 폭만으로 호출 ABI가 같아지는 것은 아니며, 함수 경계 검증은 별도다. + +| 레코드 | 크기 | 뜻 | +|---|---:|---| +| `pure_handle_v0` | 8 B | 슬롯·세대. 실행 영역 안에서만 유효 | +| `pure_span_v0` | 16 B | 버퍼 핸들·오프셋·길이 | +| `pure_step_result_v0` | 24 B | 레코드 크기·스트림 상태·오류·이번 소비량·유효 생성량·예약 필드 | +| `pure_stream_limits_v0` | 64 B | 레코드 크기·버전·프로파일·개수·예산·구간 상한·정렬 | + +이는 헤더의 크기 요구조건이며 메모리 사용량·전송량의 측정값이 아니다. +입출력 수와 `max_pending_per_context`는 첫 프로파일에서 각각 1이어야 한다. +`flags`와 `reserved`는 0이어야 한다. `struct_bytes`는 해당 크기와 정확히 일치해야 한다. +`max_input_bytes/max_output_bytes`는 1 이상이고 협상한 예산 이하, `buffer_alignment`는 +1 이상의 2의 거듭제곱이어야 한다. 호스트가 보장할 수 없는 정렬·예산은 로드 또는 open에서 거절한다. +0인 문맥·임시 예산은 해당 종류의 할당을 허용하지 않는다는 뜻이지 무제한이 아니다. + +한 요청의 길이는 `u32`, 모듈 예산·스트림의 누적 길이는 검사된 `u64`다. +JavaScript 어댑터는 `u64`를 BigInt 또는 명시적 두 워드로 전달하고 Number로 조용히 축약하지 않는다. +크기·개수·누적 산술은 실제 접근·할당 전에 검사한다. + +결과 검증 규칙: + +- `status`는 헤더의 여섯 값 중 하나다. `FAILED`에만 0이 아닌 `error`가 필요하고 다른 상태는 0이다. +- `consumed/produced`는 제공한 길이 이하이고 `MORE`는 둘 중 하나가 0보다 커야 한다. +- `reserved=0`, 레코드 크기가 일치해야 한다. 실패해도 검증된 부분 진행을 정확히 보존한다. +- 잘못된 완료는 모듈 프로토콜 오류다. 데이터는 공개하지 않고 문맥을 실패 상태로 만든다. + 접근 종료를 보장하는 신뢰 가능한 완료까지 대여를 보유한다. 길이 오류를 핑계로 진행 중 버퍼를 재사용하지 않는다. +- 헤더의 오류 번호는 이 초안의 별도 네임스페이스다. 현재 scalar VM의 오류 번호와 혼용하지 않는다. + +## 4. 논리적 제어 API + +아래는 다음 구현의 호출 의미다. 네이티브 C 함수 시그니처나 동적 로딩 심볼을 확정한 선언은 아니다. +첫 구현은 정적으로 등록한 내부 어댑터로 이 의미부터 검증한다. + +| 호출 | 결과와 수명 | +|---|---| +| `describe(module)` | 계약·기능·한도·구현 식별. 작업·대여 생성 없음 | +| `open(module, config, budget)` | 문맥 생성 또는 거절. 성공 시 문맥·숨은 내부 메모리의 예산 책임 시작 | +| `submit(context, input, output, END_INPUT)` | 런타임이 거절하거나 티켓을 접수. 준비/확정/백엔드 제출 구분은 연산 명세를 따름 | +| `cancel(ticket)` | 취소 요청을 전달한 결과. 스트림 결과나 버퍼 회수가 아님 | +| `reap(ticket)` | 아직 완료가 없으면 `WOULD_BLOCK`; 있으면 결과 회수·유효 길이 반영·대여 해제 | +| `close(context)` | 진행 작업이 있으면 `BUSY`; 없으면 내부 문맥·장기 자원 반환. 이후 핸들 무효 | + +사용하지 않는 입력이나 출력도 유효한 버퍼 핸들과 길이 0 구간으로 표시한다. +`open/submit`의 일시적 풀 포화는 `WOULD_BLOCK`, 고정 한도를 넘는 요구는 `LIMIT`, +이미 진행 요청이 있는 문맥은 `BUSY`, 잘못된 핸들·범위는 `INVALID`다. +이 접수 응답들은 `pure_step_result_v0`의 스트림 상태와 별개이며 해당 C 응답 레코드는 후속 구현에서 정한다. + +동기 어댑터도 `submit` 시 즉시 결과를 완료 슬롯에 보관하고 `reap`에서 전달할 수 있다. +호스트가 최적화로 내부 호출을 합치더라도 수명·오류·관찰 가능한 순서는 유지해야 한다. +개별 문맥은 순차 처리하며 다른 문맥 사이의 완료 순서는 제출 순서와 같다고 가정하지 않는다. + +`reap`은 요청의 완료다. 결과가 `NEED_INPUT`이면 문맥은 살아 있으며 다음 입력을 받을 수 있다. +문맥은 `DONE/FAILED/CANCELLED` 이후에도 `close`까지 예산을 차지한다. +프로그램·모듈 교체는 관련 요청·대여·열린 문맥이 모두 해소된 뒤에만 허용한다. + +## 5. 확장 범위 + +압축·인증 복호화·문서·미디어는 포맷 처리 모듈의 후보이며 모두 같은 복잡도를 갖지는 않는다. +여러 평면의 영상, 탐색 가능한 문서, 파일·네트워크의 부분 쓰기는 추가 프로파일이 필요하다. +현재 바이트 프로파일에 의미가 다른 모든 출력을 억지로 넣지 않는다. + +Pure 자체를 작은 OS로 설계한다는 [현재 방향](007-execution-domains.md)에 따라 실행·자원· +통신의 운영 모델은 Pure가 소유한다. 현재 호스트 OS는 구동 수단과 제약이며, 모듈의 의미를 +호스트의 프로세스·파일 디스크립터에 고정하지 않는다. 호스트 구동, kernel-bypass, 직접 하드웨어 +구동은 이를 실현하는 경로로 구분한다. 부팅·드라이버의 범위나 일정은 이 모듈 계약으로 확정하지 않는다. + +## 6. ABI를 구현했다고 말할 수 있는 조건 + +레코드의 `_Static_assert`가 타깃별로 컴파일되는 것은 데이터 레이아웃의 제한된 검사다. +실제 함수 호출·언어 간 호환·버전 협상·대여·완료의 검증을 대신하지 않는다. +후속 native adapter에서 함수 테이블 크기·호출 규약·오류 경계·호스트 할당 콜백·리소스 해제 책임을 +구체적인 선언으로 작성하고, 독립 C 생산자와 Zig 소비자의 실제 왕복 호출을 검사해야 한다. +Wasm 어댑터는 범위·리프트/로워·수명 검사와 복사량을 별도로 측정해야 한다. +이 단계 전에는 안정된 ABI·플러그인 호환·새 포맷 지원을 구현 완료로 보고하지 않는다. |
