Skip to content

Fix OamSpr crash and Block.RemoveAt label loss#294

Merged
jonathanpeppers merged 3 commits intomainfrom
fix-oamspr-negative-const
Mar 20, 2026
Merged

Fix OamSpr crash and Block.RemoveAt label loss#294
jonathanpeppers merged 3 commits intomainfrom
fix-oamspr-negative-const

Conversation

@jonathanpeppers
Copy link
Copy Markdown
Owner

@jonathanpeppers jonathanpeppers commented Mar 20, 2026

Two fixes discovered while getting the crypto sample (PR #211) to transpile.

Fix 1: OamSpr backward scan crash with negative constants

EmitOamSprDecsp4 crashed with KeyNotFoundException when compoundLocalIdx was -1 (unset) in compound expressions where the source was a constant-only expression. Also fixes checked byte casts for negative constant values (Ldc_i4_m1 = 0xFF).

  • Add defensive fallback when compoundLocalIdx < 0: emit constant directly instead of crashing on Locals[-1]
  • Use (byte)(value & 0xFF) instead of checked((byte)value) for constValue and 5th arg emission

Fix 2: Preserve labels in Block.RemoveAt

Block.RemoveAt(index) silently discarded labels attached to removed instructions. This caused unresolved branch labels (UnresolvedLabelException) in large programs where pattern matching handlers remove instructions at arbitrary indices. RemoveLast already preserved labels correctly -- applied the same pattern to RemoveAt.

Result

With these fixes plus sample-level workarounds (compound assignments, sfx_play), the 2,270-line crypto dungeon crawler sample transpiles to a working NES ROM and renders graphics in the emulator.

All existing tests pass.

EmitOamSprDecsp4 crashed with KeyNotFoundException when compoundLocalIdx was -1
(unset) in compound expressions where the source was a constant-only expression.
Also fix checked byte casts for negative constant values (Ldc_i4_m1 = 0xFF).

- Add defensive fallback when compoundLocalIdx < 0: emit constant directly
- Use (byte)(value & 0xFF) instead of checked((byte)value) for constValue

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a crash in the transpiler’s oam_spr/decsp4 emission path when the backward-scan identifies a “compound” argument but fails to record a valid source local (e.g., constant-only sub-expressions), and adjusts constant→byte handling to correctly match IL truncation semantics for negative constants (e.g., -1 → 0xFF).

Changes:

  • Guard compoundLocalIdx access to avoid Locals[-1] and add a fallback path for constant-only compound args.
  • Replace checked((byte)...) with (byte)(value & 0xFF) for certain constant argument emissions (including the 5th id arg).
Comments suppressed due to low confidence (1)

src/dotnes.tasks/Utilities/IL2NESWriter.OamSprites.cs:438

  • The "A already has the right value from attr" optimization can misfire when attrArg is not actually an immediate constant (e.g., isCompound or isStaticField). In those cases attrArg.constValue is still 0, so if idArg.constValue is 0 the code may skip reloading A and pass the attribute value as the 5th (id) argument. This should be gated on attrArg being a true constant argument before comparing constValue.
                // Check if A already has the right value from the 4th arg STA
                if (argInfos.Count >= 4)
                {
                    var attrArg = argInfos[3];
                    if (!attrArg.isLocal && !attrArg.isArrayElem && !idArg.isLocal
                        && attrArg.constValue == idArg.constValue)
                    {

Comment thread src/dotnes.tasks/Utilities/IL2NESWriter.OamSprites.cs Outdated
Block.RemoveAt(index) was silently discarding labels attached to removed
instructions. This caused unresolved branch labels in large programs where
pattern matching handlers remove instructions at arbitrary indices.
RemoveLast already preserved labels correctly — applied the same pattern.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jonathanpeppers jonathanpeppers changed the title Fix OamSpr backward scan crash with negative constants Fix OamSpr crash and Block.RemoveAt label loss Mar 20, 2026
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Owner Author

@jonathanpeppers jonathanpeppers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review comment addressed in 7074ca7. All 563 tests pass.

@jonathanpeppers jonathanpeppers merged commit bb1cb10 into main Mar 20, 2026
1 check passed
@jonathanpeppers jonathanpeppers deleted the fix-oamspr-negative-const branch March 20, 2026 21:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants