Skip to content

new C() of a local class allocates in place instead of calling C..new - #610

Merged
ASDAlexander77 merged 2 commits into
mainfrom
new-local-class-direct
Oct 18, 2026
Merged

ASDAlexander77 merged 2 commits into
mainfrom
new-local-class-direct

Conversation

@ASDAlexander77

Copy link
Copy Markdown
Owner

Summary

  • For a class defined in the module, new C() now emits what C..new's body would run: the ts.New and the vtable store. Before, it emitted a call to C..new.
  • The ts.New carries __owned_result, as the call did. Under rc, NewOpLowering stores a count of 1 into the block header for such a ts.New. So the caller sees no ts.Retain, which is the same ownership shape the call had.
  • Classes from elsewhere keep the C..new call. That covers declarations, imports, dynamic imports and @cpp classes. C..new is still generated for the vtable's .new slot and for other modules.
  • Stack promotion no longer inlines C..new bodies, because every local new C() site is now a ts.New. newMethodOf, newMethodBody and the call branch of promote() are removed.
  • Comments that described new C() as always a C..new call are updated.

Why no visible retain

A first version emitted ts.Retain after the ts.New. That broke -mm=own in two ways. The global-initializer check reported "takes a second reference" for let g = new H(). Two own-err tests also stopped reporting their expected errors. Making the +1 part of the allocation keeps the IR identical in ownership terms to the old call result.

ABI

There is no ABI change. The header layout and the count semantics seen by consumers are unchanged. The prebuilt DefaultLib and the CI LLVM artifact do not need rebuilding.

Testing

  • The full Release suite passes, with 0 failures out of 4672.
  • All 1469 rc and own run tests pass with -no-stack-promotion, which exercises the heap path. The 12 nonzero exits there are tests that expect an error by pass regex.
  • A heap churn loop with promotion off allocated 10M objects under rc. Peak memory stayed at 3.8 MB and nothing crashed. The same loop also ran under own and gc.

🤖 Generated with Claude Code

ASDAlexander77 and others added 2 commits October 18, 2026 23:46
For a class defined in the module, `new C()` now emits the body `C..new` would
run - the ts.New and the vtable store - instead of a call. The ts.New carries
__owned_result, as the call did, and under rc the block starts with that one
reference (NewOpLowering stores 1 into the header), so the caller sees no
ts.Retain the ownership passes would have to account for: the same ownership
shape the call had. A visible retain broke -mm=own: the global-initializer
check rejected it, and two own-err tests stopped reporting their errors.

C..new is still generated for the vtable's .new slot and for other modules.
Declarations, imports, dynamic imports and @cpp classes keep the call.

Stack promotion no longer inlines C..new bodies: every local `new C()` site is
a ts.New, so newMethodOf, newMethodBody and the call branch of promote() go.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ASDAlexander77
ASDAlexander77 merged commit 3cfa701 into main Oct 18, 2026
2 checks passed
@ASDAlexander77
ASDAlexander77 deleted the new-local-class-direct branch October 18, 2026 23:14
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