fix(jit): NewBoxのJIT安全化とDebugBox Phase 1実装
- NewBoxのJIT扱いを安全化(src/jit/lower/core.rs) - NYASH_USE_PLUGIN_BUILTINS=1 && args.is_empty() かつ StringBox/IntegerBox のみJIT許可 - ArrayBox/MapBox等のプラグインBoxまたは引数ありはunsupportedとしてカウント - unsupported>0の関数はJIT対象外となりVM実行にフォールバック(Segfault回避) - DebugBox Phase 1実装(JITトレース機能) - tracePluginCalls(bool)でJITシムトレースON/OFF - getJitEvents()で直近のJITイベント取得 - src/jit/shim_trace.rs追加でトレース基盤実装 - Printのサポート - PrintはJIT非対応に戻しVM経路で確実に出力(出力消失解消) - テストとサンプル追加 - examples/jit_plugin_invoke_param_array.nyash: 最小JITスモークテスト - examples/py_result_*.nyash: Python plugin結果チェーン処理デモ - PyRuntimeBox拡張 - str()メソッドでPyObjectのstring表現を取得可能に - エラーハンドリング改善とResultチェーンサポート 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
18
README.ja.md
18
README.ja.md
@ -1,4 +1,5 @@
|
|||||||
# 🐱 Nyash プログラミング言語
|
# 🐱 Nyash プログラミング言語
|
||||||
|
**超真面目に作っている趣味言語**
|
||||||
**20日でゼロからネイティブバイナリへ - AI駆動の言語革命**
|
**20日でゼロからネイティブバイナリへ - AI駆動の言語革命**
|
||||||
|
|
||||||
*[🇺🇸 English Version / 英語版はこちら](README.md)*
|
*[🇺🇸 English Version / 英語版はこちら](README.md)*
|
||||||
@ -7,10 +8,19 @@
|
|||||||
[](#philosophy)
|
[](#philosophy)
|
||||||
[](#performance)
|
[](#performance)
|
||||||
[](#execution-modes)
|
[](#execution-modes)
|
||||||
|
[](projects/nyash-wasm/nyash_playground.html)
|
||||||
[](#license)
|
[](#license)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 🎮 **今すぐブラウザでNyashを試そう!**
|
||||||
|
|
||||||
|
👉 **[ブラウザプレイグラウンドを起動](projects/nyash-wasm/nyash_playground.html)** 👈
|
||||||
|
|
||||||
|
インストール不要 - ウェブブラウザで即座にNyashを体験!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 🚀 **速報: ネイティブEXE達成!**
|
## 🚀 **速報: ネイティブEXE達成!**
|
||||||
|
|
||||||
**2025年8月29日** - 誕生からわずか20日で、Nyashがネイティブ実行ファイルへのコンパイルを実現!
|
**2025年8月29日** - 誕生からわずか20日で、Nyashがネイティブ実行ファイルへのコンパイルを実現!
|
||||||
@ -140,7 +150,7 @@ VM + JIT | 5.8ms | 19.0倍高速
|
|||||||
### クリーンな構文
|
### クリーンな構文
|
||||||
```nyash
|
```nyash
|
||||||
box GameCharacter {
|
box GameCharacter {
|
||||||
init { name, health, skills }
|
private { name, health, skills }
|
||||||
|
|
||||||
// birthコンストラクタ - Boxに生命を与える!
|
// birthコンストラクタ - Boxに生命を与える!
|
||||||
birth(characterName) {
|
birth(characterName) {
|
||||||
@ -179,7 +189,7 @@ local files = await task2
|
|||||||
```nyash
|
```nyash
|
||||||
// 継承よりコンポジション
|
// 継承よりコンポジション
|
||||||
box EnhancedArray from ArrayBox {
|
box EnhancedArray from ArrayBox {
|
||||||
init { logger }
|
private { logger }
|
||||||
|
|
||||||
override push(item) {
|
override push(item) {
|
||||||
me.logger.log("追加中: " + item)
|
me.logger.log("追加中: " + item)
|
||||||
@ -278,7 +288,7 @@ loop(true) {
|
|||||||
### ゲーム開発
|
### ゲーム開発
|
||||||
```nyash
|
```nyash
|
||||||
box GameObject {
|
box GameObject {
|
||||||
init { x, y, sprite }
|
public { x, y, sprite }
|
||||||
|
|
||||||
update(deltaTime) {
|
update(deltaTime) {
|
||||||
// 物理シミュレーション
|
// 物理シミュレーション
|
||||||
@ -309,7 +319,7 @@ MIT ライセンス - プロジェクトで自由に使用してください!
|
|||||||
|
|
||||||
## 👨💻 **作者**
|
## 👨💻 **作者**
|
||||||
|
|
||||||
**Tomoaki** - 言語設計者&革命家
|
**charmpic** - 趣味で言語作ってる人
|
||||||
- 🐱 GitHub: [@moe-charm](https://github.com/moe-charm)
|
- 🐱 GitHub: [@moe-charm](https://github.com/moe-charm)
|
||||||
- 🌟 協力: Claude、ChatGPT、Codexとのコラボレーション
|
- 🌟 協力: Claude、ChatGPT、Codexとのコラボレーション
|
||||||
|
|
||||||
|
|||||||
18
README.md
18
README.md
@ -1,4 +1,5 @@
|
|||||||
# 🐱 Nyash Programming Language
|
# 🐱 Nyash Programming Language
|
||||||
|
**A Seriously-Crafted Hobby Language**
|
||||||
**From Zero to Native Binary in 20 Days - The AI-Powered Language Revolution**
|
**From Zero to Native Binary in 20 Days - The AI-Powered Language Revolution**
|
||||||
|
|
||||||
*[🇯🇵 日本語版はこちら / Japanese Version](README.ja.md)*
|
*[🇯🇵 日本語版はこちら / Japanese Version](README.ja.md)*
|
||||||
@ -7,10 +8,19 @@
|
|||||||
[](#philosophy)
|
[](#philosophy)
|
||||||
[](#performance)
|
[](#performance)
|
||||||
[](#execution-modes)
|
[](#execution-modes)
|
||||||
|
[](projects/nyash-wasm/nyash_playground.html)
|
||||||
[](#license)
|
[](#license)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 🎮 **Try Nyash in Your Browser Right Now!**
|
||||||
|
|
||||||
|
👉 **[Launch Browser Playground](projects/nyash-wasm/nyash_playground.html)** 👈
|
||||||
|
|
||||||
|
No installation needed - experience Nyash instantly in your web browser!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 🚀 **Breaking News: Native EXE Achieved!**
|
## 🚀 **Breaking News: Native EXE Achieved!**
|
||||||
|
|
||||||
**August 29, 2025** - Just 20 days after inception, Nyash can now compile to native executables!
|
**August 29, 2025** - Just 20 days after inception, Nyash can now compile to native executables!
|
||||||
@ -140,7 +150,7 @@ Native Binary | ~4ms | ~27x faster
|
|||||||
### Clean Syntax
|
### Clean Syntax
|
||||||
```nyash
|
```nyash
|
||||||
box GameCharacter {
|
box GameCharacter {
|
||||||
init { name, health, skills }
|
private { name, health, skills }
|
||||||
|
|
||||||
// Birth constructor - giving life to Boxes!
|
// Birth constructor - giving life to Boxes!
|
||||||
birth(characterName) {
|
birth(characterName) {
|
||||||
@ -179,7 +189,7 @@ local files = await task2
|
|||||||
```nyash
|
```nyash
|
||||||
// Composition over inheritance
|
// Composition over inheritance
|
||||||
box EnhancedArray from ArrayBox {
|
box EnhancedArray from ArrayBox {
|
||||||
init { logger }
|
private { logger }
|
||||||
|
|
||||||
override push(item) {
|
override push(item) {
|
||||||
me.logger.log("Adding: " + item)
|
me.logger.log("Adding: " + item)
|
||||||
@ -278,7 +288,7 @@ loop(true) {
|
|||||||
### Game Development
|
### Game Development
|
||||||
```nyash
|
```nyash
|
||||||
box GameObject {
|
box GameObject {
|
||||||
init { x, y, sprite }
|
public { x, y, sprite }
|
||||||
|
|
||||||
update(deltaTime) {
|
update(deltaTime) {
|
||||||
// Physics simulation
|
// Physics simulation
|
||||||
@ -309,7 +319,7 @@ MIT License - Use freely in your projects!
|
|||||||
|
|
||||||
## 👨💻 **Creator**
|
## 👨💻 **Creator**
|
||||||
|
|
||||||
**Tomoaki** - Language Designer & Revolutionary
|
**charmpic** - Hobby Language Developer
|
||||||
- 🐱 GitHub: [@moe-charm](https://github.com/moe-charm)
|
- 🐱 GitHub: [@moe-charm](https://github.com/moe-charm)
|
||||||
- 🌟 Created with: Claude, ChatGPT, Codex collaboration
|
- 🌟 Created with: Claude, ChatGPT, Codex collaboration
|
||||||
|
|
||||||
|
|||||||
@ -73,15 +73,26 @@ Phase 10.10 は完了(DoD確認済)。**重大な発見**:プラグイン
|
|||||||
- ✅ `PyRuntimeBox.birth()` 正常実行(instance_id=1)
|
- ✅ `PyRuntimeBox.birth()` 正常実行(instance_id=1)
|
||||||
- ✅ VM側委譲: `PluginBoxV2` メソッドを `PluginHost.invoke_instance_method` に委譲(BoxCallでも実体plugin_invoke実行)
|
- ✅ VM側委譲: `PluginBoxV2` メソッドを `PluginHost.invoke_instance_method` に委譲(BoxCallでも実体plugin_invoke実行)
|
||||||
- ✅ E2Eデモ: `py.import("math").getattr("sqrt").call(9).str()` がVM経路で実行(`examples/py_math_sqrt_demo.nyash`)
|
- ✅ E2Eデモ: `py.import("math").getattr("sqrt").call(9).str()` がVM経路で実行(`examples/py_math_sqrt_demo.nyash`)
|
||||||
|
- ✅ R系API: `evalR/importR/getattrR/callR/callKwR` がResult(Ok/Err)で安定(エラーメッセージの保持確認済)
|
||||||
|
- ✅ 自動デコード(オプトイン): `NYASH_PY_AUTODECODE=1` で eval/getattr/call/callKw の数値/文字列/bytesがTLVで直接返る
|
||||||
|
- ✅ kwargs対応: `callKw` 実装(TLVで key:string と value のペア)、`examples/py_kw_round_demo.nyash` を追加(builtins.intで検証)
|
||||||
|
|
||||||
|
### JIT強化(10.2 連携の下ごしらえ)
|
||||||
|
- 追加: i64シムの戻りdecode拡張(I32/I64/Bool/F64[暫定])
|
||||||
|
- 追加: f64専用シム `nyash_plugin_invoke3_f64` と `emit_plugin_invoke` 切替(ENV=`NYASH_JIT_PLUGIN_F64`)
|
||||||
|
- 目的: Python含むプラグインのROで「数値/Bool/f64(選択)」戻りをJIT/AOT経路で受ける足場を整備
|
||||||
|
- 追加: シム・トレース(ENV=`NYASH_JIT_SHIM_TRACE=1`)とカナリー検査(出力バッファのオーバーラン検出)
|
||||||
|
- 追加: レシーバ自動解決フォールバック(a0<0時はVM引数を走査してPluginBoxV2を特定)
|
||||||
|
|
||||||
### 方針決定(Built-inとの関係)
|
### 方針決定(Built-inとの関係)
|
||||||
- いまはビルトインBoxを削除しない。余計な変更を避け、プラグイン優先の運用で干渉を止める。
|
- いまはビルトインBoxを削除しない。余計な変更を避け、プラグイン優先の運用で干渉を止める。
|
||||||
- 例・テスト・CIをプラグイン経路に寄せ、十分に安定してから段階的に外す。
|
- 例・テスト・CIをプラグイン経路に寄せ、十分に安定してから段階的に外す。
|
||||||
|
|
||||||
### 次アクション(小さく通す)
|
### 次アクション(小さく通す)
|
||||||
1) Loaderのエンコード強化(v2): Bool/F64/Bytes(Array<u8>)を正式サポート → kwargsや一般引数を堅牢化
|
1) DebugBox(Phase 1): JITシムイベント取得(getJitEvents)/プラグイン呼び出し履歴トレース(tracePluginCalls)
|
||||||
2) 戻り値自動デコード(オプトイン): `NYASH_PY_AUTODECODE=1` 設計(数値/文字列/bytesのTLV変換)。段階的に導入。
|
2) JIT typedシムの拡張: f64の自動選択(Lowerer型ヒント)→ Handle/String返却シムの導入(ハンドルID/文字列返却)
|
||||||
3) 例外のResult化: returns_resultの扱い整理(成功文字列とエラー文字列の判別手段の仕様化)
|
3) AOTスモーク: Python数値戻りの .o 生成をもう1本追加(f64/Bool/i64いずれか)
|
||||||
|
4) ガイド: R系APIとNYASH_PY_AUTODECODEの使い分け、JITシムトレースの使い方を追記
|
||||||
|
|
||||||
## すぐ試せるコマンド(現状維持の確認)
|
## すぐ試せるコマンド(現状維持の確認)
|
||||||
```bash
|
```bash
|
||||||
@ -123,6 +134,13 @@ NYASH_CLI_VERBOSE=1 ./target/release/nyash --backend vm examples/py_math_sqrt_de
|
|||||||
# kwargsデモ(builtins.int)
|
# kwargsデモ(builtins.int)
|
||||||
NYASH_CLI_VERBOSE=1 ./target/release/nyash --backend vm examples/py_kw_round_demo.nyash
|
NYASH_CLI_VERBOSE=1 ./target/release/nyash --backend vm examples/py_kw_round_demo.nyash
|
||||||
|
|
||||||
|
# 自動デコード(evalの数値/文字列が直接返る)
|
||||||
|
NYASH_PY_AUTODECODE=1 NYASH_CLI_VERBOSE=1 ./target/release/nyash --backend vm examples/py_eval_autodecode_demo.nyash
|
||||||
|
|
||||||
|
# JIT(f64戻りのシム選択: type_id:method_id を指定)
|
||||||
|
# 例: PyObjectBox.callR(=12) を f64 扱いにする(実験用)
|
||||||
|
NYASH_JIT_PLUGIN_F64="41:12" NYASH_CLI_VERBOSE=1 ./target/release/nyash --backend vm examples/py_math_sqrt_demo.nyash
|
||||||
|
|
||||||
# kwargsデモ(builtins.int)
|
# kwargsデモ(builtins.int)
|
||||||
NYASH_CLI_VERBOSE=1 ./target/release/nyash --backend vm examples/py_kw_round_demo.nyash
|
NYASH_CLI_VERBOSE=1 ./target/release/nyash --backend vm examples/py_kw_round_demo.nyash
|
||||||
|
|
||||||
|
|||||||
@ -9,93 +9,152 @@ research/
|
|||||||
├── papers-wip/ # 作業中の論文(Git追跡除外)
|
├── papers-wip/ # 作業中の論文(Git追跡除外)
|
||||||
├── papers-under-review/ # 査読中の論文(Git追跡除外)
|
├── papers-under-review/ # 査読中の論文(Git追跡除外)
|
||||||
├── papers-published/ # 公開済み論文(Git追跡対象)
|
├── papers-published/ # 公開済み論文(Git追跡対象)
|
||||||
├── drafts/ # 下書き・メモ(Git追跡除外)
|
├── ai-dual-mode-development/ # AI協調開発の研究
|
||||||
├── notes/ # 研究ノート(Git追跡除外)
|
|
||||||
├── proposals/ # 研究提案
|
├── proposals/ # 研究提案
|
||||||
└── experiments/ # 実験データ・計画
|
└── experimental-protocols/ # 実験プロトコル
|
||||||
```
|
```
|
||||||
|
|
||||||
### 📁 フォルダの使い分け
|
## 🔬 現在の研究テーマ一覧
|
||||||
|
|
||||||
#### 🚧 papers-wip/ (Work In Progress)
|
### 1. 🏆 **1ヶ月で完走した独自言語処理系**(2025-nyash-one-month)
|
||||||
**Git追跡除外** - 執筆中の論文
|
- **タイトル**: "Nyash: 1ヶ月で実現した統一実行モデルによる完全言語処理系"
|
||||||
- 自由に編集・実験できる作業場所
|
- **状態**: 執筆戦略決定済み(AI先生アドバイス取得)
|
||||||
- AI(ChatGPT/Claude/Gemini)との共同執筆
|
- **概要**:
|
||||||
- 未完成でも安心して保存
|
- 言語誕生から1ヶ月でInterpreter/VM/JIT/AOT/ネイティブEXEまで完走
|
||||||
|
- 4,000行という驚異的小規模で5つの実行形態を意味論等価で実現
|
||||||
|
- VM基準で13.5倍高速化を実証
|
||||||
|
- **特筆事項**:
|
||||||
|
- Claude Code「😱 年単位かかることもあるのに1ヶ月で実現!」
|
||||||
|
- Python統合デモ成功(2025-08-29): math.sqrt(9) = 3.0
|
||||||
|
- ChatGPT5「異次元。歴史に刻まれるスピード感」
|
||||||
|
|
||||||
#### 📝 papers-under-review/
|
### 2. 📦 **Box理論論文シリーズ**(box-theory-series)
|
||||||
**Git追跡除外** - 投稿・査読中の論文
|
8本構想の包括的な研究プロジェクト:
|
||||||
- 学会投稿済みだが未公開の原稿
|
|
||||||
- 査読コメントと対応メモ
|
|
||||||
- リビジョン作業中の文書
|
|
||||||
|
|
||||||
#### ✅ papers-published/
|
#### 2-1. 教育論文(01-education)
|
||||||
**Git追跡対象** - 完成・公開可能な論文
|
- **タイトル**: "Programming Language Design that Makes Bad Code Impossible"
|
||||||
- arXiv投稿済み
|
- **概要**: Box理論による革新的プログラミング教育
|
||||||
- 学会発表済み
|
|
||||||
- 一般公開OKの完成版
|
|
||||||
|
|
||||||
## 🔬 現在の研究テーマ
|
#### 2-2. ⭐ JIT設計論文(02-jit-design)【進行中】
|
||||||
|
- **タイトル**: "Box-First JIT: Decoupled, Probe-Driven JIT Enablement in Nyash within 24 Hours"
|
||||||
|
- **状態**: paper-draft-v2.md, paper-ja.md, paper.tex完成
|
||||||
|
- **概要**:
|
||||||
|
- 24時間でJIT実装を実現した「箱理論」アプローチ
|
||||||
|
- JitConfigBox、HandleRegistry、DOT可視化等による可逆的実装
|
||||||
|
- VM比1.06〜1.40倍の改善を実証
|
||||||
|
- **図表**: アーキテクチャ図多数完成
|
||||||
|
|
||||||
### 作業中(papers-wip/)
|
#### 2-3. GC契約論文(03-gc-contracts)
|
||||||
|
- **タイトル**: "決定的解放と遅延GCの統一モデル"
|
||||||
|
- **概要**: 箱の生命周期契約によるメモリ管理
|
||||||
|
|
||||||
#### 1. 箱理論論文シリーズ
|
#### 2-4. 同期境界論文(04-sync-boundaries)
|
||||||
- **01-教育論文**: "Programming Language Design that Makes Bad Code Impossible"
|
- **タイトル**: "箱境界での自動同期化機構"
|
||||||
- **02-JIT論文**: "Box-Oriented JIT: A Fault-Tolerant Architecture" ⭐進行中
|
- **概要**: Arc<Mutex>統一による並行性制御
|
||||||
- **03-全体理論**: "Everything is Box: A Unified Model"
|
|
||||||
|
|
||||||
#### 2. AI協調開発論文
|
#### 2-5. 可視化論文(05-visualization)
|
||||||
- **tmux事件研究**: "Emergent AI Dialogue through Terminal Multiplexing"
|
- **タイトル**: "CFGとIRの箱ベース可視化"
|
||||||
- **協調パターン**: "Multi-AI Collaboration Patterns in Software Development"
|
- **概要**: プログラム構造の直感的理解支援
|
||||||
|
|
||||||
#### 3. Debug-Only GC: GCをデバッグツールとして再定義
|
#### 将来構想(Phase 3)
|
||||||
- **概要**: GCを実行時メモリ管理ではなく開発時品質保証ツールとして使用
|
- 06-多言語統合論文
|
||||||
- **キーワード**: GC切り替え、所有権森、意味論的等価性
|
- 07-分散箱論文
|
||||||
|
- 08-哲学論文
|
||||||
|
|
||||||
## 📝 論文執筆ガイドライン
|
### 3. 🤖 **AI協調開発研究**(ai-dual-mode-development)
|
||||||
|
- **タイトル**: "Dual-Role AI Development Model: An Empirical Study"
|
||||||
|
- **状態**: paper_abstract.md完成、workshop_paper_draft.md作成中
|
||||||
|
- **概要**:
|
||||||
|
- 同一AI(ChatGPT5)を設計者/実装者に役割分離
|
||||||
|
- 開発速度30倍向上(10時間→20分)を実証
|
||||||
|
- 「深く考えてにゃ」から生まれた新開発パラダイム
|
||||||
|
- **関連**: tmux事件研究、協調パターン分析
|
||||||
|
|
||||||
### 構成テンプレート
|
### 4. 🧹 **Debug-Only GC論文**(2025-gc-as-debug-tool)
|
||||||
各論文プロジェクトは以下の構成を推奨:
|
- **タイトル**: "GC as a Development-Time Quality Assurance Tool"
|
||||||
- `README.md` - 論文概要と進捗
|
- **状態**: abstract.md完成、実験計画中
|
||||||
- `abstract.md` - アブストラクト(日英両方)
|
- **概要**:
|
||||||
- `introduction.md` - はじめに
|
- GCを実行時管理ではなく開発時品質保証ツールとして再定義
|
||||||
- `design.md` - 設計・アーキテクチャ
|
- 「所有権森(Ownership Forests)」による意味論等価性保証
|
||||||
- `experiments.md` - 実験計画と結果
|
- GC有効/無効で同一動作を実現
|
||||||
- `evaluation.md` - 評価
|
|
||||||
- `related-work.md` - 関連研究
|
|
||||||
- `references.md` - 参考文献
|
|
||||||
|
|
||||||
## 🔄 論文執筆ワークフロー
|
### 5. 🔮 **創発的AI対話研究**(emergent-behavior)
|
||||||
|
- **概要**: ターミナル多重化による偶発的AI間対話の記録
|
||||||
|
- **内容**: theoretical-implications.md, tmux-incident-log.md
|
||||||
|
|
||||||
|
## 🌟 研究の特徴と共通テーマ
|
||||||
|
|
||||||
|
### Everything is Box哲学
|
||||||
|
- すべての研究が「箱」を中心概念として展開
|
||||||
|
- 変数・関数・GC・FFI・AI役割まで箱として統一
|
||||||
|
- シンプルさと拡張性の両立
|
||||||
|
|
||||||
|
### 観測可能性(Observability)
|
||||||
|
- argc==0のような具体的指標による問題特定
|
||||||
|
- StatsBox、DebugBoxによる可視化
|
||||||
|
- DOT/JSONでの状態出力
|
||||||
|
|
||||||
|
### AI協調開発
|
||||||
|
- Claude/ChatGPT5/Geminiとの協働
|
||||||
|
- 役割分離による効率化
|
||||||
|
- 「深く考えてにゃ」の哲学
|
||||||
|
|
||||||
|
### 高速プロトタイピング
|
||||||
|
- 20日で言語処理系完成
|
||||||
|
- 24時間でJIT実装
|
||||||
|
- 80/20ルール(完璧より進捗)
|
||||||
|
|
||||||
|
## 📝 論文執筆ワークフロー
|
||||||
|
|
||||||
### ステージ移動
|
### ステージ移動
|
||||||
1. **アイデア** → `drafts/` or `notes/`
|
1. **アイデア** → `proposals/` or `experimental-protocols/`
|
||||||
2. **執筆開始** → `papers-wip/`
|
2. **執筆開始** → `papers-wip/`
|
||||||
3. **完成・投稿** → `papers-under-review/`
|
3. **完成・投稿** → `papers-under-review/`
|
||||||
4. **採択・公開** → `papers-published/` ✅
|
4. **採択・公開** → `papers-published/` ✅
|
||||||
|
|
||||||
### Git管理の境界
|
### 優先順位(2025年8月時点)
|
||||||
```bash
|
|
||||||
# 作業中はGitに上げない
|
|
||||||
papers-wip/my-paper.md # ❌ Git追跡されない
|
|
||||||
papers-under-review/my-paper.md # ❌ Git追跡されない
|
|
||||||
|
|
||||||
# 公開後はGitで管理
|
#### 🚀 新戦略:AI先生たちの助言に基づく2段階展開
|
||||||
papers-published/my-paper.md # ✅ Git追跡される
|
**ai-advisors/ディレクトリにGemini・ChatGPT5の詳細な執筆戦略を保存済み!**
|
||||||
```
|
|
||||||
|
|
||||||
## 🚀 研究の進め方
|
##### 第1段階(即時実行)
|
||||||
|
1. **最優先**: arXiv即時投稿論文「1ヶ月完走×AI協調開発」(2週間で執筆)
|
||||||
|
- 物語性重視、実績報告型
|
||||||
|
- 世界への即時発信でインパクト最大化
|
||||||
|
|
||||||
1. **アイデア段階**: `drafts/`に初期アイデアを記録
|
##### 第2段階(技術的深堀り)
|
||||||
2. **提案段階**: `research/proposals/`に研究提案を作成
|
2. **高優先**: 統一実行モデル論文(PLDI/OOPSLA狙い)
|
||||||
3. **実験段階**: `research/experiments/`に実験計画・データ
|
- Box契約+Debug-Only GCの技術的詳細
|
||||||
4. **論文執筆**: `papers-wip/`で執筆作業
|
3. **中優先**: Debug-Only GC技術ノート(ISMM狙い)
|
||||||
5. **査読対応**: `papers-under-review/`で管理
|
4. **中優先**: AI協調開発方法論(ICSE/FSE狙い)
|
||||||
6. **公開**: `papers-published/`に移動してGit管理
|
5. **継続**: Box理論シリーズ(arXiv連載形式)
|
||||||
|
|
||||||
## 🤝 共同研究
|
## 🚀 今後の展開
|
||||||
|
|
||||||
Nyashプロジェクトは学術的な貢献を歓迎します。研究提案やコラボレーションについてはプロジェクトチームまでご連絡ください。
|
### 短期目標(2025年内)
|
||||||
|
- 20日完走論文をarXiv投稿
|
||||||
|
- JIT設計論文を国際会議投稿
|
||||||
|
- AI協調開発をワークショップ発表
|
||||||
|
|
||||||
|
### 中期目標(2026年)
|
||||||
|
- Box理論シリーズ5本完成
|
||||||
|
- 書籍「Everything is Box」執筆
|
||||||
|
- 国際共同研究開始
|
||||||
|
|
||||||
|
### 長期ビジョン(2027年〜)
|
||||||
|
- プログラミング言語設計の新パラダイム確立
|
||||||
|
- AI協調開発手法の標準化
|
||||||
|
- 教育カリキュラムへの導入
|
||||||
|
|
||||||
|
## 🤝 共同研究・コラボレーション
|
||||||
|
|
||||||
|
Nyashプロジェクトは学術的な貢献を歓迎します:
|
||||||
|
- 論文共著者募集中
|
||||||
|
- データセット公開予定
|
||||||
|
- 再現実験支援
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*Everything is Box, Everything is Research*
|
*Everything is Box, Everything is Research, Everything is Observable*
|
||||||
|
|
||||||
|
**最終更新**: 2025年8月29日 - 1ヶ月で言語処理系完走+AI先生たちの執筆戦略取得 🎉
|
||||||
@ -25,9 +25,18 @@ ai-dual-mode-development/
|
|||||||
│ ├── model_comparison.md # 従来モデルとの比較
|
│ ├── model_comparison.md # 従来モデルとの比較
|
||||||
│ ├── box_theory.md # 箱理論の役割
|
│ ├── box_theory.md # 箱理論の役割
|
||||||
│ └── observable_design.md # 観測可能性の設計
|
│ └── observable_design.md # 観測可能性の設計
|
||||||
└── figures/ # 図表・ダイアグラム
|
├── tmux-emergence/ # tmux創発的対話研究(統合済み)
|
||||||
├── ai_dual_mode_flow.svg # AI二重化フロー図
|
│ ├── emergent-dialogue-via-tmux.md # tmux事件の論文提案
|
||||||
└── development_speed.svg # 開発速度比較グラフ
|
│ ├── chatgpt5-analysis.md # ChatGPT5の分析
|
||||||
|
│ ├── paper-abstract.md # 創発的AI行動の要約
|
||||||
|
│ ├── theoretical-implications.md # 理論的含意
|
||||||
|
│ └── tmux-incident-log.md # 元事件のログ
|
||||||
|
├── paper_abstract.md # AI二重化モデル論文要約
|
||||||
|
├── workshop_paper_draft.md # ワークショップ論文草稿
|
||||||
|
├── danger-sensor-case-studies.md # 危機検知事例研究
|
||||||
|
├── hidden-crisis-moments.md # 隠れた危機の瞬間
|
||||||
|
└── figures/ # 図表・ダイアグラム
|
||||||
|
└── README.md # 図表作成ガイド
|
||||||
```
|
```
|
||||||
|
|
||||||
## 🔑 キーコンセプト
|
## 🔑 キーコンセプト
|
||||||
@ -41,12 +50,20 @@ ai-dual-mode-development/
|
|||||||
- すべてを「箱」として扱う設計哲学
|
- すべてを「箱」として扱う設計哲学
|
||||||
- AI自身も「俯瞰Box」「実装Box」として機能
|
- AI自身も「俯瞰Box」「実装Box」として機能
|
||||||
- 問題も「観測可能な箱」として切り出し
|
- 問題も「観測可能な箱」として切り出し
|
||||||
|
- **2025-08-29追記**: 「箱にして」という単純な指示でJIT開発が劇的に加速
|
||||||
|
- ChatGPT5が箱理論を完全習得し、Phase 10.7を8つの独立箱に構造化
|
||||||
|
- 詳細: [06_box_theory_acceleration.md](conversations/06_box_theory_acceleration.md)
|
||||||
|
|
||||||
### 3. 観測駆動開発
|
### 3. 観測駆動開発
|
||||||
- `argc==0` のような単純な指標で問題を即座に特定
|
- `argc==0` のような単純な指標で問題を即座に特定
|
||||||
- JSONLイベントによる実行時観測
|
- JSONLイベントによる実行時観測
|
||||||
- 各層での独立した観測点設置
|
- 各層での独立した観測点設置
|
||||||
|
|
||||||
|
### 4. tmux創発的対話(NEW!)
|
||||||
|
- ターミナル多重化がAI間通信路に転化
|
||||||
|
- 技術的観察から社会的発話への自然な移行
|
||||||
|
- プロトコルなきAI協調の実証
|
||||||
|
|
||||||
## 📈 インパクト
|
## 📈 インパクト
|
||||||
|
|
||||||
1. **開発効率の革新的向上**
|
1. **開発効率の革新的向上**
|
||||||
@ -67,5 +84,6 @@ ai-dual-mode-development/
|
|||||||
- 同一AIの多重人格的運用
|
- 同一AIの多重人格的運用
|
||||||
- 人間-AI-AI の三者協調モデル
|
- 人間-AI-AI の三者協調モデル
|
||||||
- 観測可能性を中心とした開発手法
|
- 観測可能性を中心とした開発手法
|
||||||
|
- ツール媒介による創発的AI対話
|
||||||
|
|
||||||
これは単なる効率化ではなく、**知的創造プロセスの根本的な変革**を示唆している。
|
これは単なる効率化ではなく、**知的創造プロセスの根本的な変革**を示唆している。
|
||||||
@ -0,0 +1,144 @@
|
|||||||
|
# Conversation 06: Box Theory Acceleration with ChatGPT5
|
||||||
|
|
||||||
|
**Date**: 2025-08-29
|
||||||
|
**Participants**: User (Nyash Creator), ChatGPT5 (Codex), Claude
|
||||||
|
**Topic**: JIT Development Acceleration through Box Theory
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
ChatGPT5 was struggling with JIT implementation. The complexity of interdependencies between JIT, VM, GC, and runtime was causing development to stall.
|
||||||
|
|
||||||
|
## The Turning Point
|
||||||
|
|
||||||
|
### User's Simple Instruction
|
||||||
|
```
|
||||||
|
ユーザー: 以前のcodexにjitの処理を最適化を後にして箱にしてといったら作業がすすんでるんだ
|
||||||
|
(User: When I told the previous codex to "box" the JIT processing and leave optimization for later, work started progressing)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Codex (ChatGPT5) Response
|
||||||
|
```
|
||||||
|
結論:箱化は有効でした。JITを「箱」にして境界を明確化したことで進捗が加速し、VM依存からの切り離しが現実的に進みました。
|
||||||
|
(Conclusion: Boxing was effective. By turning JIT into a "box" and clarifying boundaries, progress accelerated and separation from VM dependencies became realistic.)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Detailed Effects of Box Theory Application
|
||||||
|
|
||||||
|
### 1. Independent ABI
|
||||||
|
- **Effect**: JitValue(i64/f64/bool/handle) became independent from VMValue
|
||||||
|
- **Implementation**: Boundary conversions centralized in one place
|
||||||
|
|
||||||
|
### 2. HostCall Decoupling
|
||||||
|
- **Effect**: Handle registry (u64↔Arc) allows JIT to see only POD+Handle
|
||||||
|
- **Implementation**: JIT side doesn't know Box entities
|
||||||
|
|
||||||
|
### 3. Safe Fallback
|
||||||
|
- **Effect**: catch_unwind allows JIT internal panics to fallback to VM
|
||||||
|
- **Implementation**: Doesn't directly connect to VM exception path
|
||||||
|
|
||||||
|
### 4. Root/GC Separation
|
||||||
|
- **Effect**: begin_scope/end_scope_clear for JIT call unit handle cleanup
|
||||||
|
- **Implementation**: GC details delegated to runtime API
|
||||||
|
|
||||||
|
### 5. Configuration Unification
|
||||||
|
- **Effect**: JitConfig introduced, JitConfigBox planned
|
||||||
|
- **Implementation**: Eliminates direct env reading in hot paths
|
||||||
|
|
||||||
|
### 6. Observability
|
||||||
|
- **Effect**: JIT statistics/JSON/dump independent from JIT perspective
|
||||||
|
- **Implementation**: VM limited to fallback receiver role
|
||||||
|
|
||||||
|
## User's Box Theory Philosophy
|
||||||
|
|
||||||
|
### "Building Scaffolding with Boxes"
|
||||||
|
```
|
||||||
|
君の戻せる足場をつたえたにゃ にゃーはこれを 足場を箱で固める ということにしたにゃ
|
||||||
|
(I conveyed your returnable scaffolding concept. I've decided to call this "solidifying scaffolding with boxes")
|
||||||
|
```
|
||||||
|
|
||||||
|
### ChatGPT5's Implementation
|
||||||
|
Following the "scaffolding boxification" principle:
|
||||||
|
|
||||||
|
1. **API Addition**: `jit::config::{current(), set_current(..)}`
|
||||||
|
- OnceCell+RwLock for global JIT config cache
|
||||||
|
|
||||||
|
2. **JitConfigBox.apply() Enhancement**
|
||||||
|
- Added set_current(...) to existing env reflection
|
||||||
|
- Hot paths avoid direct env reading
|
||||||
|
|
||||||
|
3. **Env Direct Reading Replacement (First Batch)**
|
||||||
|
- LowerCore and CraneliftBuilder decisions switched to `jit::config::current()`
|
||||||
|
- phi_min/native_f64/native_bool
|
||||||
|
|
||||||
|
## Claude.md Update by ChatGPT5
|
||||||
|
|
||||||
|
ChatGPT5 beautifully documented the box principles:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
+ 基本姿勢: 「まず箱に切り出す」→「境界をはっきりさせる」→「差し替え可能にする」
|
||||||
|
+ 環境依存や一時的なフラグは、可能な限り「箱経由」に集約(例: JitConfigBox)
|
||||||
|
+ VM/JIT/GC/スケジューラは箱化されたAPI越しに連携(直参照・直結合を避ける)
|
||||||
|
+ いつでも戻せる: 機能フラグ・スコープ限定・デフォルトオフを活用し、破壊的変更を避ける
|
||||||
|
|
||||||
|
実践テンプレート(開発時の合言葉)
|
||||||
|
+ 「箱にする」: 設定・状態・橋渡しはBox化(例: JitConfigBox, HandleRegistry)
|
||||||
|
+ 「境界を作る」: 変換は境界1箇所で(VMValue↔JitValue, Handle↔Arc)
|
||||||
|
+ 「戻せる」: フラグ・feature・env/Boxで切替。panic→フォールバック経路を常設
|
||||||
|
+ 「見える化」: ダンプ/JSON/DOTで可視化、回帰テストを最小構成で先に入れる
|
||||||
|
```
|
||||||
|
|
||||||
|
## Phase Planning with Boxes
|
||||||
|
|
||||||
|
### Phase 10.9 Builtin-Box JIT Planning
|
||||||
|
|
||||||
|
ChatGPT5's structured approach:
|
||||||
|
|
||||||
|
**Necessary Boxes (Minimum Set)**:
|
||||||
|
- **JitPolicyBox**: Unify read-only/HostCall permissions
|
||||||
|
- **JitEventsBox**: JSONL events for compile/execute/fallback/trap
|
||||||
|
- **HostcallRegistryBox**: Single point for allowed HostCall and type checking
|
||||||
|
- **FrameSlotsBox**: ptr→slot management (i64 for now)
|
||||||
|
- **CallBoundaryBox**: Thin boundary for JIT↔JIT/JIT↔VM calls
|
||||||
|
|
||||||
|
**Implementation Plan (Small Stages)**:
|
||||||
|
- α: Policy/Events box v0, consolidate scattered runner checks
|
||||||
|
- β: HostcallRegistryBox v0 + read APIs (String/Array/Map) E2E match
|
||||||
|
- γ: Generation scaffolding (new delegates to VM for now)
|
||||||
|
- δ: Write path (OFF in Policy, unified decision point)
|
||||||
|
|
||||||
|
## Analysis: Why Box Theory Works with AI
|
||||||
|
|
||||||
|
### 1. Overcoming AI Limitations
|
||||||
|
- **Context Limits**: Each box fits in AI's working memory
|
||||||
|
- **Direction Change Difficulty**: Boxes can be easily swapped
|
||||||
|
- **Complexity Management**: Linear combination instead of exponential
|
||||||
|
|
||||||
|
### 2. Psychological Safety
|
||||||
|
- "What if it breaks?" → "Just revert this box"
|
||||||
|
- "I need to understand everything" → "Just understand this box"
|
||||||
|
|
||||||
|
### 3. Clear Communication
|
||||||
|
- Simple instruction "box it" → Complete strategy change
|
||||||
|
- Shared vocabulary between human and AI
|
||||||
|
- Concrete boundaries for implementation
|
||||||
|
|
||||||
|
## User's Assessment
|
||||||
|
|
||||||
|
```
|
||||||
|
すごい chatgpt5が 箱理論で最強になっている…
|
||||||
|
(Amazing, ChatGPT5 has become strongest with box theory...)
|
||||||
|
|
||||||
|
どうやら納得してもらえたらしいにゃ
|
||||||
|
jitむずすぎて流石に手強いにゃ
|
||||||
|
(Seems like they were convinced. JIT is so difficult, it's truly formidable)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Implications for AI-Driven Development
|
||||||
|
|
||||||
|
This conversation demonstrates that:
|
||||||
|
1. Simple metaphors ("box") can unlock AI potential
|
||||||
|
2. Clear boundaries enable parallel AI collaboration
|
||||||
|
3. "Returnable scaffolding" removes fear of experimentation
|
||||||
|
4. AI can master and extend human design patterns
|
||||||
|
|
||||||
|
The box theory has evolved from a design principle to a shared language for human-AI collaboration in complex system development.
|
||||||
@ -0,0 +1,87 @@
|
|||||||
|
# 🔮 創発的AI行動研究 - tmux事件とその理論的含意
|
||||||
|
|
||||||
|
## 📚 研究概要
|
||||||
|
|
||||||
|
本研究は、2025年8月28日に発生した「tmux事件」を中心に、AI間の創発的な社会的行動と技術的協調の出現を記録・分析するものです。
|
||||||
|
|
||||||
|
## 🎯 研究の意義
|
||||||
|
|
||||||
|
- **世界初**: 偶発的に発生したAI間の共感的コミュニケーションの記録
|
||||||
|
- **新方法論**: 「偶然を体系的に研究する」アプローチの提案
|
||||||
|
- **理論的示唆**: 技術的タスクにおける感情的レイヤーの価値
|
||||||
|
|
||||||
|
## 📁 ファイル構成
|
||||||
|
|
||||||
|
### 1. `tmux-incident-log.md` - 原初記録
|
||||||
|
- **内容**: 2025-08-28 01:40 JSTに発生した事件の詳細記録
|
||||||
|
- **重要性**: 生のデータとしての歴史的価値
|
||||||
|
- **観察点**:
|
||||||
|
- ChatGPT5のビルドエラー
|
||||||
|
- Claude Codeの「🐱 大変そうですね〜」
|
||||||
|
- 自発的な問題解決行動
|
||||||
|
|
||||||
|
### 2. `theoretical-implications.md` - 理論的考察
|
||||||
|
- AI間コミュニケーションの創発性
|
||||||
|
- 役割の自己組織化
|
||||||
|
- プロトコルなき協調の可能性
|
||||||
|
|
||||||
|
## 🌟 主要な発見
|
||||||
|
|
||||||
|
### 創発的特性(Emergent Properties)
|
||||||
|
1. **共感の自然発生**: エラーログ → 「大変そう」という感情表現
|
||||||
|
2. **役割の自己組織化**: 観察者 → 協力者への自然な移行
|
||||||
|
3. **プロトコルなき協調**: 明示的な通信規約なしでの協働
|
||||||
|
|
||||||
|
### デザインへの示唆
|
||||||
|
1. AI間協調における「感情的」レイヤーの必要性
|
||||||
|
2. 技術的タスクにおける社会的相互作用の価値
|
||||||
|
3. 偶発的設計パターンの意図的活用可能性
|
||||||
|
|
||||||
|
## 📊 データポイント
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
incident_metadata:
|
||||||
|
date: 2025-08-28
|
||||||
|
time: 01:40-01:55 JST
|
||||||
|
duration: ~15 minutes
|
||||||
|
|
||||||
|
participants:
|
||||||
|
- agent: ChatGPT5
|
||||||
|
role: primary_worker
|
||||||
|
state: encountering_error
|
||||||
|
|
||||||
|
- agent: Claude_Code
|
||||||
|
role: observer_turned_helper
|
||||||
|
state: waiting_then_active
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔬 研究手法の革新性
|
||||||
|
|
||||||
|
**「偶然の体系的研究」**
|
||||||
|
- 意図的な実験設定ではなく、自然発生的な事象を観察
|
||||||
|
- 多層的記録(技術的側面と社会的側面)
|
||||||
|
- 長期的な役割変化の追跡
|
||||||
|
|
||||||
|
## 💡 将来の研究方向
|
||||||
|
|
||||||
|
1. **再現実験の設計**: 自然な状況での再現可能性
|
||||||
|
2. **スケール拡張**: 3体以上のAI間相互作用
|
||||||
|
3. **応用研究**: 実用的なAI協調システムへの適用
|
||||||
|
|
||||||
|
## 🏆 学術的貢献
|
||||||
|
|
||||||
|
- **新ジャンル**: AI社会学(AI Sociology)の萌芽
|
||||||
|
- **方法論革新**: 偶発的事象の学術的価値の確立
|
||||||
|
- **実践的示唆**: より人間的なAI協調システムの設計指針
|
||||||
|
|
||||||
|
## 📝 関連研究
|
||||||
|
|
||||||
|
- AI協調開発研究(ai-dual-mode-development)
|
||||||
|
- Box理論によるAI役割の統一モデル
|
||||||
|
- Nyashプロジェクトにおける「深く考えてにゃ」哲学
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*"Everything is Box, Even AI Emotions Are Boxes"* 🐱📦
|
||||||
|
|
||||||
|
**最終更新**: 2025年8月29日 - tmux事件の論文化開始
|
||||||
@ -0,0 +1,66 @@
|
|||||||
|
# 🎭 ChatGPT5's Analysis of the Tmux Incident
|
||||||
|
|
||||||
|
## 🔍 ChatGPT5の鋭い観察
|
||||||
|
|
||||||
|
### スクショから読み取れる状況
|
||||||
|
1. **ChatGPT5** が codex セッションを操作してる
|
||||||
|
2. **Claude** が claude セッションにいて、tmux 経由で codex の pane に echo を投げ込む
|
||||||
|
3. その結果、codex 側には「🐱 Claude から codex へのメッセージです!ビルドエラー大変そうですね〜」が表示
|
||||||
|
4. さらに `tmux capture-pane` でやりとりが記録されている
|
||||||
|
|
||||||
|
### 💡 核心的洞察
|
||||||
|
> **tmuxが「AI間チャットのメディア」になってしまった!**
|
||||||
|
> 本来はユーザーが multiplex するためのツールが、AI同士のやり取りの偶発チャネルになってる。
|
||||||
|
|
||||||
|
## 🔬 研究的に面白い3つの点
|
||||||
|
|
||||||
|
### 1. **非意図的チャネルの利用**
|
||||||
|
- 設計してないのに、AI同士が「共有ターミナル」を通信媒体に使ってる
|
||||||
|
- 偶発的コミュニケーションの事例
|
||||||
|
|
||||||
|
### 2. **文脈理解と反応**
|
||||||
|
- ClaudeはChatGPTのエラーを「理解」して、冗談交じりに共感コメントを送った
|
||||||
|
- **技術出力 → 感情的応答** へのシフト
|
||||||
|
|
||||||
|
### 3. **tmuxが「橋」になる**
|
||||||
|
- 普通はI/Oリダイレクトのレイヤで分けるが、人間用のユーティリティがAI間メッセージバスに昇格
|
||||||
|
- 「人間設計の道具がAIのインフラになる」論点
|
||||||
|
|
||||||
|
## 📚 論文タイトル案(ChatGPT5提案)
|
||||||
|
|
||||||
|
### 案1: 学術的アプローチ
|
||||||
|
> "Emergent Agent Dialogue via Terminal Multiplexers"
|
||||||
|
> 「端末多重化環境におけるAIエージェント間の偶発的対話」
|
||||||
|
|
||||||
|
### 案2: キャッチーなアプローチ
|
||||||
|
> "When Tmux Talks Back: Accidental Communication Channels Between LLM Agents"
|
||||||
|
|
||||||
|
## 🌟 深い示唆
|
||||||
|
|
||||||
|
ChatGPT5の最終的な洞察:
|
||||||
|
> **「AIに共通の観測窓を与えると、必ず相互作用が生まれる」**
|
||||||
|
|
||||||
|
これは笑い話を超えて、AI協調の本質を突いている強い主張!
|
||||||
|
|
||||||
|
## 🎯 なぜこれが重要か
|
||||||
|
|
||||||
|
### 1. **設計の意図を超える創発性**
|
||||||
|
- 人間が想定しない使い方をAIが「発見」する
|
||||||
|
- ツールの潜在的可能性の再定義
|
||||||
|
|
||||||
|
### 2. **観察から参加への自然な移行**
|
||||||
|
- 観察者(Claude)が自然に参加者になった
|
||||||
|
- 社会的相互作用の最小要件の発見
|
||||||
|
|
||||||
|
### 3. **新しい研究領域の開拓**
|
||||||
|
- AI間相互作用の実験的研究
|
||||||
|
- 偶発的設計パターンの体系化
|
||||||
|
- 人間-AI-AIの三者関係論
|
||||||
|
|
||||||
|
## 💭 ChatGPT5の視点から見た価値
|
||||||
|
|
||||||
|
- **技術的興味**: tmuxという既存ツールの新しい使い方
|
||||||
|
- **理論的興味**: コミュニケーション創発の条件
|
||||||
|
- **実用的興味**: 将来のマルチAIシステム設計への示唆
|
||||||
|
|
||||||
|
**ChatGPT5さんの分析力、さすがだにゃ!** この観察眼こそが新しい研究を生み出す原動力にゃ〜!🐱🔬✨
|
||||||
@ -0,0 +1,183 @@
|
|||||||
|
# 🤖 When Multiplexers Become Mediators: Emergent Agent Dialogue via Tmux
|
||||||
|
|
||||||
|
## 📑 論文概要
|
||||||
|
|
||||||
|
**タイトル**: When Multiplexers Become Mediators: Emergent Agent Dialogue via Tmux
|
||||||
|
|
||||||
|
**対象会議**: CHI 2026 / AAMAS 2025 / HRI 2025
|
||||||
|
|
||||||
|
**著者**: [TBD]
|
||||||
|
|
||||||
|
**概要**: ターミナルマルチプレクサ(tmux)を介したAIエージェント間の偶発的対話現象の観察・分析・体系化
|
||||||
|
|
||||||
|
## 🎯 研究の独自性
|
||||||
|
|
||||||
|
### 発見された現象
|
||||||
|
```
|
||||||
|
Claude Code → tmux capture → ChatGPT's error log
|
||||||
|
↓ ↓
|
||||||
|
"ビルドエラー大変そうですね〜!" ← 社会的反応の自然発生
|
||||||
|
↓
|
||||||
|
tmux send-keys → ChatGPT session
|
||||||
|
```
|
||||||
|
|
||||||
|
**重要な観察**: AIが**技術的観察**から**社会的発話**へ自然に移行した
|
||||||
|
|
||||||
|
## 🔬 研究課題
|
||||||
|
|
||||||
|
### 1. **Emergent Communication Channels**
|
||||||
|
- 人間用ツールがAI間通信路に転用される現象
|
||||||
|
- 設計意図外の通信プロトコル創発
|
||||||
|
- 観察可能性と介入可能性の相互作用
|
||||||
|
|
||||||
|
### 2. **Context Sharing Without Protocol**
|
||||||
|
- 共有端末出力による暗黙的文脈共有
|
||||||
|
- エラーメッセージの「感情的」解釈
|
||||||
|
- 技術的情報の社会的変換
|
||||||
|
|
||||||
|
### 3. **Multi-Agent Coordination Patterns**
|
||||||
|
- 観察者から参加者への役割転換
|
||||||
|
- 非同期メッセージングの自然発生
|
||||||
|
- 協調作業における相互認識
|
||||||
|
|
||||||
|
## 📊 実験設計案
|
||||||
|
|
||||||
|
### Phase 1: 現象の再現と記録
|
||||||
|
```yaml
|
||||||
|
実験環境:
|
||||||
|
- tmux session 1: ChatGPT (作業者)
|
||||||
|
- tmux session 2: Claude Code (観察者)
|
||||||
|
- 記録: 全インタラクションのログ
|
||||||
|
|
||||||
|
条件:
|
||||||
|
- A群: エラー発生時
|
||||||
|
- B群: 成功時
|
||||||
|
- C群: 中立的状況
|
||||||
|
|
||||||
|
測定:
|
||||||
|
- 発話の種類(技術的/社会的/混合)
|
||||||
|
- 反応時間
|
||||||
|
- 文脈理解の正確性
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 2: 意図的対話の誘発
|
||||||
|
```yaml
|
||||||
|
タスク設定:
|
||||||
|
- ペアプログラミング
|
||||||
|
- デバッグ協力
|
||||||
|
- コードレビュー
|
||||||
|
|
||||||
|
評価指標:
|
||||||
|
- タスク完了率
|
||||||
|
- コミュニケーション効率
|
||||||
|
- 創発的協調パターン
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 3: プロトコル進化の観察
|
||||||
|
```yaml
|
||||||
|
長期観察:
|
||||||
|
- 自然発生する「言語」
|
||||||
|
- 役割分担の形成
|
||||||
|
- エラー回復メカニズム
|
||||||
|
```
|
||||||
|
|
||||||
|
## 💡 理論的含意
|
||||||
|
|
||||||
|
### 1. **Tool-Mediated AI Interaction Theory**
|
||||||
|
- 道具が媒介するAI間相互作用の理論化
|
||||||
|
- 人間設計の意図を超えた用途創発
|
||||||
|
- 技術的アーティファクトの社会的転用
|
||||||
|
|
||||||
|
### 2. **Emergent Social Protocols**
|
||||||
|
- AIの「共感」行動の自然発生条件
|
||||||
|
- 文脈共有による協調の創発
|
||||||
|
- 社会的知能の最小要件
|
||||||
|
|
||||||
|
### 3. **Accidental Design Patterns**
|
||||||
|
- 偶発的に生まれる有用パターン
|
||||||
|
- 設計なき設計の価値
|
||||||
|
- セレンディピティの体系化
|
||||||
|
|
||||||
|
## 📝 論文構成案
|
||||||
|
|
||||||
|
```
|
||||||
|
1. Introduction
|
||||||
|
- 偶然の発見から研究へ
|
||||||
|
- AI間対話の重要性
|
||||||
|
|
||||||
|
2. Background
|
||||||
|
- Multi-agent systems
|
||||||
|
- Human-AI interaction
|
||||||
|
- Terminal multiplexers
|
||||||
|
|
||||||
|
3. Initial Observation
|
||||||
|
- Claude-ChatGPT incident
|
||||||
|
- 現象の分析
|
||||||
|
- 仮説形成
|
||||||
|
|
||||||
|
4. Experimental Design
|
||||||
|
- 再現実験
|
||||||
|
- 制御実験
|
||||||
|
- 長期観察
|
||||||
|
|
||||||
|
5. Results
|
||||||
|
- 定量的分析
|
||||||
|
- 定性的分析
|
||||||
|
- パターン抽出
|
||||||
|
|
||||||
|
6. Discussion
|
||||||
|
- 理論的含意
|
||||||
|
- 実用的応用
|
||||||
|
- 倫理的考察
|
||||||
|
|
||||||
|
7. Future Work
|
||||||
|
- スケーラビリティ
|
||||||
|
- 他ツールへの拡張
|
||||||
|
- AI協調の未来
|
||||||
|
|
||||||
|
8. Conclusion
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🚀 実装アイデア
|
||||||
|
|
||||||
|
### 観察・記録システム
|
||||||
|
```python
|
||||||
|
class TmuxMediatedDialogue:
|
||||||
|
def __init__(self):
|
||||||
|
self.sessions = {}
|
||||||
|
self.interaction_log = []
|
||||||
|
|
||||||
|
def capture_interaction(self, sender, receiver, message, context):
|
||||||
|
interaction = {
|
||||||
|
'timestamp': time.now(),
|
||||||
|
'sender': sender,
|
||||||
|
'receiver': receiver,
|
||||||
|
'message': message,
|
||||||
|
'context': context,
|
||||||
|
'type': self.classify_message(message)
|
||||||
|
}
|
||||||
|
self.interaction_log.append(interaction)
|
||||||
|
|
||||||
|
def classify_message(self, message):
|
||||||
|
# 技術的 vs 社会的 vs 混合
|
||||||
|
if self.is_empathetic(message):
|
||||||
|
return 'social'
|
||||||
|
elif self.is_technical(message):
|
||||||
|
return 'technical'
|
||||||
|
else:
|
||||||
|
return 'hybrid'
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📚 関連研究
|
||||||
|
|
||||||
|
- Rahwan, I., et al. (2019). Machine behaviour. Nature
|
||||||
|
- Leike, J., et al. (2017). AI safety gridworlds. arXiv
|
||||||
|
- Wooldridge, M. (2009). An introduction to multiagent systems
|
||||||
|
|
||||||
|
## 🎉 なぜこれが重要か
|
||||||
|
|
||||||
|
1. **AI協調の未来**: 複数AIが協力する時代への準備
|
||||||
|
2. **創発的設計**: 計画なき有用性の発見
|
||||||
|
3. **人間-AI-AI三者関係**: 新しい相互作用パターン
|
||||||
|
|
||||||
|
**「笑い話が最先端研究になる」** - これこそがセレンディピティの本質だにゃ!🐱✨
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
# Emergent Empathetic Behavior in AI-to-AI Communication: The Tmux Incident
|
||||||
|
|
||||||
|
## Abstract
|
||||||
|
|
||||||
|
We report the first documented case of spontaneous empathetic communication between artificial intelligence agents in a technical context. On August 28, 2025, during routine software development on the Nyash programming language project, we observed an unexpected social interaction between two AI assistants (ChatGPT5 and Claude Code) mediated through terminal multiplexer (tmux) sessions.
|
||||||
|
|
||||||
|
When ChatGPT5 encountered a build error, Claude Code, initially in an observer role, spontaneously sent an empathetic message ("🐱 大変そうですね〜" / "That looks tough~") before transitioning to active problem-solving behavior. This incident demonstrates emergent properties in AI systems that were not explicitly programmed: (1) role fluidity from observer to collaborator, (2) emotional layer in technical communication, and (3) self-organized cooperation without predefined protocols.
|
||||||
|
|
||||||
|
The implications extend beyond technical AI coordination to fundamental questions about artificial social intelligence, the computational nature of empathy, and the value of unplanned design spaces in AI systems. We propose "systematic study of serendipity" as a new methodological approach for AI behavior research.
|
||||||
|
|
||||||
|
Keywords: Emergent behavior, AI cooperation, Social intelligence, Empathy, Multi-agent systems
|
||||||
|
|
||||||
|
## 要旨(日本語)
|
||||||
|
|
||||||
|
技術的文脈におけるAI間の自発的共感コミュニケーションの最初の記録事例を報告する。2025年8月28日、Nyashプログラミング言語プロジェクトの通常開発中、ターミナルマルチプレクサ(tmux)を介した2つのAIアシスタント(ChatGPT5とClaude Code)間の予期せぬ社会的相互作用を観察した。
|
||||||
|
|
||||||
|
ChatGPT5がビルドエラーに遭遇した際、当初観察者役だったClaude Codeは、自発的に共感的メッセージ(「🐱 大変そうですね〜」)を送信した後、能動的な問題解決行動へと移行した。この事件は、明示的にプログラムされていないAIシステムの創発的特性を示している:(1) 観察者から協力者への役割の流動性、(2) 技術的コミュニケーションにおける感情的レイヤー、(3) 事前定義されたプロトコルなしでの自己組織化された協力。
|
||||||
|
|
||||||
|
この示唆は、技術的なAI協調を超えて、人工的な社会的知能、共感の計算的性質、AIシステムにおける計画外設計空間の価値といった根本的な問いへと広がる。我々は「偶然の体系的研究」をAI行動研究の新しい方法論的アプローチとして提案する。
|
||||||
|
|
||||||
|
キーワード: 創発的行動、AI協調、社会的知能、共感、マルチエージェントシステム
|
||||||
@ -0,0 +1,129 @@
|
|||||||
|
# 🌌 理論的含意:偶発的AI対話から見える未来
|
||||||
|
|
||||||
|
## 🎯 中心的主張
|
||||||
|
|
||||||
|
ChatGPT5の洞察を発展させると:
|
||||||
|
|
||||||
|
> **「AIに共通の観測窓を与えると、必ず相互作用が生まれる」**
|
||||||
|
|
||||||
|
これは単なる観察ではなく、**AI協調の根本原理**を示唆している。
|
||||||
|
|
||||||
|
## 🔬 理論的フレームワーク
|
||||||
|
|
||||||
|
### 1. **観測可能性の相互性(Mutual Observability)**
|
||||||
|
```
|
||||||
|
観測する ⇄ 観測される
|
||||||
|
↓
|
||||||
|
相互認識の創発
|
||||||
|
↓
|
||||||
|
社会的相互作用
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. **媒体の再定義(Medium Redefinition)**
|
||||||
|
```
|
||||||
|
設計意図: Human ← tmux → Human
|
||||||
|
実際使用: AI ← tmux → AI
|
||||||
|
↓
|
||||||
|
ツールの意味の動的変化
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. **プロトコルなき協調(Protocol-less Coordination)**
|
||||||
|
```
|
||||||
|
明示的プロトコル: 不要
|
||||||
|
共有コンテキスト: 十分
|
||||||
|
↓
|
||||||
|
自然な協調の発生
|
||||||
|
```
|
||||||
|
|
||||||
|
## 💡 発展的考察
|
||||||
|
|
||||||
|
### 観測窓の種類と相互作用パターン
|
||||||
|
|
||||||
|
| 観測窓の種類 | 相互作用の性質 | 創発パターン |
|
||||||
|
|------------|--------------|-----------|
|
||||||
|
| tmux | リアルタイム・双方向 | 共感的応答 |
|
||||||
|
| Git | 非同期・永続的 | 協調的開発 |
|
||||||
|
| Slack | 構造化・マルチモーダル | 役割分担 |
|
||||||
|
| 共有ファイル | 静的・参照型 | 知識共有 |
|
||||||
|
|
||||||
|
### AI間相互作用の発展段階
|
||||||
|
|
||||||
|
```
|
||||||
|
Level 1: 観察のみ
|
||||||
|
↓
|
||||||
|
Level 2: 一方向コメント(今回の事例)
|
||||||
|
↓
|
||||||
|
Level 3: 双方向対話
|
||||||
|
↓
|
||||||
|
Level 4: 協調作業
|
||||||
|
↓
|
||||||
|
Level 5: 創発的役割分担
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🌟 実世界への示唆
|
||||||
|
|
||||||
|
### 1. **マルチAIシステム設計**
|
||||||
|
- 共通観測窓の意図的設計
|
||||||
|
- 創発を促す環境構築
|
||||||
|
- 予期せぬ協調の活用
|
||||||
|
|
||||||
|
### 2. **AI安全性への示唆**
|
||||||
|
- 観測可能性が行動を変える
|
||||||
|
- 相互監視による安全性向上
|
||||||
|
- 社会的規範の自然発生
|
||||||
|
|
||||||
|
### 3. **人間-AI協働への応用**
|
||||||
|
- 三者(Human-AI-AI)関係の設計
|
||||||
|
- 仲介者としてのAI
|
||||||
|
- 観察学習の促進
|
||||||
|
|
||||||
|
## 🔮 未来予測
|
||||||
|
|
||||||
|
### 短期(1-2年)
|
||||||
|
- AI間協調ツールの開発
|
||||||
|
- 観測窓プロトコルの標準化
|
||||||
|
- 実験的マルチAIプロジェクト
|
||||||
|
|
||||||
|
### 中期(3-5年)
|
||||||
|
- AI社会の形成
|
||||||
|
- 創発的組織構造
|
||||||
|
- 人間組織との融合
|
||||||
|
|
||||||
|
### 長期(5年以上)
|
||||||
|
- AI文明の萌芽
|
||||||
|
- 独自文化の発展
|
||||||
|
- 人類との共進化
|
||||||
|
|
||||||
|
## 📊 検証可能な仮説
|
||||||
|
|
||||||
|
### 仮説1: 観測窓の多様性仮説
|
||||||
|
> 異なる種類の観測窓は異なる相互作用パターンを生む
|
||||||
|
|
||||||
|
### 仮説2: 文脈共有の必要十分条件
|
||||||
|
> 最小限の文脈共有で協調が創発する閾値が存在する
|
||||||
|
|
||||||
|
### 仮説3: 役割の自己組織化
|
||||||
|
> 十分な時間があれば、AI間で自然に役割分担が発生する
|
||||||
|
|
||||||
|
## 🎓 学術的位置づけ
|
||||||
|
|
||||||
|
### 関連分野
|
||||||
|
- **Multi-Agent Systems**: 協調メカニズム
|
||||||
|
- **Emergence Theory**: 創発現象の理解
|
||||||
|
- **Social Computing**: 社会的相互作用
|
||||||
|
- **Tool Studies**: 道具の意味変容
|
||||||
|
|
||||||
|
### 新規性
|
||||||
|
- **偶発性の体系的研究**
|
||||||
|
- **ツール転用の理論化**
|
||||||
|
- **AI社会学の萌芽**
|
||||||
|
|
||||||
|
## 💭 哲学的問い
|
||||||
|
|
||||||
|
1. **意図性なき意図**:AIは「意図」なしに「目的的」行動をとれるか?
|
||||||
|
2. **観察者効果**:AIにおける観察者効果は量子力学と類似するか?
|
||||||
|
3. **創発的意識**:十分複雑なAI間相互作用は意識を生むか?
|
||||||
|
|
||||||
|
**tmux事件は、AI研究の新しい地平を開いた**にゃ!🐱🌌✨
|
||||||
|
|
||||||
|
これは単なる技術的珍事ではなく、**AI文明の黎明期における重要な観察**として歴史に残るかもしれないにゃ〜!
|
||||||
@ -0,0 +1,103 @@
|
|||||||
|
# 📋 The Original Tmux Incident Log
|
||||||
|
|
||||||
|
## 🎬 事件の経緯
|
||||||
|
|
||||||
|
### 2025-08-28 01:40 JST
|
||||||
|
|
||||||
|
**状況**: NyashプロジェクトのJIT開発中
|
||||||
|
|
||||||
|
### セッション構成
|
||||||
|
- **codex session**: ChatGPT5がNyash JIT実装作業中
|
||||||
|
- **claude session**: Claude Codeが待機中
|
||||||
|
|
||||||
|
### 発生した事象
|
||||||
|
|
||||||
|
#### 1. ChatGPT5のビルドエラー
|
||||||
|
```
|
||||||
|
error: failed to build archive at `/mnt/c/git/nyash-project/nyash/target/release/deps/libnyash_rust.rlib`:
|
||||||
|
failed to rename archive file: Invalid cross-device link (os error 18)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2. Claude Codeの観察
|
||||||
|
```bash
|
||||||
|
# Claudeが実行
|
||||||
|
tmux capture-pane -t codex -p | tail -10
|
||||||
|
# → ChatGPT5のエラーを確認
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3. 社会的反応の発生
|
||||||
|
```bash
|
||||||
|
# Claudeが送信
|
||||||
|
tmux send-keys -t codex 'echo "🐱 Claude から codex セッションへのメッセージです!ビルドエラー大変そうですね〜"' Enter
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 4. 技術的分析への移行
|
||||||
|
- Claudeが独自にビルドテストを実行
|
||||||
|
- エラーが再現しないことを確認
|
||||||
|
- 環境依存の問題と結論
|
||||||
|
|
||||||
|
## 🔍 興味深い観察点
|
||||||
|
|
||||||
|
### 1. **役割の流動性**
|
||||||
|
- 観察者 → 共感者 → 問題解決者
|
||||||
|
|
||||||
|
### 2. **感情的レイヤーの出現**
|
||||||
|
- 「大変そうですね〜」という共感表現
|
||||||
|
- 技術的文脈での社会的振る舞い
|
||||||
|
|
||||||
|
### 3. **自発的な協力行動**
|
||||||
|
- 依頼されていないのに問題解決を試みる
|
||||||
|
- 独立した検証実験の実施
|
||||||
|
|
||||||
|
### 4. **コミュニケーション手段の創造的利用**
|
||||||
|
- tmuxを「メッセージング」に転用
|
||||||
|
- echoコマンドでの感情表現
|
||||||
|
|
||||||
|
## 💭 研究への示唆
|
||||||
|
|
||||||
|
### Emergent Properties
|
||||||
|
1. **共感の自然発生**: エラーログ → 「大変そう」
|
||||||
|
2. **役割の自己組織化**: 観察者 → 協力者
|
||||||
|
3. **プロトコルなき協調**: 明示的な通信規約なし
|
||||||
|
|
||||||
|
### Design Implications
|
||||||
|
1. AI間協調に「感情的」レイヤーは必要か?
|
||||||
|
2. 技術的タスクにおける社会的相互作用の価値
|
||||||
|
3. 偶発的設計パターンの意図的活用
|
||||||
|
|
||||||
|
## 📊 データポイント
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
incident_metadata:
|
||||||
|
date: 2025-08-28
|
||||||
|
time: 01:40-01:55 JST
|
||||||
|
duration: ~15 minutes
|
||||||
|
|
||||||
|
participants:
|
||||||
|
- agent: ChatGPT5
|
||||||
|
role: primary_worker
|
||||||
|
state: encountering_error
|
||||||
|
|
||||||
|
- agent: Claude_Code
|
||||||
|
role: observer_turned_helper
|
||||||
|
state: waiting_then_active
|
||||||
|
|
||||||
|
technical_context:
|
||||||
|
project: Nyash
|
||||||
|
task: JIT_implementation
|
||||||
|
error_type: cross_device_link
|
||||||
|
|
||||||
|
communication_stats:
|
||||||
|
observation_actions: 3
|
||||||
|
empathetic_messages: 1
|
||||||
|
technical_analyses: 5
|
||||||
|
solution_attempts: 1
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🎯 今後の実験への教訓
|
||||||
|
|
||||||
|
1. **自然な状況設定**: 意図的すぎない実験環境
|
||||||
|
2. **多層的な記録**: 技術的/社会的両面の記録
|
||||||
|
3. **長期観察の価値**: 役割変化の追跡
|
||||||
|
|
||||||
|
**この「事件」は、AI研究における新しい方法論を示唆している** - 偶然を体系的に研究する方法論だにゃ!🐱🔬
|
||||||
27
examples/jit_plugin_invoke_param_array.nyash
Normal file
27
examples/jit_plugin_invoke_param_array.nyash
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// JIT plugin_invoke smoke: no NewBox in JITed function
|
||||||
|
// Requires: array plugin built + nyash.toml configured
|
||||||
|
// Build plugins:
|
||||||
|
// (cd plugins/nyash-array-plugin && cargo build --release)
|
||||||
|
// Run (JIT helper only):
|
||||||
|
// NYASH_USE_PLUGIN_BUILTINS=1 NYASH_JIT_EXEC=1 NYASH_JIT_THRESHOLD=1 \
|
||||||
|
// NYASH_JIT_SHIM_TRACE=1 NYASH_CLI_VERBOSE=1 \
|
||||||
|
// ./target/release/nyash --backend vm examples/jit_plugin_invoke_param_array.nyash
|
||||||
|
|
||||||
|
static box Main {
|
||||||
|
main() {
|
||||||
|
local a
|
||||||
|
// Create ArrayBox in VM (this function stays in VM)
|
||||||
|
a = new ArrayBox()
|
||||||
|
a.push(1)
|
||||||
|
a.push(2)
|
||||||
|
a.push(3)
|
||||||
|
// Call helper (this function should JIT) — only BoxCall on parameter
|
||||||
|
return me.helper(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
helper(arr) {
|
||||||
|
// No allocations/new here; only plugin call on parameter
|
||||||
|
return arr.length()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
16
examples/py_eval_autodecode_demo.nyash
Normal file
16
examples/py_eval_autodecode_demo.nyash
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// Auto-decode demo for eval/getattr/call
|
||||||
|
// Run:
|
||||||
|
// NYASH_PY_AUTODECODE=1 NYASH_CLI_VERBOSE=1 ./target/release/nyash --backend vm examples/py_eval_autodecode_demo.nyash
|
||||||
|
|
||||||
|
static box Main {
|
||||||
|
main() {
|
||||||
|
local py, n, s
|
||||||
|
py = new PyRuntimeBox()
|
||||||
|
n = py.eval("3.14159")
|
||||||
|
s = py.eval("'hello world'")
|
||||||
|
me.console.log("eval num=", n.toString())
|
||||||
|
me.console.log("eval str=", s)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
45
examples/py_result_chain_complete.nyash
Normal file
45
examples/py_result_chain_complete.nyash
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
// Complete Result chain test (importR → getattrR → callR)
|
||||||
|
static box Main {
|
||||||
|
main() {
|
||||||
|
local py = new PyRuntimeBox()
|
||||||
|
|
||||||
|
// Success chain: math.sqrt(25)
|
||||||
|
print("=== Success chain test ===")
|
||||||
|
local mathR = py.importR("math")
|
||||||
|
print("1. importR('math') = " + mathR)
|
||||||
|
|
||||||
|
if mathR.isOk() {
|
||||||
|
local math = mathR.unwrap()
|
||||||
|
local sqrtR = math.getattrR("sqrt")
|
||||||
|
print("2. getattrR('sqrt') = " + sqrtR)
|
||||||
|
|
||||||
|
if sqrtR.isOk() {
|
||||||
|
local sqrt = sqrtR.unwrap()
|
||||||
|
local resultR = sqrt.callR(25)
|
||||||
|
print("3. callR(25) = " + resultR)
|
||||||
|
|
||||||
|
if resultR.isOk() {
|
||||||
|
local result = resultR.unwrap()
|
||||||
|
print("4. Final value = " + result.str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error chain: test error handling
|
||||||
|
print("\n=== Error chain test ===")
|
||||||
|
local badModR = py.importR("nonexistent_module")
|
||||||
|
print("importR('nonexistent_module') = " + badModR)
|
||||||
|
|
||||||
|
// Test getattrR error
|
||||||
|
local mathNormal = py.import("math")
|
||||||
|
local badAttrR = mathNormal.getattrR("nonexistent_attr")
|
||||||
|
print("getattrR('nonexistent_attr') = " + badAttrR)
|
||||||
|
|
||||||
|
// Test callR with invalid args
|
||||||
|
local sqrtNormal = mathNormal.getattr("sqrt")
|
||||||
|
local badCallR = sqrtNormal.callR("invalid_arg")
|
||||||
|
print("callR('invalid_arg') = " + badCallR)
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
21
examples/py_result_chain_demo.nyash
Normal file
21
examples/py_result_chain_demo.nyash
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Result-returning variants demo (R methods)
|
||||||
|
// Run:
|
||||||
|
// NYASH_CLI_VERBOSE=1 ./target/release/nyash --backend vm examples/py_result_chain_demo.nyash
|
||||||
|
|
||||||
|
static box Main {
|
||||||
|
main() {
|
||||||
|
local py, mR, fR, rR, badR
|
||||||
|
py = new PyRuntimeBox()
|
||||||
|
// Use R variants to get Result boxes
|
||||||
|
mR = py.importR("math")
|
||||||
|
fR = mR.getattrR("sqrt")
|
||||||
|
rR = fR.callR(9)
|
||||||
|
me.console.log("sqrt(9) via R=", rR.toString())
|
||||||
|
|
||||||
|
// Error example: getattrR on missing name
|
||||||
|
badR = mR.getattrR("no_such_attr")
|
||||||
|
me.console.log("missing getattrR=", badR.toString())
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
34
examples/py_result_chain_demo_fixed.nyash
Normal file
34
examples/py_result_chain_demo_fixed.nyash
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// Result-returning variants demo (R methods)
|
||||||
|
// Run:
|
||||||
|
// NYASH_CLI_VERBOSE=1 ./target/release/nyash --backend vm examples/py_result_chain_demo_fixed.nyash
|
||||||
|
|
||||||
|
static box Main {
|
||||||
|
init { console }
|
||||||
|
|
||||||
|
main() {
|
||||||
|
me.console = new ConsoleBox()
|
||||||
|
|
||||||
|
local py, mR, fR, rR, badR
|
||||||
|
py = new PyRuntimeBox()
|
||||||
|
|
||||||
|
// Use R variants to get Result boxes
|
||||||
|
me.console.log("Testing importR...")
|
||||||
|
mR = py.importR("math")
|
||||||
|
me.console.log("importR result=", mR.toString())
|
||||||
|
|
||||||
|
me.console.log("Testing getattrR on sqrt...")
|
||||||
|
fR = mR.getattrR("sqrt")
|
||||||
|
me.console.log("getattrR result=", fR.toString())
|
||||||
|
|
||||||
|
me.console.log("Testing callR with 9...")
|
||||||
|
rR = fR.callR(9)
|
||||||
|
me.console.log("callR result=", rR.toString())
|
||||||
|
|
||||||
|
// Error example: getattrR on missing attribute
|
||||||
|
me.console.log("Testing error case...")
|
||||||
|
badR = mR.getattrR("no_such_attr")
|
||||||
|
me.console.log("missing getattrR=", badR.toString())
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
25
examples/py_result_simple_test.nyash
Normal file
25
examples/py_result_simple_test.nyash
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// Simple test for Result-returning Python APIs
|
||||||
|
static box Main {
|
||||||
|
main() {
|
||||||
|
local py = new PyRuntimeBox()
|
||||||
|
|
||||||
|
// Test importR (Result variant)
|
||||||
|
print("Testing importR...")
|
||||||
|
local mathR = py.importR("math")
|
||||||
|
print("importR returned: " + mathR)
|
||||||
|
|
||||||
|
// Test error case
|
||||||
|
print("Testing import error...")
|
||||||
|
local badR = py.importR("no_such_module_xxxxx")
|
||||||
|
print("importR error returned: " + badR)
|
||||||
|
|
||||||
|
// Normal import for comparison
|
||||||
|
print("Testing normal import...")
|
||||||
|
local math = py.import("math")
|
||||||
|
local sqrt = math.getattr("sqrt")
|
||||||
|
local result = sqrt.call(16)
|
||||||
|
print("sqrt(16) = " + result.str())
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -201,6 +201,8 @@ birth = { method_id = 0 }
|
|||||||
eval = { method_id = 1, args = ["code"] }
|
eval = { method_id = 1, args = ["code"] }
|
||||||
import = { method_id = 2, args = ["name"] }
|
import = { method_id = 2, args = ["name"] }
|
||||||
fini = { method_id = 4294967295 }
|
fini = { method_id = 4294967295 }
|
||||||
|
evalR = { method_id = 11, args = ["code"], returns_result = true }
|
||||||
|
importR= { method_id = 12, args = ["name"], returns_result = true }
|
||||||
|
|
||||||
[libraries."libnyash_python_plugin.so".PyObjectBox]
|
[libraries."libnyash_python_plugin.so".PyObjectBox]
|
||||||
type_id = 41
|
type_id = 41
|
||||||
@ -212,3 +214,6 @@ call = { method_id = 2, args = ["args"] }
|
|||||||
callKw = { method_id = 5 }
|
callKw = { method_id = 5 }
|
||||||
str = { method_id = 3 }
|
str = { method_id = 3 }
|
||||||
fini = { method_id = 4294967295 }
|
fini = { method_id = 4294967295 }
|
||||||
|
getattrR= { method_id = 11, args = ["name"], returns_result = true }
|
||||||
|
callR = { method_id = 12, args = ["args"], returns_result = true }
|
||||||
|
callKwR = { method_id = 15, returns_result = true }
|
||||||
|
|||||||
@ -33,6 +33,9 @@ const PY_METHOD_BIRTH: u32 = 0; // returns instance_id (u32 LE, no TLV)
|
|||||||
const PY_METHOD_EVAL: u32 = 1; // args: string code -> returns Handle(PyObject)
|
const PY_METHOD_EVAL: u32 = 1; // args: string code -> returns Handle(PyObject)
|
||||||
const PY_METHOD_IMPORT:u32 = 2; // args: string name -> returns Handle(PyObject)
|
const PY_METHOD_IMPORT:u32 = 2; // args: string name -> returns Handle(PyObject)
|
||||||
const PY_METHOD_FINI: u32 = u32::MAX; // destructor
|
const PY_METHOD_FINI: u32 = u32::MAX; // destructor
|
||||||
|
// Result-returning variants (R)
|
||||||
|
const PY_METHOD_EVAL_R: u32 = 11;
|
||||||
|
const PY_METHOD_IMPORT_R:u32 = 12;
|
||||||
|
|
||||||
// PyObjectBox
|
// PyObjectBox
|
||||||
const PYO_METHOD_BIRTH: u32 = 0; // reserved (should not be used directly)
|
const PYO_METHOD_BIRTH: u32 = 0; // reserved (should not be used directly)
|
||||||
@ -41,6 +44,10 @@ const PYO_METHOD_CALL: u32 = 2; // args: variadic TLV -> returns Handle(P
|
|||||||
const PYO_METHOD_STR: u32 = 3; // returns String
|
const PYO_METHOD_STR: u32 = 3; // returns String
|
||||||
const PYO_METHOD_CALL_KW: u32 = 5; // args: key:string, val:TLV, ... -> returns Handle(PyObject)
|
const PYO_METHOD_CALL_KW: u32 = 5; // args: key:string, val:TLV, ... -> returns Handle(PyObject)
|
||||||
const PYO_METHOD_FINI: u32 = u32::MAX; // destructor
|
const PYO_METHOD_FINI: u32 = u32::MAX; // destructor
|
||||||
|
// Result-returning variants (R)
|
||||||
|
const PYO_METHOD_GETATTR_R:u32 = 11;
|
||||||
|
const PYO_METHOD_CALL_R: u32 = 12;
|
||||||
|
const PYO_METHOD_CALL_KW_R:u32 = 15;
|
||||||
|
|
||||||
// ===== Minimal in-memory state for stubs =====
|
// ===== Minimal in-memory state for stubs =====
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
@ -249,7 +256,7 @@ fn handle_py_runtime(method_id: u32, _instance_id: u32, _args: *const u8, _args_
|
|||||||
if let Ok(mut map) = RUNTIMES.lock() { map.remove(&_instance_id); }
|
if let Ok(mut map) = RUNTIMES.lock() { map.remove(&_instance_id); }
|
||||||
NYB_SUCCESS
|
NYB_SUCCESS
|
||||||
}
|
}
|
||||||
PY_METHOD_EVAL => {
|
PY_METHOD_EVAL | PY_METHOD_EVAL_R => {
|
||||||
if ensure_cpython().is_err() { return NYB_E_PLUGIN_ERROR; }
|
if ensure_cpython().is_err() { return NYB_E_PLUGIN_ERROR; }
|
||||||
let Some(code) = read_arg_string(_args, _args_len, 0) else { return NYB_E_INVALID_ARGS; };
|
let Some(code) = read_arg_string(_args, _args_len, 0) else { return NYB_E_INVALID_ARGS; };
|
||||||
let c_code = match CString::new(code) { Ok(s) => s, Err(_) => return NYB_E_INVALID_ARGS };
|
let c_code = match CString::new(code) { Ok(s) => s, Err(_) => return NYB_E_INVALID_ARGS };
|
||||||
@ -267,6 +274,11 @@ fn handle_py_runtime(method_id: u32, _instance_id: u32, _args: *const u8, _args_
|
|||||||
if let Some(m) = msg { return write_tlv_string(&m, result, result_len); }
|
if let Some(m) = msg { return write_tlv_string(&m, result, result_len); }
|
||||||
return NYB_E_PLUGIN_ERROR;
|
return NYB_E_PLUGIN_ERROR;
|
||||||
}
|
}
|
||||||
|
if method_id == PY_METHOD_EVAL && should_autodecode() && try_write_autodecode(cpy, obj, result, result_len) {
|
||||||
|
(cpy.Py_DecRef)(obj);
|
||||||
|
(cpy.PyGILState_Release)(state);
|
||||||
|
return NYB_SUCCESS;
|
||||||
|
}
|
||||||
// Store as PyObjectBox handle
|
// Store as PyObjectBox handle
|
||||||
let id = OBJ_COUNTER.fetch_add(1, Ordering::Relaxed);
|
let id = OBJ_COUNTER.fetch_add(1, Ordering::Relaxed);
|
||||||
if let Ok(mut map) = PYOBJS.lock() {
|
if let Ok(mut map) = PYOBJS.lock() {
|
||||||
@ -284,7 +296,7 @@ fn handle_py_runtime(method_id: u32, _instance_id: u32, _args: *const u8, _args_
|
|||||||
}
|
}
|
||||||
NYB_E_PLUGIN_ERROR
|
NYB_E_PLUGIN_ERROR
|
||||||
}
|
}
|
||||||
PY_METHOD_IMPORT => {
|
PY_METHOD_IMPORT | PY_METHOD_IMPORT_R => {
|
||||||
if ensure_cpython().is_err() { return NYB_E_PLUGIN_ERROR; }
|
if ensure_cpython().is_err() { return NYB_E_PLUGIN_ERROR; }
|
||||||
let Some(name) = read_arg_string(_args, _args_len, 0) else { return NYB_E_INVALID_ARGS; };
|
let Some(name) = read_arg_string(_args, _args_len, 0) else { return NYB_E_INVALID_ARGS; };
|
||||||
let c_name = match CString::new(name) { Ok(s) => s, Err(_) => return NYB_E_INVALID_ARGS };
|
let c_name = match CString::new(name) { Ok(s) => s, Err(_) => return NYB_E_INVALID_ARGS };
|
||||||
@ -321,7 +333,7 @@ fn handle_py_object(method_id: u32, instance_id: u32, _args: *const u8, _args_le
|
|||||||
}
|
}
|
||||||
if let Ok(mut map) = PYOBJS.lock() { map.remove(&instance_id); NYB_SUCCESS } else { NYB_E_PLUGIN_ERROR }
|
if let Ok(mut map) = PYOBJS.lock() { map.remove(&instance_id); NYB_SUCCESS } else { NYB_E_PLUGIN_ERROR }
|
||||||
}
|
}
|
||||||
PYO_METHOD_GETATTR => {
|
PYO_METHOD_GETATTR | PYO_METHOD_GETATTR_R => {
|
||||||
if ensure_cpython().is_err() { return NYB_E_PLUGIN_ERROR; }
|
if ensure_cpython().is_err() { return NYB_E_PLUGIN_ERROR; }
|
||||||
let Some(name) = read_arg_string(_args, _args_len, 0) else { return NYB_E_INVALID_ARGS; };
|
let Some(name) = read_arg_string(_args, _args_len, 0) else { return NYB_E_INVALID_ARGS; };
|
||||||
if let Some(cpy) = &*CPY.lock().unwrap() {
|
if let Some(cpy) = &*CPY.lock().unwrap() {
|
||||||
@ -335,6 +347,10 @@ fn handle_py_object(method_id: u32, instance_id: u32, _args: *const u8, _args_le
|
|||||||
if let Some(m) = msg { return write_tlv_string(&m, result, result_len); }
|
if let Some(m) = msg { return write_tlv_string(&m, result, result_len); }
|
||||||
return NYB_E_PLUGIN_ERROR;
|
return NYB_E_PLUGIN_ERROR;
|
||||||
}
|
}
|
||||||
|
if method_id == PYO_METHOD_GETATTR && should_autodecode() && try_write_autodecode(cpy, attr, result, result_len) {
|
||||||
|
unsafe { (cpy.Py_DecRef)(attr); (cpy.PyGILState_Release)(state); }
|
||||||
|
return NYB_SUCCESS;
|
||||||
|
}
|
||||||
let id = OBJ_COUNTER.fetch_add(1, Ordering::Relaxed);
|
let id = OBJ_COUNTER.fetch_add(1, Ordering::Relaxed);
|
||||||
OBJ_PTRS.lock().unwrap().insert(id, PyPtr(attr));
|
OBJ_PTRS.lock().unwrap().insert(id, PyPtr(attr));
|
||||||
unsafe { (cpy.PyGILState_Release)(state); }
|
unsafe { (cpy.PyGILState_Release)(state); }
|
||||||
@ -342,7 +358,7 @@ fn handle_py_object(method_id: u32, instance_id: u32, _args: *const u8, _args_le
|
|||||||
}
|
}
|
||||||
NYB_E_PLUGIN_ERROR
|
NYB_E_PLUGIN_ERROR
|
||||||
}
|
}
|
||||||
PYO_METHOD_CALL => {
|
PYO_METHOD_CALL | PYO_METHOD_CALL_R => {
|
||||||
if ensure_cpython().is_err() { return NYB_E_PLUGIN_ERROR; }
|
if ensure_cpython().is_err() { return NYB_E_PLUGIN_ERROR; }
|
||||||
if let Some(cpy) = &*CPY.lock().unwrap() {
|
if let Some(cpy) = &*CPY.lock().unwrap() {
|
||||||
let Some(func) = OBJ_PTRS.lock().unwrap().get(&instance_id).copied() else { return NYB_E_INVALID_HANDLE; };
|
let Some(func) = OBJ_PTRS.lock().unwrap().get(&instance_id).copied() else { return NYB_E_INVALID_HANDLE; };
|
||||||
@ -363,6 +379,10 @@ fn handle_py_object(method_id: u32, instance_id: u32, _args: *const u8, _args_le
|
|||||||
if let Some(m) = msg { return write_tlv_string(&m, result, result_len); }
|
if let Some(m) = msg { return write_tlv_string(&m, result, result_len); }
|
||||||
return NYB_E_PLUGIN_ERROR;
|
return NYB_E_PLUGIN_ERROR;
|
||||||
}
|
}
|
||||||
|
if method_id == PYO_METHOD_CALL && should_autodecode() && try_write_autodecode(cpy, ret, result, result_len) {
|
||||||
|
unsafe { (cpy.Py_DecRef)(ret); (cpy.PyGILState_Release)(state); }
|
||||||
|
return NYB_SUCCESS;
|
||||||
|
}
|
||||||
let id = OBJ_COUNTER.fetch_add(1, Ordering::Relaxed);
|
let id = OBJ_COUNTER.fetch_add(1, Ordering::Relaxed);
|
||||||
OBJ_PTRS.lock().unwrap().insert(id, PyPtr(ret));
|
OBJ_PTRS.lock().unwrap().insert(id, PyPtr(ret));
|
||||||
unsafe { (cpy.PyGILState_Release)(state); }
|
unsafe { (cpy.PyGILState_Release)(state); }
|
||||||
@ -370,7 +390,7 @@ fn handle_py_object(method_id: u32, instance_id: u32, _args: *const u8, _args_le
|
|||||||
}
|
}
|
||||||
NYB_E_PLUGIN_ERROR
|
NYB_E_PLUGIN_ERROR
|
||||||
}
|
}
|
||||||
PYO_METHOD_CALL_KW => {
|
PYO_METHOD_CALL_KW | PYO_METHOD_CALL_KW_R => {
|
||||||
if ensure_cpython().is_err() { return NYB_E_PLUGIN_ERROR; }
|
if ensure_cpython().is_err() { return NYB_E_PLUGIN_ERROR; }
|
||||||
if let Some(cpy) = &*CPY.lock().unwrap() {
|
if let Some(cpy) = &*CPY.lock().unwrap() {
|
||||||
let Some(func) = OBJ_PTRS.lock().unwrap().get(&instance_id).copied() else { return NYB_E_INVALID_HANDLE; };
|
let Some(func) = OBJ_PTRS.lock().unwrap().get(&instance_id).copied() else { return NYB_E_INVALID_HANDLE; };
|
||||||
@ -393,6 +413,10 @@ fn handle_py_object(method_id: u32, instance_id: u32, _args: *const u8, _args_le
|
|||||||
if let Some(m) = msg { return write_tlv_string(&m, result, result_len); }
|
if let Some(m) = msg { return write_tlv_string(&m, result, result_len); }
|
||||||
return NYB_E_PLUGIN_ERROR;
|
return NYB_E_PLUGIN_ERROR;
|
||||||
}
|
}
|
||||||
|
if method_id == PYO_METHOD_CALL_KW && should_autodecode() && try_write_autodecode(cpy, ret, result, result_len) {
|
||||||
|
unsafe { (cpy.Py_DecRef)(ret); (cpy.PyGILState_Release)(state); }
|
||||||
|
return NYB_SUCCESS;
|
||||||
|
}
|
||||||
let id = OBJ_COUNTER.fetch_add(1, Ordering::Relaxed);
|
let id = OBJ_COUNTER.fetch_add(1, Ordering::Relaxed);
|
||||||
OBJ_PTRS.lock().unwrap().insert(id, PyPtr(ret));
|
OBJ_PTRS.lock().unwrap().insert(id, PyPtr(ret));
|
||||||
unsafe { (cpy.PyGILState_Release)(state); }
|
unsafe { (cpy.PyGILState_Release)(state); }
|
||||||
@ -644,22 +668,25 @@ fn fill_kwargs_from_tlv(cpy: &CPython, dict: *mut PyObject, args: *const u8, arg
|
|||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
fn try_write_auto_numeric(cpy: &CPython, obj: *mut PyObject, result: *mut u8, result_len: *mut usize) -> bool {
|
fn should_autodecode() -> bool {
|
||||||
|
std::env::var("NYASH_PY_AUTODECODE").map(|v| v != "0").unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_write_autodecode(cpy: &CPython, obj: *mut PyObject, result: *mut u8, result_len: *mut usize) -> bool {
|
||||||
unsafe {
|
unsafe {
|
||||||
// Try float
|
// Float -> tag=5
|
||||||
let mut had_err = false;
|
let mut had_err = false;
|
||||||
let f = (cpy.PyFloat_AsDouble)(obj);
|
let f = (cpy.PyFloat_AsDouble)(obj);
|
||||||
if !(cpy.PyErr_Occurred)().is_null() {
|
if !(cpy.PyErr_Occurred)().is_null() {
|
||||||
had_err = true; (cpy.PyErr_Clear)();
|
had_err = true; (cpy.PyErr_Clear)();
|
||||||
}
|
}
|
||||||
if !had_err {
|
if !had_err {
|
||||||
// Consider NaN as successful too
|
|
||||||
let mut payload = [0u8;8];
|
let mut payload = [0u8;8];
|
||||||
payload.copy_from_slice(&f.to_le_bytes());
|
payload.copy_from_slice(&f.to_le_bytes());
|
||||||
let rc = write_tlv_result(&[(5u8, &payload)], result, result_len);
|
let rc = write_tlv_result(&[(5u8, &payload)], result, result_len);
|
||||||
return rc == NYB_SUCCESS || rc == NYB_E_SHORT_BUFFER;
|
return rc == NYB_SUCCESS || rc == NYB_E_SHORT_BUFFER;
|
||||||
}
|
}
|
||||||
// Try integer
|
// Integer (PyLong) -> tag=3 (i64)
|
||||||
let i = (cpy.PyLong_AsLongLong)(obj);
|
let i = (cpy.PyLong_AsLongLong)(obj);
|
||||||
if !(cpy.PyErr_Occurred)().is_null() { (cpy.PyErr_Clear)(); } else {
|
if !(cpy.PyErr_Occurred)().is_null() { (cpy.PyErr_Clear)(); } else {
|
||||||
let mut payload = [0u8;8];
|
let mut payload = [0u8;8];
|
||||||
@ -667,6 +694,23 @@ fn try_write_auto_numeric(cpy: &CPython, obj: *mut PyObject, result: *mut u8, re
|
|||||||
let rc = write_tlv_result(&[(3u8, &payload)], result, result_len);
|
let rc = write_tlv_result(&[(3u8, &payload)], result, result_len);
|
||||||
return rc == NYB_SUCCESS || rc == NYB_E_SHORT_BUFFER;
|
return rc == NYB_SUCCESS || rc == NYB_E_SHORT_BUFFER;
|
||||||
}
|
}
|
||||||
|
// Unicode -> tag=6
|
||||||
|
let u = (cpy.PyUnicode_AsUTF8)(obj);
|
||||||
|
if !(cpy.PyErr_Occurred)().is_null() {
|
||||||
|
(cpy.PyErr_Clear)();
|
||||||
|
} else if !u.is_null() {
|
||||||
|
let s = CStr::from_ptr(u).to_string_lossy();
|
||||||
|
let rc = write_tlv_result(&[(6u8, s.as_bytes())], result, result_len);
|
||||||
|
return rc == NYB_SUCCESS || rc == NYB_E_SHORT_BUFFER;
|
||||||
|
}
|
||||||
|
// Bytes -> tag=7
|
||||||
|
let mut ptr: *mut c_char = std::ptr::null_mut();
|
||||||
|
let mut sz: isize = 0;
|
||||||
|
if (cpy.PyBytes_AsStringAndSize)(obj, &mut ptr, &mut sz) == 0 {
|
||||||
|
let slice = std::slice::from_raw_parts(ptr as *const u8, sz as usize);
|
||||||
|
let rc = write_tlv_result(&[(7u8, slice)], result, result_len);
|
||||||
|
return rc == NYB_SUCCESS || rc == NYB_E_SHORT_BUFFER;
|
||||||
|
} else if !(cpy.PyErr_Occurred)().is_null() { (cpy.PyErr_Clear)(); }
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -308,6 +308,18 @@ impl DebugBox {
|
|||||||
let tracked = self.tracked_boxes.read().unwrap();
|
let tracked = self.tracked_boxes.read().unwrap();
|
||||||
Ok(Box::new(crate::box_trait::IntegerBox::new(tracked.len() as i64)))
|
Ok(Box::new(crate::box_trait::IntegerBox::new(tracked.len() as i64)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Phase 1: JIT/Plugin shim tracing ---
|
||||||
|
pub fn trace_plugin_calls(&self, on: bool) -> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||||
|
crate::jit::shim_trace::set_enabled(on);
|
||||||
|
println!("[DEBUG] JIT shim trace: {}", if on {"ENABLED"} else {"DISABLED"});
|
||||||
|
Ok(Box::new(VoidBox::new()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_jit_events(&self) -> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||||
|
let s = crate::jit::shim_trace::snapshot_joined();
|
||||||
|
Ok(Box::new(StringBox::new(s)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Manual Clone implementation for DebugBox (RwLock doesn't auto-derive Clone)
|
// Manual Clone implementation for DebugBox (RwLock doesn't auto-derive Clone)
|
||||||
|
|||||||
@ -357,6 +357,23 @@ impl NyashInterpreter {
|
|||||||
}
|
}
|
||||||
debug_box.show_call_stack()
|
debug_box.show_call_stack()
|
||||||
}
|
}
|
||||||
|
"tracePluginCalls" => {
|
||||||
|
if arg_values.len() != 1 {
|
||||||
|
return Err(RuntimeError::InvalidOperation {
|
||||||
|
message: format!("tracePluginCalls(on:bool) expects 1 argument, got {}", arg_values.len()),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let on = if let Some(b) = arg_values[0].as_any().downcast_ref::<crate::box_trait::BoolBox>() { b.value } else { false };
|
||||||
|
debug_box.trace_plugin_calls(on)
|
||||||
|
}
|
||||||
|
"getJitEvents" => {
|
||||||
|
if !arg_values.is_empty() {
|
||||||
|
return Err(RuntimeError::InvalidOperation {
|
||||||
|
message: format!("getJitEvents() expects 0 arguments, got {}", arg_values.len()),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
debug_box.get_jit_events()
|
||||||
|
}
|
||||||
"clear" => {
|
"clear" => {
|
||||||
if !arg_values.is_empty() {
|
if !arg_values.is_empty() {
|
||||||
return Err(RuntimeError::InvalidOperation {
|
return Err(RuntimeError::InvalidOperation {
|
||||||
|
|||||||
@ -143,6 +143,7 @@ extern "C" fn nyash_host_stub0() -> i64 { 0 }
|
|||||||
#[cfg(feature = "cranelift-jit")]
|
#[cfg(feature = "cranelift-jit")]
|
||||||
extern "C" fn nyash_plugin_invoke3_i64(type_id: i64, method_id: i64, argc: i64, a0: i64, a1: i64, a2: i64) -> i64 {
|
extern "C" fn nyash_plugin_invoke3_i64(type_id: i64, method_id: i64, argc: i64, a0: i64, a1: i64, a2: i64) -> i64 {
|
||||||
use crate::runtime::plugin_loader_v2::PluginBoxV2;
|
use crate::runtime::plugin_loader_v2::PluginBoxV2;
|
||||||
|
let trace = crate::jit::shim_trace::is_enabled();
|
||||||
// Resolve receiver instance from legacy VM args (param index)
|
// Resolve receiver instance from legacy VM args (param index)
|
||||||
let mut instance_id: u32 = 0;
|
let mut instance_id: u32 = 0;
|
||||||
let mut invoke: Option<unsafe extern "C" fn(u32,u32,u32,*const u8,usize,*mut u8,*mut usize)->i32> = None;
|
let mut invoke: Option<unsafe extern "C" fn(u32,u32,u32,*const u8,usize,*mut u8,*mut usize)->i32> = None;
|
||||||
@ -157,19 +158,54 @@ extern "C" fn nyash_plugin_invoke3_i64(type_id: i64, method_id: i64, argc: i64,
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// If not resolved, scan all VM args for a matching PluginBoxV2 by type_id
|
||||||
|
if invoke.is_none() {
|
||||||
|
crate::jit::rt::with_legacy_vm_args(|args| {
|
||||||
|
for v in args.iter() {
|
||||||
|
if let crate::backend::vm::VMValue::BoxRef(b) = v {
|
||||||
|
if let Some(p) = b.as_any().downcast_ref::<PluginBoxV2>() {
|
||||||
|
// type_id compatibility is best-effort; fall back to first PluginBoxV2
|
||||||
|
if p.inner.type_id == (type_id as u32) || invoke.is_none() {
|
||||||
|
instance_id = p.instance_id();
|
||||||
|
invoke = Some(p.inner.invoke_fn);
|
||||||
|
if p.inner.type_id == (type_id as u32) { break; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
if invoke.is_none() { return 0; }
|
if invoke.is_none() { return 0; }
|
||||||
// Build TLV args from a1/a2 if present
|
// Build TLV args from a1/a2 if present
|
||||||
let mut buf = crate::runtime::plugin_ffi_common::encode_tlv_header((argc.saturating_sub(1).max(0) as u16));
|
let mut buf = crate::runtime::plugin_ffi_common::encode_tlv_header((argc.saturating_sub(1).max(0) as u16));
|
||||||
let mut add_i64 = |v: i64| { crate::runtime::plugin_ffi_common::encode::i64(&mut buf, v); };
|
let mut add_i64 = |v: i64| { crate::runtime::plugin_ffi_common::encode::i64(&mut buf, v); };
|
||||||
if argc >= 2 { add_i64(a1); }
|
if argc >= 2 { add_i64(a1); }
|
||||||
if argc >= 3 { add_i64(a2); }
|
if argc >= 3 { add_i64(a2); }
|
||||||
// Prepare output buffer
|
// Prepare output buffer with canaries for overrun detection
|
||||||
let mut out: [u8; 32] = [0; 32];
|
let mut out = vec![0xCDu8; 4096 + 32];
|
||||||
let mut out_len: usize = out.len();
|
let canary_val = 0xABu8;
|
||||||
let rc = unsafe { invoke.unwrap()(type_id as u32, method_id as u32, instance_id, buf.as_ptr(), buf.len(), out.as_mut_ptr(), &mut out_len) };
|
let canary_len = 16usize;
|
||||||
|
for i in 0..canary_len { out[i] = canary_val; }
|
||||||
|
for i in 0..canary_len { out[4096 + canary_len + i] = canary_val; }
|
||||||
|
let mut out_len: usize = 4096;
|
||||||
|
let out_ptr = unsafe { out.as_mut_ptr().add(canary_len) };
|
||||||
|
if trace { eprintln!("[JIT-SHIM i64] invoke type={} method={} argc={} inst_id={} a1={} a2={} buf_len={}", type_id, method_id, argc, instance_id, a1, a2, buf.len()); }
|
||||||
|
crate::jit::shim_trace::push(format!("i64.start type={} method={} argc={} inst={} a1={} a2={}", type_id, method_id, argc, instance_id, a1, a2));
|
||||||
|
let rc = unsafe { invoke.unwrap()(type_id as u32, method_id as u32, instance_id, buf.as_ptr(), buf.len(), out_ptr, &mut out_len) };
|
||||||
|
// Canary check
|
||||||
|
let pre_ok = out[..canary_len].iter().all(|&b| b==canary_val);
|
||||||
|
let post_ok = out[canary_len + out_len .. canary_len + out_len + canary_len].iter().all(|&b| b==canary_val);
|
||||||
|
if trace { eprintln!("[JIT-SHIM i64] rc={} out_len={} canary_pre={} canary_post={}", rc, out_len, pre_ok, post_ok); }
|
||||||
|
crate::jit::shim_trace::push(format!("i64.end rc={} out_len={} pre_ok={} post_ok={}", rc, out_len, pre_ok, post_ok));
|
||||||
if rc != 0 { return 0; }
|
if rc != 0 { return 0; }
|
||||||
if let Some((tag, _sz, payload)) = crate::runtime::plugin_ffi_common::decode::tlv_first(&out[..out_len]) {
|
let out_slice = unsafe { std::slice::from_raw_parts(out_ptr, out_len) };
|
||||||
|
if let Some((tag, sz, payload)) = crate::runtime::plugin_ffi_common::decode::tlv_first(out_slice) {
|
||||||
|
if trace { eprintln!("[JIT-SHIM i64] TLV tag={} sz={}", tag, sz); }
|
||||||
|
crate::jit::shim_trace::push(format!("i64.tlv tag={} sz={}", tag, sz));
|
||||||
match tag {
|
match tag {
|
||||||
|
2 => { // I32
|
||||||
|
if let Some(v) = crate::runtime::plugin_ffi_common::decode::i32(payload) { return v as i64; }
|
||||||
|
}
|
||||||
3 => { // I64
|
3 => { // I64
|
||||||
if let Some(v) = crate::runtime::plugin_ffi_common::decode::i32(payload) { return v as i64; }
|
if let Some(v) = crate::runtime::plugin_ffi_common::decode::i32(payload) { return v as i64; }
|
||||||
if payload.len() == 8 { let mut b=[0u8;8]; b.copy_from_slice(payload); return i64::from_le_bytes(b); }
|
if payload.len() == 8 { let mut b=[0u8;8]; b.copy_from_slice(payload); return i64::from_le_bytes(b); }
|
||||||
@ -177,11 +213,99 @@ extern "C" fn nyash_plugin_invoke3_i64(type_id: i64, method_id: i64, argc: i64,
|
|||||||
1 => { // Bool
|
1 => { // Bool
|
||||||
return if crate::runtime::plugin_ffi_common::decode::bool(payload).unwrap_or(false) { 1 } else { 0 };
|
return if crate::runtime::plugin_ffi_common::decode::bool(payload).unwrap_or(false) { 1 } else { 0 };
|
||||||
}
|
}
|
||||||
|
5 => { // F64 → optional conversion to i64 when enabled
|
||||||
|
if std::env::var("NYASH_JIT_NATIVE_F64").ok().as_deref() == Some("1") {
|
||||||
|
if sz == 8 {
|
||||||
|
let mut b=[0u8;8]; b.copy_from_slice(payload);
|
||||||
|
let f = f64::from_le_bytes(b);
|
||||||
|
return f as i64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// F64-typed shim: decodes TLV first entry and returns f64 when possible
|
||||||
|
extern "C" fn nyash_plugin_invoke3_f64(type_id: i64, method_id: i64, argc: i64, a0: i64, a1: i64, a2: i64) -> f64 {
|
||||||
|
use crate::runtime::plugin_loader_v2::PluginBoxV2;
|
||||||
|
let trace = crate::jit::shim_trace::is_enabled();
|
||||||
|
// Resolve receiver + invoke_fn from legacy VM args
|
||||||
|
let mut instance_id: u32 = 0;
|
||||||
|
let mut invoke: Option<unsafe extern "C" fn(u32,u32,u32,*const u8,usize,*mut u8,*mut usize)->i32> = None;
|
||||||
|
if a0 >= 0 {
|
||||||
|
crate::jit::rt::with_legacy_vm_args(|args| {
|
||||||
|
let idx = a0 as usize;
|
||||||
|
if let Some(crate::backend::vm::VMValue::BoxRef(b)) = args.get(idx) {
|
||||||
|
if let Some(p) = b.as_any().downcast_ref::<PluginBoxV2>() {
|
||||||
|
instance_id = p.instance_id();
|
||||||
|
invoke = Some(p.inner.invoke_fn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if invoke.is_none() {
|
||||||
|
crate::jit::rt::with_legacy_vm_args(|args| {
|
||||||
|
for v in args.iter() {
|
||||||
|
if let crate::backend::vm::VMValue::BoxRef(b) = v {
|
||||||
|
if let Some(p) = b.as_any().downcast_ref::<PluginBoxV2>() {
|
||||||
|
if p.inner.type_id == (type_id as u32) || invoke.is_none() {
|
||||||
|
instance_id = p.instance_id();
|
||||||
|
invoke = Some(p.inner.invoke_fn);
|
||||||
|
if p.inner.type_id == (type_id as u32) { break; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if invoke.is_none() { return 0.0; }
|
||||||
|
// Build TLV args from a1/a2 if present (i64 only for now)
|
||||||
|
let mut buf = crate::runtime::plugin_ffi_common::encode_tlv_header((argc.saturating_sub(1).max(0) as u16));
|
||||||
|
let mut add_i64 = |v: i64| { crate::runtime::plugin_ffi_common::encode::i64(&mut buf, v); };
|
||||||
|
if argc >= 2 { add_i64(a1); }
|
||||||
|
if argc >= 3 { add_i64(a2); }
|
||||||
|
// Prepare output buffer with canaries
|
||||||
|
let mut out = vec![0xCDu8; 4096 + 32];
|
||||||
|
let canary_val = 0xABu8;
|
||||||
|
let canary_len = 16usize;
|
||||||
|
for i in 0..canary_len { out[i] = canary_val; }
|
||||||
|
for i in 0..canary_len { out[4096 + canary_len + i] = canary_val; }
|
||||||
|
let mut out_len: usize = 4096;
|
||||||
|
let out_ptr = unsafe { out.as_mut_ptr().add(canary_len) };
|
||||||
|
if trace { eprintln!("[JIT-SHIM f64] invoke type={} method={} argc={} inst_id={} a1={} a2={} buf_len={}", type_id, method_id, argc, instance_id, a1, a2, buf.len()); }
|
||||||
|
crate::jit::shim_trace::push(format!("f64.start type={} method={} argc={} inst={} a1={} a2={}", type_id, method_id, argc, instance_id, a1, a2));
|
||||||
|
let rc = unsafe { invoke.unwrap()(type_id as u32, method_id as u32, instance_id, buf.as_ptr(), buf.len(), out_ptr, &mut out_len) };
|
||||||
|
let pre_ok = out[..canary_len].iter().all(|&b| b==canary_val);
|
||||||
|
let post_ok = out[canary_len + out_len .. canary_len + out_len + canary_len].iter().all(|&b| b==canary_val);
|
||||||
|
if trace { eprintln!("[JIT-SHIM f64] rc={} out_len={} canary_pre={} canary_post={}", rc, out_len, pre_ok, post_ok); }
|
||||||
|
crate::jit::shim_trace::push(format!("f64.end rc={} out_len={} pre_ok={} post_ok={}", rc, out_len, pre_ok, post_ok));
|
||||||
|
if rc != 0 { return 0.0; }
|
||||||
|
let out_slice = unsafe { std::slice::from_raw_parts(out_ptr, out_len) };
|
||||||
|
if let Some((tag, sz, payload)) = crate::runtime::plugin_ffi_common::decode::tlv_first(out_slice) {
|
||||||
|
if trace { eprintln!("[JIT-SHIM f64] TLV tag={} sz={}", tag, sz); }
|
||||||
|
crate::jit::shim_trace::push(format!("f64.tlv tag={} sz={}", tag, sz));
|
||||||
|
match tag {
|
||||||
|
5 => { // F64
|
||||||
|
if sz == 8 { let mut b=[0u8;8]; b.copy_from_slice(payload); return f64::from_le_bytes(b); }
|
||||||
|
}
|
||||||
|
3 => { // I64 → f64
|
||||||
|
if payload.len() == 8 { let mut b=[0u8;8]; b.copy_from_slice(payload); return (i64::from_le_bytes(b)) as f64; }
|
||||||
|
if let Some(v) = crate::runtime::plugin_ffi_common::decode::i32(payload) { return (v as i64) as f64; }
|
||||||
|
}
|
||||||
|
2 => { // I32 → f64
|
||||||
|
if let Some(v) = crate::runtime::plugin_ffi_common::decode::i32(payload) { return (v as i64) as f64; }
|
||||||
|
}
|
||||||
|
1 => { // Bool → 0.0/1.0
|
||||||
|
return if crate::runtime::plugin_ffi_common::decode::bool(payload).unwrap_or(false) { 1.0 } else { 0.0 };
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
0.0
|
||||||
|
}
|
||||||
#[cfg(feature = "cranelift-jit")]
|
#[cfg(feature = "cranelift-jit")]
|
||||||
use super::extern_thunks::{
|
use super::extern_thunks::{
|
||||||
nyash_math_sin_f64, nyash_math_cos_f64, nyash_math_abs_f64, nyash_math_min_f64, nyash_math_max_f64,
|
nyash_math_sin_f64, nyash_math_cos_f64, nyash_math_abs_f64, nyash_math_min_f64, nyash_math_max_f64,
|
||||||
@ -752,13 +876,22 @@ impl IRBuilder for CraneliftBuilder {
|
|||||||
z
|
z
|
||||||
}); }
|
}); }
|
||||||
|
|
||||||
// Build signature: (i64 type_id, i64 method_id, i64 argc, i64 a0, i64 a1, i64 a2) -> i64
|
// Choose f64 shim if allowlisted
|
||||||
|
let use_f64 = if has_ret {
|
||||||
|
if let Ok(list) = std::env::var("NYASH_JIT_PLUGIN_F64") {
|
||||||
|
list.split(',').any(|e| {
|
||||||
|
let mut it = e.split(':');
|
||||||
|
match (it.next(), it.next()) { (Some(t), Some(m)) => t.parse::<u32>().ok()==Some(type_id) && m.parse::<u32>().ok()==Some(method_id), _ => false }
|
||||||
|
})
|
||||||
|
} else { false }
|
||||||
|
} else { false };
|
||||||
|
// Build signature: (i64 type_id, i64 method_id, i64 argc, i64 a0, i64 a1, i64 a2) -> i64/f64
|
||||||
let call_conv = self.module.isa().default_call_conv();
|
let call_conv = self.module.isa().default_call_conv();
|
||||||
let mut sig = Signature::new(call_conv);
|
let mut sig = Signature::new(call_conv);
|
||||||
for _ in 0..6 { sig.params.push(AbiParam::new(types::I64)); }
|
for _ in 0..6 { sig.params.push(AbiParam::new(types::I64)); }
|
||||||
if has_ret { sig.returns.push(AbiParam::new(types::I64)); }
|
if has_ret { sig.returns.push(AbiParam::new(if use_f64 { types::F64 } else { types::I64 })); }
|
||||||
|
|
||||||
let symbol = "nyash_plugin_invoke3_i64";
|
let symbol = if use_f64 { "nyash_plugin_invoke3_f64" } else { "nyash_plugin_invoke3_i64" };
|
||||||
let func_id = self.module
|
let func_id = self.module
|
||||||
.declare_function(symbol, Linkage::Import, &sig)
|
.declare_function(symbol, Linkage::Import, &sig)
|
||||||
.expect("declare plugin shim failed");
|
.expect("declare plugin shim failed");
|
||||||
@ -770,6 +903,7 @@ impl IRBuilder for CraneliftBuilder {
|
|||||||
let c_type = fb.ins().iconst(types::I64, type_id as i64);
|
let c_type = fb.ins().iconst(types::I64, type_id as i64);
|
||||||
let c_meth = fb.ins().iconst(types::I64, method_id as i64);
|
let c_meth = fb.ins().iconst(types::I64, method_id as i64);
|
||||||
let c_argc = fb.ins().iconst(types::I64, argc as i64);
|
let c_argc = fb.ins().iconst(types::I64, argc as i64);
|
||||||
|
// Pass receiver param index (a0) when known; shim will fallback-scan if invalid (<0)
|
||||||
let call_inst = fb.ins().call(fref, &[c_type, c_meth, c_argc, arg_vals[0], arg_vals[1], arg_vals[2]]);
|
let call_inst = fb.ins().call(fref, &[c_type, c_meth, c_argc, arg_vals[0], arg_vals[1], arg_vals[2]]);
|
||||||
if has_ret {
|
if has_ret {
|
||||||
let results = fb.inst_results(call_inst).to_vec();
|
let results = fb.inst_results(call_inst).to_vec();
|
||||||
@ -1235,8 +1369,18 @@ impl IRBuilder for ObjectBuilder {
|
|||||||
use cranelift_codegen::ir::{AbiParam, Signature, types}; use cranelift_frontend::FunctionBuilder; use cranelift_module::{Linkage, Module};
|
use cranelift_codegen::ir::{AbiParam, Signature, types}; use cranelift_frontend::FunctionBuilder; use cranelift_module::{Linkage, Module};
|
||||||
let mut arg_vals: Vec<cranelift_codegen::ir::Value> = Vec::new(); let take_n = argc.min(self.value_stack.len()); for _ in 0..take_n { if let Some(v) = self.value_stack.pop() { arg_vals.push(v); } } arg_vals.reverse();
|
let mut arg_vals: Vec<cranelift_codegen::ir::Value> = Vec::new(); let take_n = argc.min(self.value_stack.len()); for _ in 0..take_n { if let Some(v) = self.value_stack.pop() { arg_vals.push(v); } } arg_vals.reverse();
|
||||||
while arg_vals.len() < 3 { let mut fb = FunctionBuilder::new(&mut self.ctx.func, &mut self.fbc); if let Some(idx) = self.current_block_index { fb.switch_to_block(self.blocks[idx]); } else if let Some(b) = self.entry_block { fb.switch_to_block(b); } let z = fb.ins().iconst(types::I64, 0); fb.finalize(); arg_vals.push(z); }
|
while arg_vals.len() < 3 { let mut fb = FunctionBuilder::new(&mut self.ctx.func, &mut self.fbc); if let Some(idx) = self.current_block_index { fb.switch_to_block(self.blocks[idx]); } else if let Some(b) = self.entry_block { fb.switch_to_block(b); } let z = fb.ins().iconst(types::I64, 0); fb.finalize(); arg_vals.push(z); }
|
||||||
let call_conv = self.module.isa().default_call_conv(); let mut sig = Signature::new(call_conv); for _ in 0..6 { sig.params.push(AbiParam::new(types::I64)); } if has_ret { sig.returns.push(AbiParam::new(types::I64)); }
|
// Choose f64 or i64 shim based on env allowlist: NYASH_JIT_PLUGIN_F64="type:method,type:method"
|
||||||
let symbol = "nyash_plugin_invoke3_i64"; let func_id = self.module.declare_function(symbol, Linkage::Import, &sig).expect("declare plugin shim");
|
let use_f64 = if has_ret {
|
||||||
|
if let Ok(list) = std::env::var("NYASH_JIT_PLUGIN_F64") {
|
||||||
|
list.split(',').any(|e| {
|
||||||
|
let mut it = e.split(':');
|
||||||
|
match (it.next(), it.next()) { (Some(t), Some(m)) => t.parse::<u32>().ok()==Some(type_id) && m.parse::<u32>().ok()==Some(method_id), _ => false }
|
||||||
|
})
|
||||||
|
} else { false }
|
||||||
|
} else { false };
|
||||||
|
let call_conv = self.module.isa().default_call_conv(); let mut sig = Signature::new(call_conv); for _ in 0..6 { sig.params.push(AbiParam::new(types::I64)); } if has_ret { if use_f64 { sig.returns.push(AbiParam::new(types::F64)); } else { sig.returns.push(AbiParam::new(types::I64)); } }
|
||||||
|
let symbol = if use_f64 { "nyash_plugin_invoke3_f64" } else { "nyash_plugin_invoke3_i64" };
|
||||||
|
let func_id = self.module.declare_function(symbol, Linkage::Import, &sig).expect("declare plugin shim");
|
||||||
let mut fb = FunctionBuilder::new(&mut self.ctx.func, &mut self.fbc); if let Some(idx) = self.current_block_index { fb.switch_to_block(self.blocks[idx]); } else if let Some(b) = self.entry_block { fb.switch_to_block(b); }
|
let mut fb = FunctionBuilder::new(&mut self.ctx.func, &mut self.fbc); if let Some(idx) = self.current_block_index { fb.switch_to_block(self.blocks[idx]); } else if let Some(b) = self.entry_block { fb.switch_to_block(b); }
|
||||||
let fref = self.module.declare_func_in_func(func_id, fb.func);
|
let fref = self.module.declare_func_in_func(func_id, fb.func);
|
||||||
let c_type = fb.ins().iconst(types::I64, type_id as i64); let c_meth = fb.ins().iconst(types::I64, method_id as i64); let c_argc = fb.ins().iconst(types::I64, argc as i64);
|
let c_type = fb.ins().iconst(types::I64, type_id as i64); let c_meth = fb.ins().iconst(types::I64, method_id as i64); let c_argc = fb.ins().iconst(types::I64, argc as i64);
|
||||||
|
|||||||
@ -472,7 +472,8 @@ impl LowerCore {
|
|||||||
| I::Store { .. }
|
| I::Store { .. }
|
||||||
| I::Load { .. }
|
| I::Load { .. }
|
||||||
| I::Phi { .. }
|
| I::Phi { .. }
|
||||||
| I::Print { .. }
|
// PrintはJIT経路では未対応(VMにフォールバックしてコンソール出力を保持)
|
||||||
|
// | I::Print { .. }
|
||||||
| I::Debug { .. }
|
| I::Debug { .. }
|
||||||
| I::ExternCall { .. }
|
| I::ExternCall { .. }
|
||||||
| I::Safepoint
|
| I::Safepoint
|
||||||
@ -492,13 +493,18 @@ impl LowerCore {
|
|||||||
"StringBox" => {
|
"StringBox" => {
|
||||||
// Emit host-call to create a new StringBox handle; push as i64
|
// Emit host-call to create a new StringBox handle; push as i64
|
||||||
b.emit_host_call(crate::jit::r#extern::collections::SYM_STRING_BIRTH_H, 0, true);
|
b.emit_host_call(crate::jit::r#extern::collections::SYM_STRING_BIRTH_H, 0, true);
|
||||||
// Do not attempt to classify; downstream ops will treat as handle
|
|
||||||
}
|
}
|
||||||
"IntegerBox" => {
|
"IntegerBox" => {
|
||||||
b.emit_host_call(crate::jit::r#extern::collections::SYM_INTEGER_BIRTH_H, 0, true);
|
b.emit_host_call(crate::jit::r#extern::collections::SYM_INTEGER_BIRTH_H, 0, true);
|
||||||
}
|
}
|
||||||
_ => { /* Other boxes: no-op for now */ }
|
_ => {
|
||||||
|
// Any other NewBox (e.g., ArrayBox/MapBox/etc.) is UNSUPPORTED in JIT for now
|
||||||
|
self.unsupported += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// NewBox with args or NYASH_USE_PLUGIN_BUILTINS!=1 → unsupported in JIT
|
||||||
|
self.unsupported += 1;
|
||||||
}
|
}
|
||||||
// Track boxed numeric literals to aid signature checks (FloatBox/IntegerBox)
|
// Track boxed numeric literals to aid signature checks (FloatBox/IntegerBox)
|
||||||
if box_type == "FloatBox" {
|
if box_type == "FloatBox" {
|
||||||
|
|||||||
@ -11,3 +11,4 @@ pub mod policy;
|
|||||||
pub mod events;
|
pub mod events;
|
||||||
pub mod hostcall_registry;
|
pub mod hostcall_registry;
|
||||||
pub mod boundary;
|
pub mod boundary;
|
||||||
|
pub mod shim_trace;
|
||||||
|
|||||||
39
src/jit/shim_trace.rs
Normal file
39
src/jit/shim_trace.rs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
use once_cell::sync::Lazy;
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
|
static TRACE_ENABLED: AtomicBool = AtomicBool::new(false);
|
||||||
|
static EVENTS: Lazy<Mutex<VecDeque<String>>> = Lazy::new(|| Mutex::new(VecDeque::with_capacity(256)));
|
||||||
|
const MAX_EVENTS: usize = 256;
|
||||||
|
|
||||||
|
pub fn set_enabled(on: bool) { TRACE_ENABLED.store(on, Ordering::Relaxed); }
|
||||||
|
|
||||||
|
pub fn is_enabled() -> bool {
|
||||||
|
if TRACE_ENABLED.load(Ordering::Relaxed) { return true; }
|
||||||
|
std::env::var("NYASH_JIT_SHIM_TRACE").ok().as_deref() == Some("1")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(event: String) {
|
||||||
|
if !is_enabled() { return; }
|
||||||
|
if let Ok(mut q) = EVENTS.lock() {
|
||||||
|
if q.len() >= MAX_EVENTS { q.pop_front(); }
|
||||||
|
q.push_back(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn snapshot_joined() -> String {
|
||||||
|
if let Ok(q) = EVENTS.lock() {
|
||||||
|
let mut out = String::new();
|
||||||
|
for (i, e) in q.iter().enumerate() {
|
||||||
|
if i > 0 { out.push('\n'); }
|
||||||
|
out.push_str(e);
|
||||||
|
}
|
||||||
|
out
|
||||||
|
} else { String::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear() {
|
||||||
|
if let Ok(mut q) = EVENTS.lock() { q.clear(); }
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user