[swift-dev] Understanding runtime entry points

Austin Zheng austinzheng at gmail.com
Wed Jan 6 14:57:29 CST 2016


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 <spestov at apple.com> wrote:

> Hi Austin,
>
> > On Jan 1, 2016, at 10:58 PM, Austin Zheng via swift-dev <
> swift-dev at 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 at swift.org
> > https://lists.swift.org/mailman/listinfo/swift-dev
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-dev/attachments/20160106/cd58334a/attachment.html>


More information about the swift-dev mailing list