All checks were successful
Build / build (push) Successful in 11m9s
123 lines
3.1 KiB
Markdown
123 lines
3.1 KiB
Markdown
---
|
||
date: 2024-09-22 21:15
|
||
---
|
||
|
||
## 基本方針
|
||
|
||
- ヒープに確保する。
|
||
- MIRでリテラル、setarrayelement、getarrayelementみたいな専用命令を作る。
|
||
- [[LLVM]]みたいにgetelementptrの実装は難しい
|
||
- なぜなら、VMでのMOV命令がスタックの位置を直接指す実装だから
|
||
- ので、VMにも同じように専用命令を生やす
|
||
- get/setarrayelementの命令フォーマット
|
||
- destination,heap上のarray番号,indexの値を指すレジスタ番号
|
||
- ArrayのワードサイズはVMで確保されたヒープ上に書き込まれていて、インデックス\*ワードサイズの計算はランタイムに行うということでいいかなあ
|
||
|
||
|
||
## GCについて
|
||
|
||
Reference Countにする場合、Dropをどう実装するか
|
||
|
||
drop_array()、drop_closure()をプリミティブ命令として用意する?
|
||
|
||
プリミティブな値の配列ならそのまま開放してよし、オブジェクトを含む(配列の配列とか、クロージャの配列)なら再帰的にdropする必要あり
|
||
|
||
drop命令をどのタイミングで挿入するか
|
||
mirgenでletの生存期間を調べるしかない
|
||
bindsでArgumentの区別はされてるから、環境参照してArgument以外を全部dropする、みたいな感じでええのか
|
||
|
||
```rust
|
||
|
||
enum UpvalueKind{
|
||
Open{base_ptr:u64,offset:u64},
|
||
Closed(ObjectIdx)
|
||
}
|
||
struct Upvalue{
|
||
data:UpvalueKind,
|
||
ty: ObjType,
|
||
}
|
||
|
||
type SharedUpValue = Rc<RefCell<Upvalue>>
|
||
struct Closure{
|
||
pub fnproto_i: u64,
|
||
pub base_ptr: u64, //base pointer to current closure, to calculate open upvalue
|
||
pub is_closed: bool,
|
||
pub upvalues: Vec<SharedUpValue>,
|
||
pub state_storage:StateStorage,
|
||
}
|
||
struct Array{
|
||
pub d_size:TypeSize,
|
||
pub raw_data: Vec<RawVal>,
|
||
}
|
||
union HeapObject{
|
||
clousre: Closure,
|
||
array: Array,
|
||
primitive: Vec<RawVal>,
|
||
}
|
||
struct RcObject{
|
||
refcount:u64,
|
||
data: HeapObject
|
||
}
|
||
type = ObjectStorage=SlotMap<DefaultKey, RcObject>;
|
||
type = ObjectIdx = DefaultKey;
|
||
|
||
impl Machine{
|
||
...
|
||
fn drop_closure(&mut self, objectid:ObjectIdx){
|
||
let obj = self.get_object_mut(objectid);
|
||
obj.refcount-=1;
|
||
if obj.refcount==0{
|
||
let cls = unsafe{ &obj.data.closure };
|
||
cls.upvalue.iter().for_each(|upv|{
|
||
upv
|
||
})
|
||
self.object_storage.remove(objectid)
|
||
}
|
||
}
|
||
}
|
||
|
||
```
|
||
|
||
|
||
## 用途
|
||
|
||
例えばcatさんに作ってもらったこの辺の再帰を用いたコードがあるとする
|
||
|
||
```rust
|
||
fn gen_metalic_rec(times,freq,oscproto){
|
||
if(times>0){
|
||
let next = gen_metalic_rec(times-1,freq*1.176,oscproto)
|
||
let osc = oscproto();
|
||
| | { osc(freq) + next() }
|
||
}else{
|
||
| | 0.0
|
||
}
|
||
}
|
||
fn gen_metalic(times,freq){
|
||
let gen = gen_metalic_rec(times,freq,| | square_0);
|
||
| | gen() / times
|
||
}
|
||
let lowest_freq = 200.0
|
||
let myoscbank = gen_metalic(6,lowest_freq)
|
||
```
|
||
|
||
こういう組み込み関数を与えて、
|
||
|
||
```rust
|
||
extern enumerate_by: (times,init:float,(x:float,acc:float)->float)->[float]
|
||
```
|
||
|
||
```rust
|
||
|
||
fn metalic(times,lowest_freq){
|
||
let freqs = enumerate_by(times,lowest_freq, |_x,acc| acc*1.167)
|
||
let res = map(freqs,|f| `square_0(liftf(f)))
|
||
|> foldl(_, |x,acc| `{ $x + $acc } )
|
||
`{$res / liftf(times)}
|
||
}
|
||
fn dsp(){
|
||
metalic!(6,200)
|
||
}
|
||
|
||
```
|