mem: メモリ管理と低レベルロード/ストア
目的:
- WASM 線形メモリ上でのアロケータと基本的な load/store を提供します。
実装(アルゴリズム):
- free list と bump を併用し、8 バイト境界に整列します。
- 0..4 に heap_ptr、4..8 に free_list_head を置きます。
注意(重要):
- 領域の再利用は簡易的で、細かな最適化は行いません。
- 無効なポインタを渡すと未定義動作になります。
計算量:
- alloc_raw/free は平均 O(1) ですが、free list の探索で O(n) になり得ます。
todo memory.copy などを使って効率を上げる
#entry main
#target std
#import "std/test" as *
#import "core/mem" as *
fn main <()*>()> ():
assert_eq_i32 0 align8 0;
assert_eq_i32 8 align8 1;
assert_eq_i32 8 align8 8;
assert_eq_i32 16 align8 9;#entry main
#target std
#import "std/test" as *
#import "core/mem" as *
fn main <()*>()> ():
let p alloc_raw 4;
assert ne 0 p;
store_i32 p 123;
assert_eq_i32 123 load_i32 p;
dealloc_raw p 4;mem_size: 現在のメモリページ数を返す
目的:
- wasm の memory.size を返します。
実装(アルゴリズム):
- wasm 命令を直接実行します。
注意(重要):
- 1 ページ = 64KiB です。
- llvm では内部線形メモリの擬似ページ数を返します。
計算量:
- O(1)
mem_grow: メモリを拡張する
目的:
- pages だけメモリを拡張し、以前のページ数を返します。
実装(アルゴリズム):
- wasm の memory.grow を呼びます。
注意(重要):
- 失敗時は -1 を返します。
- llvm では擬似線形メモリの総量(64MiB)を超える要求を失敗扱いにします。
計算量:
- O(1)
align8: 8 バイト境界に切り上げる
目的:
- n を 8 の倍数に切り上げます。
実装(アルゴリズム):
- (n+7)/8*8 を計算します。
注意(重要):
- 8 バイト整列はアロケータの前提です。
計算量:
- O(1)
alloc_raw: ヒープから領域を確保する(生ポインタAPI)
目的:
- size バイトの領域を返します(失敗時は 0)。
実装(アルゴリズム):
- free list を探索し、合うブロックが無ければ bump で拡張します。
注意(重要):
- size<=0 の場合は 0 を返します。
- 返り値 0 は失敗を意味します。
計算量:
- 平均 O(1) / 最悪 O(n)
dealloc_raw: 領域を解放する(生ポインタAPI)
目的:
- ptr を free list に戻します。
実装(アルゴリズム):
- ブロック先頭に size を書き、free list 先頭へ挿入します。
注意(重要):
- ptr<=0 は無視します。
- size は alloc_raw 時のサイズと一致させてください。
計算量:
- O(1)
realloc_raw: 既存領域を再確保する(生ポインタAPI)
目的:
- サイズ変更した領域を返します。
実装(アルゴリズム):
- 新領域を確保し、必要バイトをコピーして旧領域を解放します。
注意(重要):
- ptr<=0 は新規 alloc_raw と同等です。
- new_size<=0 は解放して 0 を返します。
計算量:
- O(n)
alloc: alloc の結果を Result で返す安全API
目的:
- 失敗時に
0ではなくResult::Errを返し、呼び出し側で明示的に処理できるようにします。
実装(アルゴリズム):
alloc_rawの返値を検査し、ptr>0ならOk(ptr)、それ以外はErr(\"mem.alloc failed\")を返します。
注意(重要):
- 生ポインタが必要な場合は
alloc_rawを使います。
計算量:
- O(1)(
alloc本体を除く)
realloc: realloc の結果を Result で返す安全API
目的:
- 再確保失敗を
Resultで扱い、エラー伝播しやすくします。
実装(アルゴリズム):
new_size<=0は仕様通りOk(0)とします。realloc_rawの返値が 0 かどうかで成功/失敗を判定します。
注意(重要):
new_size>0で0が返った場合のみErrを返します。
計算量:
- O(1)(
realloc本体を除く)
dealloc: dealloc の前提を検査する安全API
目的:
- 不正な引数を早期に検出し、呼び出し側へ
Resultで返します。
実装(アルゴリズム):
ptr<=0またはsize<0をErrとし、それ以外はdealloc_raw後にOk(())を返します。
計算量:
- O(1)
load_i32: i32 を読み出す
目的:
- ptr から i32 をロードします。
実装(アルゴリズム):
- wasm の i32.load を実行します。
注意(重要):
- アラインメントは呼び出し側の責任です。
計算量:
- O(1)
store_i32: i32 を書き込む
目的:
- ptr に i32 をストアします。
実装(アルゴリズム):
- wasm の i32.store を実行します。
注意(重要):
- アラインメントは呼び出し側の責任です。
計算量:
- O(1)
load_u8: 1 バイトを読み出す
目的:
- ptr から unsigned byte を読みます。
実装(アルゴリズム):
- wasm の i32.load8_u を実行します。
注意(重要):
- 返り値は i32 に拡張されます。
計算量:
- O(1)
store_u8: 1 バイトを書き込む
目的:
- ptr に 1 バイトを書き込みます。
実装(アルゴリズム):
- wasm の i32.store8 を実行します。
注意(重要):
- v の下位 8 ビットのみが使われます。
計算量:
- O(1)
memset_u8: バイト列を同じ値で埋める
目的:
ptrからlenバイトをvalue(下位 8bit)で埋めます。
実装(アルゴリズム):
- 0..len を順に走査し、
store_u8で書き込みます。
注意(重要):
ptrは少なくともlenバイトの有効領域を指している必要があります。
計算量:
- O(len)
#entry main
#target std
#import "std/test" as *
#import "core/mem" as *
fn main <()*>()> ():
let p <i32> alloc_raw 8;
memset_u8 p 8 65;
assert_eq_i32 65 load_u8 add p 0;
assert_eq_i32 65 load_u8 add p 7;
dealloc_raw p 8;fill_u8: memset_u8 の同義 API
目的:
- 競プロ向けの名前でバイト埋め API を提供します。
実装(アルゴリズム):
memset_u8を呼び出す薄いラッパです。
注意(重要):
valueは下位 8bit が使用されます。
計算量:
- O(len)
fill_i32: i32 配列を同じ値で埋める
目的:
ptrからcount個のi32要素をvalueで埋めます。
実装(アルゴリズム):
- 0..count を順に走査し、
store_i32で書き込みます。
注意(重要):
ptrは少なくともcount * 4バイトの有効領域を指している必要があります。
計算量:
- O(count)
#entry main
#target std
#import "std/test" as *
#import "core/mem" as *
fn main <()*>()> ():
let p <i32> alloc_raw 16;
fill_i32 p 4 42;
assert_eq_i32 42 load_i32 add p 0;
assert_eq_i32 42 load_i32 add p 12;
dealloc_raw p 16;memset_u8: MemPtr<u8> を受け取る安全オーバーロード
目的:
- 無効ポインタを
Result::Errとして扱い、i32生ポインタ境界を減らします。
fill_u8: MemPtr<u8> を受け取る安全オーバーロード
目的:
fill_u8をMemPtrで利用できるようにし、呼び出し側の生ポインタ露出を減らします。
fill_i32: MemPtr<i32> を受け取る安全オーバーロード
目的:
- 無効ポインタを
Result::Errとして扱い、i32生ポインタ境界を減らします。
load_i32: MemPtr<i32> から i32 を安全に読み出すオーバーロード
目的:
- 無効ポインタを
Option::Noneとして扱います。
store_i32: MemPtr<i32> へ i32 を安全に書き込むオーバーロード
目的:
- 無効ポインタを
Result::Errとして返し、未定義動作を避けます。
load_u8: MemPtr<u8> から 1 バイトを安全に読み出すオーバーロード
目的:
- 無効ポインタを
Option::Noneとして扱います。
store_u8: MemPtr<u8> へ 1 バイトを書き込む安全オーバーロード
目的:
- 無効ポインタを
Result::Errとして返し、未定義動作を避けます。
size_of: 型のサイズを取得する
目的:
- .T のサイズ(バイト)を返します。
実装(アルゴリズム):
- intrinsic "size_of" を呼びます。
注意(重要):
- サイズはコンパイル時に決まります。
計算量:
- O(1)
align_of: 型のアラインメントを取得する
目的:
- .T のアラインメント(バイト)を返します。
実装(アルゴリズム):
- intrinsic "align_of" を呼びます。
注意(重要):
- アラインメントはコンパイル時に決まります。
計算量:
- O(1)
load: 任意型をロードする
目的:
- ptr から .T を読み出します。
実装(アルゴリズム):
- intrinsic "load" を呼びます。
注意(重要):
- 型とメモリ内容の整合性は呼び出し側の責任です。
計算量:
- O(1)
store: 任意型をストアする
目的:
- ptr に .T を書き込みます。
実装(アルゴリズム):
- intrinsic "store" を呼びます。
注意(重要):
- 型とメモリ内容の整合性は呼び出し側の責任です。
計算量:
- O(1)