Hey Slava, Thanks a lot for your detailed responses; it definitely helps to understand how structs are passed to the C++ function.
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. Best, Austin On Wed, Jan 6, 2016 at 11:37 AM, Slava Pestov <spes...@apple.com> wrote: > Hi Austin, > > > On Jan 1, 2016, at 10:58 PM, Austin Zheng via swift-dev < > swift-dev@swift.org> wrote: > > > > Hello, > > > > 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. > > > > More specifically, here's an example: the '_EnumMirror' struct below > represents a mirror reflecting a value whose type is an enum. > > > > ------ > > > > struct _EnumMirror : _MirrorType { > > let data: _MagicMirrorData > > var value: Any { return data.value } > > var valueType: Any.Type { return data.valueType } > > // ... more stuff > > > > var caseName: UnsafePointer<CChar> { > > @_silgen_name("swift_EnumMirror_caseName")get > > } > > // ... (more stuff) > > } > > > > ------ > > > > 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): > > > > extern "C" > > const char *swift_EnumMirror_caseName(HeapObject *owner, > > const OpaqueValue *value, > > const Metadata *type) { > > if (!isEnumReflectable(type)) > > return nullptr; > > > > const auto Enum = static_cast<const EnumMetadata *>(type); > > const auto &Description = Enum->Description->Enum; > > > > unsigned tag; > > getEnumMirrorInfo(value, type, &tag, nullptr, nullptr); // > effectively, same as "tag = type->vw_getEnumTag(value);" > > return getFieldName(Description.CaseNames, tag); > > } > > > > 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). > > > > * swift_EnumMirror_caseName takes three arguments, but the Swift call > site doesn't seem to specify what gets passed into the function. > > 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. > > > 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. > > Right. > > > > > * 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. > > 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? > > > 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. > > 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. > > They're not really documented anywhere except for in the source code > itself -- see here: > > include/swift/Runtime/Metadata.h > lib/IRGen/ValueWitness.h > > Slava > > > > > Thanks a lot for your time. > > > > Best, > > Austin > > > > _______________________________________________ > > swift-dev mailing list > > swift-dev@swift.org > > https://lists.swift.org/mailman/listinfo/swift-dev > >
_______________________________________________ swift-dev mailing list swift-dev@swift.org https://lists.swift.org/mailman/listinfo/swift-dev