Repository navigation
Ray tracer: parameters captured by copy, direct calls to methods no class overrides - #759
Merged
Merged
Conversation
…o a heap cell A captured parameter was always moved into a heap cell shared by the frame and the closure's box, so the ray tracer's getNaturalColor made six cells per call for its addLight callback. A parameter that neither the body nor a closure in it assigns (collectAssignedNames, which now also counts ++ and --) is captured by copy, as `this` and a const already were. -mm=own: a closure that does not escape borrows the copy, as spec 70 lets it borrow `this` (OwnershipFacts isBorrowableCapture: a parameter's read, or a copy the enclosing closure's box holds). Generator parameters, callbacks and Shared<T> handles stay in cells. An escaping closure over a parameter's copy is refused with the message its cell got. Ray tracer, median ms (main -> this): gc 273 -> 97, none 158 -> 97, rc 171 -> 134, own 143 -> 104. ctest 6527/6527; fuzz seeds 79000-79599 clean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s its funclet bundle A `using` whose disposal may throw is entered through a catch-all that ends the way a cleanup does, in a `resume` (windowsCleanupCatches). With the disposal a direct call (a @Final class), MLIR's inliner put its `throw` straight into that catch. The scan leaves an inlined `_CxxThrowException` out of the calls it gives the funclet bundle, expecting the catchret placed ahead of the region's end to take it out of the funclet; a region ending in `resume` gets no catchret, so the throw stayed in the funclet with no bundle, and the program crashed once optimized (00using_dispose_throws: callerCatches, bothThrow, with --opt). Such a region now bundles them like its other calls. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Once the module is generated, every class it made is known (moduleClasses, imported sources' too). A method no class in the module overrides, of a class nothing outside the module can extend - not exported, declared, imported or a C++ binding, nor a base of one - is reached by a vtable call alone, so devirtualizeClosedMethods makes its ThisVirtualSymbolRef a ThisSymbolRef, as ClassMethodAccess does for a @Final receiver, and LLVM can inline it. Ray tracer, median ms (main -> parameters by copy -> this): gc 266 -> 97 -> 79, none 157 -> 96 -> 79, rc 171 -> 133 -> 120, own 143 -> 104 -> 86; Rust idiomatic 55. Test 00class_method_devirtualized (overrides declared after the call, two classes down, generic and function-local subclasses, abstract) and an IR check of which calls are direct. ctest 6534/6534; fuzz seeds 80000-80599 clean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Ray tracer performance (item 5): two compiler changes, and a Windows EH crash on main that the second one exposed.
Changes
getNaturalColormade six cells per call foraddLight. A parameter that neither the body nor a closure in it assigns (++/--now count as assignments) is captured by copy, asthisand aconstalready were.-mm=own: a closure that does not escape borrows the copy, generalizing spec 70'sthisrule (isBorrowableCapture: a parameter's read, or a copy the enclosing closure's box holds). Generator parameters, callbacks andShared<T>handles stay in cells. An escaping closure over a parameter's copy is still refused with the old "its value is the caller's" message.constcopy now compiles under own; it was an error on main.resumekeeps its funclet bundle (2dab213). This was already broken on main: ausingwhose disposal is a direct call (a@finalclass) and throws crashed with--opt, because MLIR's inliner put thethrowinside the catch funclet with no"funclet"bundle.00using_dispose_throws(callerCatches,bothThrow) caught it once change 3 made dispose calls direct.ThisSymbolRefinstead ofThisVirtualSymbolRef, as a@finalreceiver already does. "Nothing outside can extend" means the class is not exported, declared, imported or a C++ binding, and is not a base of such a class.Ray tracer
Median of 7 runs, ms; every build prints the same checksum, and neither benchmark source changed.
Testing
lib.tscompiles under own, rc, gc and none.own/own_param_capture_copies(all four models);tests/00class_method_devirtualized: overrides declared after the call, two classes down, generic and function-local subclasses, and abstract methods;class-method-devirtualized.cmake: an IR check of which calls are direct. It fails on main's compiler.linuxCleanupCatches. Read00using_dispose_throwsand00class_method_devirtualizedfirst on the Linux CI.Known
Intersection | null(README variant B, about 16 ms). Its null test compares the type tag as a string, so fixing it means changing how null is stored in a union.🤖 Generated with Claude Code