Phase 21.7 normalization: optimization pre-work + bench harness expansion

- Add opt-in optimizations (defaults OFF)
  - Ret purity verifier: NYASH_VERIFY_RET_PURITY=1
  - strlen FAST enhancement for const handles
  - FAST_INT gate for same-BB SSA optimization
  - length cache for string literals in llvmlite
- Expand bench harness (tools/perf/microbench.sh)
  - Add branch/call/stringchain/arraymap/chip8/kilo cases
  - Auto-calculate ratio vs C reference
  - Document in benchmarks/README.md
- Compiler health improvements
  - Unify PHI insertion to insert_phi_at_head()
  - Add NYASH_LLVM_SKIP_BUILD=1 for build reuse
- Runtime & safety enhancements
  - Clarify Rust/Hako ownership boundaries
  - Strengthen receiver localization (LocalSSA/pin/after-PHIs)
  - Stop excessive PluginInvoke→BoxCall rewrites
- Update CURRENT_TASK.md, docs, and canaries

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-11-13 16:40:58 +09:00
parent 9e2fa1e36e
commit dda65b94b7
160 changed files with 6773 additions and 1692 deletions

View File

@ -123,6 +123,85 @@ pub fn populate_from_toml(
Ok(policy)
}
/// Resolve a using target name into a concrete path token.
/// - Returns plain file path for modules/package files
/// - Returns a marker token `dylib:<path>` for kind="dylib" packages
/// - Searches relative to `context_dir` then `using_paths` for bare names
/// - When `strict` and multiple candidates exist, returns Err
pub fn resolve_using_target_common(
tgt: &str,
modules: &[(String, String)],
using_paths: &[String],
packages: &HashMap<String, UsingPackage>,
context_dir: Option<&std::path::Path>,
strict: bool,
verbose: bool,
) -> Result<String, String> {
// 1) modules mapping
if let Some((_, p)) = modules.iter().find(|(n, _)| n == tgt) {
if verbose { eprintln!("[using/resolve] modules '{}' -> '{}'", tgt, p); }
return Ok(p.clone());
}
// 2) named packages
if let Some(pkg) = packages.get(tgt) {
match pkg.kind {
PackageKind::Dylib => {
let out = format!("dylib:{}", pkg.path);
if verbose { eprintln!("[using/resolve] dylib '{}' -> '{}'", tgt, out); }
return Ok(out);
}
PackageKind::Package => {
let base = std::path::Path::new(&pkg.path);
let out = if let Some(m) = &pkg.main {
if matches!(base.extension().and_then(|s| s.to_str()), Some("nyash") | Some("hako")) {
pkg.path.clone()
} else {
base.join(m).to_string_lossy().to_string()
}
} else {
if matches!(base.extension().and_then(|s| s.to_str()), Some("nyash") | Some("hako")) {
pkg.path.clone()
} else {
let leaf = base.file_name().and_then(|s| s.to_str()).unwrap_or(tgt);
let hako = base.join(format!("{}.hako", leaf));
if hako.exists() { hako.to_string_lossy().to_string() }
else { base.join(format!("{}.hako", leaf)).to_string_lossy().to_string() }
}
};
if verbose { eprintln!("[using/resolve] package '{}' -> '{}'", tgt, out); }
return Ok(out);
}
}
}
// 3) relative: prefer cwd > using_paths; .hako first then .nyash
let rel_hako = tgt.replace('.', "/") + ".hako";
let rel_ny = tgt.replace('.', "/") + ".nyash";
let mut cand: Vec<String> = Vec::new();
if let Some(dir) = context_dir {
let c1 = dir.join(&rel_hako);
if c1.exists() { cand.push(c1.to_string_lossy().to_string()); }
let c2 = dir.join(&rel_ny);
if c2.exists() { cand.push(c2.to_string_lossy().to_string()); }
}
for base in using_paths {
let p = std::path::Path::new(base);
let c1 = p.join(&rel_hako);
if c1.exists() { cand.push(c1.to_string_lossy().to_string()); }
let c2 = p.join(&rel_ny);
if c2.exists() { cand.push(c2.to_string_lossy().to_string()); }
}
if cand.is_empty() {
if verbose { eprintln!("[using] unresolved '{}' (searched: rel+paths)", tgt); }
return Err(format!("using: unresolved '{}': searched relative and using.paths", tgt));
}
if cand.len() > 1 && strict {
return Err(format!("ambiguous using '{}': {}", tgt, cand.join(", ")));
}
let out = cand.remove(0);
if verbose { eprintln!("[using/resolve] '{}' -> '{}'", tgt, out); }
Ok(out)
}
fn load_workspace_modules(
nyash_dir: &std::path::Path,
workspace_tbl: &toml::value::Table,