...as emsdk 5.0.3 deprecated the predefined EMSCRIPTEN macro (see
<https://github.com/emscripten-core/emscripten/commit/506052bd8b4e23ded7f2351c62ca3b24d40c8cf3>
"Warn about usage of deprecated EMSCRIPTEN macro. NFC (#26381)"), causing
failures like
> In file included from static/source/unoembindhelpers/PrimaryBindings.cxx:29:
> In file included from include/sfx2/viewsh.hxx:35:
> In file included from include/editeng/outliner.hxx:32:
> In file included from include/tools/color.hxx:26:
> include/osl/endian.h:66:15: error: macro 'EMSCRIPTEN' has been marked as deprecated: use __EMSCRIPTEN__ instead [-Werror,-Wdeprecated-pragma]
> 66 | #elif defined EMSCRIPTEN
> | ^
> /home/sberg/emsdk/5.0.4/emsdk/emscripten/main/cache/sysroot/include/emscripten/emscripten.h:35:66: note: macro marked 'deprecated' here
> 35 | #pragma clang deprecated(EMSCRIPTEN, "use __EMSCRIPTEN__ instead")
> | ^
To avoid confusion, also suppress the -D$(OS) in
solenv/gbuild/platform/unxgcc.mk that would unnecessarily keep defining
EMSCRIPTEN.
Change-Id: Ic1f187cf1c6417cd95d4092e9cea01a665bd1b2f
Reviewed-on: https://gerrit.collaboraoffice.com/c/core/+/34
Reviewed-by: Michael Stahl <michael.stahl@collabora.com>
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
(cherry picked from commit 50291c2ed83bdb49bb827a4a12905d94b8c42035)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/205167
Tested-by: Jenkins
Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
...that had been added with f90c68316c "WASM: add
Emscripten demo application". Whatever the original intention, it has probably
served its purpose by now---and now only negatively impacts (re-)build times.
Change-Id: I2bda8d12b91e741c4d0f7d3f02597e0e9505a73a
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/172087
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <stephan.bergmann@allotropia.de>
...as there can be situations (cf. the newly added test code in embindtest.js)
where objects that need to be deleted are passed as payload of the exception
value to be thrown. So there now is a (mandatory, as Embind doesn't allow to
implicitly pass undefined) third parameter now that must be an array of objects
on which to call .delete().
(75fe059974 "Embind: throwUnoException from JS"
had deliberately made throwUnoException take two arguments, because if it
"directly took a css::uno::Any argument, JS client code would need to create one
with `new Module.uno_Any(...)` and call .delete() on it, but there is no place
where it could call .delete()". There now would be such a place, but it would
probably still be tedious most of the time to explicitly construct a new uno_Any
to pass into throwUnoException both as the exception and in the toDelete array.
So keep that design decision to have throwUnoException take individual type and
value arguments.)
Change-Id: Idec029d9e500457b02d20d899b9a2328cd7a5d7e
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/171024
Reviewed-by: Stephan Bergmann <stephan.bergmann@allotropia.de>
Tested-by: Jenkins
As we need to generate data upfront for all the UNOIDL entities anyway, we might
just as well extend that with annotations (keyed to some new
Module.unoTagSymbol) that are useful at runtime. The general idea is to let
such annotations be objects with certain well-known keys, the main one being a
string-valued `kind` representing the UNOIDL kind of the annotated data.
As a first thing, individual UNOIDL enum type enumerators are annotated with a
`type` representing the UNOIDL enum type they belong to. That turns out to be
useful for some experimental approach of mine where I wrap the Embind-based JS
binding in something that makes the result more idiomatic JS.
Change-Id: Iec466bab05ba3d1b56b2398e5c361465af49dc13
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/170398
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <stephan.bergmann@allotropia.de>
...after 875997c896 "Properly implement
cppu::throwException for Emscripten" had implemented only those parts that were
absolutely necessary for that exception throwing. As detailed in the commit
message there, wasmcallgen has been extended to additionally generate all the
required vtable slot call trampoline code (which cannot be generated on the fly
for Wasm, as would be done for other platforms). Consequently, some of the
"callvirtualfunction"-centric file names have been changed to "generated" as the
output of wasmcallgen is now more general. (And wasmcallgen itself should also
be renamed, in a follow-up commit. And when adding to the wasmcallgen code
here, some existing parts of its implementation have been cleaned up, too.)
There is no direct way to test this half of the Wasm UNO bridge directly from
unotest/source/embindtest/embindtest.js, so a new
org.libreoffice.embindtest.BridgeTest singleton has been added, which triggers
new test code in unotest/source/embindtest/embindtest.cxx that tests the bridge
in a way similar to testtools' bridgetest machinery.
Change-Id: I521a1d6c2160aedc814f7603b0b99861e5fbd1eb
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/170374
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <stephan.bergmann@allotropia.de>
...by implementing (for now) just enough of the cpp2uno half of the Wasm UNO
bridge to make it work. In general, that half suffers from the same issue as
the already-implemented uno2cpp half, namely that Wasm doesn't allow to generate
code on the fly (which, in this case, would be needed to implement the vtable
slot trampoline functions). So, for now just hard-code the few
vtableSlotFunction_* that are needed by the UNO interfaces for
cppuhelper/source/exc_thrower.cxx. (A proper fix would probably use the same
approach as for the uno2cpp half, and use something like wasmcallgen to generate
at least all the vtableSlotFunction_* needed for udkapi/offapi upfront.)
The RTTI for the exceptions needs to be unique across the executable for
exception catching to actually work (as it compares exception types by RTTI
address rather than by name). We thus need to export all the relevant RTTI
symbols (which I hacked into the existing wasmcallgen for now, even if that
makes that executable's name a slight misnomer now), and access them with a new
jsGetExportedSymbol. (This exporting would also be needed by the "classical"
approach of using dlsym on the main module, cf.
<https://gerrit.libreoffice.org/c/core/+/167187> "WIP: Emscripten: Set up
support for dlsym from main module". And while that dlsym approach would work,
it is much simpler to just use that jsGetExportedSymbol than to use a dlsym
detour, and thereby avoid all the hassle of -sMAIN_MODULE detailed in the commit
message of that Gerrit change.)
It also turned out that including Emscripten's <cxxabi.h> needs
__USING_WASM_EXCEPTIONS__ to be defined, because it uses that in its declaration
of __cxa_throw. (The source for setting that define internally in Emscripten is
get_cflags in the emsdk's upstream/emscripten/tools/system_libs.py, which
defines __USING_EMSCRIPTEN_EXCEPTIONS__ for the non-Wasm, Emscripten JS
exception mode, and defines __USING_WASM_EXCEPTIONS__ for
--enable-wasm-exceptions, which we use. The commit message of
f4ec967599 "Fix redefinion of Emscripten
__cxxabiv1::__cxa_exception" documents my prior confusion of when one or the
other would be defined.)
Change-Id: Id08765ab5b4ce1553dc3a61648324526185cb64c
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/170246
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <stephan.bergmann@allotropia.de>
...with a new Module.catchUnoException JS function that can be used in a JS
catch block to provide the thrown UNO exception as an Any. (For a non-C++
exception, it rethrows the exception, and for a non-UNO C++ exception it maps it
to css.uno.RuntimeException.)
The implementation reuses parts of bridges/source/cpp_uno/gcc3_wasm/, which have
been moved to a new StaticLibrary_emscriptencxxabi.
Change-Id: I708fe6121c43a1b9736de5dff449f6c4f32a45f3
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/169325
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <stephan.bergmann@allotropia.de>
When a JS function implementing a UNO interface method returns any or a sequence
type (like queryInterface, getType, and getImplementationId in uno.js), it
could not create a new instance of that type and return it, as it would have
needed to call .delete() on that instance, but couldn't. In uno.js, getType and
getImplementationId solved that by returning pre-instantiated instances that
were deleted in the final release call. But that did not work for
queryInterface, as pre-instantiating the relevant any instances would have
caused cyclic references that would have caused the final release call never to
occur.
So redesign the C++ the_wrapper classes (used by the Embind allow_subclass
machinery): If a UNO interface method returns any or a sequence type (i.e., a
type on which .delete() must be called), change the JS implemenation's return
type from by-value (which meant that the C++ code received a copy) to
by-reference---which means that now the C++ code can access the original
instance and delete it. But which also means that the JS code must always
return a fresh instance now!
(Ideally, the embindmaker-generated code would use by-pointer rather than
by-reference for that return type, but that caused
> emsdk/upstream/emscripten/cache/sysroot/include/emscripten/wire.h:116:19: error: static assertion failed due to requirement '!std::is_pointer<com::sun::star::uno::Any *>::value': Implicitly binding raw pointers is illegal. Specify allow_raw_pointer<arg<?>>
> 116 | static_assert(!std::is_pointer<T*>::value, "Implicitly binding raw pointers is illegal. Specify allow_raw_pointer<arg<?>>");
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~
errors with no obvious place where to put such allow_raw_pointer markers, so
lets go with this little hack at least for now.)
Change-Id: I3c37b79b8fbf09c19782c6532bc95d4d63505c63
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/169008
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <stephan.bergmann@allotropia.de>
...that proved useful in experiments wrapping a JS Proxy around the Embind
representation of C++ UNO objects.
Change-Id: Ia4018ec8dee2c222fb76ba8e2f529f4845f0134c
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/168518
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <stephan.bergmann@allotropia.de>
...by making the general UNO -> C++ function call case work (modulo handling
exceptions, which I'll look into later).
Wasm call_indirect unfortunately needs to statically know the call target's
signature, so we statically need to know all possible signatures. So introduce
wasmcallgen helper to scan the existing UNOIDL API upfront and generate the
relevant callvirtualfunction-wrapper.cxx and callvirtualfunction-inst.s code.
(The good thing is that the number of different signatures is somewhat limited,
each parameter can only be one of i32, i64, f32, or f64. So even if 3rd-party
extensions bring along new UNOIDL interface methods, chances are relatively high
that the signatures needed for them would already be covered by the existing
ones.)
Testing this can nicely be done in unotest/source/embindtest/embindtest.js via
css.script.Invocation (which internally exercises the relevant code). (Instead
of adding individual org.libreoffice.embindtest.StructLong/String etc., it would
be nicer to introduce some polymorphic StructOne<T>, but the Emind UNO binding
does not support polymorphic structs, so the embindtest.js code would not work.)
Change-Id: If829c9e3772bfd27561f3ad743d38a71d11545b6
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167308
Reviewed-by: Stephan Bergmann <stephan.bergmann@allotropia.de>
Tested-by: Jenkins
...by using UnoInOutParam in all cases. Some types whose Embind mappings don't
employ any smart pointers (like any and sequence) would have worked directly
with pointers, but others (like string and type) would have caused Embind errors
at runtime. So consistently use UnoInOutParam in all cases (and generate
bindings for all the used cases in embindmaker).
Change-Id: If26551bf4e99d10748aec1597d6e99f994dfd86e
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/166854
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <stephan.bergmann@allotropia.de>
(the types that are meant to be passed directly by pointer will need more
thought, to make them actually work)
Change-Id: Ia0f2e6f5335fad1140629477e89fc96121c2927e
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/166318
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <stephan.bergmann@allotropia.de>
$equals was the last remaining special $... method that we added to the UNO
interfaces, and it looks better anyway to turn it into a symmetric free function
(that can be called with null for either argument) that is actually independent
of specific interface types
Change-Id: I22a1d08b8b15a0ed2dd37fa9fbc95f568641dec3
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/166317
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <stephan.bergmann@allotropia.de>
...which are needed at compile time (the emscripten::class_<T> ctor always
records the address of emscripten::internal::raw_destructor<T>, even in cases
where it never calls it; and raw_destructor internally calls delete, but the
dtor of the UNO interface types is protected) but not at runtime (as those UNO
interface types are only accessed through css::uno::Reference smart pointers)
Change-Id: I09e4f258f8dfc0fc53c0fe7210c7f709d86be176
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/166304
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <stephan.bergmann@allotropia.de>
The existing code had two issues: For one, e.g. calling a function that
returned a null interface reference mapped that to JS null, while querying an
object for a non-supported interface via `new css.uno.X...(y)` mapped that to
an "empty" JS object instead. (So checking for a non-null reference needed to
be done as either `x !=== null` or as `x.is()`, depending on context.) And for
another, while calling $is() on a non-"empty" object worked fine, it failed on
such an "empty" object (as the Embind internals of that object lacked the $$
property).
So change the querying mechanism from the `new css.uno.X...(y)` constructor to a
`css.uno.X....query(y)` function call syntax, which now returns JS null when
querying for a non-supported interface. (And drop the broken $is method.)
Change-Id: I8fa488ab2892423f2a461d9b72db47e1d4df3b8d
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/166255
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <stephan.bergmann@allotropia.de>
(If throwUnoException directly took a css::uno::Any argument, JS client code
would need to create one with `new Module.uno_Any(...)` and call .delete() on
it, but there is no place where it could call .delete(), so make
throwUnoException take two arguments instead and assemble the css::uno::Any on
the C++ side.)
Change-Id: Iae4ae6af804354d5cf752115e272b79d61427440
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/166253
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <stephan.bergmann@allotropia.de>
Given the reasoning in 0957ee9f5d "Embind: No need
for $query", those sharing_policies appear to be (solely) about upcasting of
those smart pointers, and css::uno::Type doesn't involve any class hierarchies,
so NONE ("no upcasting", in genericPointerToWireType in Emscripten's
src/embind/embind.js) appears to be the best match here.
Change-Id: I74b74d3c31cc17a7fd0a6d072160316e60884557
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/166160
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <stephan.bergmann@allotropia.de>
...to "upcast" from css::uno::Reference<T> to base
css::uno::Reference<css::uno::XInterface>. My understanding now is that due to
the sharing_policy::INTRUSIVE we specify for
emscripten::smart_ptr_trait<css::uno::Reference<T>>
(include/static/unoembindhelpers/PrimaryBindings.hxx), Embind can internally
"upcast" from a css::uno::Reference<T> to a base
css::uno::Reference<css::uno::XInterface> by just treating the encapsulated raw
pointer of type T* as a raw pointer of type css::uno::XInterface* (see the use
of that sharingPolicy in genericPointerToWireType in Emscripten's
src/embind/embind.js; though documentation of that Embind sharing_policy is
rather poor).
Change-Id: I6ed60a9c94af6aba6fc6119bf644da7f507a997f
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/166142
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <stephan.bergmann@allotropia.de>
...taking a full UNO Type instead of just a UNO Type class (so that it will be
able to construct Any containing sequence, enum, struct, exception, and
interface, in later steps); moving the Type argument first (as that looks more
natural), and renaming from Any to uno_Any (in line with the other uno_Type,
uno_Sequence_..., etc.)
Change-Id: I154681c4b9187f5f5d037d503652fe7bcd41adcd
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164593
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <stephan.bergmann@allotropia.de>
...where it failed with
> In file included from static/source/unoembindhelpers/PrimaryBindings.cxx:13:
> In file included from ~/emsdk/upstream/emscripten/cache/sysroot/include/emscripten/bind.h:23:
> ~/emsdk/upstream/emscripten/cache/sysroot/include/emscripten/val.h:226:20: error: assigning to 'void *' from 'const void *' discards qualifiers
> 226 | cursor->w[0].p = wt;
> | ^~
> ~/emsdk/upstream/emscripten/cache/sysroot/include/emscripten/val.h:248:3: note: in instantiation of function template specialization 'emscripten::internal::writeGenericWireType<const void>' requested here
> 248 | writeGenericWireType(cursor, BindingType<First>::toWireType(std::forward<First>(first)));
> | ^
> ~/emsdk/upstream/emscripten/cache/sysroot/include/emscripten/val.h:256:5: note: in instantiation of function template specialization 'emscripten::internal::writeGenericWireTypes<const void *>' requested here
> 256 | writeGenericWireTypes(cursor, std::forward<Args>(args)...);
> | ^
> static/source/unoembindhelpers/PrimaryBindings.cxx:309:56: note: in instantiation of member function 'emscripten::internal::WireTypePack<const void *>::WireTypePack' requested here
> 309 | emscripten::internal::WireTypePack argv(self.getValue());
> | ^
see the comment at
<https://github.com/emscripten-core/emscripten/commit/0f83fd40533248cce42464e1b9b586281202f247#r139443236>
"[Wasm64] Fix embind with addresses over 4gb (#20071)"
Change-Id: I1f472e9dc57b3abfbe1ba8a0f3a3bd70c1c484f4
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164463
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <stephan.bergmann@allotropia.de>
...which taps into the internals of emscripten::val, which is based on
std::type_info identifiers, so we need an additional statically-built mapping
between UNO (enum, for now) types and std::type_info
Change-Id: I9fc1ff33fe31a1e1052504905de446ed2193e014
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164359
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <stephan.bergmann@allotropia.de>
...which should be rare enough in practical use that it should be sufficient to
only have toString-functionality for instances mapped from C++ to JS, but no
constructor for new instances on the JS side. (The natural choice for the
latter would be a mapping of the C++
> inline Type( TypeClass eTypeClass, const ::rtl::OUString & rTypeName );
constructor, but which requires a mapping for the css::uno::TypeClass UNOIDL
enum, which is only provided "later" through CustomTarget_static/unoembind, so
would at least conceptually be a bit dirty.)
This Embind mapping treats css::uno::Type as a smart pointer for the underlying
typelib_TypeDescriptionReference, to benefit from the fallback garbage
collection (in more recent Emscripten versions, at least) for smart pointers,
obviating the need to call .delete() on each instance mapped to JS.
Change-Id: Ic113967c264c28641dfd1fe159012c85519f4a9b
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164140
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <stephan.bergmann@allotropia.de>
The constants are only reflected directly as JS values in the generated *.js
file. Reflecting them via emscripten::constant in the generated *.cxx did not
work well: Most importantly, emscripten::constant (and its underlying
_embind_register_constant) coerce all values to double, so UNO (unsigned) hyper
would not survive as JS BigInt, which would then cause e.g.
> console.assert(test.isHyper(uno.org.libreoffice.embindtest.Constants.Hyper));
passing such a (JS number, not BigInt) value into the
org.libreoffice.embindtest.XTest::isHyper method (which expects a UNO hyper) to
fail. (Also, constants of UNO boolean type would be represented as numbers 0/1
rather than as false/true.)
Change-Id: I056db0ccce0bf40eb53728fd439cc74964eb6951
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164097
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <stephan.bergmann@allotropia.de>
Upcoming code that changes the Embind'ing of UNO sequences will require
availability of the UNO type manager during that Embind init code, so only call
that after UNO has been bootstrapped (rather than as part of the initialization
of global static data, which is what EMSCRIPTEN_BINDINGS does).
Change-Id: Iba19851ffb82c055dcab10a28a8c1fafa9d2a414
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164065
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <stephan.bergmann@allotropia.de>