Skip to content
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

[SwiftBindings] Added TypeMetadata, removed SwiftTypeInfo #2804

Open
wants to merge 3 commits into
base: feature/swift-bindings
Choose a base branch
from

Conversation

stephen-hawley
Copy link

@stephen-hawley stephen-hawley commented Nov 21, 2024

This is a very simple implementation of TypeMetadata to get @jkurdek unblocked.

It includes access to the metadata kind and not a lot else for now.

The goal of this is to be used as a runtime type not a compile time type.

For the time being I removed SwiftTypeInfo which uses info pulled directly from the data structures in the dylib. We should discuss this in more detail in terms of how we want to get this information. As background, it's not a great idea to fully load a dylib at compile time since it can execute arbitrary code (see __attribute__((constructor))) just by being loaded and may have dependencies that we don't know about or may load dependencies that conflict with the binding tool itself.

TypeMetadata is designed to be used in any place that a Swift call needs a type metadata object, such as implicit arguments in a generic function or in an existential type. To get one, you should use this as the return type for a Metadata Accessor function or the appropriate Swift runtime call to generate/get them from a cache for tuples, functions etc.

Added issues to address:
#2800
#2801
#2802
#2803

@@ -292,7 +293,7 @@ private List<BaseDecl> CollectDeclarations(IEnumerable<Node> nodes, BaseDecl par
{
decl = CreateClassDecl(node, parentDecl, moduleDecl);
}
typeRecord.SwiftTypeInfo = swiftTypeInfo;
typeRecord.SwiftTypeInfo = swiftTypeInfo;
Copy link
Member

Choose a reason for hiding this comment

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

This doesn't look intentional? Unindent by one space?

/// </summary>
[Flags]
public enum TypeMetadataFlags {
/// <summary>
Copy link
Member

Choose a reason for hiding this comment

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

Would it make sense to add a None = 0 value, since this enum represents flags?

Comment on lines 16 to 24
MetadataKindIsNonType = 0x400,
/// <summary>
/// The metadata doesn't live on the heap
/// </summary>
MetadataKindIsNonHeap = 0x200,
/// <summary>
/// The type is private to the runtime
/// </summary>
MetadataKindIsRuntimePrivate = 0x100,
Copy link
Member

Choose a reason for hiding this comment

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

Is MetadataKind a common prefix for all values, or will there be more flags that aren't MetadataKind flags? If the former, the prefix should be removed:

Suggested change
MetadataKindIsNonType = 0x400,
/// <summary>
/// The metadata doesn't live on the heap
/// </summary>
MetadataKindIsNonHeap = 0x200,
/// <summary>
/// The type is private to the runtime
/// </summary>
MetadataKindIsRuntimePrivate = 0x100,
IsNonType = 0x400,
/// <summary>
/// The metadata doesn't live on the heap
/// </summary>
IsNonHeap = 0x200,
/// <summary>
/// The type is private to the runtime
/// </summary>
IsRuntimePrivate = 0x100,

Comment on lines 142 to 145
get {
ThrowOnInvalid ();
long val = ReadPointerSizedInt (handle);
if (val == 0)
Copy link
Member

Choose a reason for hiding this comment

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

Looks like there's a mix of spaces and tabs here.

@rolfbjarne
Copy link
Member

For the time being I removed SwiftTypeInfo which uses info pulled directly from the data structures in the dylib. We should discuss this in more detail in terms of how we want to get this information. As background, it's not a great idea to fully load a dylib at compile time since it can execute arbitrary code (see __attribute__((constructor))) just by being loaded and may have dependencies that we don't know about or may load dependencies that conflict with the binding tool itself.

Also you can't load dylibs for other than the current platform (so you won't be able to load dylibs for iOS on macOS for instance).

/// <summary>
/// Represents the type metadata for a Swift type
/// </summary>
public readonly struct TypeMetadata : IEquatable<TypeMetadata> {
Copy link
Member

Choose a reason for hiding this comment

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

How this correlates with SwiftMetadata? Do we plan to use metadata for type semantics on the C# side or only as an unmanaged pointer for callconv?

Copy link
Author

Choose a reason for hiding this comment

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

SwiftMetadata is based off the same type, but the difference here is that I'm not trying to define it as a ref struct but an struct with an opaque pointer so that it's easy to manipulate, compare, hash, and pass to and from p/invokes (the most common operations by far) and because it is going to escape the stack.
SwiftMetadata as is feels like a binding-time type not a runtime type.
I learned early on that we can't rely on it at binding time because of generics. It appears the only thing it gets used for at binding time is putting in a Size value in the StructLayout attribute.
For this I have several questions: 1 - do we need that? 2 - if we do, can't we get it in some other way (for example, follow the steps in the doc'n here.
In the larger picture, we need a binding-time type database, which is it's own thing, but certainly one of the things we can put into in optional properties for Size, Stride, and Alignment so that we can calculate a new Struct's size. But like I said, that's a larger discussion.

Copy link
Member

@jkurdek jkurdek Nov 22, 2024

Choose a reason for hiding this comment

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

1 - do we need that?

I think this might be relevant #2796 (comment). tldr: we need to check

Copy link
Author

Choose a reason for hiding this comment

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

It's not really relevant since we can't know unbound generic type sizes at compile time ever. Having the Size at compile time is only beneficial for frozen structs and frozen enums.

Copy link
Member

@jkurdek jkurdek left a comment

Choose a reason for hiding this comment

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

Thanks for bringing that in! My only concern at the moment is that we have now both TypeMetadata and SwiftMetadata which duplicate some code and as far I can understand duplicate some functionality. I think we should discuss the boundaries of responsibility / merge those two

/// Represents the type metadata for a Swift type
/// </summary>
public readonly struct TypeMetadata : IEquatable<TypeMetadata> {
readonly IntPtr handle;
Copy link
Member

Choose a reason for hiding this comment

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

Will this become SwiftHandle in the future?

Copy link
Author

Choose a reason for hiding this comment

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

That's a great question - since this is a private member and we should never (1) need to access this outside of the TypeMetadata (and I don't think we ever would) and (2) get this type from any other place that as an implicit argument passed to us from Swift or as a return from an explicit call, it's fine to leave it as an IntPtr.

@stephen-hawley
Copy link
Author

Thanks for bringing that in! My only concern at the moment is that we have now both TypeMetadata and SwiftMetadata which duplicate some code and as far I can understand duplicate some functionality. I think we should discuss the boundaries of responsibility / merge those two

My inclination is that the binding time functionality of SwiftMetadata should exist in a different form and that TypeMetadata should be kept as bare-bones as possible.

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.

4 participants