Skip to content

[RemoteMirror] Fix demangle node corruption caused by excessively eager clearing of the NodeFactory. #64674

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 30, 2023

Conversation

mikeash
Copy link
Contributor

@mikeash mikeash commented Mar 28, 2023

We clear the NodeFactory to prevent unbounded buildup of allocated memory, but this is done too eagerly. In particular, normalizeReflectionName can end up clearing the factory while the calling code is still using nodes that were allocated from it.

To keep peak memory usage low while avoiding this problem, we introduce a checkpoint mechanism in NodeFactory. A checkpoint can be pushed and then subsequently popped. When a checkpoint is popped, only the nodes allocated since the checkpoint was pushed are invalidated and the memory reclaimed. This allows us to quickly clear short-lived nodes like those created in normalizeReflectionName, while preserving longer-lived nodes used in code calling it. Uses of clearNodeFactory are replaced with this checkpoint mechanism.

rdar://106547092

@mikeash mikeash requested review from al45tair and btroller March 28, 2023 16:47
@mikeash
Copy link
Contributor Author

mikeash commented Mar 28, 2023

@swift-ci please test

@mikeash
Copy link
Contributor Author

mikeash commented Mar 28, 2023

@swift-ci please test macos platform

Copy link
Contributor

@al45tair al45tair left a comment

Choose a reason for hiding this comment

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

LGTM.

@@ -93,6 +93,7 @@ RemoteRef<char> TypeRefBuilder::readTypeRef(uint64_t remoteAddr) {
/// Load and normalize a mangled name so it can be matched with string equality.
llvm::Optional<std::string>
TypeRefBuilder::normalizeReflectionName(RemoteRef<char> reflectionName) {
auto checkpoint = pushNodeFactoryCheckpoint();
Copy link
Contributor

Choose a reason for hiding this comment

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

A lot of code that does this seems to follow the pattern

auto checkpoint = pushNodeFactoryCheckpoint();
...
popNodeFactoryCheckpoint(checkpoint);

which makes me wonder whether we should have a

template <typename T, typename F>
T withScopedNodes(F func) {
  auto checkpoint = pushNodeFactoryCheckpoint();
  T result = func();
  popNodeFactoryCheckpoint(checkpoint);
  return result;
}

or similar (obviously that's written OTOH in a Github comment, but you get the idea).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

RAII would be more idiomatic in C++. I've gone ahead and added a little RAII wrapper and switched over to that. The scoping makes things less convenient in a couple of places where we declare locals that get used later, but overall it's nicer.

Copy link
Contributor

Choose a reason for hiding this comment

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

:-) I seems to have Swift on the brain at the moment. Yes, RAII is more idiomatic in C++.

@mikeash mikeash force-pushed the remotemirror-nodefactory-clear-fix branch from 9f18a44 to 4fda3b4 Compare March 29, 2023 17:07
@mikeash
Copy link
Contributor Author

mikeash commented Mar 29, 2023

@swift-ci please test

…er clearing of the NodeFactory.

We clear the NodeFactory to prevent unbounded buildup of allocated memory, but this is done too eagerly. In particular, normalizeReflectionName can end up clearing the factory while the calling code is still using nodes that were allocated from it.

To keep peak memory usage low while avoiding this problem, we introduce a checkpoint mechanism in NodeFactory. A checkpoint can be pushed and then subsequently popped. When a checkpoint is popped, only the nodes allocated since the checkpoint was pushed are invalidated and the memory reclaimed. This allows us to quickly clear short-lived nodes like those created in normalizeReflectionName, while preserving longer-lived nodes used in code calling it. Uses of clearNodeFactory are replaced with this checkpoint mechanism.

rdar://106547092
@mikeash mikeash force-pushed the remotemirror-nodefactory-clear-fix branch from 4fda3b4 to fbc3f69 Compare March 29, 2023 20:59
@mikeash
Copy link
Contributor Author

mikeash commented Mar 29, 2023

@swift-ci please test

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