Skip to content

Update MethodDictionary rebuild to speed up trait recompilation - #19870

Open
jecisc wants to merge 43 commits into
pharo-project:Pharo14from
jecisc:kernel/trait-rebuild
Open

Update MethodDictionary rebuild to speed up trait recompilation#19870
jecisc wants to merge 43 commits into
pharo-project:Pharo14from
jecisc:kernel/trait-rebuild

Conversation

@jecisc

@jecisc jecisc commented Jul 8, 2026

Copy link
Copy Markdown
Member

This PR brings multiple speed up for large trait recompilation.

Recompiling large traits can be really slow because it needs to rebuild the method dictionary of each of the trait user.

This was done by iterating over the selectors of the trait composition and installing a copy of the method associated in the user. But we traversed multiple time the trait composition by doing this.

Now I build a compilation info object containing all the info directly preventing multiple visits of the trait composition.

Most of the time we still spend in the rebuild is spend in recompiling the methods if the user has a slot. The installation time of the method is much shorter.

For comparison, in a vanilla Moose image it was taking 72sec to add a slot to TEntityMetaLevelDependency. With this change it drops to 27sec.

There might be ways to speed up a little more operations, I might explore this later.

jecisc added 30 commits June 15, 2026 23:14

@Gabriel-Darbord Gabriel-Darbord left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for this PR, this is great for Moose where traits are omnipresent :)
I have a few technical and quality suggestions.
I can't really comment on semantics and validity, but I don't see any blatant issue there.

Comment thread src/Traits/TaAliasMethod.class.st Outdated
Comment thread src/Traits/TaAliasMethod.class.st
Comment thread src/Traits/TaClassCompositionElement.class.st Outdated
Comment thread src/Traits/TaCompositionElement.class.st Outdated
Comment thread src/Traits/TaPrecedenceComposition.class.st Outdated
Comment thread src/Traits/TraitedClass.class.st Outdated
Comment on lines +260 to +265
removedSelectors := self methodDict keys reject: [ :aSelector |
(compilationInfos anySatisfy: [ :compilationInfo | compilationInfo selector = aSelector ]) or: [ self isSelectorToKeep: aSelector ] ].
modified := modified | removedSelectors isNotEmpty.
removedSelectors do: [ :aSelector |
self methodDict removeKey: aSelector.
self removeFromProtocols: aSelector ].
self methodDict removeKey: aSelector.
self removeFromProtocols: aSelector ].

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

removedSelectors seems like an unnecessary intermediate collection:

	self methodDict keys do: [ :aSelector |
		((compilationInfos anySatisfy: [ :compilationInfo | compilationInfo selector = aSelector ]) or: [ self isSelectorToKeep: aSelector ]) ifTrue: [
			modified := true.
			self methodDict removeKey: aSelector.
			self removeFromProtocols: aSelector ] ].

Explicitly use keys do: instead of keysDo: to avoid modification during iteration.
You could also try swapping conditions to check isSelectorToKeep: first to be potentially faster.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I did not really check this part of the code since it did not appear in the profiler. I'll try to check soon :)

Comment thread src/Traits/TraitMethodCompilationInfo.class.st Outdated
Comment thread src/Traits/TraitMethodCompilationInfo.class.st Outdated
nextPutAll: '>>';
print: selector.

self compiledMethod ifNotNil: [ :cm | cm isRequired ifTrue: [ aStream nextPutAll: ' - Explicit requirement' ] ].

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If memoized and not afraid of concurrency (compiledMethod could change between nil check and block execution, but I don't think that's a concern for this data structure): cm isRequired -> self isExplicitRequirement

@Ducasse

Ducasse commented Jul 31, 2026

Copy link
Copy Markdown
Member

@jecisc let us know when this is ready.

jecisc and others added 2 commits August 14, 2026 20:13
@jecisc jecisc added the Version: Pharo 14 Issue to fix in Pharo 14 label Aug 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants