feat: MIR builder TypeOp lowering for is/as methods and isType/asType functions
- Add early TypeOp lowering in build_expression for method-style is()/as() - Add early TypeOp lowering in build_expression for function-style isType()/asType() - Add special handling in build_print_statement for print(isType/asType(...)) - Fix MIR optimizer borrow checker issues and remove obsolete BoxFieldLoad - Extract string literal helper supports both direct literals and StringBox wrappers - Note: isType call generation still has issues (undefined SSA value in print) 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -36,26 +36,26 @@
|
|||||||
|
|
||||||
## 🚧 次にやること(再開方針)
|
## 🚧 次にやること(再開方針)
|
||||||
|
|
||||||
1) 命令セットダイエットのPoC実装(短期)
|
1) MIR26 前進(短期)
|
||||||
- 現状: VMに `TypeOp/WeakRef/Barrier` 実行経路(等価)とPrinter対応。Builderに補助APIを追加済(未置換)。
|
- プリンタ拡張: `TypeOp/WeakRef/Barrier` を `--mir-verbose` に明示表示
|
||||||
- 次: Builder内の該当箇所を補助APIに置換(flag onで新命令を吐く/offで従来どおり)
|
- スナップショット整備: 代表ケースで flag ON/OFF のMIR差分固定化
|
||||||
|
- vm-stats差分: `weak_field_poc.nyash` 等で JSON 取得・比較(キー: TypeOp/WeakRef/Barrier)
|
||||||
- 旗: `mir_typeop_poc`(TypeCheck/Cast→TypeOp)、`mir_refbarrier_unify_poc`(Weak*/Barrier→統合)
|
- 旗: `mir_typeop_poc`(TypeCheck/Cast→TypeOp)、`mir_refbarrier_unify_poc`(Weak*/Barrier→統合)
|
||||||
- 成果物: スナップショット(flag on/off)+ vm-statsのキー確認(TypeOp/WeakRef/Barrier)
|
|
||||||
|
|
||||||
2) VM×プラグインのE2E拡張(短期)
|
2) Builder適用拡大(短期〜中期)
|
||||||
- HTTP: 遅延応答・大ボディの計測、到達不能時のERR安定化の再検証(代表は追加済)
|
- 言語 `is/as` 導線(最小でも擬似ノード)→ `emit_type_check/emit_cast` へ配線
|
||||||
- Socket: 反復タイムアウトの追加ケース(代表は追加済)
|
- 弱参照: 既存の `RefGet/RefSet` パスは弱フィールドで `WeakLoad/WeakNew`+Barrier(flag ONで統合命令)
|
||||||
- 成果物: 必要に応じてE2E追補と `VM_README.md` のTips更新
|
|
||||||
|
|
||||||
3) ResultBox単一路線への統合(中期)
|
3) VM/Verifierの補強(中期)
|
||||||
- 新`NyashResultBox`へ統合、旧`ResultBox`は薄いラッパーとして段階移行
|
- `TypeOp(Cast)` の数値キャスト(Int/Float)安全化、誤用時TypeError整備
|
||||||
- 成果物: 実装整理・移行メモ・影響調査
|
- Verifierに26命令整合(Barrier位置、WeakRef整合、支配関係)チェックを追加
|
||||||
|
|
||||||
4) Array系の本実装(必要時・中期)
|
4) VM×プラグインE2Eの維持(短期)
|
||||||
- VMの `ArrayGet/ArraySet` 実装済み。BoxCall fast-pathの整合性と回帰テストを充実
|
- HTTP/Socketの回帰確認(Void防御・遅延サーバ軽量化は済)
|
||||||
|
- 必要に応じて `VM_README.md` にTips追記
|
||||||
|
|
||||||
5) BoxCall高速化(性能段階)
|
5) BoxCall高速化(性能段階)
|
||||||
- vm-statsでホットなBoxCallの高速化(命令セット統合より効果大の可能性)
|
- `--vm-stats` ホットパス特定後、Fast-path/キャッシュ適用
|
||||||
|
|
||||||
## ▶ 実行コマンド例
|
## ▶ 実行コマンド例
|
||||||
|
|
||||||
@ -73,6 +73,21 @@ cargo test -q --features plugins e2e_interpreter_plugin_filebox_close_void
|
|||||||
cargo test -q --features plugins e2e_vm_plugin_filebox_close_void
|
cargo test -q --features plugins e2e_vm_plugin_filebox_close_void
|
||||||
```
|
```
|
||||||
|
|
||||||
|
MIR26 PoC(弱参照・Barrier統合):
|
||||||
|
```bash
|
||||||
|
# 弱フィールドPoC(flag OFF: WeakNew/WeakLoad/BarrierRead/Write)
|
||||||
|
NYASH_VM_STATS=1 NYASH_VM_STATS_JSON=1 ./target/release/nyash --backend vm --vm-stats --vm-stats-json local_tests/weak_field_poc.nyash > vm_stats_weak_default.json
|
||||||
|
|
||||||
|
# flag ON: WeakRef/Barrier 統合
|
||||||
|
cargo build --release --features mir_refbarrier_unify_poc -q
|
||||||
|
NYASH_VM_STATS=1 NYASH_VM_STATS_JSON=1 ./target/release/nyash --backend vm --vm-stats --vm-stats-json local_tests/weak_field_poc.nyash > vm_stats_weak_unified.json
|
||||||
|
```
|
||||||
|
|
||||||
|
MIRダンプ(プリンタ拡張後の確認):
|
||||||
|
```bash
|
||||||
|
./target/release/nyash --dump-mir --mir-verbose local_tests/weak_field_poc.nyash | sed -n '1,200p'
|
||||||
|
```
|
||||||
|
|
||||||
MIRダンプ/検証:
|
MIRダンプ/検証:
|
||||||
```bash
|
```bash
|
||||||
nyash --dump-mir --mir-verbose examples/plugin_box_sample.nyash
|
nyash --dump-mir --mir-verbose examples/plugin_box_sample.nyash
|
||||||
@ -84,7 +99,7 @@ nyash --verify examples/plugin_box_sample.nyash
|
|||||||
- メタ降格: Debug / Nop / Safepoint(ビルドモードで制御)
|
- メタ降格: Debug / Nop / Safepoint(ビルドモードで制御)
|
||||||
|
|
||||||
---
|
---
|
||||||
最終更新: 2025年8月23日(VM強化・E2E拡張・me参照安定化・TypeOp/WeakRef/Barrier PoC完了/次段はBuilder置換とスナップショット)
|
最終更新: 2025年8月23日(VM強化・E2E拡張・me参照安定化・TypeOp/WeakRef/Barrier PoC完了/次段はプリンタ拡張・スナップショット・is/as導線)
|
||||||
|
|
||||||
## 🔁 再起動後の再開手順(ショート)
|
## 🔁 再起動後の再開手順(ショート)
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
Submodule nekocode-temp updated: 509c8b7de8...9e0879ba14
@ -12,6 +12,26 @@ impl NyashInterpreter {
|
|||||||
/// 関数呼び出しを実行 - 🌍 革命的実装:GlobalBoxのメソッド呼び出し
|
/// 関数呼び出しを実行 - 🌍 革命的実装:GlobalBoxのメソッド呼び出し
|
||||||
pub(super) fn execute_function_call(&mut self, name: &str, arguments: &[ASTNode])
|
pub(super) fn execute_function_call(&mut self, name: &str, arguments: &[ASTNode])
|
||||||
-> Result<Box<dyn NyashBox>, RuntimeError> {
|
-> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||||
|
// Fallback: built-in type ops as global functions: isType(value, "Type"), asType(value, "Type")
|
||||||
|
if (name == "isType" || name == "asType") && arguments.len() == 2 {
|
||||||
|
// Evaluate args
|
||||||
|
let val = self.execute_expression(&arguments[0])?;
|
||||||
|
let ty_box = self.execute_expression(&arguments[1])?;
|
||||||
|
// Get type name string
|
||||||
|
let type_name = if let Some(s) = ty_box.as_any().downcast_ref::<crate::box_trait::StringBox>() {
|
||||||
|
s.value.clone()
|
||||||
|
} else {
|
||||||
|
return Err(RuntimeError::InvalidOperation { message: "Type name must be a string".to_string() });
|
||||||
|
};
|
||||||
|
|
||||||
|
if name == "isType" {
|
||||||
|
let matched = Self::matches_type_name(&val, &type_name);
|
||||||
|
return Ok(Box::new(crate::box_trait::BoolBox::new(matched)));
|
||||||
|
} else {
|
||||||
|
// asType: minimal safe cast (int<->float), otherwise identity
|
||||||
|
return Self::cast_to_type(val, &type_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
// コンストラクタ内での親コンストラクタ呼び出しチェック
|
// コンストラクタ内での親コンストラクタ呼び出しチェック
|
||||||
if let Some(context) = self.current_constructor_context.clone() {
|
if let Some(context) = self.current_constructor_context.clone() {
|
||||||
if let Some(parent_class) = context.parent_class {
|
if let Some(parent_class) = context.parent_class {
|
||||||
@ -94,4 +114,43 @@ impl NyashInterpreter {
|
|||||||
eprintln!("Warning: Failed to register global function: {}", err);
|
eprintln!("Warning: Failed to register global function: {}", err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper: match a NyashBox value against a simple type name
|
||||||
|
fn matches_type_name(val: &Box<dyn NyashBox>, type_name: &str) -> bool {
|
||||||
|
let tn = val.type_name();
|
||||||
|
match type_name {
|
||||||
|
"Integer" | "Int" | "I64" => tn == "IntegerBox",
|
||||||
|
"Float" | "F64" => tn == "FloatBox",
|
||||||
|
"Bool" | "Boolean" => tn == "BoolBox",
|
||||||
|
"String" => tn == "StringBox",
|
||||||
|
"Void" | "Unit" => tn == "VoidBox",
|
||||||
|
other => tn == other || tn == format!("{}Box", other),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper: cast box to a target type name (minimal support)
|
||||||
|
fn cast_to_type(val: Box<dyn NyashBox>, type_name: &str) -> Result<Box<dyn NyashBox>, RuntimeError> {
|
||||||
|
match type_name {
|
||||||
|
"Integer" | "Int" | "I64" => {
|
||||||
|
// Float -> Integer (truncate), Integer -> Integer, else error
|
||||||
|
if let Some(i) = val.as_any().downcast_ref::<crate::box_trait::IntegerBox>() {
|
||||||
|
Ok(Box::new(crate::box_trait::IntegerBox::new(i.value)))
|
||||||
|
} else if let Some(f) = val.as_any().downcast_ref::<crate::boxes::FloatBox>() {
|
||||||
|
Ok(Box::new(crate::box_trait::IntegerBox::new(f.value as i64)))
|
||||||
|
} else {
|
||||||
|
Ok(val) // identity fallback for now
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"Float" | "F64" => {
|
||||||
|
if let Some(f) = val.as_any().downcast_ref::<crate::boxes::FloatBox>() {
|
||||||
|
Ok(Box::new(crate::boxes::FloatBox::new(f.value)))
|
||||||
|
} else if let Some(i) = val.as_any().downcast_ref::<crate::box_trait::IntegerBox>() {
|
||||||
|
Ok(Box::new(crate::boxes::FloatBox::new(i.value as f64)))
|
||||||
|
} else {
|
||||||
|
Ok(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Ok(val),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -46,6 +46,22 @@ impl NyashInterpreter {
|
|||||||
|
|
||||||
// オブジェクトを評価(通常のメソッド呼び出し)
|
// オブジェクトを評価(通常のメソッド呼び出し)
|
||||||
let obj_value = self.execute_expression(object)?;
|
let obj_value = self.execute_expression(object)?;
|
||||||
|
|
||||||
|
// Fallback: built-in type ops as instance methods: value.is("Type"), value.as("Type")
|
||||||
|
if (method == "is" || method == "as") && arguments.len() == 1 {
|
||||||
|
let ty_box = self.execute_expression(&arguments[0])?;
|
||||||
|
let type_name = if let Some(s) = ty_box.as_any().downcast_ref::<crate::box_trait::StringBox>() {
|
||||||
|
s.value.clone()
|
||||||
|
} else {
|
||||||
|
return Err(RuntimeError::InvalidOperation { message: "Type name must be a string".to_string() });
|
||||||
|
};
|
||||||
|
if method == "is" {
|
||||||
|
let matched = super::functions::NyashInterpreter::matches_type_name(&obj_value, &type_name);
|
||||||
|
return Ok(Box::new(crate::box_trait::BoolBox::new(matched)));
|
||||||
|
} else {
|
||||||
|
return super::functions::NyashInterpreter::cast_to_type(obj_value, &type_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
eprintln!("🔍 DEBUG: execute_method_call - object evaluated to type_name='{}', box_id={}",
|
eprintln!("🔍 DEBUG: execute_method_call - object evaluated to type_name='{}', box_id={}",
|
||||||
obj_value.type_name(), obj_value.box_id());
|
obj_value.type_name(), obj_value.box_id());
|
||||||
|
|||||||
@ -43,6 +43,12 @@ pub struct MirBuilder {
|
|||||||
|
|
||||||
/// Names of user-defined boxes declared in the current module
|
/// Names of user-defined boxes declared in the current module
|
||||||
pub(super) user_defined_boxes: HashSet<String>,
|
pub(super) user_defined_boxes: HashSet<String>,
|
||||||
|
|
||||||
|
/// Weak field registry: BoxName -> {weak field names}
|
||||||
|
pub(super) weak_fields_by_box: HashMap<String, HashSet<String>>,
|
||||||
|
|
||||||
|
/// Remember class of object fields after assignments: (base_id, field) -> class_name
|
||||||
|
pub(super) field_origin_class: HashMap<(ValueId, String), String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MirBuilder {
|
impl MirBuilder {
|
||||||
@ -58,6 +64,8 @@ impl MirBuilder {
|
|||||||
pending_phis: Vec::new(),
|
pending_phis: Vec::new(),
|
||||||
value_origin_newbox: HashMap::new(),
|
value_origin_newbox: HashMap::new(),
|
||||||
user_defined_boxes: HashSet::new(),
|
user_defined_boxes: HashSet::new(),
|
||||||
|
weak_fields_by_box: HashMap::new(),
|
||||||
|
field_origin_class: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,6 +211,8 @@ impl MirBuilder {
|
|||||||
let me_id = self.value_gen.next();
|
let me_id = self.value_gen.next();
|
||||||
f.params.push(me_id);
|
f.params.push(me_id);
|
||||||
self.variable_map.insert("me".to_string(), me_id);
|
self.variable_map.insert("me".to_string(), me_id);
|
||||||
|
// Record origin: 'me' belongs to this box type (enables weak field wiring)
|
||||||
|
self.value_origin_newbox.insert(me_id, box_name.clone());
|
||||||
// user parameters continue as %1..N
|
// user parameters continue as %1..N
|
||||||
for p in ¶ms {
|
for p in ¶ms {
|
||||||
let pid = self.value_gen.next();
|
let pid = self.value_gen.next();
|
||||||
@ -318,6 +328,17 @@ impl MirBuilder {
|
|||||||
},
|
},
|
||||||
|
|
||||||
ASTNode::MethodCall { object, method, arguments, .. } => {
|
ASTNode::MethodCall { object, method, arguments, .. } => {
|
||||||
|
// Early TypeOp lowering for method-style is()/as()
|
||||||
|
if (method == "is" || method == "as") && arguments.len() == 1 {
|
||||||
|
if let Some(type_name) = Self::extract_string_literal(&arguments[0]) {
|
||||||
|
let obj_val = self.build_expression(*object.clone())?;
|
||||||
|
let ty = Self::parse_type_name_to_mir(&type_name);
|
||||||
|
let dst = self.value_gen.next();
|
||||||
|
let op = if method == "is" { super::TypeOpKind::Check } else { super::TypeOpKind::Cast };
|
||||||
|
self.emit_instruction(MirInstruction::TypeOp { dst, op, value: obj_val, ty })?;
|
||||||
|
return Ok(dst);
|
||||||
|
}
|
||||||
|
}
|
||||||
self.build_method_call(*object.clone(), method.clone(), arguments.clone())
|
self.build_method_call(*object.clone(), method.clone(), arguments.clone())
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -338,6 +359,17 @@ impl MirBuilder {
|
|||||||
},
|
},
|
||||||
|
|
||||||
ASTNode::FunctionCall { name, arguments, .. } => {
|
ASTNode::FunctionCall { name, arguments, .. } => {
|
||||||
|
// Early TypeOp lowering for function-style isType()/asType()
|
||||||
|
if (name == "isType" || name == "asType") && arguments.len() == 2 {
|
||||||
|
if let Some(type_name) = Self::extract_string_literal(&arguments[1]) {
|
||||||
|
let val = self.build_expression(arguments[0].clone())?;
|
||||||
|
let ty = Self::parse_type_name_to_mir(&type_name);
|
||||||
|
let dst = self.value_gen.next();
|
||||||
|
let op = if name == "isType" { super::TypeOpKind::Check } else { super::TypeOpKind::Cast };
|
||||||
|
self.emit_instruction(MirInstruction::TypeOp { dst, op, value: val, ty })?;
|
||||||
|
return Ok(dst);
|
||||||
|
}
|
||||||
|
}
|
||||||
self.build_function_call(name.clone(), arguments.clone())
|
self.build_function_call(name.clone(), arguments.clone())
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -389,14 +421,14 @@ impl MirBuilder {
|
|||||||
self.build_local_statement(variables.clone(), initial_values.clone())
|
self.build_local_statement(variables.clone(), initial_values.clone())
|
||||||
},
|
},
|
||||||
|
|
||||||
ASTNode::BoxDeclaration { name, methods, is_static, fields, constructors, .. } => {
|
ASTNode::BoxDeclaration { name, methods, is_static, fields, constructors, weak_fields, .. } => {
|
||||||
if is_static && name == "Main" {
|
if is_static && name == "Main" {
|
||||||
self.build_static_main_box(methods.clone())
|
self.build_static_main_box(methods.clone())
|
||||||
} else {
|
} else {
|
||||||
// Support user-defined boxes - handle as statement, return void
|
// Support user-defined boxes - handle as statement, return void
|
||||||
// Track as user-defined (eligible for method lowering)
|
// Track as user-defined (eligible for method lowering)
|
||||||
self.user_defined_boxes.insert(name.clone());
|
self.user_defined_boxes.insert(name.clone());
|
||||||
self.build_box_declaration(name.clone(), methods.clone(), fields.clone())?;
|
self.build_box_declaration(name.clone(), methods.clone(), fields.clone(), weak_fields.clone())?;
|
||||||
|
|
||||||
// Phase 2: Lower constructors (birth/N) into MIR functions
|
// Phase 2: Lower constructors (birth/N) into MIR functions
|
||||||
// Function name pattern: "{BoxName}.{constructor_key}" (e.g., "Person.birth/1")
|
// Function name pattern: "{BoxName}.{constructor_key}" (e.g., "Person.birth/1")
|
||||||
@ -535,6 +567,17 @@ impl MirBuilder {
|
|||||||
|
|
||||||
/// Build function call
|
/// Build function call
|
||||||
fn build_function_call(&mut self, name: String, args: Vec<ASTNode>) -> Result<ValueId, String> {
|
fn build_function_call(&mut self, name: String, args: Vec<ASTNode>) -> Result<ValueId, String> {
|
||||||
|
// Minimal TypeOp wiring via function-style: isType(value, "Type"), asType(value, "Type")
|
||||||
|
if (name == "isType" || name == "asType") && args.len() == 2 {
|
||||||
|
if let Some(type_name) = Self::extract_string_literal(&args[1]) {
|
||||||
|
let val = self.build_expression(args[0].clone())?;
|
||||||
|
let ty = Self::parse_type_name_to_mir(&type_name);
|
||||||
|
let dst = self.value_gen.next();
|
||||||
|
let op = if name == "isType" { super::TypeOpKind::Check } else { super::TypeOpKind::Cast };
|
||||||
|
self.emit_instruction(MirInstruction::TypeOp { dst, op, value: val, ty })?;
|
||||||
|
return Ok(dst);
|
||||||
|
}
|
||||||
|
}
|
||||||
// Build argument values
|
// Build argument values
|
||||||
let mut arg_values = Vec::new();
|
let mut arg_values = Vec::new();
|
||||||
for arg in args {
|
for arg in args {
|
||||||
@ -563,6 +606,24 @@ impl MirBuilder {
|
|||||||
|
|
||||||
/// Build print statement - converts to console output
|
/// Build print statement - converts to console output
|
||||||
fn build_print_statement(&mut self, expression: ASTNode) -> Result<ValueId, String> {
|
fn build_print_statement(&mut self, expression: ASTNode) -> Result<ValueId, String> {
|
||||||
|
// Early lowering for print(isType(...)) / print(asType(...)) to avoid undefined SSA when optimizations run
|
||||||
|
if let ASTNode::FunctionCall { name, arguments, .. } = &expression {
|
||||||
|
if (name == "isType" || name == "asType") && arguments.len() == 2 {
|
||||||
|
if let Some(type_name) = Self::extract_string_literal(&arguments[1]) {
|
||||||
|
let val = self.build_expression(arguments[0].clone())?;
|
||||||
|
let ty = Self::parse_type_name_to_mir(&type_name);
|
||||||
|
let dst = self.value_gen.next();
|
||||||
|
let op = if name == "isType" { super::TypeOpKind::Check } else { super::TypeOpKind::Cast };
|
||||||
|
self.emit_instruction(MirInstruction::TypeOp { dst, op, value: val, ty })?;
|
||||||
|
self.emit_instruction(MirInstruction::Print {
|
||||||
|
value: dst,
|
||||||
|
effects: EffectMask::PURE.add(Effect::Io),
|
||||||
|
})?;
|
||||||
|
return Ok(dst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let value = self.build_expression(expression)?;
|
let value = self.build_expression(expression)?;
|
||||||
|
|
||||||
// For now, use a special Print instruction (minimal scope)
|
// For now, use a special Print instruction (minimal scope)
|
||||||
@ -885,18 +946,51 @@ impl MirBuilder {
|
|||||||
|
|
||||||
/// Build field access: object.field
|
/// Build field access: object.field
|
||||||
fn build_field_access(&mut self, object: ASTNode, field: String) -> Result<ValueId, String> {
|
fn build_field_access(&mut self, object: ASTNode, field: String) -> Result<ValueId, String> {
|
||||||
|
// Clone the object before building expression if we need to check it later
|
||||||
|
let object_clone = object.clone();
|
||||||
|
|
||||||
// First, build the object expression to get its ValueId
|
// First, build the object expression to get its ValueId
|
||||||
let object_value = self.build_expression(object)?;
|
let object_value = self.build_expression(object)?;
|
||||||
|
|
||||||
// Get the field from the object using RefGet
|
// Get the field from the object using RefGet
|
||||||
let result_id = self.value_gen.next();
|
let field_val = self.value_gen.next();
|
||||||
self.emit_instruction(MirInstruction::RefGet {
|
self.emit_instruction(MirInstruction::RefGet {
|
||||||
dst: result_id,
|
dst: field_val,
|
||||||
reference: object_value,
|
reference: object_value,
|
||||||
field,
|
field: field.clone(),
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(result_id)
|
// If we recorded origin class for this field on this base object, propagate it to this value id
|
||||||
|
if let Some(class_name) = self.field_origin_class.get(&(object_value, field.clone())).cloned() {
|
||||||
|
self.value_origin_newbox.insert(field_val, class_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we can infer the box type and the field is weak, emit WeakLoad (+ optional barrier)
|
||||||
|
let mut inferred_class: Option<String> = self.value_origin_newbox.get(&object_value).cloned();
|
||||||
|
// Fallback: if the object is a nested field access like (X.Y).Z, consult recorded field origins for X.Y
|
||||||
|
if inferred_class.is_none() {
|
||||||
|
if let ASTNode::FieldAccess { object: inner_obj, field: ref parent_field, .. } = object_clone {
|
||||||
|
// Build inner base to get a stable id and consult mapping
|
||||||
|
if let Ok(base_id) = self.build_expression(*inner_obj.clone()) {
|
||||||
|
if let Some(cls) = self.field_origin_class.get(&(base_id, parent_field.clone())) {
|
||||||
|
inferred_class = Some(cls.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(class_name) = inferred_class {
|
||||||
|
if let Some(weak_set) = self.weak_fields_by_box.get(&class_name) {
|
||||||
|
if weak_set.contains(&field) {
|
||||||
|
// Barrier (read) PoC
|
||||||
|
let _ = self.emit_barrier_read(field_val);
|
||||||
|
// WeakLoad
|
||||||
|
let loaded = self.emit_weak_load(field_val)?;
|
||||||
|
return Ok(loaded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(field_val)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build new expression: new ClassName(arguments)
|
/// Build new expression: new ClassName(arguments)
|
||||||
@ -941,15 +1035,38 @@ impl MirBuilder {
|
|||||||
fn build_field_assignment(&mut self, object: ASTNode, field: String, value: ASTNode) -> Result<ValueId, String> {
|
fn build_field_assignment(&mut self, object: ASTNode, field: String, value: ASTNode) -> Result<ValueId, String> {
|
||||||
// Build the object and value expressions
|
// Build the object and value expressions
|
||||||
let object_value = self.build_expression(object)?;
|
let object_value = self.build_expression(object)?;
|
||||||
let value_result = self.build_expression(value)?;
|
let mut value_result = self.build_expression(value)?;
|
||||||
|
|
||||||
|
// If we can infer the box type and the field is weak, create WeakRef before store
|
||||||
|
if let Some(class_name) = self.value_origin_newbox.get(&object_value).cloned() {
|
||||||
|
if let Some(weak_set) = self.weak_fields_by_box.get(&class_name) {
|
||||||
|
if weak_set.contains(&field) {
|
||||||
|
value_result = self.emit_weak_new(value_result)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Set the field using RefSet
|
// Set the field using RefSet
|
||||||
self.emit_instruction(MirInstruction::RefSet {
|
self.emit_instruction(MirInstruction::RefSet {
|
||||||
reference: object_value,
|
reference: object_value,
|
||||||
field,
|
field: field.clone(),
|
||||||
value: value_result,
|
value: value_result,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
// Emit a write barrier for weak fields (PoC)
|
||||||
|
if let Some(class_name) = self.value_origin_newbox.get(&object_value).cloned() {
|
||||||
|
if let Some(weak_set) = self.weak_fields_by_box.get(&class_name) {
|
||||||
|
if weak_set.contains(&field) {
|
||||||
|
let _ = self.emit_barrier_write(value_result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Record origin class for this field (if the value originates from NewBox of a known class)
|
||||||
|
if let Some(class_name) = self.value_origin_newbox.get(&value_result).cloned() {
|
||||||
|
self.field_origin_class.insert((object_value, field.clone()), class_name);
|
||||||
|
}
|
||||||
|
|
||||||
// Return the assigned value
|
// Return the assigned value
|
||||||
Ok(value_result)
|
Ok(value_result)
|
||||||
}
|
}
|
||||||
@ -1059,6 +1176,19 @@ impl MirBuilder {
|
|||||||
|
|
||||||
/// Build method call: object.method(arguments)
|
/// Build method call: object.method(arguments)
|
||||||
fn build_method_call(&mut self, object: ASTNode, method: String, arguments: Vec<ASTNode>) -> Result<ValueId, String> {
|
fn build_method_call(&mut self, object: ASTNode, method: String, arguments: Vec<ASTNode>) -> Result<ValueId, String> {
|
||||||
|
// Minimal TypeOp wiring via method-style syntax: value.is("Type") / value.as("Type")
|
||||||
|
if (method == "is" || method == "as") && arguments.len() == 1 {
|
||||||
|
if let ASTNode::Literal { value: crate::ast::LiteralValue::String(type_name), .. } = &arguments[0] {
|
||||||
|
// Build the object expression
|
||||||
|
let object_value = self.build_expression(object.clone())?;
|
||||||
|
// Map string to MIR type
|
||||||
|
let mir_ty = Self::parse_type_name_to_mir(type_name);
|
||||||
|
let dst = self.value_gen.next();
|
||||||
|
let op = if method == "is" { super::TypeOpKind::Check } else { super::TypeOpKind::Cast };
|
||||||
|
self.emit_instruction(MirInstruction::TypeOp { dst, op, value: object_value, ty: mir_ty })?;
|
||||||
|
return Ok(dst);
|
||||||
|
}
|
||||||
|
}
|
||||||
// ExternCall判定はobjectの変数解決より先に行う(未定義変数で落とさない)
|
// ExternCall判定はobjectの変数解決より先に行う(未定義変数で落とさない)
|
||||||
if let ASTNode::Variable { name: object_name, .. } = object.clone() {
|
if let ASTNode::Variable { name: object_name, .. } = object.clone() {
|
||||||
// Build argument expressions first (externはobject自体を使わない)
|
// Build argument expressions first (externはobject自体を使わない)
|
||||||
@ -1098,6 +1228,17 @@ impl MirBuilder {
|
|||||||
// Build the object expression
|
// Build the object expression
|
||||||
let object_value = self.build_expression(object.clone())?;
|
let object_value = self.build_expression(object.clone())?;
|
||||||
|
|
||||||
|
// Secondary interception for is/as in case early path did not trigger
|
||||||
|
if (method == "is" || method == "as") && arguments.len() == 1 {
|
||||||
|
if let ASTNode::Literal { value: crate::ast::LiteralValue::String(type_name), .. } = &arguments[0] {
|
||||||
|
let mir_ty = Self::parse_type_name_to_mir(type_name);
|
||||||
|
let dst = self.value_gen.next();
|
||||||
|
let op = if method == "is" { super::TypeOpKind::Check } else { super::TypeOpKind::Cast };
|
||||||
|
self.emit_instruction(MirInstruction::TypeOp { dst, op, value: object_value, ty: mir_ty })?;
|
||||||
|
return Ok(dst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Build argument expressions
|
// Build argument expressions
|
||||||
let mut arg_values = Vec::new();
|
let mut arg_values = Vec::new();
|
||||||
for arg in &arguments {
|
for arg in &arguments {
|
||||||
@ -1161,6 +1302,35 @@ impl MirBuilder {
|
|||||||
})?;
|
})?;
|
||||||
Ok(result_id)
|
Ok(result_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Map a user-facing type name to MIR type
|
||||||
|
fn parse_type_name_to_mir(name: &str) -> super::MirType {
|
||||||
|
match name {
|
||||||
|
"Integer" | "Int" | "I64" => super::MirType::Integer,
|
||||||
|
"Float" | "F64" => super::MirType::Float,
|
||||||
|
"Bool" | "Boolean" => super::MirType::Bool,
|
||||||
|
"String" => super::MirType::String,
|
||||||
|
"Void" | "Unit" => super::MirType::Void,
|
||||||
|
other => super::MirType::Box(other.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extract string literal from AST node if possible
|
||||||
|
/// Supports: Literal("Type") and new StringBox("Type")
|
||||||
|
fn extract_string_literal(node: &ASTNode) -> Option<String> {
|
||||||
|
match node {
|
||||||
|
ASTNode::Literal { value: crate::ast::LiteralValue::String(s), .. } => Some(s.clone()),
|
||||||
|
ASTNode::New { class, arguments, .. } if class == "StringBox" => {
|
||||||
|
if arguments.len() == 1 {
|
||||||
|
if let ASTNode::Literal { value: crate::ast::LiteralValue::String(s), .. } = &arguments[0] {
|
||||||
|
return Some(s.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Build from expression: from Parent.method(arguments)
|
/// Build from expression: from Parent.method(arguments)
|
||||||
fn build_from_expression(&mut self, parent: String, method: String, arguments: Vec<ASTNode>) -> Result<ValueId, String> {
|
fn build_from_expression(&mut self, parent: String, method: String, arguments: Vec<ASTNode>) -> Result<ValueId, String> {
|
||||||
@ -1193,7 +1363,7 @@ impl MirBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Build box declaration: box Name { fields... methods... }
|
/// Build box declaration: box Name { fields... methods... }
|
||||||
fn build_box_declaration(&mut self, name: String, methods: std::collections::HashMap<String, ASTNode>, fields: Vec<String>) -> Result<(), String> {
|
fn build_box_declaration(&mut self, name: String, methods: std::collections::HashMap<String, ASTNode>, fields: Vec<String>, weak_fields: Vec<String>) -> Result<(), String> {
|
||||||
// For Phase 8.4, we'll emit metadata instructions to register the box type
|
// For Phase 8.4, we'll emit metadata instructions to register the box type
|
||||||
// In a full implementation, this would register type information for later use
|
// In a full implementation, this would register type information for later use
|
||||||
|
|
||||||
@ -1212,6 +1382,12 @@ impl MirBuilder {
|
|||||||
value: ConstValue::String(format!("__field_{}_{}", name, field)),
|
value: ConstValue::String(format!("__field_{}_{}", name, field)),
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Record weak fields for this box
|
||||||
|
if !weak_fields.is_empty() {
|
||||||
|
let set: HashSet<String> = weak_fields.into_iter().collect();
|
||||||
|
self.weak_fields_by_box.insert(name.clone(), set);
|
||||||
|
}
|
||||||
|
|
||||||
// Process methods - now methods is a HashMap
|
// Process methods - now methods is a HashMap
|
||||||
for (method_name, method_ast) in methods {
|
for (method_name, method_ast) in methods {
|
||||||
|
|||||||
@ -16,6 +16,7 @@ pub mod ownership_verifier_simple; // Simple ownership forest verification for c
|
|||||||
pub mod printer;
|
pub mod printer;
|
||||||
pub mod value_id;
|
pub mod value_id;
|
||||||
pub mod effect;
|
pub mod effect;
|
||||||
|
pub mod optimizer;
|
||||||
|
|
||||||
// Re-export main types for easy access
|
// Re-export main types for easy access
|
||||||
pub use instruction::{MirInstruction, BinaryOp, CompareOp, UnaryOp, ConstValue, MirType, TypeOpKind, WeakRefOp, BarrierOp};
|
pub use instruction::{MirInstruction, BinaryOp, CompareOp, UnaryOp, ConstValue, MirType, TypeOpKind, WeakRefOp, BarrierOp};
|
||||||
@ -28,6 +29,7 @@ pub use ownership_verifier_simple::{OwnershipVerifier, OwnershipError, Ownership
|
|||||||
pub use printer::MirPrinter;
|
pub use printer::MirPrinter;
|
||||||
pub use value_id::{ValueId, LocalId, ValueIdGenerator};
|
pub use value_id::{ValueId, LocalId, ValueIdGenerator};
|
||||||
pub use effect::{EffectMask, Effect};
|
pub use effect::{EffectMask, Effect};
|
||||||
|
pub use optimizer::MirOptimizer;
|
||||||
|
|
||||||
/// MIR compilation result
|
/// MIR compilation result
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@ -54,7 +56,11 @@ impl MirCompiler {
|
|||||||
/// Compile AST to MIR module with verification
|
/// Compile AST to MIR module with verification
|
||||||
pub fn compile(&mut self, ast: crate::ast::ASTNode) -> Result<MirCompileResult, String> {
|
pub fn compile(&mut self, ast: crate::ast::ASTNode) -> Result<MirCompileResult, String> {
|
||||||
// Convert AST to MIR using builder
|
// Convert AST to MIR using builder
|
||||||
let module = self.builder.build_module(ast)?;
|
let mut module = self.builder.build_module(ast)?;
|
||||||
|
|
||||||
|
// Optimize (safety net lowering for is/as → TypeOp 等)
|
||||||
|
let mut optimizer = MirOptimizer::new();
|
||||||
|
let _ = optimizer.optimize_module(&mut module);
|
||||||
|
|
||||||
// Verify the generated MIR
|
// Verify the generated MIR
|
||||||
let verification_result = self.verifier.verify_module(&module);
|
let verification_result = self.verifier.verify_module(&module);
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
* - Dead code elimination
|
* - Dead code elimination
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use super::{MirModule, MirFunction, MirInstruction, ValueId, EffectMask, Effect};
|
use super::{MirModule, MirFunction, MirInstruction, ValueId, MirType, TypeOpKind};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
/// MIR optimization passes
|
/// MIR optimization passes
|
||||||
@ -50,6 +50,9 @@ impl MirOptimizer {
|
|||||||
|
|
||||||
// Pass 4: Intrinsic function optimization
|
// Pass 4: Intrinsic function optimization
|
||||||
stats.merge(self.optimize_intrinsic_calls(module));
|
stats.merge(self.optimize_intrinsic_calls(module));
|
||||||
|
|
||||||
|
// Pass 4.5: Lower well-known intrinsics (is/as → TypeOp) as a safety net
|
||||||
|
stats.merge(self.lower_type_ops(module));
|
||||||
|
|
||||||
// Pass 5: BoxField dependency optimization
|
// Pass 5: BoxField dependency optimization
|
||||||
stats.merge(self.optimize_boxfield_operations(module));
|
stats.merge(self.optimize_boxfield_operations(module));
|
||||||
@ -196,7 +199,8 @@ impl MirOptimizer {
|
|||||||
MirInstruction::Const { value, .. } => format!("const_{:?}", value),
|
MirInstruction::Const { value, .. } => format!("const_{:?}", value),
|
||||||
MirInstruction::BinOp { op, lhs, rhs, .. } => format!("binop_{:?}_{}_{}", op, lhs.as_u32(), rhs.as_u32()),
|
MirInstruction::BinOp { op, lhs, rhs, .. } => format!("binop_{:?}_{}_{}", op, lhs.as_u32(), rhs.as_u32()),
|
||||||
MirInstruction::Compare { op, lhs, rhs, .. } => format!("cmp_{:?}_{}_{}", op, lhs.as_u32(), rhs.as_u32()),
|
MirInstruction::Compare { op, lhs, rhs, .. } => format!("cmp_{:?}_{}_{}", op, lhs.as_u32(), rhs.as_u32()),
|
||||||
MirInstruction::BoxFieldLoad { box_val, field, .. } => format!("boxload_{}_{}", box_val.as_u32(), field),
|
// BoxFieldLoad removed from instruction set
|
||||||
|
// MirInstruction::BoxFieldLoad { box_val, field, .. } => format!("boxload_{}_{}", box_val.as_u32(), field),
|
||||||
MirInstruction::Call { func, args, .. } => {
|
MirInstruction::Call { func, args, .. } => {
|
||||||
let args_str = args.iter().map(|v| v.as_u32().to_string()).collect::<Vec<_>>().join(",");
|
let args_str = args.iter().map(|v| v.as_u32().to_string()).collect::<Vec<_>>().join(",");
|
||||||
format!("call_{}_{}", func.as_u32(), args_str)
|
format!("call_{}_{}", func.as_u32(), args_str)
|
||||||
@ -253,6 +257,102 @@ impl MirOptimizer {
|
|||||||
// 3. Identity elimination (e.g., x + 0 → x)
|
// 3. Identity elimination (e.g., x + 0 → x)
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Safety-net lowering: convert known is/as patterns into TypeOp when possible
|
||||||
|
fn lower_type_ops(&mut self, module: &mut MirModule) -> OptimizationStats {
|
||||||
|
let mut stats = OptimizationStats::new();
|
||||||
|
for (_name, function) in &mut module.functions {
|
||||||
|
stats.intrinsic_optimizations += self.lower_type_ops_in_function(function);
|
||||||
|
}
|
||||||
|
stats
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lower_type_ops_in_function(&mut self, function: &mut MirFunction) -> usize {
|
||||||
|
// Build a simple definition map: ValueId -> (block_id, index)
|
||||||
|
let mut def_map: std::collections::HashMap<ValueId, (super::basic_block::BasicBlockId, usize)> = std::collections::HashMap::new();
|
||||||
|
for (bb_id, block) in &function.blocks {
|
||||||
|
for (i, inst) in block.instructions.iter().enumerate() {
|
||||||
|
if let Some(dst) = inst.dst_value() {
|
||||||
|
def_map.insert(dst, (*bb_id, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(term) = &block.terminator {
|
||||||
|
if let Some(dst) = term.dst_value() {
|
||||||
|
def_map.insert(dst, (*bb_id, usize::MAX));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut lowered = 0;
|
||||||
|
|
||||||
|
// Collect replacements first to avoid borrow checker issues
|
||||||
|
let mut replacements: Vec<(super::basic_block::BasicBlockId, usize, MirInstruction)> = Vec::new();
|
||||||
|
|
||||||
|
// First pass: identify replacements
|
||||||
|
for (bb_id, block) in &function.blocks {
|
||||||
|
for i in 0..block.instructions.len() {
|
||||||
|
let replace = match &block.instructions[i] {
|
||||||
|
MirInstruction::BoxCall { dst, box_val, method, args, .. } => {
|
||||||
|
let is_is = method == "is" || method == "isType";
|
||||||
|
let is_as = method == "as" || method == "asType";
|
||||||
|
if (is_is || is_as) && args.len() == 1 {
|
||||||
|
// Try to resolve type name from arg
|
||||||
|
let arg_id = args[0];
|
||||||
|
if let Some((def_bb, def_idx)) = def_map.get(&arg_id).copied() {
|
||||||
|
// Look for pattern: NewBox StringBox(Const String)
|
||||||
|
if let Some(def_block) = function.blocks.get(&def_bb) {
|
||||||
|
if def_idx < def_block.instructions.len() {
|
||||||
|
if let MirInstruction::NewBox { box_type, args: sb_args, .. } = &def_block.instructions[def_idx] {
|
||||||
|
if box_type == "StringBox" && sb_args.len() == 1 {
|
||||||
|
let str_id = sb_args[0];
|
||||||
|
if let Some((sbb, sidx)) = def_map.get(&str_id).copied() {
|
||||||
|
if let Some(sblock) = function.blocks.get(&sbb) {
|
||||||
|
if sidx < sblock.instructions.len() {
|
||||||
|
if let MirInstruction::Const { value, .. } = &sblock.instructions[sidx] {
|
||||||
|
if let super::instruction::ConstValue::String(s) = value {
|
||||||
|
// Build TypeOp to replace
|
||||||
|
let ty = map_type_name(s);
|
||||||
|
let op = if is_is { TypeOpKind::Check } else { TypeOpKind::Cast };
|
||||||
|
let new_inst = MirInstruction::TypeOp {
|
||||||
|
dst: dst.unwrap_or(*box_val),
|
||||||
|
op,
|
||||||
|
value: *box_val,
|
||||||
|
ty,
|
||||||
|
};
|
||||||
|
Some(new_inst)
|
||||||
|
} else { None }
|
||||||
|
} else { None }
|
||||||
|
} else { None }
|
||||||
|
} else { None }
|
||||||
|
} else { None }
|
||||||
|
} else { None }
|
||||||
|
} else { None }
|
||||||
|
} else { None }
|
||||||
|
} else { None }
|
||||||
|
} else { None }
|
||||||
|
} else { None }
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(new_inst) = replace {
|
||||||
|
replacements.push((*bb_id, i, new_inst));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second pass: apply replacements
|
||||||
|
for (bb_id, idx, new_inst) in replacements {
|
||||||
|
if let Some(block) = function.blocks.get_mut(&bb_id) {
|
||||||
|
if idx < block.instructions.len() {
|
||||||
|
block.instructions[idx] = new_inst;
|
||||||
|
lowered += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lowered
|
||||||
|
}
|
||||||
|
|
||||||
/// Optimize BoxField operations
|
/// Optimize BoxField operations
|
||||||
fn optimize_boxfield_operations(&mut self, module: &mut MirModule) -> OptimizationStats {
|
fn optimize_boxfield_operations(&mut self, module: &mut MirModule) -> OptimizationStats {
|
||||||
@ -280,6 +380,18 @@ impl MirOptimizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Map string type name to MIR type (optimizer-level helper)
|
||||||
|
fn map_type_name(name: &str) -> MirType {
|
||||||
|
match name {
|
||||||
|
"Integer" | "Int" | "I64" => MirType::Integer,
|
||||||
|
"Float" | "F64" => MirType::Float,
|
||||||
|
"Bool" | "Boolean" => MirType::Bool,
|
||||||
|
"String" => MirType::String,
|
||||||
|
"Void" | "Unit" => MirType::Void,
|
||||||
|
other => MirType::Box(other.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for MirOptimizer {
|
impl Default for MirOptimizer {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new()
|
Self::new()
|
||||||
@ -377,4 +489,4 @@ mod tests {
|
|||||||
assert!(key.contains("const"));
|
assert!(key.contains("const"));
|
||||||
assert!(key.contains("42"));
|
assert!(key.contains("42"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
27
tools/vm_stats_diff.sh
Normal file
27
tools/vm_stats_diff.sh
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
if [ $# -ne 2 ]; then
|
||||||
|
echo "Usage: $0 <stats_before.json> <stats_after.json>" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
A="$1"
|
||||||
|
B="$2"
|
||||||
|
|
||||||
|
if [ ! -f "$A" ] || [ ! -f "$B" ]; then
|
||||||
|
echo "Input files not found" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Extract counts objects and join keys
|
||||||
|
KEYS=$(jq -r '.counts | keys[]' "$A" "$B" | sort -u)
|
||||||
|
|
||||||
|
printf "%-14s %8s %8s %8s\n" "OP" "A" "B" "+/-"
|
||||||
|
for k in $KEYS; do
|
||||||
|
va=$(jq -r --arg k "$k" '.counts[$k] // 0' "$A")
|
||||||
|
vb=$(jq -r --arg k "$k" '.counts[$k] // 0' "$B")
|
||||||
|
d=$(( vb - va ))
|
||||||
|
printf "%-14s %8d %8d %8d\n" "$k" "$va" "$vb" "$d"
|
||||||
|
done | sort -k1,1
|
||||||
|
|
||||||
75
vm_stats_weak_default.json
Normal file
75
vm_stats_weak_default.json
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
🔌 v2 plugin system initialized from nyash.toml
|
||||||
|
✅ v2 plugin system fully configured
|
||||||
|
🚀 Nyash VM Backend - Executing file: local_tests/weak_field_poc.nyash 🚀
|
||||||
|
0
|
||||||
|
{
|
||||||
|
"counts": {
|
||||||
|
"BarrierRead": 1,
|
||||||
|
"BarrierWrite": 1,
|
||||||
|
"BoxCall": 2,
|
||||||
|
"Const": 9,
|
||||||
|
"NewBox": 2,
|
||||||
|
"Print": 1,
|
||||||
|
"RefGet": 4,
|
||||||
|
"RefSet": 3,
|
||||||
|
"Return": 3,
|
||||||
|
"Safepoint": 1,
|
||||||
|
"WeakLoad": 1,
|
||||||
|
"WeakNew": 1
|
||||||
|
},
|
||||||
|
"elapsed_ms": 0.194731,
|
||||||
|
"timestamp_ms": 1755956955634,
|
||||||
|
"top20": [
|
||||||
|
{
|
||||||
|
"count": 9,
|
||||||
|
"op": "Const"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"count": 4,
|
||||||
|
"op": "RefGet"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"count": 3,
|
||||||
|
"op": "RefSet"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"count": 3,
|
||||||
|
"op": "Return"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"count": 2,
|
||||||
|
"op": "BoxCall"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"count": 2,
|
||||||
|
"op": "NewBox"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"count": 1,
|
||||||
|
"op": "BarrierRead"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"count": 1,
|
||||||
|
"op": "BarrierWrite"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"count": 1,
|
||||||
|
"op": "Print"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"count": 1,
|
||||||
|
"op": "Safepoint"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"count": 1,
|
||||||
|
"op": "WeakLoad"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"count": 1,
|
||||||
|
"op": "WeakNew"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"total": 29
|
||||||
|
}
|
||||||
|
✅ VM execution completed successfully!
|
||||||
|
Result: IntegerBox { value: 0, base: BoxBase { id: 4, parent_type_id: None } }
|
||||||
65
vm_stats_weak_unified.json
Normal file
65
vm_stats_weak_unified.json
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
🔌 v2 plugin system initialized from nyash.toml
|
||||||
|
✅ v2 plugin system fully configured
|
||||||
|
🚀 Nyash VM Backend - Executing file: local_tests/weak_field_poc.nyash 🚀
|
||||||
|
0
|
||||||
|
{
|
||||||
|
"counts": {
|
||||||
|
"Barrier": 2,
|
||||||
|
"BoxCall": 2,
|
||||||
|
"Const": 9,
|
||||||
|
"NewBox": 2,
|
||||||
|
"Print": 1,
|
||||||
|
"RefGet": 4,
|
||||||
|
"RefSet": 3,
|
||||||
|
"Return": 3,
|
||||||
|
"Safepoint": 1,
|
||||||
|
"WeakRef": 2
|
||||||
|
},
|
||||||
|
"elapsed_ms": 0.16804799999999998,
|
||||||
|
"timestamp_ms": 1755957108401,
|
||||||
|
"top20": [
|
||||||
|
{
|
||||||
|
"count": 9,
|
||||||
|
"op": "Const"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"count": 4,
|
||||||
|
"op": "RefGet"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"count": 3,
|
||||||
|
"op": "RefSet"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"count": 3,
|
||||||
|
"op": "Return"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"count": 2,
|
||||||
|
"op": "Barrier"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"count": 2,
|
||||||
|
"op": "BoxCall"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"count": 2,
|
||||||
|
"op": "NewBox"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"count": 2,
|
||||||
|
"op": "WeakRef"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"count": 1,
|
||||||
|
"op": "Print"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"count": 1,
|
||||||
|
"op": "Safepoint"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"total": 29
|
||||||
|
}
|
||||||
|
✅ VM execution completed successfully!
|
||||||
|
Result: IntegerBox { value: 0, base: BoxBase { id: 4, parent_type_id: None } }
|
||||||
Reference in New Issue
Block a user