From b7fbc499b68435d85e0b45cf29332b0e926a9add Mon Sep 17 00:00:00 2001 From: Devin Bidwell Date: Sun, 14 Dec 2025 02:54:56 -0700 Subject: [PATCH 1/3] WIP fix stack overflow --- rust_compiler/Cargo.lock | 2 +- rust_compiler/libs/compiler/src/v1.rs | 2 +- rust_compiler/libs/optimizer/src/leaf_function.rs | 4 ++++ rust_compiler/libs/optimizer/src/lib.rs | 2 +- rust_compiler/src/main.rs | 9 ++++++++- 5 files changed, 15 insertions(+), 4 deletions(-) diff --git a/rust_compiler/Cargo.lock b/rust_compiler/Cargo.lock index ca51170..17bf0df 100644 --- a/rust_compiler/Cargo.lock +++ b/rust_compiler/Cargo.lock @@ -930,7 +930,7 @@ checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[package]] name = "slang" -version = "0.3.0" +version = "0.3.1" dependencies = [ "anyhow", "clap", diff --git a/rust_compiler/libs/compiler/src/v1.rs b/rust_compiler/libs/compiler/src/v1.rs index e5647fb..1cf26e6 100644 --- a/rust_compiler/libs/compiler/src/v1.rs +++ b/rust_compiler/libs/compiler/src/v1.rs @@ -264,7 +264,7 @@ impl<'a> Compiler<'a> { fn next_label_name(&mut self) -> Cow<'a, str> { self.label_counter += 1; - Cow::from(format!("L{}", self.label_counter)) + Cow::from(format!("__internal_L{}", self.label_counter)) } fn expression( diff --git a/rust_compiler/libs/optimizer/src/leaf_function.rs b/rust_compiler/libs/optimizer/src/leaf_function.rs index f8783f1..1d88555 100644 --- a/rust_compiler/libs/optimizer/src/leaf_function.rs +++ b/rust_compiler/libs/optimizer/src/leaf_function.rs @@ -14,6 +14,10 @@ pub fn find_leaf_functions(instructions: &[InstructionNode]) -> HashSet for node in instructions { match &node.instruction { Instruction::LabelDef(label) => { + if label.starts_with("__internal_L") { + continue; + } + // If we were tracking a function, and it remained a leaf until now, save it. if let Some(name) = current_label.take() && is_current_leaf diff --git a/rust_compiler/libs/optimizer/src/lib.rs b/rust_compiler/libs/optimizer/src/lib.rs index e4397e6..ffd97e1 100644 --- a/rust_compiler/libs/optimizer/src/lib.rs +++ b/rust_compiler/libs/optimizer/src/lib.rs @@ -99,7 +99,7 @@ fn optimize_leaf_functions<'a>( // First scan: Identify instructions to remove and capture RA offsets for (i, node) in input.iter().enumerate() { match &node.instruction { - Instruction::LabelDef(label) => { + Instruction::LabelDef(label) if !label.starts_with("__internal_L") => { current_function = Some(label.to_string()); function_start_indices.insert(label.to_string(), i); } diff --git a/rust_compiler/src/main.rs b/rust_compiler/src/main.rs index da60b84..47494bb 100644 --- a/rust_compiler/src/main.rs +++ b/rust_compiler/src/main.rs @@ -53,6 +53,9 @@ struct Args { /// The output file for the compiled program. If not set, output will go to stdout. #[arg(short, long)] output_file: Option, + /// Should Slang attempt to optimize the output? + #[arg(short = 'z', long)] + optimize: bool, } fn run_logic<'a>() -> Result<(), Error<'a>> { @@ -107,7 +110,11 @@ fn run_logic<'a>() -> Result<(), Error<'a>> { } } - optimizer::optimize(instructions).write(&mut writer)?; + if args.optimize { + optimizer::optimize(instructions).write(&mut writer)?; + } else { + instructions.write(&mut writer)?; + } writer.flush()?; From 6d5c179eac1b82cefda03e576a974068367a5f77 Mon Sep 17 00:00:00 2001 From: Devin Bidwell Date: Sun, 14 Dec 2025 03:16:58 -0700 Subject: [PATCH 2/3] Fixed stack overflow due to improper handling of leaf functions --- Changelog.md | 4 ++++ ModData/About/About.xml | 2 +- csharp_mod/Plugin.cs | 2 +- csharp_mod/stationeersSlang.csproj | 2 +- rust_compiler/Cargo.lock | 2 +- rust_compiler/Cargo.toml | 2 +- rust_compiler/libs/optimizer/src/lib.rs | 4 +++- 7 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Changelog.md b/Changelog.md index d2179ce..46dc71e 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,9 @@ # Changelog +[0.3.2] + +- Fixed stack overflow due to incorrect optimization of 'leaf' functions + [0.3.1] - Fixed possible `KeyNotFoundException` in C# code due to invalid diff --git a/ModData/About/About.xml b/ModData/About/About.xml index d3a0e4f..23fe752 100644 --- a/ModData/About/About.xml +++ b/ModData/About/About.xml @@ -2,7 +2,7 @@ Slang JoeDiertay - 0.3.1 + 0.3.2 [h1]Slang: High-Level Programming for Stationeers[/h1] diff --git a/csharp_mod/Plugin.cs b/csharp_mod/Plugin.cs index 36123c5..339cf1b 100644 --- a/csharp_mod/Plugin.cs +++ b/csharp_mod/Plugin.cs @@ -41,7 +41,7 @@ namespace Slang { public const string PluginGuid = "com.biddydev.slang"; public const string PluginName = "Slang"; - public const string PluginVersion = "0.3.1"; + public const string PluginVersion = "0.3.2"; public static Mod MOD = new Mod(PluginName, PluginVersion); diff --git a/csharp_mod/stationeersSlang.csproj b/csharp_mod/stationeersSlang.csproj index 57a61e0..3e4c048 100644 --- a/csharp_mod/stationeersSlang.csproj +++ b/csharp_mod/stationeersSlang.csproj @@ -5,7 +5,7 @@ enable StationeersSlang Slang Compiler Bridge - 0.3.1 + 0.3.2 true latest diff --git a/rust_compiler/Cargo.lock b/rust_compiler/Cargo.lock index 17bf0df..511d7ef 100644 --- a/rust_compiler/Cargo.lock +++ b/rust_compiler/Cargo.lock @@ -930,7 +930,7 @@ checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[package]] name = "slang" -version = "0.3.1" +version = "0.3.2" dependencies = [ "anyhow", "clap", diff --git a/rust_compiler/Cargo.toml b/rust_compiler/Cargo.toml index 5b2305a..260e0c0 100644 --- a/rust_compiler/Cargo.toml +++ b/rust_compiler/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "slang" -version = "0.3.1" +version = "0.3.2" edition = "2021" [workspace] diff --git a/rust_compiler/libs/optimizer/src/lib.rs b/rust_compiler/libs/optimizer/src/lib.rs index ffd97e1..ea75c06 100644 --- a/rust_compiler/libs/optimizer/src/lib.rs +++ b/rust_compiler/libs/optimizer/src/lib.rs @@ -174,7 +174,9 @@ fn optimize_leaf_functions<'a>( continue; // SKIP (Remove) } - if let Instruction::LabelDef(l) = &node.instruction { + if let Instruction::LabelDef(l) = &node.instruction + && !l.starts_with("__internal_L") + { processing_function = Some(l.to_string()); } From b98817c8a0e67e2138d74c22c6df3b4e19527dff Mon Sep 17 00:00:00 2001 From: Devin Bidwell Date: Sun, 14 Dec 2025 03:23:49 -0700 Subject: [PATCH 3/3] Fixed tests to show new line label convention for internal labels --- .../compiler/src/test/binary_expression.rs | 4 +- .../libs/compiler/src/test/branching.rs | 32 ++++++------- .../test/declaration_function_invocation.rs | 24 +++++----- .../compiler/src/test/declaration_literal.rs | 4 +- .../compiler/src/test/function_declaration.rs | 14 +++--- rust_compiler/libs/compiler/src/test/loops.rs | 48 +++++++++---------- 6 files changed, 63 insertions(+), 63 deletions(-) diff --git a/rust_compiler/libs/compiler/src/test/binary_expression.rs b/rust_compiler/libs/compiler/src/test/binary_expression.rs index 4ac0754..e4bef54 100644 --- a/rust_compiler/libs/compiler/src/test/binary_expression.rs +++ b/rust_compiler/libs/compiler/src/test/binary_expression.rs @@ -52,8 +52,8 @@ fn nested_binary_expressions() -> Result<()> { add r1 r10 r9 mul r2 r1 r8 move r15 r2 - j L1 - L1: + j __internal_L1 + __internal_L1: sub r0 sp 1 get ra db r0 sub sp sp 1 diff --git a/rust_compiler/libs/compiler/src/test/branching.rs b/rust_compiler/libs/compiler/src/test/branching.rs index 155c535..92f876b 100644 --- a/rust_compiler/libs/compiler/src/test/branching.rs +++ b/rust_compiler/libs/compiler/src/test/branching.rs @@ -22,9 +22,9 @@ fn test_if_statement() -> anyhow::Result<()> { main: move r8 10 sgt r1 r8 5 - beqz r1 L1 + beqz r1 __internal_L1 move r8 20 - L1: + __internal_L1: " } ); @@ -54,12 +54,12 @@ fn test_if_else_statement() -> anyhow::Result<()> { main: move r8 0 sgt r1 10 5 - beqz r1 L2 + beqz r1 __internal_L2 move r8 1 - j L1 - L2: + j __internal_L1 + __internal_L2: move r8 2 - L1: + __internal_L1: " } ); @@ -91,18 +91,18 @@ fn test_if_else_if_statement() -> anyhow::Result<()> { main: move r8 0 seq r1 r8 1 - beqz r1 L2 + beqz r1 __internal_L2 move r8 10 - j L1 - L2: + j __internal_L1 + __internal_L2: seq r2 r8 2 - beqz r2 L4 + beqz r2 __internal_L4 move r8 20 - j L3 - L4: + j __internal_L3 + __internal_L4: move r8 30 - L3: - L1: + __internal_L3: + __internal_L1: " } ); @@ -145,10 +145,10 @@ fn test_spilled_variable_update_in_branch() -> anyhow::Result<()> { move r14 7 push 8 seq r1 r8 1 - beqz r1 L1 + beqz r1 __internal_L1 sub r0 sp 1 put db r0 99 - L1: + __internal_L1: sub sp sp 1 " } diff --git a/rust_compiler/libs/compiler/src/test/declaration_function_invocation.rs b/rust_compiler/libs/compiler/src/test/declaration_function_invocation.rs index dbdfaca..e4e8fa7 100644 --- a/rust_compiler/libs/compiler/src/test/declaration_function_invocation.rs +++ b/rust_compiler/libs/compiler/src/test/declaration_function_invocation.rs @@ -17,7 +17,7 @@ fn no_arguments() -> anyhow::Result<()> { j main doSomething: push ra - L1: + __internal_L1: sub r0 sp 1 get ra db r0 sub sp sp 1 @@ -59,14 +59,14 @@ fn let_var_args() -> anyhow::Result<()> { push ra mul r1 r8 2 move r15 r1 - j L1 - L1: + j __internal_L1 + __internal_L1: sub r0 sp 1 get ra db r0 sub sp sp 1 j ra main: - L2: + __internal_L2: move r8 123 push r8 push r8 @@ -77,8 +77,8 @@ fn let_var_args() -> anyhow::Result<()> { move r9 r15 pow r1 r9 2 move r9 r1 - j L2 - L3: + j __internal_L2 + __internal_L3: " } ); @@ -127,8 +127,8 @@ fn inline_literal_args() -> anyhow::Result<()> { pop r9 push ra move r15 5 - j L1 - L1: + j __internal_L1 + __internal_L1: sub r0 sp 1 get ra db r0 sub sp sp 1 @@ -170,7 +170,7 @@ fn mixed_args() -> anyhow::Result<()> { pop r8 pop r9 push ra - L1: + __internal_L1: sub r0 sp 1 get ra db r0 sub sp sp 1 @@ -214,8 +214,8 @@ fn with_return_statement() -> anyhow::Result<()> { pop r8 push ra move r15 456 - j L1 - L1: + j __internal_L1 + __internal_L1: sub r0 sp 1 get ra db r0 sub sp sp 1 @@ -251,7 +251,7 @@ fn with_negative_return_literal() -> anyhow::Result<()> { doSomething: push ra move r15 -1 - L1: + __internal_L1: sub r0 sp 1 get ra db r0 sub sp sp 1 diff --git a/rust_compiler/libs/compiler/src/test/declaration_literal.rs b/rust_compiler/libs/compiler/src/test/declaration_literal.rs index 550e332..58927c4 100644 --- a/rust_compiler/libs/compiler/src/test/declaration_literal.rs +++ b/rust_compiler/libs/compiler/src/test/declaration_literal.rs @@ -133,8 +133,8 @@ fn test_boolean_return() -> anyhow::Result<()> { getTrue: push ra move r15 1 - j L1 - L1: + j __internal_L1 + __internal_L1: sub r0 sp 1 get ra db r0 sub sp sp 1 diff --git a/rust_compiler/libs/compiler/src/test/function_declaration.rs b/rust_compiler/libs/compiler/src/test/function_declaration.rs index 18f5b84..2c909f6 100644 --- a/rust_compiler/libs/compiler/src/test/function_declaration.rs +++ b/rust_compiler/libs/compiler/src/test/function_declaration.rs @@ -21,7 +21,7 @@ fn test_function_declaration_with_spillover_params() -> anyhow::Result<()> { pop r13 pop r14 push ra - L1: + __internal_L1: sub r0 sp 1 get ra db r0 sub sp sp 3 @@ -54,12 +54,12 @@ fn test_early_return() -> anyhow::Result<()> { doSomething: push ra seq r1 1 1 - beqz r1 L2 - j L1 - L2: + beqz r1 __internal_L2 + j __internal_L1 + __internal_L2: move r8 3 - j L1 - L1: + j __internal_L1 + __internal_L1: sub r0 sp 1 get ra db r0 sub sp sp 1 @@ -90,7 +90,7 @@ fn test_function_declaration_with_register_params() -> anyhow::Result<()> { pop r8 pop r9 push ra - L1: + __internal_L1: sub r0 sp 1 get ra db r0 sub sp sp 1 diff --git a/rust_compiler/libs/compiler/src/test/loops.rs b/rust_compiler/libs/compiler/src/test/loops.rs index 83745f0..b803354 100644 --- a/rust_compiler/libs/compiler/src/test/loops.rs +++ b/rust_compiler/libs/compiler/src/test/loops.rs @@ -14,7 +14,7 @@ fn test_infinite_loop() -> anyhow::Result<()> { " }; - // Labels: L1 (start), L2 (end) + // __internal_Labels: L1 (start), L2 (end) assert_eq!( compiled, indoc! { @@ -22,11 +22,11 @@ fn test_infinite_loop() -> anyhow::Result<()> { j main main: move r8 0 - L1: + __internal_L1: add r1 r8 1 move r8 r1 - j L1 - L2: + j __internal_L1 + __internal_L2: " } ); @@ -49,7 +49,7 @@ fn test_loop_break() -> anyhow::Result<()> { " }; - // Labels: L1 (start), L2 (end), L3 (if end - implicit else label) + // __internal_Labels: L1 (start), L2 (end), L3 (if end - implicit else label) assert_eq!( compiled, indoc! { @@ -57,15 +57,15 @@ fn test_loop_break() -> anyhow::Result<()> { j main main: move r8 0 - L1: + __internal_L1: add r1 r8 1 move r8 r1 sgt r2 r8 10 - beqz r2 L3 - j L2 - L3: - j L1 - L2: + beqz r2 __internal_L3 + j __internal_L2 + __internal_L3: + j __internal_L1 + __internal_L2: " } ); @@ -85,7 +85,7 @@ fn test_while_loop() -> anyhow::Result<()> { " }; - // Labels: L1 (start), L2 (end) + // __internal_Labels: L1 (start), L2 (end) assert_eq!( compiled, indoc! { @@ -93,13 +93,13 @@ fn test_while_loop() -> anyhow::Result<()> { j main main: move r8 0 - L1: + __internal_L1: slt r1 r8 10 - beqz r1 L2 + beqz r1 __internal_L2 add r2 r8 1 move r8 r2 - j L1 - L2: + j __internal_L1 + __internal_L2: " } ); @@ -123,7 +123,7 @@ fn test_loop_continue() -> anyhow::Result<()> { "# }; - // Labels: L1 (start), L2 (end), L3 (if end) + // __internal_Labels: L1 (start), L2 (end), L3 (if end) assert_eq!( compiled, indoc! { @@ -131,16 +131,16 @@ fn test_loop_continue() -> anyhow::Result<()> { j main main: move r8 0 - L1: + __internal_L1: add r1 r8 1 move r8 r1 slt r2 r8 5 - beqz r2 L3 - j L1 - L3: - j L2 - j L1 - L2: + beqz r2 __internal_L3 + j __internal_L1 + __internal_L3: + j __internal_L2 + j __internal_L1 + __internal_L2: " } );