Skip to content

Add Op::PushCsgWrap: eliminate union/difference/intersection's native reentry - #67

Merged
revarbat merged 1 commit into
mainfrom
csg-wrap-bytecode
Aug 1, 2026
Merged

Add Op::PushCsgWrap: eliminate union/difference/intersection's native reentry#67
revarbat merged 1 commit into
mainfrom
csg-wrap-bytecode

Conversation

@revarbat

@revarbat revarbat commented Aug 1, 2026

Copy link
Copy Markdown
Member

Summary

  • union()/difference()/intersection() were the last construct still falling to Op::NativeStatement when they wrap a recursive call, capping recursion at kMaxDriveVmNativeDepth=40 (the same Windows native-reentry risk Op::PushBuiltinWrap (Close the NativeStatement gap for translate/color/modifier-wrapped recursion #63) and Op::CallChildren (Add Op::CallChildren: eliminate children()'s native reentry #66) already closed for every other builtin-with-children).
  • They were left out of Op::PushBuiltinWrap because resolveCsg needs per-top-level-child "group_sizes" bookkeeping a single flat bracket can't represent (e.g. difference(){ A; B; C; } = A − (B∪C), even when A itself expands to more than one body).
  • New Op::PushCsgWrap/CsgGroupStart/CsgGroupEnd/PopCsgWrap replicate resolveCsg's own two-pass shape (all assignments first, then one group per geometry statement) as inline compiled bytecode. A wrapped recursive call now compiles straight to Op::CallModule — zero native stack cost, bounded only by the heap-sized kMaxVmCallStackDepth (1,000,000) instead of 40.

Test plan

  • Full 727-test suite green both OSCAD_BYTECODE_VM on (default) and off (OSCAD_BYTECODE_VM=0), up from 721 (6 new tests).
  • New tests: recursion succeeds well past the old 40-level ceiling for union/difference/intersection each; the same chain pushed past kMaxCsgTreeDepth=2000 still errors cleanly (now via the correct, orthogonal guard); $-named-arg propagation into a compiled CSG wrap's children; assignment-before-geometry-statement ordering preserved; group_sizes/multi-body-operand grouping correctness inside a compiled module body.
  • Real-world smoke check: BOSL2's examples/fractal_tree.scad (deep attach()/attachable() recursion, exercising union/difference through BOSL2's own internals) renders cleanly via the VM path.
  • Version bumped to 0.13.5.

🤖 Generated with Claude Code

… reentry

A recursive call wrapped in union()/difference()/intersection() still fell
to Op::NativeStatement, costing one real native C++ frame per level and
capping recursion at kMaxDriveVmNativeDepth=40 -- the same Windows-crash
risk Op::PushBuiltinWrap already closed for translate/rotate/scale/mirror/
multmatrix/resize/color/#/%/! and Op::CallChildren closed for children().
These three were left out because resolveCsg needs per-top-level-child
"group_sizes" bookkeeping that a single flat bracket can't represent.

Op::PushCsgWrap/CsgGroupStart/CsgGroupEnd/PopCsgWrap replicate resolveCsg's
own two-pass shape (every assignment evaluated first, then one group per
geometry statement) as inline compiled bytecode, so a wrapped recursive
call now compiles straight to Op::CallModule -- zero native stack cost,
bounded only by the heap-sized kMaxVmCallStackDepth.
@revarbat
revarbat merged commit 2d4c675 into main Aug 1, 2026
3 checks passed
@revarbat
revarbat deleted the csg-wrap-bytecode branch August 1, 2026 14:02
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.

1 participant