Phase 10.7/10.5c: include cycle detection (VM/Interpreter), minimal pyc IR→Nyash, String unification bridge (VM partial), add core plugins: RegexBox/EncodingBox/TOMLBox/PathBox + examples; wire nyash.toml; begin String interop for internal vs plugin boxes; update CURRENT_TASK.md
This commit is contained in:
@ -0,0 +1,200 @@
|
||||
# Phase 11.5a: Write Barrier除去によるGC最適化
|
||||
|
||||
## 🎯 目標
|
||||
JITコンパイル時にescape analysisを行い、不要なwrite barrierを除去してGC性能を大幅に向上させる。
|
||||
|
||||
## 📊 現状の問題
|
||||
|
||||
### 現在のVM実装
|
||||
```rust
|
||||
// すべてのrefset操作でbarrierが呼ばれる
|
||||
pub fn execute_ref_set(&mut self, reference: ValueId, field: &str, value: ValueId)
|
||||
-> Result<ControlFlow, VMError> {
|
||||
// ... 値の設定 ...
|
||||
|
||||
// 常にwrite barrierが実行される
|
||||
gc_write_barrier_site(&self.runtime, "RefSet");
|
||||
Ok(ControlFlow::Continue)
|
||||
}
|
||||
```
|
||||
|
||||
### オーバーヘッド
|
||||
- 単純な代入でも毎回barrier呼び出し
|
||||
- Stack上のローカル変数でも不要にbarrier
|
||||
- ループ内での大量のbarrier呼び出し
|
||||
|
||||
## 🚀 実装計画
|
||||
|
||||
### Step 1: Escape Analysis基盤
|
||||
```rust
|
||||
// mir/escape_analysis.rs
|
||||
pub struct EscapeAnalysis {
|
||||
// allocation site追跡
|
||||
allocations: HashMap<ValueId, AllocInfo>,
|
||||
// escape状態
|
||||
escapes: HashSet<ValueId>,
|
||||
// 解析結果キャッシュ
|
||||
cache: HashMap<FunctionId, EscapeInfo>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct AllocInfo {
|
||||
location: BasicBlockId,
|
||||
kind: AllocKind,
|
||||
size: Option<usize>,
|
||||
}
|
||||
|
||||
enum AllocKind {
|
||||
NewBox, // new StringBox()
|
||||
ArrayNew, // []
|
||||
RefNew, // ユーザー定義Box
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2: MIR解析
|
||||
```rust
|
||||
impl EscapeAnalysis {
|
||||
/// 関数内でのescape解析
|
||||
pub fn analyze_function(&mut self, func: &MirFunction) -> EscapeInfo {
|
||||
// 1. allocation site収集
|
||||
for (bb_id, bb) in &func.basic_blocks {
|
||||
for inst in &bb.instructions {
|
||||
match inst {
|
||||
MirInstruction::NewBox { dst, .. } |
|
||||
MirInstruction::ArrayNew { dst, .. } |
|
||||
MirInstruction::RefNew { dst, .. } => {
|
||||
self.allocations.insert(*dst, AllocInfo {
|
||||
location: bb_id,
|
||||
kind: self.classify_alloc(inst),
|
||||
size: self.estimate_size(inst),
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. escape point検出
|
||||
self.find_escape_points(func);
|
||||
|
||||
// 3. 結果集計
|
||||
EscapeInfo {
|
||||
non_escaping: self.collect_non_escaping(),
|
||||
barrier_sites: self.collect_barrier_sites(),
|
||||
}
|
||||
}
|
||||
|
||||
fn find_escape_points(&mut self, func: &MirFunction) {
|
||||
// return文でのescape
|
||||
// 関数引数としてのescape
|
||||
// グローバル変数へのescape
|
||||
// プラグイン呼び出しでのescape
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: JIT統合
|
||||
```rust
|
||||
// jit/lower/builder.rs
|
||||
impl<'a> LoweringBuilder<'a> {
|
||||
fn emit_ref_set(&mut self, reference: Value, field: &str, value: Value) {
|
||||
// escape解析結果を確認
|
||||
let needs_barrier = self.escape_info
|
||||
.map(|info| info.needs_barrier(reference))
|
||||
.unwrap_or(true); // 解析なしなら保守的にbarrier
|
||||
|
||||
if needs_barrier {
|
||||
// barrierあり
|
||||
self.emit_gc_barrier(BarrierKind::Write);
|
||||
} else {
|
||||
// barrier除去!
|
||||
if self.config.trace_opt {
|
||||
eprintln!("[JIT] barrier removed at {:?}", self.current_location());
|
||||
}
|
||||
}
|
||||
|
||||
// 実際のstore操作
|
||||
self.emit_store(reference, field, value);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 4: 最適化レベル設定
|
||||
```rust
|
||||
// 環境変数で制御
|
||||
NYASH_JIT_ESCAPE_ANALYSIS=1 # escape analysis有効化
|
||||
NYASH_JIT_BARRIER_OPT=1 # barrier最適化有効化
|
||||
NYASH_JIT_BARRIER_STATS=1 # 統計出力
|
||||
```
|
||||
|
||||
## 📈 期待される効果
|
||||
|
||||
### ベンチマーク例
|
||||
```nyash
|
||||
// 大量のローカル変数操作
|
||||
function processData(n) {
|
||||
local sum = 0
|
||||
local temp = new MapBox()
|
||||
|
||||
loop(i < n) {
|
||||
temp.set(i, i * 2) // escape analysisでbarrier除去
|
||||
sum = sum + temp.get(i)
|
||||
i = i + 1
|
||||
}
|
||||
|
||||
return sum
|
||||
}
|
||||
```
|
||||
|
||||
### 性能改善予測
|
||||
- ローカル変数操作: 90%以上のbarrier除去
|
||||
- ループ内操作: 80%以上の高速化
|
||||
- 全体的なGCオーバーヘッド: 50%削減
|
||||
|
||||
## 🔍 検証方法
|
||||
|
||||
### 1. Barrier統計
|
||||
```json
|
||||
{
|
||||
"total_barriers": 10000,
|
||||
"removed_barriers": 8500,
|
||||
"removal_rate": 0.85,
|
||||
"sites": {
|
||||
"RefSet": { "total": 5000, "removed": 4800 },
|
||||
"ArraySet": { "total": 3000, "removed": 2500 },
|
||||
"MapSet": { "total": 2000, "removed": 1200 }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 性能測定
|
||||
```bash
|
||||
# barrier最適化なし
|
||||
NYASH_JIT_ESCAPE_ANALYSIS=0 ./target/release/nyash --benchmark
|
||||
|
||||
# barrier最適化あり
|
||||
NYASH_JIT_ESCAPE_ANALYSIS=1 ./target/release/nyash --benchmark
|
||||
```
|
||||
|
||||
## 🚧 実装上の注意点
|
||||
|
||||
1. **保守的な解析**
|
||||
- 不明な場合は必ずbarrierを残す
|
||||
- プラグイン境界では常にbarrier
|
||||
|
||||
2. **デバッグ性**
|
||||
- 除去したbarrierサイトを記録
|
||||
- GCエラー時の診断情報
|
||||
|
||||
3. **段階的実装**
|
||||
- まずローカル変数のみ
|
||||
- 次にループ不変式
|
||||
- 最後に関数間解析
|
||||
|
||||
## 🎉 完了基準
|
||||
|
||||
- [ ] Escape analysis基本実装
|
||||
- [ ] MIR解析パス追加
|
||||
- [ ] JIT統合
|
||||
- [ ] ベンチマーク50%改善
|
||||
- [ ] ドキュメント更新
|
||||
@ -0,0 +1,240 @@
|
||||
# Phase 11.5b: Atomic操作最適化によるsync処理高速化
|
||||
|
||||
## 🎯 目標
|
||||
Arc<Mutex>の重いロック操作を、可能な限り軽量なatomic操作に置き換えて性能を向上させる。
|
||||
|
||||
## 📊 現状の問題
|
||||
|
||||
### 現在の実装
|
||||
```rust
|
||||
// すべてのBox操作でMutexロック
|
||||
pub fn get_field(&self, name: &str) -> Option<Box<dyn NyashBox>> {
|
||||
let fields = self.fields.lock().unwrap(); // 重い!
|
||||
fields.get(name).cloned()
|
||||
}
|
||||
|
||||
// Read-onlyでも同じコスト
|
||||
pub fn to_string(&self) -> String {
|
||||
let value = self.value.lock().unwrap(); // 不要なロック!
|
||||
value.clone()
|
||||
}
|
||||
```
|
||||
|
||||
### パフォーマンス問題
|
||||
- Read操作でも排他ロックのオーバーヘッド
|
||||
- 複数スレッドでのcontention
|
||||
- Cache line bouncing
|
||||
|
||||
## 🚀 実装計画
|
||||
|
||||
### Step 1: Read-only path分析
|
||||
```rust
|
||||
// mir/readonly_analysis.rs
|
||||
pub struct ReadOnlyAnalysis {
|
||||
// メソッドのread-only性
|
||||
readonly_methods: HashMap<(TypeId, String), bool>,
|
||||
// フィールドのimmutability
|
||||
immutable_fields: HashMap<(TypeId, String), bool>,
|
||||
}
|
||||
|
||||
impl ReadOnlyAnalysis {
|
||||
pub fn analyze_box_types(&mut self, registry: &BoxRegistry) {
|
||||
// StringBox.length() -> read-only
|
||||
self.mark_readonly("StringBox", "length");
|
||||
self.mark_readonly("StringBox", "isEmpty");
|
||||
|
||||
// IntegerBox.value() -> read-only
|
||||
self.mark_readonly("IntegerBox", "value");
|
||||
|
||||
// プラグインメソッドも解析
|
||||
self.analyze_plugin_methods();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2: Atomic wrapper実装
|
||||
```rust
|
||||
// runtime/atomic_box.rs
|
||||
pub struct AtomicBox<T: NyashBox> {
|
||||
// Read-optimized RwLock
|
||||
inner: Arc<RwLock<T>>,
|
||||
// Atomic cache for immutable data
|
||||
cached_string: AtomicPtr<String>,
|
||||
cached_int: AtomicI64,
|
||||
}
|
||||
|
||||
impl<T: NyashBox> AtomicBox<T> {
|
||||
/// Lock-free read for cached values
|
||||
pub fn read_cached(&self) -> Option<Box<dyn NyashBox>> {
|
||||
// Atomic loadでキャッシュチェック
|
||||
let ptr = self.cached_string.load(Ordering::Acquire);
|
||||
if !ptr.is_null() {
|
||||
unsafe {
|
||||
let s = &*ptr;
|
||||
return Some(Box::new(StringBox::new(s.clone())));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Optimized read path
|
||||
pub fn read_optimized<F, R>(&self, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&T) -> R
|
||||
{
|
||||
// Try read lock first (non-blocking)
|
||||
if let Ok(guard) = self.inner.try_read() {
|
||||
return f(&*guard);
|
||||
}
|
||||
|
||||
// Fallback to regular read
|
||||
let guard = self.inner.read().unwrap();
|
||||
f(&*guard)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: JIT最適化
|
||||
```rust
|
||||
// jit/lower/atomic_opt.rs
|
||||
impl<'a> LoweringBuilder<'a> {
|
||||
fn emit_box_method_call(&mut self,
|
||||
box_val: Value,
|
||||
method: &str,
|
||||
args: &[Value]
|
||||
) -> Value {
|
||||
// Read-only解析結果確認
|
||||
if self.readonly_info.is_readonly_method(box_val, method) {
|
||||
// Atomic fast path
|
||||
self.emit_atomic_read_path(box_val, method, args)
|
||||
} else {
|
||||
// 通常のMutexパス
|
||||
self.emit_mutex_path(box_val, method, args)
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_atomic_read_path(&mut self,
|
||||
box_val: Value,
|
||||
method: &str,
|
||||
args: &[Value]
|
||||
) -> Value {
|
||||
// 1. Atomic loadでcacheチェック
|
||||
let cache_ptr = self.emit_atomic_load(box_val, "cache");
|
||||
|
||||
// 2. Cache hit判定
|
||||
let is_valid = self.emit_null_check(cache_ptr);
|
||||
|
||||
// 3. 条件分岐
|
||||
let then_block = self.create_block();
|
||||
let else_block = self.create_block();
|
||||
self.emit_branch(is_valid, then_block, else_block);
|
||||
|
||||
// Cache hit: lock-free return
|
||||
self.switch_to_block(then_block);
|
||||
let cached = self.emit_load(cache_ptr);
|
||||
self.emit_jump(merge_block);
|
||||
|
||||
// Cache miss: RwLock読み取り
|
||||
self.switch_to_block(else_block);
|
||||
let value = self.emit_rwlock_read(box_val, method);
|
||||
self.emit_jump(merge_block);
|
||||
|
||||
// Merge
|
||||
self.switch_to_block(merge_block);
|
||||
self.emit_phi(vec![(cached, then_block), (value, else_block)])
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 4: Memory ordering最適化
|
||||
```rust
|
||||
// プラットフォーム別最適化
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn emit_memory_fence(&mut self, ordering: Ordering) {
|
||||
match ordering {
|
||||
Ordering::Relaxed => {}, // x86は強いメモリモデル
|
||||
Ordering::Acquire => self.emit_lfence(),
|
||||
Ordering::Release => self.emit_sfence(),
|
||||
Ordering::SeqCst => self.emit_mfence(),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
fn emit_memory_fence(&mut self, ordering: Ordering) {
|
||||
// ARMは弱いメモリモデル
|
||||
match ordering {
|
||||
Ordering::Relaxed => {},
|
||||
Ordering::Acquire => self.emit_dmb_ld(),
|
||||
Ordering::Release => self.emit_dmb_st(),
|
||||
Ordering::SeqCst => self.emit_dmb(),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 📈 期待される効果
|
||||
|
||||
### ベンチマーク
|
||||
```nyash
|
||||
// Read-heavy workload
|
||||
function sumStringLengths(strings) {
|
||||
local total = 0
|
||||
loop(s in strings) {
|
||||
total = total + s.length() // Atomic最適化
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
// 性能改善
|
||||
// Before: 1000ms (Mutex contention)
|
||||
// After: 100ms (Lock-free reads)
|
||||
```
|
||||
|
||||
### 改善予測
|
||||
- Read操作: 90%高速化
|
||||
- Read/Write混在: 50%高速化
|
||||
- マルチスレッド: スケーラビリティ大幅向上
|
||||
|
||||
## 🔍 検証方法
|
||||
|
||||
### 1. Lock統計
|
||||
```json
|
||||
{
|
||||
"total_operations": 100000,
|
||||
"mutex_locks": 10000,
|
||||
"atomic_reads": 90000,
|
||||
"lock_reduction": 0.9,
|
||||
"contention_events": 50
|
||||
}
|
||||
```
|
||||
|
||||
### 2. プロファイリング
|
||||
```bash
|
||||
# Mutexプロファイル
|
||||
NYASH_PROFILE_LOCKS=1 ./target/release/nyash bench.nyash
|
||||
|
||||
# Atomic最適化後
|
||||
NYASH_ATOMIC_OPT=1 ./target/release/nyash bench.nyash
|
||||
```
|
||||
|
||||
## 🚧 実装上の注意点
|
||||
|
||||
1. **正確性**
|
||||
- Memory orderingの正しさ
|
||||
- ABA問題の回避
|
||||
- Weak pointer対応
|
||||
|
||||
2. **互換性**
|
||||
- 既存APIの維持
|
||||
- プラグインとの相互運用
|
||||
|
||||
3. **デバッグ性**
|
||||
- Race condition検出
|
||||
- Lock順序の追跡
|
||||
|
||||
## 🎉 完了基準
|
||||
|
||||
- [ ] Read-only分析実装
|
||||
- [ ] AtomicBox wrapper実装
|
||||
- [ ] JIT統合
|
||||
- [ ] マルチスレッドベンチマーク
|
||||
- [ ] プラットフォーム別最適化
|
||||
@ -0,0 +1,295 @@
|
||||
# Phase 11.5c: Coroutine実装による非同期処理の完成
|
||||
|
||||
## 🎯 目標
|
||||
async/await構文を追加し、JITレベルでcoroutineをstate machineに変換して高性能な非同期処理を実現する。
|
||||
|
||||
## 📊 現状と目標
|
||||
|
||||
### 現在の非同期処理
|
||||
```nyash
|
||||
// nowait文(スレッドベース)
|
||||
nowait result = heavyComputation()
|
||||
// ...
|
||||
local value = wait result // FutureBoxから取得
|
||||
```
|
||||
|
||||
### 目標の構文
|
||||
```nyash
|
||||
// async/await(coroutineベース)
|
||||
async function fetchData(url) {
|
||||
local response = await httpGet(url)
|
||||
local json = await response.json()
|
||||
return json.data
|
||||
}
|
||||
|
||||
// 複数の非同期処理
|
||||
async function fetchAll(urls) {
|
||||
local promises = []
|
||||
loop(url in urls) {
|
||||
promises.push(fetchData(url))
|
||||
}
|
||||
return await Promise.all(promises)
|
||||
}
|
||||
```
|
||||
|
||||
## 🚀 実装計画
|
||||
|
||||
### Step 1: AST拡張
|
||||
```rust
|
||||
// ast.rs
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ASTNode {
|
||||
// 既存
|
||||
Function { name: String, params: Vec<String>, body: Box<ASTNode> },
|
||||
|
||||
// 新規追加
|
||||
AsyncFunction {
|
||||
name: String,
|
||||
params: Vec<String>,
|
||||
body: Box<ASTNode>
|
||||
},
|
||||
AwaitExpression {
|
||||
expression: Box<ASTNode>
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2: MIR Coroutine命令
|
||||
```rust
|
||||
// mir/instruction.rs
|
||||
pub enum MirInstruction {
|
||||
// 既存命令...
|
||||
|
||||
// Coroutine関連
|
||||
/// Coroutine生成
|
||||
CoroutineCreate {
|
||||
dst: ValueId,
|
||||
func: FunctionId,
|
||||
captures: Vec<ValueId>,
|
||||
},
|
||||
|
||||
/// Yield point(await)
|
||||
CoroutineYield {
|
||||
value: ValueId,
|
||||
resume_label: BasicBlockId,
|
||||
},
|
||||
|
||||
/// Coroutine再開
|
||||
CoroutineResume {
|
||||
dst: Option<ValueId>,
|
||||
coroutine: ValueId,
|
||||
value: Option<ValueId>,
|
||||
},
|
||||
|
||||
/// Promise結合
|
||||
PromiseAll {
|
||||
dst: ValueId,
|
||||
promises: Vec<ValueId>,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: State Machine変換
|
||||
```rust
|
||||
// mir/coroutine_transform.rs
|
||||
pub struct CoroutineTransform {
|
||||
state_enum: HashMap<FunctionId, StateEnum>,
|
||||
}
|
||||
|
||||
/// async関数をstate machineに変換
|
||||
impl CoroutineTransform {
|
||||
pub fn transform_async_function(&mut self,
|
||||
func: &MirFunction
|
||||
) -> MirFunction {
|
||||
// 1. await pointsを収集
|
||||
let await_points = self.collect_await_points(func);
|
||||
|
||||
// 2. State enum生成
|
||||
let states = self.generate_states(await_points);
|
||||
|
||||
// 3. State machine関数生成
|
||||
let state_machine = self.build_state_machine(func, states);
|
||||
|
||||
// 4. Coroutine wrapper生成
|
||||
self.wrap_as_coroutine(state_machine)
|
||||
}
|
||||
|
||||
fn build_state_machine(&self,
|
||||
func: &MirFunction,
|
||||
states: Vec<State>
|
||||
) -> MirFunction {
|
||||
// switch(state) {
|
||||
// case State0: ... goto await1 or return
|
||||
// case State1: ... goto await2 or return
|
||||
// ...
|
||||
// }
|
||||
|
||||
let mut builder = MirBuilder::new();
|
||||
|
||||
// Coroutine state
|
||||
let state_var = builder.emit_local("state");
|
||||
let locals = builder.emit_local("locals");
|
||||
|
||||
// Main dispatch loop
|
||||
let loop_bb = builder.create_block();
|
||||
builder.emit_jump(loop_bb);
|
||||
|
||||
builder.switch_to_block(loop_bb);
|
||||
let state = builder.emit_load(state_var);
|
||||
|
||||
// State dispatch
|
||||
for (i, state) in states.iter().enumerate() {
|
||||
let state_bb = builder.create_block();
|
||||
builder.emit_case(state.id, state_bb);
|
||||
|
||||
builder.switch_to_block(state_bb);
|
||||
self.emit_state_code(&mut builder, state);
|
||||
}
|
||||
|
||||
builder.build()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 4: JIT Coroutine最適化
|
||||
```rust
|
||||
// jit/lower/coroutine.rs
|
||||
impl<'a> LoweringBuilder<'a> {
|
||||
/// Coroutineのstack switching最適化
|
||||
fn emit_coroutine_switch(&mut self,
|
||||
from: Value,
|
||||
to: Value
|
||||
) {
|
||||
if self.config.use_fast_switch {
|
||||
// レジスタのみ保存(最適化)
|
||||
self.emit_save_registers();
|
||||
self.emit_switch_stack(to);
|
||||
self.emit_restore_registers();
|
||||
} else {
|
||||
// フルコンテキスト保存
|
||||
self.emit_full_context_save(from);
|
||||
self.emit_full_context_restore(to);
|
||||
}
|
||||
}
|
||||
|
||||
/// Inline可能なawaitの検出
|
||||
fn try_inline_await(&mut self,
|
||||
await_expr: &MirInstruction
|
||||
) -> Option<Value> {
|
||||
// Promise.resolvedなら即値返却
|
||||
if self.is_resolved_promise(await_expr) {
|
||||
return Some(self.emit_immediate_value());
|
||||
}
|
||||
|
||||
// 小さなasync関数ならインライン化
|
||||
if self.is_small_async(await_expr) {
|
||||
return Some(self.inline_async_call(await_expr));
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 5: ランタイムサポート
|
||||
```rust
|
||||
// boxes/promise_box.rs
|
||||
pub struct PromiseBox {
|
||||
state: Arc<Mutex<PromiseState>>,
|
||||
base: BoxBase,
|
||||
}
|
||||
|
||||
enum PromiseState {
|
||||
Pending(Vec<Box<dyn FnOnce(Box<dyn NyashBox>)>>),
|
||||
Resolved(Box<dyn NyashBox>),
|
||||
Rejected(String),
|
||||
}
|
||||
|
||||
impl PromiseBox {
|
||||
pub fn all(promises: Vec<Box<PromiseBox>>) -> Box<PromiseBox> {
|
||||
// 全Promise完了待ち
|
||||
let result = PromiseBox::new();
|
||||
let remaining = Arc::new(AtomicUsize::new(promises.len()));
|
||||
|
||||
for (i, promise) in promises.iter().enumerate() {
|
||||
promise.then(move |value| {
|
||||
// 結果収集
|
||||
if remaining.fetch_sub(1, Ordering::SeqCst) == 1 {
|
||||
result.resolve(collected_values);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Box::new(result)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 📈 期待される効果
|
||||
|
||||
### パフォーマンス比較
|
||||
```nyash
|
||||
// Before: Thread-based
|
||||
nowait results = []
|
||||
loop(url in urls) {
|
||||
nowait r = httpGet(url) // 新スレッド生成
|
||||
results.push(r)
|
||||
}
|
||||
|
||||
// After: Coroutine-based
|
||||
async function fetchAll(urls) {
|
||||
return await Promise.all(
|
||||
urls.map(url => httpGet(url)) // Stack switching only
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### 改善予測
|
||||
- メモリ使用量: 1/100(スレッドstack vs coroutine state)
|
||||
- コンテキストスイッチ: 1000倍高速
|
||||
- 同時接続数: 10,000+対応可能
|
||||
|
||||
## 🔍 検証方法
|
||||
|
||||
### 1. Coroutine統計
|
||||
```json
|
||||
{
|
||||
"total_coroutines": 10000,
|
||||
"active_coroutines": 500,
|
||||
"yield_count": 50000,
|
||||
"average_yield_ns": 100,
|
||||
"stack_memory_mb": 10
|
||||
}
|
||||
```
|
||||
|
||||
### 2. ベンチマーク
|
||||
```bash
|
||||
# 10000並行リクエスト
|
||||
./target/release/nyash bench/async_stress.nyash
|
||||
|
||||
# メモリプロファイル
|
||||
NYASH_COROUTINE_STATS=1 ./target/release/nyash bench/async_memory.nyash
|
||||
```
|
||||
|
||||
## 🚧 実装上の注意点
|
||||
|
||||
1. **Stack管理**
|
||||
- Segmented stack対応
|
||||
- Stack overflow検出
|
||||
- GC root scanning
|
||||
|
||||
2. **エラー伝播**
|
||||
- async境界でのエラー
|
||||
- Promise rejection chain
|
||||
|
||||
3. **デバッグ対応**
|
||||
- async stack trace
|
||||
- Coroutine状態可視化
|
||||
|
||||
## 🎉 完了基準
|
||||
|
||||
- [ ] async/await構文実装
|
||||
- [ ] MIR coroutine変換
|
||||
- [ ] JIT最適化
|
||||
- [ ] Promise/PromiseBox実装
|
||||
- [ ] 10000並行処理ベンチマーク達成
|
||||
307
docs/development/roadmap/phases/phase-11.5/FIRST-FIVE-APPS.md
Normal file
307
docs/development/roadmap/phases/phase-11.5/FIRST-FIVE-APPS.md
Normal file
@ -0,0 +1,307 @@
|
||||
# 🚀 First Five Apps - Nyashの実力を証明する最初の5本
|
||||
|
||||
## 🎯 概要
|
||||
Phase 11.5完了を待たずに、**今すぐ作れる**実用アプリ5本で、Nyashの産業レベルの完成度を世に示します。
|
||||
すべて「Everything is Box/PluginInvoke」で統一実装し、VM/JIT/AOT/WASMの全バックエンドで動作確認します。
|
||||
|
||||
## 📋 アプリケーション一覧
|
||||
|
||||
### 1. ny-echo(最小CLI)- 基本I/O検証
|
||||
**目的**: I/O・StringBoxの道通し確認
|
||||
|
||||
```nyash
|
||||
// apps/ny-echo/main.nyash
|
||||
static box Main {
|
||||
main(args) {
|
||||
local console = new ConsoleBox()
|
||||
local options = parseArgs(args)
|
||||
|
||||
loop(true) {
|
||||
local input = console.readLine()
|
||||
if input == null { break }
|
||||
|
||||
local output = input
|
||||
if options.get("upper") {
|
||||
output = input.toUpperCase()
|
||||
} else if options.get("lower") {
|
||||
output = input.toLowerCase()
|
||||
}
|
||||
|
||||
console.log(output)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**受入基準**:
|
||||
- [ ] VM/JIT/AOT/GCオン・オフすべてでtrace_hash一致
|
||||
- [ ] 100万行処理で性能劣化なし
|
||||
- [ ] メモリリークなし(GCカウンター確認)
|
||||
|
||||
### 2. ny-jsonlint(Python連携デモ)- プラグイン統合
|
||||
**目的**: PyRuntimeBox/PyObjectBox経由のPluginInvoke検証
|
||||
|
||||
```nyash
|
||||
// apps/ny-jsonlint/main.nyash
|
||||
static box Main {
|
||||
init { py, console }
|
||||
|
||||
main(args) {
|
||||
me.py = new PyRuntimeBox()
|
||||
me.console = new ConsoleBox()
|
||||
|
||||
local filename = args.get(1)
|
||||
if filename == null {
|
||||
me.console.error("Usage: ny-jsonlint <file.json>")
|
||||
return 1
|
||||
}
|
||||
|
||||
local file = new FileBox()
|
||||
file.open(filename, "r")
|
||||
local content = file.read()
|
||||
file.close()
|
||||
|
||||
local result = me.py.eval("
|
||||
import json
|
||||
try:
|
||||
json.loads(content)
|
||||
'OK'
|
||||
except Exception as e:
|
||||
f'NG: {str(e)}'
|
||||
", new MapBox().set("content", content))
|
||||
|
||||
me.console.log(result)
|
||||
return result.startsWith("OK") ? 0 : 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**受入基準**:
|
||||
- [ ] OS差なく実行(Windows/Linux/macOS)
|
||||
- [ ] --sealedモードで完全再現可能
|
||||
- [ ] 大規模JSON(10MB)でも安定動作
|
||||
|
||||
### 3. ny-array-bench(性能デモ)- ベンチマーク基準
|
||||
**目的**: ArrayBox map/reduce、StatsBox導入、性能可視化
|
||||
|
||||
```nyash
|
||||
// apps/ny-array-bench/main.nyash
|
||||
static box Main {
|
||||
init { stats }
|
||||
|
||||
main(args) {
|
||||
me.stats = new StatsBox()
|
||||
local sizes = [1000, 10000, 100000]
|
||||
|
||||
loop(size in sizes) {
|
||||
me.benchArrayOps(size)
|
||||
}
|
||||
|
||||
// 結果をJSON出力(CI集計用)
|
||||
local result = me.stats.toJSON()
|
||||
print(result)
|
||||
}
|
||||
|
||||
benchArrayOps(size) {
|
||||
local array = new ArrayBox()
|
||||
|
||||
// 1. 配列生成
|
||||
me.stats.startTimer("create_" + size)
|
||||
loop(i < size) {
|
||||
array.push(i)
|
||||
}
|
||||
me.stats.endTimer("create_" + size)
|
||||
|
||||
// 2. map操作
|
||||
me.stats.startTimer("map_" + size)
|
||||
local doubled = array.map(|x| x * 2)
|
||||
me.stats.endTimer("map_" + size)
|
||||
|
||||
// 3. reduce操作
|
||||
me.stats.startTimer("reduce_" + size)
|
||||
local sum = doubled.reduce(|a, b| a + b, 0)
|
||||
me.stats.endTimer("reduce_" + size)
|
||||
|
||||
// VM基準の相対性能を記録
|
||||
me.stats.recordRelative("vm", 1.0)
|
||||
if IS_JIT { me.stats.recordRelative("jit", SPEEDUP) }
|
||||
if IS_AOT { me.stats.recordRelative("aot", SPEEDUP) }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**受入基準**:
|
||||
- [ ] VM=1.0x基準でJIT/AOTの倍率表示
|
||||
- [ ] fallbacks=0(完全最適化)
|
||||
- [ ] 結果JSON自動出力(CI集計可能)
|
||||
|
||||
### 4. ny-filegrep(実用ミニ)- ファイルI/O実用例
|
||||
**目的**: BytesBox/FileBox(プラグイン)I/O、実用的なツール
|
||||
|
||||
```nyash
|
||||
// apps/ny-filegrep/main.nyash
|
||||
static box Main {
|
||||
init { pattern, recursive, results }
|
||||
|
||||
main(args) {
|
||||
me.parseArgs(args)
|
||||
me.results = new ArrayBox()
|
||||
|
||||
local path = args.getLast() || "."
|
||||
me.searchPath(path)
|
||||
|
||||
// 結果表示
|
||||
loop(result in me.results) {
|
||||
print(result)
|
||||
}
|
||||
|
||||
return me.results.length() > 0 ? 0 : 1
|
||||
}
|
||||
|
||||
searchPath(path) {
|
||||
local file = new FileBox()
|
||||
|
||||
if file.isDirectory(path) {
|
||||
if me.recursive {
|
||||
local entries = file.listDir(path)
|
||||
loop(entry in entries) {
|
||||
me.searchPath(path + "/" + entry)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
me.searchFile(path)
|
||||
}
|
||||
}
|
||||
|
||||
searchFile(filepath) {
|
||||
local file = new FileBox()
|
||||
file.open(filepath, "r")
|
||||
|
||||
local lineNum = 0
|
||||
loop(true) {
|
||||
local line = file.readLine()
|
||||
if line == null { break }
|
||||
|
||||
lineNum = lineNum + 1
|
||||
if line.contains(me.pattern) {
|
||||
me.results.push(filepath + ":" + lineNum + ":" + line)
|
||||
}
|
||||
}
|
||||
|
||||
file.close()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**受入基準**:
|
||||
- [ ] Windows/Linux/macOSで同一結果
|
||||
- [ ] 大規模ディレクトリ(1万ファイル)対応
|
||||
- [ ] メモリ効率的(ストリーム処理)
|
||||
|
||||
### 5. ny-http-hello(WASM/ネイティブ両対応)- Web実用例
|
||||
**目的**: NetBox(プラグイン)とイベントループ、FutureBox活用
|
||||
|
||||
```nyash
|
||||
// apps/ny-http-hello/main.nyash
|
||||
static box Main {
|
||||
init { server, running }
|
||||
|
||||
main(args) {
|
||||
local port = args.get(1) || "8080"
|
||||
me.server = new HttpServerBox()
|
||||
me.running = true
|
||||
|
||||
// シグナルハンドラー設定
|
||||
registerSignal("SIGINT", || me.stop())
|
||||
|
||||
// サーバー起動
|
||||
me.server.start(port.toInteger())
|
||||
print("Server listening on http://localhost:" + port)
|
||||
|
||||
// リクエストループ
|
||||
loop(me.running) {
|
||||
nowait request = me.server.accept()
|
||||
me.handleRequest(wait request)
|
||||
}
|
||||
|
||||
me.server.stop()
|
||||
return 0
|
||||
}
|
||||
|
||||
handleRequest(request) {
|
||||
local response = new HttpResponseBox()
|
||||
|
||||
if request.path() == "/" {
|
||||
response.setStatus(200)
|
||||
response.setHeader("Content-Type", "text/plain")
|
||||
response.write("Hello from Nyash!")
|
||||
} else {
|
||||
response.setStatus(404)
|
||||
response.write("Not Found")
|
||||
}
|
||||
|
||||
request.respond(response)
|
||||
}
|
||||
|
||||
stop() {
|
||||
print("Shutting down...")
|
||||
me.running = false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**受入基準**:
|
||||
- [ ] 100req/s程度のスモーク通過
|
||||
- [ ] 停止シグナルでクリーンfini
|
||||
- [ ] WASMビルドでも動作(制限付き)
|
||||
|
||||
## 🎯 実装優先順位
|
||||
|
||||
1. **ny-echo** - 最小実装、CI基盤確立
|
||||
2. **ny-array-bench** - 性能基準確立
|
||||
3. **ny-jsonlint** - プラグイン統合実証
|
||||
4. **ny-filegrep** - 実用性実証
|
||||
5. **ny-http-hello** - Web対応実証
|
||||
|
||||
## 📊 成功指標
|
||||
|
||||
### 全体指標
|
||||
- [ ] 5アプリすべてがVM/JIT/AOTで動作
|
||||
- [ ] CIでの自動テスト確立
|
||||
- [ ] ドキュメント・サンプル完備
|
||||
|
||||
### 性能指標
|
||||
- [ ] JIT: VMの5倍以上高速
|
||||
- [ ] AOT: VMの10倍以上高速
|
||||
- [ ] メモリ使用量: 同等機能のPython比50%以下
|
||||
|
||||
### 品質指標
|
||||
- [ ] ゼロクラッシュ(1000回実行)
|
||||
- [ ] メモリリークなし(長時間実行)
|
||||
- [ ] プラットフォーム差異なし
|
||||
|
||||
## 🚀 配布戦略
|
||||
|
||||
### リリース形式
|
||||
```
|
||||
nyash-apps-v1.0/
|
||||
├── bin/
|
||||
│ ├── ny-echo[.exe]
|
||||
│ ├── ny-jsonlint[.exe]
|
||||
│ ├── ny-array-bench[.exe]
|
||||
│ ├── ny-filegrep[.exe]
|
||||
│ └── ny-http-hello[.exe]
|
||||
├── examples/
|
||||
│ └── *.nyash (ソースコード)
|
||||
├── benchmarks/
|
||||
│ └── results.json
|
||||
└── README.md
|
||||
```
|
||||
|
||||
### 展開先
|
||||
- GitHub Releases
|
||||
- Homebrew (macOS)
|
||||
- Scoop (Windows)
|
||||
- Docker Hub (コンテナ版)
|
||||
|
||||
これで「30日で作った言語」の実力を世界に示せます!🎉
|
||||
@ -0,0 +1,191 @@
|
||||
# Phase 11.5 実装ガイド - ChatGPT5向け
|
||||
|
||||
## 🎯 実装の全体像
|
||||
|
||||
Phase 11.5は、Nyashの性能を産業レベルに引き上げる最終段階です。3つの主要な最適化を行います:
|
||||
|
||||
1. **Write Barrier除去** - GCオーバーヘッドを90%削減
|
||||
2. **Atomic最適化** - sync処理を10倍高速化
|
||||
3. **Coroutine実装** - 真の非同期処理を実現
|
||||
|
||||
## 📋 実装順序と依存関係
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[11.5a: Write Barrier除去] --> D[統合テスト]
|
||||
B[11.5b: Atomic最適化] --> D
|
||||
C[11.5c: Coroutine実装] --> D
|
||||
D --> E[Phase 11.5完了]
|
||||
```
|
||||
|
||||
各タスクは独立して実装可能ですが、統合テストで相互作用を検証します。
|
||||
|
||||
## 🔧 技術的な実装詳細
|
||||
|
||||
### 1. Write Barrier除去の実装手順
|
||||
|
||||
#### Step 1: MIR拡張
|
||||
```rust
|
||||
// src/mir/escape_analysis.rs (新規作成)
|
||||
use crate::mir::{MirFunction, MirInstruction, ValueId};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
pub struct EscapeAnalysis {
|
||||
allocations: HashMap<ValueId, AllocSite>,
|
||||
escapes: HashSet<ValueId>,
|
||||
}
|
||||
|
||||
impl EscapeAnalysis {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
allocations: HashMap::new(),
|
||||
escapes: HashSet::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn analyze(&mut self, func: &MirFunction) -> EscapeInfo {
|
||||
// 実装のポイント:
|
||||
// 1. NewBox, RefNew命令を追跡
|
||||
// 2. Return, Call命令でescape判定
|
||||
// 3. ループ不変式も考慮
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Step 2: VM統合
|
||||
```rust
|
||||
// src/backend/vm_instructions.rs の修正
|
||||
pub fn execute_ref_set(&mut self, reference: ValueId, field: &str, value: ValueId)
|
||||
-> Result<ControlFlow, VMError> {
|
||||
// 既存のコード...
|
||||
|
||||
// Escape analysisの結果を確認
|
||||
if let Some(escape_info) = &self.escape_info {
|
||||
if !escape_info.escapes(reference) {
|
||||
// Barrierスキップ!
|
||||
return Ok(ControlFlow::Continue);
|
||||
}
|
||||
}
|
||||
|
||||
// 通常のbarrier処理
|
||||
gc_write_barrier_site(&self.runtime, "RefSet");
|
||||
Ok(ControlFlow::Continue)
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Atomic最適化の実装手順
|
||||
|
||||
#### Step 1: BoxCore拡張
|
||||
```rust
|
||||
// src/box_trait.rs の修正
|
||||
pub trait BoxCore: Send + Sync {
|
||||
// 既存のメソッド...
|
||||
|
||||
/// Read-onlyメソッドかどうか
|
||||
fn is_readonly_method(&self, method: &str) -> bool {
|
||||
// デフォルトはfalse(保守的)
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// 各Boxで実装
|
||||
impl BoxCore for StringBox {
|
||||
fn is_readonly_method(&self, method: &str) -> bool {
|
||||
matches!(method, "length" | "isEmpty" | "charAt")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Step 2: Atomic wrapper
|
||||
```rust
|
||||
// src/runtime/atomic_box.rs (新規作成)
|
||||
use std::sync::atomic::{AtomicPtr, Ordering};
|
||||
use std::sync::Arc;
|
||||
use parking_lot::RwLock; // より高速なRwLock
|
||||
|
||||
pub struct AtomicBox<T> {
|
||||
inner: Arc<RwLock<T>>,
|
||||
cache: AtomicPtr<CachedValue>,
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Coroutine実装の実装手順
|
||||
|
||||
#### Step 1: Parser拡張
|
||||
```rust
|
||||
// src/parser/keywords.rs の修正
|
||||
pub const RESERVED_WORDS: &[&str] = &[
|
||||
// 既存のキーワード...
|
||||
"async",
|
||||
"await",
|
||||
];
|
||||
|
||||
// src/parser/expressions.rs の修正
|
||||
fn parse_function_declaration(&mut self) -> Result<ASTNode, ParseError> {
|
||||
let is_async = self.consume_keyword("async");
|
||||
// 既存のパース処理...
|
||||
}
|
||||
```
|
||||
|
||||
#### Step 2: MIR Coroutine変換
|
||||
```rust
|
||||
// src/mir/coroutine_transform.rs (新規作成)
|
||||
pub fn transform_async_function(func: &MirFunction) -> MirFunction {
|
||||
// State machine変換のアルゴリズム:
|
||||
// 1. await箇所でstateを分割
|
||||
// 2. ローカル変数をstate構造体に移動
|
||||
// 3. switch文で状態遷移を実装
|
||||
}
|
||||
```
|
||||
|
||||
## 🎯 ChatGPT5への実装指示
|
||||
|
||||
### Phase 11.5a(最優先)
|
||||
1. `src/mir/escape_analysis.rs`を作成
|
||||
2. 基本的なallocation追跡を実装
|
||||
3. VM統合でbarrier除去をテスト
|
||||
4. ベンチマークで効果測定
|
||||
|
||||
### Phase 11.5b(次優先)
|
||||
1. `BoxCore::is_readonly_method`を追加
|
||||
2. 主要Boxで実装(StringBox, IntegerBox)
|
||||
3. RwLock移行を段階的に実施
|
||||
|
||||
### Phase 11.5c(最後)
|
||||
1. Parser拡張(async/await)
|
||||
2. 基本的なPromiseBox実装
|
||||
3. 簡単なasync関数の動作確認
|
||||
|
||||
## 📊 成功指標
|
||||
|
||||
各フェーズの完了基準:
|
||||
|
||||
### 11.5a: Write Barrier除去
|
||||
- [ ] escape_analysis.rsが動作
|
||||
- [ ] 簡単なループでbarrier除去確認
|
||||
- [ ] ベンチマークで30%以上改善
|
||||
|
||||
### 11.5b: Atomic最適化
|
||||
- [ ] Read-onlyメソッドの識別
|
||||
- [ ] RwLock使用でread性能向上
|
||||
- [ ] マルチスレッドベンチマーク改善
|
||||
|
||||
### 11.5c: Coroutine実装
|
||||
- [ ] async/awaitがパース可能
|
||||
- [ ] 簡単なasync関数が実行可能
|
||||
- [ ] Promiseチェーンが動作
|
||||
|
||||
## 🚀 実装開始コマンド
|
||||
|
||||
```bash
|
||||
# ブランチ作成
|
||||
git checkout -b phase-11.5-jit-integration
|
||||
|
||||
# テスト駆動開発
|
||||
cargo test escape_analysis
|
||||
|
||||
# ベンチマーク実行
|
||||
./target/release/nyash --benchmark --iterations 1000
|
||||
```
|
||||
|
||||
頑張ってください、ChatGPT5!これが完成すれば、Nyashは本当に世界クラスの言語になります!
|
||||
169
docs/development/roadmap/phases/phase-11.5/README.md
Normal file
169
docs/development/roadmap/phases/phase-11.5/README.md
Normal file
@ -0,0 +1,169 @@
|
||||
# Phase 11.5: JIT完全統合 - sync/GC/非同期の最終実装
|
||||
|
||||
## 🎯 概要
|
||||
Phase 11.5は、Nyashの全実行レイヤー(インタープリター/MIR/VM/JIT)でsync処理、GC処理、非同期処理を完全に統合する最終フェーズです。
|
||||
|
||||
## 📊 現状分析(2025-08-30)
|
||||
|
||||
### ✅ 完了済み
|
||||
1. **基本アーキテクチャ**
|
||||
- Everything is Box哲学の完全実装
|
||||
- インタープリター → MIR → VM → JIT パイプライン
|
||||
- プラグインシステム(C ABI/TLVハンドル)
|
||||
|
||||
2. **sync処理**
|
||||
- Arc<Mutex>/Arc<RwLock>による完全スレッドセーフ設計
|
||||
- 全レイヤーでの一貫した同期化
|
||||
|
||||
3. **GC基礎**
|
||||
- カウンティングGC実装(NYASH_GC_COUNTING=1)
|
||||
- Read/Writeバリア実装
|
||||
- VMセーフポイント
|
||||
|
||||
4. **非同期基礎**
|
||||
- FutureBox/TimerBox実装
|
||||
- SingleThreadScheduler
|
||||
- nowait/wait文
|
||||
|
||||
## 🚀 Phase 11.5 タスク一覧
|
||||
|
||||
### 1. JIT sync処理統合
|
||||
- [ ] **1.1 Atomic操作の最適化**
|
||||
- Arc<Mutex>アクセスのJIT最適化
|
||||
- Lock elision(不要なロック除去)
|
||||
- Read-only pathでのロック回避
|
||||
|
||||
- [ ] **1.2 Memory ordering最適化**
|
||||
- Relaxed/Acquire/Release semanticsの活用
|
||||
- プラットフォーム別最適化(x86/ARM)
|
||||
|
||||
### 2. JIT GC統合
|
||||
- [ ] **2.1 Write barrier除去**
|
||||
- Escape analysisによる不要バリア検出
|
||||
- Stack allocation最適化
|
||||
- Generational hypothesis活用
|
||||
|
||||
- [ ] **2.2 Safepoint最適化**
|
||||
- Loop safepoint挿入
|
||||
- Call site safepoint
|
||||
- Polling overhead削減
|
||||
|
||||
- [ ] **2.3 GC情報の伝播**
|
||||
- Stack map生成
|
||||
- Root set tracking
|
||||
- Precise GC対応
|
||||
|
||||
### 3. JIT 非同期処理統合
|
||||
- [ ] **3.1 Coroutine変換**
|
||||
- async/await → state machine変換
|
||||
- Stack switching最適化
|
||||
- Continuation passing
|
||||
|
||||
- [ ] **3.2 スケジューラー統合**
|
||||
- Work stealing queue
|
||||
- CPU affinity最適化
|
||||
- Yield point最適化
|
||||
|
||||
### 4. 統合テスト・ベンチマーク
|
||||
- [ ] **4.1 性能測定**
|
||||
- sync処理のオーバーヘッド測定
|
||||
- GC pause time測定
|
||||
- 非同期処理のレイテンシ測定
|
||||
|
||||
- [ ] **4.2 正確性検証**
|
||||
- Race condition検出
|
||||
- Memory leak検出
|
||||
- Deadlock検出
|
||||
|
||||
## 📋 実装優先順位
|
||||
|
||||
### Phase 11.5a: Write barrier除去(最重要)
|
||||
```rust
|
||||
// 現在: すべてのBox操作でbarrier
|
||||
vm.execute_ref_set() -> gc.barrier(Write)
|
||||
|
||||
// 目標: JITでescape analysisして除去
|
||||
if !escapes_to_heap(value) {
|
||||
// barrierスキップ
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 11.5b: Atomic最適化
|
||||
```rust
|
||||
// 現在: Arc<Mutex>の重いロック
|
||||
let value = box.lock().unwrap().clone();
|
||||
|
||||
// 目標: Read-onlyならatomic load
|
||||
if is_read_only(box) {
|
||||
atomic_load_relaxed(box)
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 11.5c: Coroutine実装
|
||||
```nyash
|
||||
// 将来構文
|
||||
async function fetchData() {
|
||||
local result = await httpGet("...")
|
||||
return result
|
||||
}
|
||||
```
|
||||
|
||||
## 🎯 成功基準
|
||||
|
||||
1. **性能向上**
|
||||
- sync処理: 50%以上のロックオーバーヘッド削減
|
||||
- GC: 90%以上のwrite barrier除去
|
||||
- 非同期: ネイティブthread並みの性能
|
||||
|
||||
2. **互換性維持**
|
||||
- 既存のNyashコードがそのまま動作
|
||||
- プラグインシステムとの完全互換
|
||||
|
||||
3. **デバッグ性**
|
||||
- JIT最適化の可視化(NYASH_JIT_OPT_TRACE)
|
||||
- GC統計の詳細化
|
||||
- 非同期処理のトレース
|
||||
|
||||
## 📅 実装スケジュール(推定)
|
||||
|
||||
- **Week 1-2**: Write barrier除去とescape analysis
|
||||
- **Week 3**: Atomic操作最適化
|
||||
- **Week 4**: Coroutine基礎実装
|
||||
- **Week 5**: 統合テストとベンチマーク
|
||||
- **Week 6**: ドキュメント化と最適化
|
||||
|
||||
## 🔧 技術的詳細
|
||||
|
||||
### Escape Analysis実装案
|
||||
```rust
|
||||
// MIR解析でallocサイトを特定
|
||||
struct EscapeAnalysis {
|
||||
allocations: HashMap<ValueId, AllocSite>,
|
||||
escapes: HashSet<ValueId>,
|
||||
}
|
||||
|
||||
impl EscapeAnalysis {
|
||||
fn analyze(&mut self, func: &MirFunction) {
|
||||
// 1. allocation site収集
|
||||
// 2. data flow解析
|
||||
// 3. escape判定
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### JIT統合ポイント
|
||||
```rust
|
||||
// cranelift-jitでのbarrier除去
|
||||
if !self.escape_info.escapes(value) {
|
||||
// emit_call(gc_write_barrier) をスキップ
|
||||
}
|
||||
```
|
||||
|
||||
## 🎉 期待される成果
|
||||
|
||||
Phase 11.5完了により、Nyashは:
|
||||
- **産業レベルの性能**: GC pauseがマイクロ秒単位
|
||||
- **真の並行性**: lock-free data structures対応
|
||||
- **モダンな非同期**: async/await完全サポート
|
||||
|
||||
これにより、**30日で作られたとは思えない**世界クラスの言語が完成します!
|
||||
162
docs/development/roadmap/phases/phase-11.5/WASM-ISSUES.md
Normal file
162
docs/development/roadmap/phases/phase-11.5/WASM-ISSUES.md
Normal file
@ -0,0 +1,162 @@
|
||||
# WASM実装の問題と改善計画
|
||||
|
||||
## 🚨 現状の問題
|
||||
|
||||
### 1. **2つのWASM実装が存在**
|
||||
- **Rust→WASM**: `wasm-pack build`でNyashインタープリター全体をWASMに(動作する)
|
||||
- **MIR→WASM**: `--compile-wasm`でNyashコードをWASMに変換(ほぼ動かない)
|
||||
|
||||
### 2. **MIR→WASM実装の問題点**
|
||||
```rust
|
||||
// src/backend/wasm/codegen.rs より
|
||||
pub fn generate_module(...) -> Result<WasmModule, WasmError> {
|
||||
// 基本的な命令しか実装されていない
|
||||
// - 算術演算
|
||||
// - 制御フロー
|
||||
// - print文(ホスト関数呼び出し)
|
||||
|
||||
// 未実装:
|
||||
// - Box操作(NewBox, BoxCall, PluginInvoke)
|
||||
// - 配列操作
|
||||
// - プラグインシステム
|
||||
// - GC/メモリ管理
|
||||
}
|
||||
```
|
||||
|
||||
### 3. **根本的な設計問題**
|
||||
- **Box抽象の表現困難**: Everything is BoxをWASMの型システムで表現できない
|
||||
- **動的ディスパッチ**: BoxCallやPluginInvokeの実装が困難
|
||||
- **GCの不在**: WASMにはGCがない(WasmGC提案はまだ実験的)
|
||||
- **プラグインFFI**: C ABIをWASM環境で実現できない
|
||||
|
||||
## 📊 現状の実装状況
|
||||
|
||||
### 実装済み(動作するもの)
|
||||
```nyash
|
||||
// 基本的な算術
|
||||
function add(a, b) {
|
||||
return a + b
|
||||
}
|
||||
|
||||
// 単純な制御フロー
|
||||
function factorial(n) {
|
||||
if n <= 1 { return 1 }
|
||||
return n * factorial(n - 1)
|
||||
}
|
||||
|
||||
// print文(ホスト関数経由)
|
||||
print("Hello WASM")
|
||||
```
|
||||
|
||||
### 未実装(動作しないもの)
|
||||
```nyash
|
||||
// Box操作
|
||||
local str = new StringBox("hello") // ❌ NewBox未実装
|
||||
str.toUpperCase() // ❌ BoxCall未実装
|
||||
|
||||
// 配列
|
||||
local arr = [1, 2, 3] // ❌ 配列リテラル未実装
|
||||
arr.push(4) // ❌ ArrayBox未実装
|
||||
|
||||
// プラグイン
|
||||
local file = new FileBox() // ❌ PluginInvoke未実装
|
||||
```
|
||||
|
||||
## 🤔 なぜRust→WASMは動くのか
|
||||
|
||||
```toml
|
||||
# Cargo.toml
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
wasm-bindgen = "0.2"
|
||||
```
|
||||
|
||||
- **すべてのBox実装がそのままWASMに**: Arc<Mutex>も含めて
|
||||
- **wasm-bindgenの魔法**: JavaScript↔Rust境界を自動生成
|
||||
- **制限事項**: 一部のBox(TimerBox、FileBox等)は除外
|
||||
|
||||
## 🚀 改善案
|
||||
|
||||
### Option 1: MIR→WASM実装の完成(困難)
|
||||
```wat
|
||||
;; BoxをWASMテーブルで管理
|
||||
(table $boxes 1000 externref)
|
||||
(global $next_box_id (mut i32) (i32.const 0))
|
||||
|
||||
;; NewBox実装
|
||||
(func $new_string_box (param $str i32) (result i32)
|
||||
;; 新しいBox IDを割り当て
|
||||
(local $box_id i32)
|
||||
(local.set $box_id (global.get $next_box_id))
|
||||
|
||||
;; JavaScriptでStringBoxを作成
|
||||
(table.set $boxes
|
||||
(local.get $box_id)
|
||||
(call $js_create_string_box (local.get $str)))
|
||||
|
||||
;; IDを返す
|
||||
(local.get $box_id)
|
||||
)
|
||||
```
|
||||
|
||||
**問題点**:
|
||||
- JavaScript側にBox実装が必要
|
||||
- 性能オーバーヘッドが大きい
|
||||
- プラグインシステムとの統合困難
|
||||
|
||||
### Option 2: Rust→WASMの活用(現実的)
|
||||
```rust
|
||||
// NyashコードをRustに変換してからWASMに
|
||||
nyash_code → rust_code → wasm
|
||||
|
||||
// 例:
|
||||
// Nyash: local s = new StringBox("hello")
|
||||
// Rust: let s = Box::new(StringBox::new("hello".to_string()));
|
||||
// WASM: (自動生成)
|
||||
```
|
||||
|
||||
### Option 3: WASMランタイムの埋め込み(革新的)
|
||||
```wat
|
||||
;; 最小VMをWASMに埋め込む
|
||||
(module
|
||||
;; MIRバイトコードを格納
|
||||
(data (i32.const 0) "\01\02\03...")
|
||||
|
||||
;; VMインタープリター
|
||||
(func $vm_execute
|
||||
;; MIR命令をデコード・実行
|
||||
)
|
||||
|
||||
;; エントリーポイント
|
||||
(func (export "main")
|
||||
(call $vm_execute)
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
## 🎯 推奨アプローチ
|
||||
|
||||
### Phase 1: 現状維持
|
||||
- **Rust→WASM**: ブラウザでNyashを動かす用途で活用
|
||||
- **MIR→WASM**: 実験的機能として残す
|
||||
|
||||
### Phase 2: Nyash→Rust変換
|
||||
- NyashコードをRustに変換する仕組みを作る
|
||||
- 生成されたRustコードをwasm-packでビルド
|
||||
|
||||
### Phase 3: WasmGC待ち
|
||||
- WasmGC仕様が安定したら本格実装
|
||||
- Box型システムをWasmGCで表現
|
||||
|
||||
## 📝 結論
|
||||
|
||||
現在のMIR→WASM実装は**実験的**なもので、実用レベルには達していません。一方、Rust→WASMは**すでに動作**しており、ブラウザでNyashを体験してもらうには十分です。
|
||||
|
||||
**当面は**:
|
||||
1. Rust→WASMでプレイグラウンド提供
|
||||
2. ネイティブ実行(VM/JIT/AOT)に注力
|
||||
3. WasmGCの成熟を待つ
|
||||
|
||||
これが現実的な戦略です!
|
||||
@ -0,0 +1,102 @@
|
||||
# プラグインBoxの箱引数宣言方法
|
||||
|
||||
## 📊 nyash_box.tomlでの宣言
|
||||
|
||||
### 1. 基本的な箱引数の宣言
|
||||
|
||||
```toml
|
||||
[HttpRequestBox.methods.respond]
|
||||
id = 3
|
||||
args = [ { name = "resp", type = "box" } ] # type = "box" で箱引数を宣言
|
||||
returns = { type = "void" }
|
||||
```
|
||||
|
||||
### 2. 引数の型一覧
|
||||
|
||||
| 型指定 | 説明 | TLVタグ |
|
||||
|--------|------|---------|
|
||||
| `"i64"` | 64ビット整数 | 3 |
|
||||
| `"f64"` | 64ビット浮動小数点 | 5 |
|
||||
| `"string"` | UTF-8文字列 | 6 |
|
||||
| `"bool"` | 真偽値 | 1 |
|
||||
| `"box"` | **箱(ハンドル)** | 8 |
|
||||
|
||||
### 3. 実際の使用例
|
||||
|
||||
#### NetプラグインのHttpRequestBox
|
||||
```toml
|
||||
[HttpRequestBox]
|
||||
type_id = 21
|
||||
|
||||
[HttpRequestBox.methods.respond]
|
||||
id = 3
|
||||
args = [ { name = "resp", type = "box" } ] # HttpResponseBoxを受け取る
|
||||
returns = { type = "void" }
|
||||
```
|
||||
|
||||
使用方法(Nyash):
|
||||
```nyash
|
||||
local request = server.accept() // HttpRequestBox
|
||||
local response = new HttpResponseBox() // 別のプラグインBox
|
||||
response.setStatus(200)
|
||||
request.respond(response) // 箱を引数として渡す!
|
||||
```
|
||||
|
||||
#### 戻り値が箱の例
|
||||
```toml
|
||||
[HttpServerBox.methods.accept]
|
||||
id = 3
|
||||
args = []
|
||||
returns = { type = "box" } # HttpRequestBoxを返す
|
||||
```
|
||||
|
||||
## 🔧 C実装側での処理
|
||||
|
||||
### TLVデコード
|
||||
```c
|
||||
// HttpRequestBox.respondの実装例
|
||||
case 3: { // respond
|
||||
// 引数をデコード
|
||||
if (args_len < 12) return -1; // header(4) + handle(8)
|
||||
|
||||
// TLVタグチェック
|
||||
uint8_t tag = args[4];
|
||||
if (tag != 8) return -1; // TAG_HANDLE = 8
|
||||
|
||||
// ハンドルデータ取得
|
||||
uint32_t resp_type_id = *(uint32_t*)&args[8];
|
||||
uint32_t resp_instance_id = *(uint32_t*)&args[12];
|
||||
|
||||
// HttpResponseBox(type_id=22)であることを確認
|
||||
if (resp_type_id != 22) return -1;
|
||||
|
||||
// レスポンス処理...
|
||||
}
|
||||
```
|
||||
|
||||
## 💡 重要なポイント
|
||||
|
||||
### 1. 型安全性
|
||||
- `type = "box"`は任意の箱を受け取れる
|
||||
- 実装側で`type_id`チェックにより型安全性を確保
|
||||
|
||||
### 2. 相互運用性
|
||||
- 異なるプラグイン間でも箱の受け渡しが可能
|
||||
- ハンドル(type_id + instance_id)により参照
|
||||
|
||||
### 3. 宣言の簡潔さ
|
||||
```toml
|
||||
# シンプルな宣言
|
||||
args = [ { name = "box_arg", type = "box" } ]
|
||||
|
||||
# 複数の箱引数も可能
|
||||
args = [
|
||||
{ name = "box1", type = "box" },
|
||||
{ name = "box2", type = "box" },
|
||||
{ name = "count", type = "i64" }
|
||||
]
|
||||
```
|
||||
|
||||
## 🎯 結論
|
||||
|
||||
プラグインBoxは`nyash_box.toml`で`type = "box"`と宣言するだけで、他の箱を引数に取ることができます。C ABIレベルではTLVハンドル(タグ8)として処理され、完全な相互運用性が実現されています。
|
||||
@ -0,0 +1,115 @@
|
||||
# プラグインBoxは既に箱を引数に取れる!
|
||||
|
||||
## 🎯 重要な発見
|
||||
|
||||
**プラグインBoxは既にC ABIレベルで箱を引数に取ることができます!**
|
||||
|
||||
## 📊 実装の詳細
|
||||
|
||||
### 1. TLVプロトコルでのハンドルサポート
|
||||
|
||||
```rust
|
||||
// TLVタグ定義
|
||||
const TAG_HANDLE: u8 = 8; // プラグインハンドル用
|
||||
|
||||
// ハンドルエンコード関数
|
||||
pub fn plugin_handle(buf: &mut Vec<u8>, type_id: u32, instance_id: u32) {
|
||||
buf.push(TAG_HANDLE);
|
||||
buf.push(0u8); // reserved
|
||||
buf.extend_from_slice(&(8u16).to_le_bytes()); // size = 8
|
||||
buf.extend_from_slice(&type_id.to_le_bytes()); // 4 bytes
|
||||
buf.extend_from_slice(&instance_id.to_le_bytes()); // 4 bytes
|
||||
}
|
||||
```
|
||||
|
||||
### 2. プラグイン呼び出し時の処理
|
||||
|
||||
```rust
|
||||
// Nyashコード
|
||||
box1.process(box2, box3)
|
||||
|
||||
// ↓ VM/プラグインローダーでの処理
|
||||
for arg in args {
|
||||
if let Some(p) = arg.as_any().downcast_ref::<PluginBoxV2>() {
|
||||
// 箱引数はハンドルとしてエンコード
|
||||
encode::plugin_handle(&mut tlv, p.type_id, p.instance_id);
|
||||
}
|
||||
// ... 他の型の処理
|
||||
}
|
||||
|
||||
// ↓ C ABIプラグイン側
|
||||
int32_t nyash_plugin_invoke(
|
||||
uint32_t type_id,
|
||||
uint32_t method_id,
|
||||
uint32_t instance_id,
|
||||
const uint8_t* args, // TLVエンコードされた引数
|
||||
size_t args_len,
|
||||
uint8_t* result,
|
||||
size_t* result_len
|
||||
) {
|
||||
// TLVデコード
|
||||
uint8_t tag;
|
||||
uint32_t arg_type_id, arg_instance_id;
|
||||
|
||||
if (decode_handle(args, &tag, &arg_type_id, &arg_instance_id)) {
|
||||
// ハンドル引数を処理
|
||||
// arg_type_id と arg_instance_id で箱を特定
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🔄 実際の使用例
|
||||
|
||||
### Nyashレベル
|
||||
```nyash
|
||||
// FileBoxがStringBoxを引数に取る例
|
||||
local file = new FileBox()
|
||||
local path = new StringBox("/tmp/test.txt")
|
||||
file.open(path) // StringBox(プラグインBox)を引数に!
|
||||
|
||||
// ArrayBoxがMapBoxを引数に取る例
|
||||
local array = new ArrayBox()
|
||||
local map = new MapBox()
|
||||
array.push(map) // MapBox(プラグインBox)を引数に!
|
||||
```
|
||||
|
||||
### プラグイン間の相互運用
|
||||
```nyash
|
||||
// NetBoxがJSONBoxを引数に取る例
|
||||
local net = new NetBox()
|
||||
local json = new JSONBox()
|
||||
json.set("url", "https://api.example.com")
|
||||
net.post(json) // JSONBoxを引数として渡す
|
||||
```
|
||||
|
||||
## 💡 重要なポイント
|
||||
|
||||
### 1. ハンドルによる間接参照
|
||||
- 箱の実体は渡さない(メモリ安全性)
|
||||
- `(type_id, instance_id)`のペアで識別
|
||||
- プラグイン側でハンドルから実体にアクセス
|
||||
|
||||
### 2. 型安全性
|
||||
- `type_id`で型を識別可能
|
||||
- 不正な型の場合はエラー返却
|
||||
|
||||
### 3. 所有権管理
|
||||
- インスタンスIDで参照管理
|
||||
- プラグイン間でも安全に共有
|
||||
|
||||
## 🎯 結論
|
||||
|
||||
**C ABIの制約があっても、ハンドル機構により箱は箱を引数に取れる!**
|
||||
|
||||
これは既に実装済みの機能であり、プラグイン間での高度な連携が可能です。
|
||||
|
||||
### 埋め込みVMへの示唆
|
||||
|
||||
既存のTLVハンドル機構をそのまま使えば、埋め込みVMでも同じように箱引数をサポートできます:
|
||||
|
||||
1. Nyashスクリプト内で箱を引数に使用
|
||||
2. MIRバイトコードにBoxCall命令を含める
|
||||
3. 埋め込みVMがTLVエンコードでC ABIプラグインを呼び出し
|
||||
4. ハンドル経由で箱を渡す
|
||||
|
||||
**Everything is Box、そしてC ABIでも箱は箱を扱える!**
|
||||
Reference in New Issue
Block a user