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

Reply via email to