<div dir="ltr">Hey Slava,<div><br></div><div>Thanks a lot for your detailed responses; it definitely helps to understand how structs are passed to the C++ function.</div><div><br></div><div>In a separate email, Joe Groff mentioned that there was a difference between passing the enum value and passing a pointer to it. I think that might be the root of my problem. I'll try a few things and send over a better code sample tonight, if there are still issues.</div><div><br></div><div>Best,</div><div>Austin</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Jan 6, 2016 at 11:37 AM, Slava Pestov <span dir="ltr"><<a href="mailto:spestov@apple.com" target="_blank">spestov@apple.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi Austin,<br>
<div><div class="h5"><br>
> On Jan 1, 2016, at 10:58 PM, Austin Zheng via swift-dev <<a href="mailto:swift-dev@swift.org">swift-dev@swift.org</a>> wrote:<br>
><br>
> Hello,<br>
><br>
> I'm trying to better understand how calls are made between the Swift standard library code and the runtime entry points. I've read through most of the documentation in the repo but still have some questions.<br>
><br>
> More specifically, here's an example: the '_EnumMirror' struct below represents a mirror reflecting a value whose type is an enum.<br>
><br>
> ------<br>
><br>
> struct _EnumMirror : _MirrorType {<br>
> let data: _MagicMirrorData<br>
> var value: Any { return data.value }<br>
> var valueType: Any.Type { return data.valueType }<br>
> // ... more stuff<br>
><br>
> var caseName: UnsafePointer<CChar> {<br>
> @_silgen_name("swift_EnumMirror_caseName")get<br>
> }<br>
> // ... (more stuff)<br>
> }<br>
><br>
> ------<br>
><br>
> The 'caseName' property represents the name of the enum value's case (e.g. "FirstCase" in Foo.FirstCase) as a C string. This property's getter calls into a C++ runtime function named "swift_EnumMirror_caseName", which is reproduced below (from Reflection.mm):<br>
><br>
> extern "C"<br>
> const char *swift_EnumMirror_caseName(HeapObject *owner,<br>
> const OpaqueValue *value,<br>
> const Metadata *type) {<br>
> if (!isEnumReflectable(type))<br>
> return nullptr;<br>
><br>
> const auto Enum = static_cast<const EnumMetadata *>(type);<br>
> const auto &Description = Enum->Description->Enum;<br>
><br>
> unsigned tag;<br>
> getEnumMirrorInfo(value, type, &tag, nullptr, nullptr); // effectively, same as "tag = type->vw_getEnumTag(value);"<br>
> return getFieldName(Description.CaseNames, tag);<br>
> }<br>
><br>
> Now, I had a few questions about exactly how this interoperation works, because I'd like to be able to get the name of an enum case using this entry point from a different context (not from within an _EnumMirror property).<br>
><br>
> * swift_EnumMirror_caseName takes three arguments, but the Swift call site doesn't seem to specify what gets passed into the function.<br>
<br>
</div></div>The three arguments together form the 'self' value of the call. That is, an EnumMirror is a struct containing a pointer to the owner object, a pointer to the value being reflected, and runtime type information for the value. You can see this if you look at how the _MagicMirrorData struct is defined on the swift side.<br>
<span class=""><br>
> Is there a convention that is implicitly passing properties on _EnumMirror as arguments into the C++ function when it's being called? I did note that there were other runtime entry points (like "swift_MagicMirrorData_summary") where the number of arguments in the Swift function matched the number of arguments in the C++ function, but in those cases the Swift function was a free function and not a method.<br>
<br>
</span>Right.<br>
<span class=""><br>
><br>
> * What I really want to do is to get the tag of an enum. I wrote a different entry point that omits the unused "owner" property and simply calls swift_EnumMirror_caseName with nullptr as the first argument. This other C++ function takes 'value' (an OpaqueValue*) and 'type' (a Metadata*). I've surmised that 'type' should be the Swift metatype of the enum instance (e.g. myEnum.dynamicType), and I do get the case names table. However, if I pass in the enum instance itself as 'value', my tag is always retrieved as 0.<br>
<br>
</span>The value should indeed be a pointer to the enum value itself. Not sure why it's not working for you, maybe you can share more code?<br>
<span class=""><br>
> I noticed that there's some sort of indirection in the form of "vw_getEnumTag", which goes through something called the "value witness". Is there somewhere I can read up about the value witness concept? I assume the reason the 'original' code worked was because it was passing in a different object as 'value', maybe one that could serve as a value witness for the reflected-upon instance's type.<br>
<br>
</span>The value witness table is a member of the type metadata. It contains entry points for runtime manipulation of values of that type. The value witness table is used for runtime generics (when I have a generic parameter 'T' and a value of type 'T', the value witness functions are used for copying/moving/destroying/etc values of type 'T'). They are also used for reflection.<br>
<br>
They're not really documented anywhere except for in the source code itself -- see here:<br>
<br>
include/swift/Runtime/Metadata.h<br>
lib/IRGen/ValueWitness.h<br>
<br>
Slava<br>
<span class=""><br>
><br>
> Thanks a lot for your time.<br>
><br>
> Best,<br>
> Austin<br>
><br>
</span>> _______________________________________________<br>
> swift-dev mailing list<br>
> <a href="mailto:swift-dev@swift.org">swift-dev@swift.org</a><br>
> <a href="https://lists.swift.org/mailman/listinfo/swift-dev" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-dev</a><br>
<br>
</blockquote></div><br></div>