Skip to content

[Runtime] Create an external generic metadata builder. #70771

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
Jan 11, 2024

Conversation

mikeash
Copy link
Contributor

@mikeash mikeash commented Jan 8, 2024

Create a version of the metadata specialization code which is abstracted so that it can work in different contexts, such as building specialized metadata from dylibs on disk rather than from inside a running process.

The GenericMetadataBuilder class is templatized on a ReaderWriter. The ReaderWriter abstracts out everything that's different between in-process and external construction of this data. Instead of reading and writing pointers directly, the builder calls the ReaderWriter to resolve and write pointers. The ReaderWriter also handles symbol lookups and looking up other Swift types by name.

This is accompanied by a simple implementation of the ReaderWriter which works in-process. The abstracted calls to resolve and write pointers are implemented using standard pointer dereferencing.

A new SWIFT_DEBUG_VALIDATE_EXTERNAL_GENERIC_METADATA_BUILDER environment variable uses the in-process ReaderWriter to validate the builder by running it in parallel with the existing metadata builder code in the runtime. When enabled, the GenericMetadataBuilder is used to build a second copy of metadata built by the runtime, and the two are compared to ensure that they match. When this environment variable is not set, the new builder code is inactive.

The builder is incomplete, and this initial version only works on structs. Any unsupported type produces an error, and skips the validation.

rdar://116592420

