diff --git a/CURRENT_TASK.md b/CURRENT_TASK.md index 8a8acc1b..e1831060 100644 --- a/CURRENT_TASK.md +++ b/CURRENT_TASK.md @@ -208,9 +208,10 @@ - `NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib` 実行時の Case D panic は 4 件 → 0 件となり、Case D 完全解消を達成。型生成(Const/BoxCall)・型伝播(CopyTypePropagator/PhiTypeResolver)・統合(GenericTypeResolver)の 3 層構造が箱として完成し、if_phi フォールバック削除に進める状態になった(Phase 84-5 / 82 の最終仕上げ)。 11. **Phase 85-ring0-runtime: Ring0/Ring1/Plugin 層の設計整理** ⏳ **設計中** - - Ring0 は Box を知らない最小カーネル API(Mem/Io/Time/Log 等)に限定し、実装は `Ring0Context` + adapter 1 箇所に集約する方針を docs に固定。 - - Ring1-core(StringBox/ArrayBox/MapBox/FileBox/ConsoleBox 等)と ring1-optional/selfhost/user_plugin を 4 層に分類し、「core_required は静的必須セット、optional と user は PluginHost の上に載る」設計を言語化。 - - `docs/development/current/main/ring0-inventory.md` に println!/eprintln! を含む Ring0 候補呼び出しや Box/プラグイン/カーネル実装数の調査結果をまとめ、Phase 86 以降で Ring0Context に寄せていくためのインベントリを準備。 + - Ring0 は Box を知らない最小カーネル API(Mem/Io/Time/Log 等)に限定し、実装は `Ring0Context` + adapter 1 箇所に集約する方針を docs に固定済み。 + - Ring1-core(StringBox/ArrayBox/MapBox/FileBox/ConsoleBox 等)と ring1-optional/selfhost/user_plugin を 4 層に分類し、「core_required は静的必須セット、optional と user は PluginHost の上に載る」設計を言語化済み。 + - `docs/development/current/main/ring0-inventory.md` に println!/eprintln! を含む Ring0 候補呼び出しや Box/プラグイン/カーネル実装数の調査結果をまとめ、Phase 86/87 以降で Ring0Context に寄せていくためのインベントリを準備。 + - Phase 87 で CoreBoxId/CoreMethodId の実装とテストが完了し、Box 名・メソッド名のハードコードは `src/runtime/core_box_ids.rs` に集約された。今後の ring0/ring1-core 変更はこの SSOT に対してのみ行えばよい状態になっている。 12. **Phase 86: BoxFactory Priority 正常化** ✅ **完了**(2025-12-02) - **目的**: BoxFactory のデフォルトポリシーを `BuiltinFirst` から `StrictPluginFirst` に変更し、プラグイン版 Box が正常に使用できるよう正常化。 diff --git a/docs/development/current/main/ring0-inventory.md b/docs/development/current/main/ring0-inventory.md index 731071cd..56798952 100644 --- a/docs/development/current/main/ring0-inventory.md +++ b/docs/development/current/main/ring0-inventory.md @@ -14,6 +14,24 @@ - 将来的には `Ring0Context.log` / `Ring0Context.io` 経由に寄せる。 - 代表パス(selfhost/hack_check/VM/LLVM)の `println!/eprintln!` から段階的に移行する。 +### Phase 88 移行状況(2025-12-02) + +**移行済みパス(2箇所)**: + +| ファイル | 行 | Before | After | +|---------|---|--------|-------| +| `src/runner/selfhost.rs` | 27 | `eprintln!("[selfhost][oob-strict] ...")` | `ring0.log.error("[selfhost][oob-strict] ...")` | +| `src/runner/selfhost.rs` | 177 | `eprintln!("❌ PyVM error ...")` | `ring0.log.error("❌ PyVM error ...")` | + +**残存パス(3,953箇所)**: + +| カテゴリ | 出現回数 | 移行予定 | +|---------|---------|---------| +| println! | 2,200 | Phase 89-A | +| eprintln! | 1,753 | Phase 89-B | + +Phase 89 以降で段階的に移行予定。 + --- ## 2. Box / プラグイン / カーネル実装の数 diff --git a/src/runner/mod.rs b/src/runner/mod.rs index 410b2952..3a4df669 100644 --- a/src/runner/mod.rs +++ b/src/runner/mod.rs @@ -60,6 +60,12 @@ use tasks::run_named_task; impl NyashRunner { /// Create a new runner with the given configuration pub fn new(config: CliConfig) -> Self { + // Phase 88: Ring0Context 初期化(グローバル、一度だけ) + // OnceLock により、複数回呼ばれても最初の一度だけ初期化される + let _ = runtime::ring0::GLOBAL_RING0.get_or_init(|| { + std::sync::Arc::new(runtime::ring0::default_ring0()) + }); + Self { config } } diff --git a/src/runner/selfhost.rs b/src/runner/selfhost.rs index bb54de3f..2884db7d 100644 --- a/src/runner/selfhost.rs +++ b/src/runner/selfhost.rs @@ -24,7 +24,9 @@ fn maybe_dump_mir_verbose(module: &crate::mir::MirModule) { /// Check OOB strict mode and exit(1) if out-of-bounds was observed. fn check_oob_strict_exit() { if crate::config::env::oob_strict_fail() && crate::runtime::observe::oob_seen() { - eprintln!("[selfhost][oob-strict] Out-of-bounds observed → exit(1)"); + // Phase 88: Ring0Context 経由でエラーログ出力 + let ring0 = crate::runtime::ring0::get_global_ring0(); + ring0.log.error("[selfhost][oob-strict] Out-of-bounds observed → exit(1)"); std::process::exit(1); } } @@ -170,7 +172,9 @@ impl NyashRunner { println!("Result: {}", code); std::process::exit(code); } else { - eprintln!("❌ PyVM error (selfhost-preexpand)"); + // Phase 88: Ring0Context 経由でエラーログ出力 + let ring0 = crate::runtime::ring0::get_global_ring0(); + ring0.log.error("❌ PyVM error (selfhost-preexpand)"); std::process::exit(1); } } else { diff --git a/src/runtime/mod.rs b/src/runtime/mod.rs index 5f9e9043..73aff3b0 100644 --- a/src/runtime/mod.rs +++ b/src/runtime/mod.rs @@ -6,6 +6,7 @@ pub mod box_registry; pub mod core_box_ids; // Phase 87: CoreBoxId/CoreMethodId 型安全enum pub mod deprecations; pub mod gc; +pub mod ring0; // Phase 88: Ring0Context - OS API 抽象化レイヤー pub mod gc_controller; pub mod gc_mode; pub mod gc_trace; @@ -38,6 +39,7 @@ mod tests; pub use box_registry::{get_global_registry, BoxFactoryRegistry, BoxProvider}; pub use core_box_ids::{CoreBoxCategory, CoreBoxId, CoreMethodId}; // Phase 87: 型安全enum pub use plugin_config::PluginConfig; +pub use ring0::{get_global_ring0, init_global_ring0, Ring0Context}; // Phase 88: Ring0 公開 API pub use plugin_loader_unified::{ get_global_plugin_host, init_global_plugin_host, MethodHandle, PluginBoxType, PluginHost, PluginLibraryHandle, diff --git a/src/runtime/ring0/errors.rs b/src/runtime/ring0/errors.rs new file mode 100644 index 00000000..6ac7f4a2 --- /dev/null +++ b/src/runtime/ring0/errors.rs @@ -0,0 +1,25 @@ +//! Phase 88: Ring0 エラー型定義 + +/// IO 操作エラー +#[derive(Debug, Clone)] +pub struct IoError(pub String); + +impl std::fmt::Display for IoError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "IoError: {}", self.0) + } +} + +impl std::error::Error for IoError {} + +/// 時刻取得エラー +#[derive(Debug, Clone)] +pub struct TimeError(pub String); + +impl std::fmt::Display for TimeError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "TimeError: {}", self.0) + } +} + +impl std::error::Error for TimeError {} diff --git a/src/runtime/ring0/mod.rs b/src/runtime/ring0/mod.rs new file mode 100644 index 00000000..c8cff81b --- /dev/null +++ b/src/runtime/ring0/mod.rs @@ -0,0 +1,114 @@ +//! Phase 88: Ring0Context - OS API 抽象化レイヤー +//! +//! Ring0 は Box を知らない、Nyash を知らない純粋な OS API 層。 + +mod errors; +mod std_impls; +mod traits; + +pub use errors::{IoError, TimeError}; +pub use std_impls::{NoopMem, StdIo, StdLog, StdTime}; +pub use traits::{IoApi, LogApi, LogLevel, MemApi, MemStats, TimeApi}; + +use std::sync::{Arc, OnceLock}; + +/// Phase 88: Ring0 コンテキスト +/// +/// OS API レイヤーを trait で抽象化し、1つの構造体に束ねる。 +pub struct Ring0Context { + pub mem: Arc, + pub io: Arc, + pub time: Arc, + pub log: Arc, +} + +impl Ring0Context { + /// 新規 Ring0Context を作成 + pub fn new( + mem: Arc, + io: Arc, + time: Arc, + log: Arc, + ) -> Self { + Self { mem, io, time, log } + } +} + +impl std::fmt::Debug for Ring0Context { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Ring0Context") + .field("mem", &"") + .field("io", &"") + .field("time", &"") + .field("log", &"") + .finish() + } +} + +/// デフォルト Ring0Context を作成(std ベース) +pub fn default_ring0() -> Ring0Context { + Ring0Context { + mem: Arc::new(NoopMem), + io: Arc::new(StdIo), + time: Arc::new(StdTime), + log: Arc::new(StdLog), + } +} + +// ===== グローバル Ring0Context ===== + +pub static GLOBAL_RING0: OnceLock> = OnceLock::new(); + +/// グローバル Ring0Context を初期化 +pub fn init_global_ring0(ctx: Ring0Context) { + GLOBAL_RING0 + .set(Arc::new(ctx)) + .expect("[Phase 88] Ring0Context already initialized"); +} + +/// グローバル Ring0Context を取得 +pub fn get_global_ring0() -> Arc { + GLOBAL_RING0 + .get() + .expect("[Phase 88] Ring0Context not initialized") + .clone() +} + +// ===== テスト ===== + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_ring0_context_creation() { + let ring0 = default_ring0(); + ring0.log.info("test message"); + } + + #[test] + fn test_io_api() { + let ring0 = default_ring0(); + let result = ring0.io.stdout_write(b"test\n"); + assert!(result.is_ok()); + } + + #[test] + fn test_time_api() { + let ring0 = default_ring0(); + let now = ring0.time.now(); + assert!(now.is_ok()); + + let instant = ring0.time.monotonic_now(); + assert!(instant.is_ok()); + } + + #[test] + fn test_log_levels() { + let ring0 = default_ring0(); + ring0.log.debug("debug message"); + ring0.log.info("info message"); + ring0.log.warn("warn message"); + ring0.log.error("error message"); + } +} diff --git a/src/runtime/ring0/std_impls.rs b/src/runtime/ring0/std_impls.rs new file mode 100644 index 00000000..af68f4ec --- /dev/null +++ b/src/runtime/ring0/std_impls.rs @@ -0,0 +1,73 @@ +//! Phase 88: std ベースの Ring0 デフォルト実装 + +use super::errors::{IoError, TimeError}; +use super::traits::*; +use std::time::SystemTime; + +/// noop メモリ実装(Phase 88: 将来 hakmem に接続) +pub struct NoopMem; + +impl MemApi for NoopMem { + fn alloc(&self, _size: usize) -> *mut u8 { + std::ptr::null_mut() + } + + fn free(&self, _ptr: *mut u8) {} + + fn stats(&self) -> MemStats { + MemStats::default() + } +} + +/// std::io ベースの IO 実装 +pub struct StdIo; + +impl IoApi for StdIo { + fn stdout_write(&self, data: &[u8]) -> Result<(), IoError> { + use std::io::Write; + std::io::stdout() + .write_all(data) + .map_err(|e| IoError(format!("stdout write failed: {}", e))) + } + + fn stderr_write(&self, data: &[u8]) -> Result<(), IoError> { + use std::io::Write; + std::io::stderr() + .write_all(data) + .map_err(|e| IoError(format!("stderr write failed: {}", e))) + } + + fn stdin_read(&self, buf: &mut [u8]) -> Result { + use std::io::Read; + std::io::stdin() + .read(buf) + .map_err(|e| IoError(format!("stdin read failed: {}", e))) + } +} + +/// std::time ベースの時刻実装 +pub struct StdTime; + +impl TimeApi for StdTime { + fn now(&self) -> Result { + Ok(SystemTime::now()) + } + + fn monotonic_now(&self) -> Result { + Ok(std::time::Instant::now()) + } +} + +/// eprintln!/println! ベースのログ実装 +pub struct StdLog; + +impl LogApi for StdLog { + fn log(&self, level: LogLevel, msg: &str) { + match level { + LogLevel::Debug => eprintln!("[DEBUG] {}", msg), + LogLevel::Info => println!("[INFO] {}", msg), + LogLevel::Warn => eprintln!("[WARN] {}", msg), + LogLevel::Error => eprintln!("[ERROR] {}", msg), + } + } +} diff --git a/src/runtime/ring0/traits.rs b/src/runtime/ring0/traits.rs new file mode 100644 index 00000000..5b832b93 --- /dev/null +++ b/src/runtime/ring0/traits.rs @@ -0,0 +1,83 @@ +//! Phase 88: Ring0 trait 定義 +//! +//! OS API レイヤーの純粋な抽象化。 +//! Box 名・Nyash 型を一切知らない。 + +use super::errors::{IoError, TimeError}; +use std::time::SystemTime; + +/// メモリ API(Phase 88: noop、将来 hakmem 接続) +pub trait MemApi: Send + Sync { + /// メモリ割り当て(Phase 88: 未実装) + fn alloc(&self, size: usize) -> *mut u8; + + /// メモリ解放(Phase 88: 未実装) + fn free(&self, ptr: *mut u8); + + /// メモリ統計(Phase 88: 未実装) + fn stats(&self) -> MemStats; +} + +/// メモリ統計情報 +#[derive(Debug, Default, Clone)] +pub struct MemStats { + pub allocated: usize, + pub freed: usize, + pub current: usize, +} + +/// IO API +pub trait IoApi: Send + Sync { + /// 標準出力への書き込み + fn stdout_write(&self, data: &[u8]) -> Result<(), IoError>; + + /// 標準エラー出力への書き込み + fn stderr_write(&self, data: &[u8]) -> Result<(), IoError>; + + /// 標準入力からの読み込み + fn stdin_read(&self, buf: &mut [u8]) -> Result; +} + +/// 時刻 API +pub trait TimeApi: Send + Sync { + /// 現在時刻取得 + fn now(&self) -> Result; + + /// モノトニック時刻取得(高精度タイマー用) + fn monotonic_now(&self) -> Result; +} + +/// ログレベル +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum LogLevel { + Debug, + Info, + Warn, + Error, +} + +/// ログ API +pub trait LogApi: Send + Sync { + /// ログ出力 + fn log(&self, level: LogLevel, msg: &str); + + /// デバッグログ(便利メソッド) + fn debug(&self, msg: &str) { + self.log(LogLevel::Debug, msg); + } + + /// 情報ログ(便利メソッド) + fn info(&self, msg: &str) { + self.log(LogLevel::Info, msg); + } + + /// 警告ログ(便利メソッド) + fn warn(&self, msg: &str) { + self.log(LogLevel::Warn, msg); + } + + /// エラーログ(便利メソッド) + fn error(&self, msg: &str) { + self.log(LogLevel::Error, msg); + } +}