Files
quartz-research-note/content/mimiumの配列実装.md
松浦 知也 Matsuura Tomoya b1cc13e269
All checks were successful
Build / build (push) Successful in 11m9s
[obsidian] vault backup: 2025-09-20 11:57:22[
2025-09-20 11:57:22 +09:00

3.1 KiB
Raw Blame History

date
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する、みたいな感じでええのか


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さんに作ってもらったこの辺の再帰を用いたコードがあるとする

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)

こういう組み込み関数を与えて、

extern enumerate_by: (times,init:float,(x:float,acc:float)->float)->[float]

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)
}