[PATCH] D48807: Add llvm::Any

David Blaikie via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 2 13:32:29 PDT 2018


dblaikie added a comment.

In https://reviews.llvm.org/D48807#1149775, @zturner wrote:

> I've wanted this for quite a long time.  My original motivation for this was back when i was working primarily in LLDB.  There's a lot of places where `void*` is passed around as a generic parameter to a user callback.  So, for example, you say `DoSomethingAsynchronously(Callback, Param)` and when the thing is finished, it invokes `Callback(Param)`.  There are obviously better ways to do this if you're designing this from the beginning, but it's not always easy to retrofit that into an existing design.  So I think several places in LLDB could be cleaned up by replacing some `void*` with `Any`.  Note those places still exist today, so `Any` could be useful there right now.


Would it be expensive to reimplement those APIs using stateful functors while providing the backwards compatibility with something like:

  void register(void (*f)(void*), void *v) { register([f, v] { f(v); }); }

Or is there something in the implementation (rather than the existing usage) that makes migrating difficult?

> More recently while designing a basic API for a tracing library, I've gravitated towards a design where the library generates events (represented by some structure) depending on what happens.  But since tracing is heavily platform dependent, there's only so much of this that you can abstract away into a common structure and there will be some additional pieces that only make sense on the particular platform.  So you call:
> 
>   unique_ptr<EventBase> Event = llvm::trace::WaitForEvent();
>   // Do something depending on what kind of event it is.
>   llvm::trace::ContinueFromEvent(std::move(Event));
> 
> 
> In order for every possible platform to implement this correctly, there may need to be some platform-specific state maintained between the call to Wait and the call to Continue.  Linux might need to pass the exact signal value and parameters.  Windows might need to pass the exact `EXCEPTION_RECORD` structure <https://docs.microsoft.com/en-us/windows/desktop/api/winnt/ns-winnt-_exception_record> that the OS filled out for us right before we return from `WaitForEvent()`.  It's useful to be able to put that into an `Any`, so that we have something like:
> 
>   class EventBase {
>     TraceEventType Type;
>     uint64_t ThreadId;
>     uint64_t ProcessId;
>     Any PlatformPiece;
>   };
>   
>   class ThreadCreatedEvent : public EventBase {
>     void *EntryPoint;
>     void *TlsArea;
>     // Etc.
>   };
>   
>   class BreakpointEvent : public EventBase {
>     uint64_t Address;
>   };
> 
> 
> and so forth and so on.  When creating this struct before returning from `WaitForEvent()`, the library can set `PlatformPiece` to some structure that would contain any platform-specific state needed to properly continue.  I prefer not to use inheritance and `llvm::cast` here (e.g. `WindowsBreakpointEvent`, `PosixBreakpointEvent`, etc) because it just leads to inheritance hierarchy explosion and ultimately it's no more type-safe than `any` (someone still has to make an assumption about exactly what type it is).

If this is host-platform specific, why would this need to be runtime variable at all? Wouldn't the PlatformPiece be hardcoded to some specific layout based on the host platform the compiler was built for/running on?

> Hopefully that all makes sense.

I think so - hopefully I'm replying in a way that does too.


https://reviews.llvm.org/D48807





More information about the llvm-commits mailing list