@mikeash mikeash requested a review from al45tair as a code owner January 8, 2024 19:56
Comment on lines 54 to 65
/// This helper constructor takes a callable which is passed a char**, and
/// places the error string into that pointer. This is intended to be used
/// with a lambda that calls asprintf, and exists for the use of the
/// MAKE_ERROR macro.
template <typename Fn>
BuilderError(const Fn &makeString) {
char *string = nullptr;
makeString(&string);
if (string)
errorString = string;
else
errorString = "<could not create error string>";
free(string);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Rather than doing this and using the MAKE_ERROR macro, how about having a variadic constructor, e.g.

Suggested change
/// This helper constructor takes a callable which is passed a char**, and
/// places the error string into that pointer. This is intended to be used
/// with a lambda that calls asprintf, and exists for the use of the
/// MAKE_ERROR macro.
template <typename Fn>
BuilderError(const Fn &makeString) {
char *string = nullptr;
makeString(&string);
if (string)
errorString = string;
else
errorString = "<could not create error string>";
free(string);
}
template <class... Args>
[[gnu::format(printf, 1, 2)]]
BuilderError(const char *fmt, Args&&... args) {
char *string = nullptr;
asprintf(&string, fmt, std::forward<Args>(args)...);
if (string)
errorString = string;
else
errorString = "<could not create error string>";
std::free(string);
}

(That might generate a GCC compatibility warning, in which case maybe we want to turn off -Wgcc-compat, or rewrite it to be variadic instead of using a parameter pack.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It does indeed complain, so I wrote it as a regular variadic function instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No idea why I didn't just write a variadic constructor in the first place. The mysteries of the human brain....

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe you were thinking of adding __FILE__ and __LINE__ to it or something.

.DefaultInstantiationPattern.get());
auto extraDataSize = genericValueDataExtraSize(valueDescriptor, pattern);
if (auto *error = extraDataSize.getError()) {
printf("Failed to get extra data size: %s\n", error->cStr());
Copy link
Contributor

Choose a reason for hiding this comment

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

Do these want to go to stdout, or stderr, or some logging thing? And should they have some prefix to indicate where they're coming from?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've redone this stuff to be a little more sensible. They all go to stderr now, and they all go through a validationLog function which prints a prefix on everything, with the exception of the metadata dumper which expects to be able to print partial lines and so doesn't like prefixes much.

I also decided that validation and the various logs aren't quite the same thing, so I changed it to make SWIFT_DEBUG_VALIDATE_EXTERNAL_GENERIC_METADATA_BUILDER an integer, where 1 does the validation silently unless there's an error, and 2 does full logging along with it.

@mikeash mikeash force-pushed the generic-metadata-builder branch 2 times, most recently from 0eb2b8e to 249870c Compare January 9, 2024 21:26
@mikeash
Copy link
Contributor Author

mikeash commented Jan 9, 2024

Updated with review feedback. Also conditionalized uses of dladdr/dlsym on SWIFT_STDLIB_HAS_DLADDR.

@mikeash
Copy link
Contributor Author

mikeash commented Jan 9, 2024

@swift-ci please test

@mikeash mikeash force-pushed the generic-metadata-builder branch from 249870c to 60fc209 Compare January 9, 2024 22:03
@mikeash
Copy link
Contributor Author

mikeash commented Jan 9, 2024

It would help if I actually added the new MathUtils.h file.

@mikeash
Copy link
Contributor Author

mikeash commented Jan 9, 2024

@swift-ci please test

template <typename T = char>
BuilderErrorOr<Buffer<const T>> getSymbolPointer(const char *name) {
#if SWIFT_STDLIB_HAS_DLADDR
void *ptr = dlsym(RTLD_SELF, name);
Copy link
Contributor

Choose a reason for hiding this comment

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

Linux doesn't have RTLD_SELF, but does have dlsym(), dladdr() and so on. They don't work as well as on Darwin, mind — they'll only find exported symbols (and they won't work at all if someone statically links with Musl, because in that situation while the APIs exist, they do nothing).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I changed this to check for #ifdef RTLD_SELF and use RTLD_DEFAULT otherwise. Only finding exported symbols is OK for our purposes. Not working at all on Musl is not, but we don't need this to work there at the moment. If we do, we replace the dlsym with a list of the functions we need to be able to find.

#include "swift/ABI/TargetLayout.h"
#include "swift/Runtime/EnvironmentVariables.h"
#include "swift/Runtime/Metadata.h"
#include <dlfcn.h>
Copy link
Contributor

@al45tair al45tair Jan 10, 2024

Choose a reason for hiding this comment

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

Should probably remove this line

Suggested change
#include <dlfcn.h>

(There's a conditional include of it just below.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oops! Fixed.

#include "swift/Basic/MathUtils.h"
#include "swift/Demangling/TypeLookupError.h"
#include "llvm/Support/Casting.h"
#include <dlfcn.h>
Copy link
Contributor

Choose a reason for hiding this comment

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

<dlfcn.h> doesn't exist on Windows. We should probably conditionalise this.

Suggested change
#include <dlfcn.h>
#if SWIFT_STDLIB_HAS_DLADDR
#include <dlfcn.h>
#endif

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's actually just a leftover, the only use of dl* is in the .cpp file. Removed.

@al45tair
Copy link
Contributor

The other problem looks to be some test that checks the symbols exported from libswiftCore.

@mikeash mikeash force-pushed the generic-metadata-builder branch from 60fc209 to 9aa0300 Compare January 10, 2024 15:32
@mikeash mikeash requested a review from a team as a code owner January 10, 2024 15:32
@mikeash
Copy link
Contributor Author

mikeash commented Jan 10, 2024

@swift-ci please test

@mikeash mikeash force-pushed the generic-metadata-builder branch from 9aa0300 to aa10c91 Compare January 10, 2024 19:30
@mikeash
Copy link
Contributor Author

mikeash commented Jan 10, 2024

SWIFT_STDLIB_HAS_DLADDR is true when building for Windows, apparently. Rather than wrangle with the complexity of correcting that in the build system, I've added a conditional for __has_include(<dlfcn.h>) and we can figure out the build side separately. Windows also doesn't like the use of vasprintf, which is why we have our own swift_vasprintf which I've now switched to here.

@mikeash
Copy link
Contributor Author

mikeash commented Jan 10, 2024

@swift-ci please test

@mikeash mikeash force-pushed the generic-metadata-builder branch from aa10c91 to 7b368ef Compare January 10, 2024 23:19
@mikeash
Copy link
Contributor Author

mikeash commented Jan 10, 2024

Windows doesn't like flockfile. It's not really needed here so I removed the uses.

@mikeash
Copy link
Contributor Author

mikeash commented Jan 10, 2024

@swift-ci please test

Create a version of the metadata specialization code which is abstracted so that it can work in different contexts, such as building specialized metadata from dylibs on disk rather than from inside a running process.

The GenericMetadataBuilder class is templatized on a ReaderWriter. The ReaderWriter abstracts out everything that's different between in-process and external construction of this data. Instead of reading and writing pointers directly, the builder calls the ReaderWriter to resolve and write pointers. The ReaderWriter also handles symbol lookups and looking up other Swift types by name.

This is accompanied by a simple implementation of the ReaderWriter which works in-process. The abstracted calls to resolve and write pointers are implemented using standard pointer dereferencing.

A new SWIFT_DEBUG_VALIDATE_EXTERNAL_GENERIC_METADATA_BUILDER environment variable uses the in-process ReaderWriter to validate the builder by running it in parallel with the existing metadata builder code in the runtime. When enabled, the GenericMetadataBuilder is used to build a second copy of metadata built by the runtime, and the two are compared to ensure that they match. When this environment variable is not set, the new builder code is inactive.

The builder is incomplete, and this initial version only works on structs. Any unsupported type produces an error, and skips the validation.

rdar://116592420
@mikeash mikeash force-pushed the generic-metadata-builder branch from 7b368ef to 29c350e Compare January 11, 2024 14:15
@mikeash
Copy link
Contributor Author

mikeash commented Jan 11, 2024

Need to disable the test on Windows since the lack of dlsym there causes validation to fail. We can complete Windows support separately.

@mikeash
Copy link
Contributor Author

mikeash commented Jan 11, 2024

@swift-ci please smoke test

@mikeash
Copy link
Contributor Author

mikeash commented Jan 11, 2024

Hit the Concurrency/flow_isolation.swift failure, test disabled in #70844. Retrying.

@mikeash
Copy link
Contributor Author

mikeash commented Jan 11, 2024

@swift-ci please smoke test

@mikeash mikeash merged commit feae5f1 into swiftlang:main Jan 11, 2024
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