Skip to content

Conversation

stbergmann
Copy link
Contributor

...for cases where a dynamically given user-defined type is known to be ABI-compatible with a statically given wire type (e.g., an enum type being compatible with its underlying type, or a struct type being compatible with const void*; for the latter, a returned const void* needs to be transformed somehow into the desired dynamic type before destructors are run and the pointed-to object is destroyed).

In LibreOffice, I have a scenario where I combine val with a C++ Any type that dynamically knows what type it holds, which does not fit with the statically typed val constructor and as getter. Prior to d8dda21 "[embind] Use a single invoker mechanism (#24577)", I had tapped into the internals of emscripten/val.h (https://git.libreoffice.org/core/+/c35985a4b42d6a7d654b4fd1f99a966b75ee28a6%5E%21 "Embind construction of UNO Any enum", https://git.libreoffice.org/core/+/2995a0e0785911322c9d57e98b925073ff6cb6bd%5E%21 "Embind construction of UNO Any sequence/struct/exception/interface"), which no longer works. So I'm proposing here adding the relevant code (which only makes sense for __has_feature(cxx_rtti)) to Emscripten.

(The JS code now needs to keep track and reuse generated method callers. I have no idea how better to implement in JS such a lookup map from signatures (tuples of EM_INVOKER_KIND values and argument types) to method caller IDs, other than going via a cheesy string representation?)

@sbc100 sbc100 requested a review from RReverser July 28, 2025 19:06
@RReverser
Copy link
Collaborator

I'm having trouble reasoning about this code, to be honest, but then, I'm not that familiar with C++ RTTI and also hard to say what it's supposed to do without a test / example. Could you add one please and maybe @brendandahl can also take a look?

Just wanted to say that I also wanted to submit one final PR that changes caller mechanism further that I've been working towards, but had a few setbacks that delayed it. I don't want to block this PR on mine, just saying we might end up having some further merge conflicts.

@stbergmann
Copy link
Contributor Author

Yeah, sorry for not adding a test example from the get-go. Added one now, hope it clarifies things a bit (it might still look a bit unmotivated that it wants to use std::type_info, but the real scenario that I'm facing is bigger and more complex, and that kind of dynamic behavior does make sense there).

@brendandahl
Copy link
Collaborator

I haven't looked too deeply at this yet, but a few initial thoughts:

  1. Have you seen the custom marshaling and could that be used to achieve what you want?
  2. Would this be easier if we supported std::any as a binding type?

...for cases where a dynamically given user-defined type is known to be
ABI-compatible with a statically given wire type (e.g., an enum type being
compatible with its underlying type, or a struct type being compatible with
`const void*`; for the latter, a returned `const void*` needs to be transformed
somehow into the desired dynamic type before destructors are run and the
pointed-to object is destroyed).
@stbergmann
Copy link
Contributor Author

I haven't looked too deeply at this yet, but a few initial thoughts:

1. Have you seen the [custom marshaling](https://github.com/emscripten-core/emscripten/blob/main/test/embind/test_custom_marshal.cpp) and could that be used to achieve what you want?

2. Would this be easier if we supported `std::any` as a binding type?

It doesn't look like either of those would help me here. My scenario is that at runtime I know that I have either (a) a (statically unknown) enumeration type, for which all I know dynamically at runtime is that its underlying type is int; or (b) a (statically unknown) struct type, for which all I know dynamically at runtime is a (pointer to a) function (operating on void pointers) that can copy an instance of that struct type.

And e.g. std::any only allows to access a contained value of statically-known type (there is no generic, void-pointer std::any "value getter function", just the statically-typed std::any_cast). And Emscripten's custom marshalling doesn't seem to help me out here either (and on the rest of the surface, the existing marshalling for the involved types is just fine, it's just this one special additional use case that isn't served.)

I acknowledge that this is some rather specialized use case. But it would be great if we could keep it supported somehow...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants