Files
hakorune/src/config/env.rs
Selfhosting Dev c8063c9e41 pyvm: split op handlers into ops_core/ops_box/ops_ctrl; add ops_flow + intrinsic; delegate vm.py without behavior change
net-plugin: modularize constants (consts.rs) and sockets (sockets.rs); remove legacy commented socket code; fix unused imports
mir: move instruction unit tests to tests/mir_instruction_unit.rs (file lean-up); no semantic changes
runner/pyvm: ensure using pre-strip; misc docs updates

Build: cargo build ok; legacy cfg warnings remain as before
2025-09-21 08:53:00 +09:00

451 lines
15 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! Global environment configuration aggregator (管理棟)
//!
//! Consolidates NYASH_* environment variables across subsystems and
//! optionally applies overrides from `nyash.toml`.
use std::collections::BTreeMap;
#[derive(Debug, Clone, Default)]
pub struct NyashEnv {
/// JIT-related configuration (delegates to jit::config)
pub jit: crate::jit::config::JitConfig,
/// Arbitrary key-value overrides loaded from nyash.toml [env]
pub overrides: BTreeMap<String, String>,
}
impl NyashEnv {
pub fn from_env() -> Self {
Self {
jit: crate::jit::config::JitConfig::from_env(),
overrides: BTreeMap::new(),
}
}
/// Apply current struct values into process environment
pub fn apply_env(&self) {
self.jit.apply_env();
for (k, v) in &self.overrides {
std::env::set_var(k, v);
}
}
}
// Global current env config (thread-safe)
use once_cell::sync::OnceCell;
use std::sync::RwLock;
static GLOBAL_ENV: OnceCell<RwLock<NyashEnv>> = OnceCell::new();
static PHI_ON_GATED_WARNED: OnceCell<()> = OnceCell::new();
pub fn current() -> NyashEnv {
if let Some(lock) = GLOBAL_ENV.get() {
if let Ok(cfg) = lock.read() {
return cfg.clone();
}
}
NyashEnv::from_env()
}
pub fn set_current(cfg: NyashEnv) {
if let Some(lock) = GLOBAL_ENV.get() {
if let Ok(mut w) = lock.write() {
*w = cfg;
return;
}
}
let _ = GLOBAL_ENV.set(RwLock::new(cfg));
}
/// Load overrides from nyash.toml `[env]` table and apply them to process env.
///
/// Example:
/// [env]
/// NYASH_JIT_THRESHOLD = "1"
/// NYASH_CLI_VERBOSE = "1"
pub fn bootstrap_from_toml_env() {
// Allow disabling nyash.toml env bootstrapping for isolated smokes/CI
if std::env::var("NYASH_SKIP_TOML_ENV").ok().as_deref() == Some("1") {
return;
}
let path = "nyash.toml";
let content = match std::fs::read_to_string(path) {
Ok(s) => s,
Err(_) => return,
};
let Ok(value) = toml::from_str::<toml::Value>(&content) else {
return;
};
let Some(env_tbl) = value.get("env").and_then(|v| v.as_table()) else {
return;
};
let mut overrides: BTreeMap<String, String> = BTreeMap::new();
for (k, v) in env_tbl {
if let Some(s) = v.as_str() {
std::env::set_var(k, s);
overrides.insert(k.clone(), s.to_string());
} else if let Some(b) = v.as_bool() {
let sv = if b { "1" } else { "0" };
std::env::set_var(k, sv);
overrides.insert(k.clone(), sv.to_string());
} else if let Some(n) = v.as_integer() {
let sv = n.to_string();
std::env::set_var(k, &sv);
overrides.insert(k.clone(), sv);
}
}
// Merge into global
let mut cur = current();
cur.overrides.extend(overrides);
set_current(cur);
}
/// Get await maximum milliseconds, centralized here for consistency.
pub fn await_max_ms() -> u64 {
std::env::var("NYASH_AWAIT_MAX_MS")
.ok()
.and_then(|s| s.parse().ok())
.unwrap_or(5000)
}
// ---- MIR PHI-less (edge-copy) mode ----
/// Enable MIR PHI non-generation. Bridge/Builder emit edge copies instead of PHI.
pub fn mir_no_phi() -> bool {
match std::env::var("NYASH_MIR_NO_PHI").ok() {
Some(v) => {
let lv = v.to_ascii_lowercase();
let requested_no_phi = !(lv == "0" || lv == "false" || lv == "off");
if requested_no_phi {
return true;
}
// PHI-on requested
#[cfg(feature = "phi-legacy")]
{
return false;
}
#[cfg(not(feature = "phi-legacy"))]
{
if PHI_ON_GATED_WARNED.set(()).is_ok() {
eprintln!(
"[nyash] PHI-on requested but disabled in this build (missing 'phi-legacy' feature). Falling back to PHI-off."
);
}
return true;
}
}
// Default: ON for MIR13 stability (PHI generation off by default)
None => true,
}
}
/// Allow verifier to skip SSA/dominance/merge checks for PHI-less MIR.
pub fn verify_allow_no_phi() -> bool {
std::env::var("NYASH_VERIFY_ALLOW_NO_PHI").ok().as_deref() == Some("1") || mir_no_phi()
}
/// Enable strict edge-copy policy verification in PHI-off mode.
/// When enabled, merge blocks must receive merged values via predecessor copies only,
/// and the merge block itself must not introduce a self-copy to the merged destination.
pub fn verify_edge_copy_strict() -> bool {
std::env::var("NYASH_VERIFY_EDGE_COPY_STRICT").ok().as_deref() == Some("1")
}
// ---- LLVM harness toggle (llvmlite) ----
pub fn llvm_use_harness() -> bool {
std::env::var("NYASH_LLVM_USE_HARNESS").ok().as_deref() == Some("1")
}
// ---- Phase 11.8 MIR cleanup toggles ----
/// Core-13 minimal MIR mode toggle
/// Default: ON (unless explicitly disabled with NYASH_MIR_CORE13=0)
pub fn mir_core13() -> bool {
match std::env::var("NYASH_MIR_CORE13").ok() {
Some(v) => {
let lv = v.to_ascii_lowercase();
!(lv == "0" || lv == "false" || lv == "off")
}
None => true,
}
}
pub fn mir_ref_boxcall() -> bool {
std::env::var("NYASH_MIR_REF_BOXCALL").ok().as_deref() == Some("1") || mir_core13()
}
pub fn mir_array_boxcall() -> bool {
std::env::var("NYASH_MIR_ARRAY_BOXCALL").ok().as_deref() == Some("1") || mir_core13()
}
pub fn mir_plugin_invoke() -> bool {
std::env::var("NYASH_MIR_PLUGIN_INVOKE").ok().as_deref() == Some("1")
}
pub fn plugin_only() -> bool {
std::env::var("NYASH_PLUGIN_ONLY").ok().as_deref() == Some("1")
}
/// Core-13 "pure" mode: after normalization, only the 13 canonical ops are allowed.
/// If enabled, the optimizer will try lightweight rewrites for Load/Store/NewBox/Unary,
/// and the final verifier will reject any remaining non-Core-13 ops.
pub fn mir_core13_pure() -> bool {
std::env::var("NYASH_MIR_CORE13_PURE").ok().as_deref() == Some("1")
}
// ---- Optimizer diagnostics ----
pub fn opt_debug() -> bool {
std::env::var("NYASH_OPT_DEBUG").is_ok()
}
pub fn opt_diag() -> bool {
std::env::var("NYASH_OPT_DIAG").is_ok()
}
pub fn opt_diag_forbid_legacy() -> bool {
std::env::var("NYASH_OPT_DIAG_FORBID_LEGACY").is_ok()
}
pub fn opt_diag_fail() -> bool {
std::env::var("NYASH_OPT_DIAG_FAIL").is_ok()
}
// ---- GC/Runtime tracing (execution-affecting visibility) ----
pub fn gc_trace() -> bool {
std::env::var("NYASH_GC_TRACE").ok().as_deref() == Some("1")
}
pub fn gc_barrier_trace() -> bool {
std::env::var("NYASH_GC_BARRIER_TRACE").ok().as_deref() == Some("1")
}
pub fn runtime_checkpoint_trace() -> bool {
std::env::var("NYASH_RUNTIME_CHECKPOINT_TRACE")
.ok()
.as_deref()
== Some("1")
}
pub fn vm_pic_stats() -> bool {
std::env::var("NYASH_VM_PIC_STATS").ok().as_deref() == Some("1")
}
pub fn vm_vt_trace() -> bool {
std::env::var("NYASH_VM_VT_TRACE").ok().as_deref() == Some("1")
}
pub fn vm_pic_trace() -> bool {
std::env::var("NYASH_VM_PIC_TRACE").ok().as_deref() == Some("1")
}
pub fn gc_barrier_strict() -> bool {
std::env::var("NYASH_GC_BARRIER_STRICT").ok().as_deref() == Some("1")
}
/// Return 0 (off) to 3 (max) for `NYASH_GC_TRACE`.
pub fn gc_trace_level() -> u8 {
match std::env::var("NYASH_GC_TRACE").ok().as_deref() {
Some("1") => 1,
Some("2") => 2,
Some("3") => 3,
Some(_) => 1,
None => 0,
}
}
// ---- GC mode and instrumentation ----
/// Return current GC mode string (auto default = "rc+cycle").
/// Allowed: "auto", "rc+cycle", "minorgen", "stw", "rc", "off"
pub fn gc_mode() -> String {
match std::env::var("NYASH_GC_MODE").ok() {
Some(m) if !m.trim().is_empty() => m,
_ => "rc+cycle".to_string(),
}
}
/// Brief metrics emission (text)
pub fn gc_metrics() -> bool {
std::env::var("NYASH_GC_METRICS").ok().as_deref() == Some("1")
}
/// JSON metrics emission (single line)
pub fn gc_metrics_json() -> bool {
std::env::var("NYASH_GC_METRICS_JSON").ok().as_deref() == Some("1")
}
/// Leak diagnostics on exit
pub fn gc_leak_diag() -> bool {
std::env::var("NYASH_GC_LEAK_DIAG").ok().as_deref() == Some("1")
}
/// Optional allocation threshold; if Some(n) and exceeded, print warning
pub fn gc_alloc_threshold() -> Option<u64> {
std::env::var("NYASH_GC_ALLOC_THRESHOLD").ok()?.parse().ok()
}
// ---- Cleanup (method-level postfix) policy toggles ----
/// Allow `return` inside a cleanup block. Default: false (0)
pub fn cleanup_allow_return() -> bool {
match std::env::var("NYASH_CLEANUP_ALLOW_RETURN").ok() {
Some(v) => {
let lv = v.to_ascii_lowercase();
!(lv == "0" || lv == "false" || lv == "off")
}
None => false,
}
}
/// Allow `throw` inside a cleanup block. Default: false (0)
pub fn cleanup_allow_throw() -> bool {
match std::env::var("NYASH_CLEANUP_ALLOW_THROW").ok() {
Some(v) => {
let lv = v.to_ascii_lowercase();
!(lv == "0" || lv == "false" || lv == "off")
}
None => false,
}
}
/// Run a collection every N safepoints (if Some)
pub fn gc_collect_sp_interval() -> Option<u64> {
std::env::var("NYASH_GC_COLLECT_SP").ok()?.parse().ok()
}
/// Run a collection when allocated bytes since last >= N (if Some)
pub fn gc_collect_alloc_bytes() -> Option<u64> {
std::env::var("NYASH_GC_COLLECT_ALLOC").ok()?.parse().ok()
}
// ---- Rewriter flags (optimizer transforms)
pub fn rewrite_debug() -> bool {
std::env::var("NYASH_REWRITE_DEBUG").ok().as_deref() == Some("1")
}
pub fn rewrite_safepoint() -> bool {
std::env::var("NYASH_REWRITE_SAFEPOINT").ok().as_deref() == Some("1")
}
pub fn rewrite_future() -> bool {
std::env::var("NYASH_REWRITE_FUTURE").ok().as_deref() == Some("1")
}
// ---- Phase 12: Nyash ABI (vtable) toggles ----
pub fn abi_vtable() -> bool {
std::env::var("NYASH_ABI_VTABLE").ok().as_deref() == Some("1")
}
pub fn abi_strict() -> bool {
std::env::var("NYASH_ABI_STRICT").ok().as_deref() == Some("1")
}
// ---- ExternCall strict diagnostics ----
pub fn extern_strict() -> bool {
std::env::var("NYASH_EXTERN_STRICT").ok().as_deref() == Some("1")
}
pub fn extern_trace() -> bool {
std::env::var("NYASH_EXTERN_TRACE").ok().as_deref() == Some("1")
}
// ---- Phase 12: thresholds and routing policies ----
/// PIC hotness threshold before promoting to mono cache.
pub fn vm_pic_threshold() -> u32 {
std::env::var("NYASH_VM_PIC_THRESHOLD")
.ok()
.and_then(|s| s.parse().ok())
.unwrap_or(8)
}
/// Route VM ExternCall via name→slot handlers when available
pub fn extern_route_slots() -> bool {
std::env::var("NYASH_EXTERN_ROUTE_SLOTS").ok().as_deref() == Some("1")
}
// ---- Runner/CLI common toggles (hot-path centralization)
pub fn cli_verbose() -> bool {
std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1")
}
pub fn enable_using() -> bool {
std::env::var("NYASH_ENABLE_USING").ok().as_deref() == Some("1")
}
pub fn vm_use_py() -> bool {
std::env::var("NYASH_VM_USE_PY").ok().as_deref() == Some("1")
}
pub fn pipe_use_pyvm() -> bool {
std::env::var("NYASH_PIPE_USE_PYVM").ok().as_deref() == Some("1")
}
pub fn vm_use_dispatch() -> bool {
std::env::var("NYASH_VM_USE_DISPATCH").ok().as_deref() == Some("1")
}
// Self-host compiler knobs
pub fn ny_compiler_timeout_ms() -> u64 {
std::env::var("NYASH_NY_COMPILER_TIMEOUT_MS")
.ok()
.and_then(|s| s.parse().ok())
.unwrap_or(2000)
}
pub fn ny_compiler_emit_only() -> bool {
std::env::var("NYASH_NY_COMPILER_EMIT_ONLY").unwrap_or_else(|_| "1".to_string()) == "1"
}
pub fn ny_compiler_skip_py() -> bool {
std::env::var("NYASH_NY_COMPILER_SKIP_PY").ok().as_deref() == Some("1")
}
pub fn use_ny_compiler_exe() -> bool {
std::env::var("NYASH_USE_NY_COMPILER_EXE").ok().as_deref() == Some("1")
}
pub fn ny_compiler_exe_path() -> Option<String> {
std::env::var("NYASH_NY_COMPILER_EXE_PATH").ok()
}
pub fn ny_compiler_min_json() -> bool {
std::env::var("NYASH_NY_COMPILER_MIN_JSON").ok().as_deref() == Some("1")
}
pub fn selfhost_read_tmp() -> bool {
std::env::var("NYASH_SELFHOST_READ_TMP").ok().as_deref() == Some("1")
}
pub fn ny_compiler_stage3() -> bool {
std::env::var("NYASH_NY_COMPILER_STAGE3").ok().as_deref() == Some("1")
}
/// Core (Rust) parser Stage-3 gate
/// When enabled, the Rust parser accepts Stage-3 surface (try/catch/finally, throw).
/// Default is OFF to keep Stage-2 stable.
pub fn parser_stage3() -> bool {
std::env::var("NYASH_PARSER_STAGE3").ok().as_deref() == Some("1")
}
/// Parser gate for BlockPostfix Catch acceptance
/// Enabled when either NYASH_BLOCK_CATCH=1 or Stage3 gate is on.
/// Phase 15.5 allows parsing a standalone `{ ... }` block optionally followed by
/// a single `catch (...) { ... }` and/or `finally { ... }`, which is folded into
/// ASTNode::TryCatch with the preceding block as the try body.
pub fn block_postfix_catch() -> bool {
std::env::var("NYASH_BLOCK_CATCH").ok().as_deref() == Some("1") || parser_stage3()
}
/// Bridge lowering: use Result-style try/throw lowering instead of MIR Catch/Throw
/// When on, try/catch is lowered using structured blocks and direct jumps,
/// without emitting MIR Throw/Catch. The thrown value is routed to catch via
/// block parameters (PHI-off uses edge-copy).
pub fn try_result_mode() -> bool {
std::env::var("NYASH_TRY_RESULT_MODE").ok().as_deref() == Some("1")
}
/// Parser gate for method-level postfix catch/finally acceptance on method definitions.
/// Enabled when either NYASH_METHOD_CATCH=1 or Stage3 gate is on.
pub fn method_catch() -> bool {
std::env::var("NYASH_METHOD_CATCH").ok().as_deref() == Some("1") || parser_stage3()
}
/// Entry policy: allow top-level `main` resolution in addition to `Main.main`.
/// Default: false (prefer explicit `static box Main { main(...) }`).
pub fn entry_allow_toplevel_main() -> bool {
match std::env::var("NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN").ok() {
Some(v) => {
let v = v.to_ascii_lowercase();
v == "1" || v == "true" || v == "on"
}
None => false,
}
}
/// Parser gate for expression-level postfix catch/cleanup acceptance.
/// Enabled when Stage-3 gate is on (NYASH_PARSER_STAGE3=1). Separate gate can
/// be introduced in future if needed, but we keep minimal toggles now.
pub fn expr_postfix_catch() -> bool {
parser_stage3()
}
/// Parser gate for Unified Members (stored/computed/once/birth_once).
/// Default: ON during Phase-15 (set NYASH_ENABLE_UNIFIED_MEMBERS=0|false|off to disable).
pub fn unified_members() -> bool {
match std::env::var("NYASH_ENABLE_UNIFIED_MEMBERS").ok() {
Some(v) => {
let lv = v.to_ascii_lowercase();
!(lv == "0" || lv == "false" || lv == "off")
}
None => true,
}
}
pub fn ny_compiler_child_args() -> Option<String> {
std::env::var("NYASH_NY_COMPILER_CHILD_ARGS").ok()
}
pub fn ny_compiler_use_tmp_only() -> bool {
std::env::var("NYASH_NY_COMPILER_USE_TMP_ONLY")
.ok()
.as_deref()
== Some("1")
}