COM ABI support?

Hi all,

Just curious, does anyone know how much of the Microsoft COM ABI
subset of the MSVC C++ ABI Clang currently supports? Can clang be used
to implement COM objects and interfaces using C++ inheritance (i.e.
instead of using C-style explicit function tables, etc.?)

(I'm hoping this is a cogent question rather than something which
reveals my ignorance/misunderstanding of the situation...)

Thanks!
Stephen

Did you try COM with Clang?
I doubt COM requires special ABI support from the compiler.
A COM interface is just a group of abstract virtual function,
same as how we use the concept "interface" in C++.
There is no special thing in COM, IMHO.

Wang,

Correct me if I'm wrong, but, as I understand it (my last usage of COM
was maybe 10 years ago...), COM interfaces are a language-independent
ABI that happen to be implementable using C++ virtual inheritance
using MSVC. In other words, any language can access COM objects by
creating data structures that map to the interface exposed by COM
(which allows dynamic dispatch through tables of function pointers and
standardized interface querying and memory management interface);
however, in order for COM objects to also be C++ objects (i.e. for the
dynamic dispatch in COM to map to virtual dispatch in C++), it
requires that, among other things, the C++ ABI used by the compiler
creates virtual tables that are laid out in the same manner that COM
objects lay out their interface tables. Since Microsoft is the author
of the COM ABI and also MSVC, they obviously saw to it that the
latter's ABI is compatible with the former; however, full MSVC C++ ABI
compatibility is not required to be compatible with the COM subset.

The reason why I am asking is because it seems like the difficult part
of supporting the MSVC C++ ABI is reverse engineering various details
that Microsoft does not have documented anywhere, like name mangling
schemes and various rules for things like constructor/destructor
creation and linkages. However, it seems like a lot of this is not
really required for the COM subset; for the most part, just making
virtual table structures and calling conventions conform to the COM
ABI would be enough for COM support, so I'm wondering if that's
already there or not. I could not find any prior discussion about this
topic in particular.

Thanks,
Stephen

COM uses pure abstract base classes, but *not* virtual inheritance. Which makes for a simpler vtable layout. And is the reason why you have to be careful returning the correct pointer in IUnknown::QueryInterface (COM's dynamic_cast on steroids) when inheriting from multiple interfaces.

-Nico

Hi Nico,

Correct me if I'm wrong, but, as I understand it (my last usage of COM
was maybe 10 years ago...), COM interfaces are a language-independent
ABI that happen to be implementable using C++ virtual inheritance
using MSVC.

COM uses pure abstract base classes, but *not* virtual inheritance. Which
makes for a simpler vtable layout. And is the reason why you have to be
careful returning the correct pointer in IUnknown::QueryInterface (COM's
dynamic_cast on steroids) when inheriting from multiple interfaces.

I was about to answer the same thing, but hesitated. I know COM avoids
use virtual inheritance, and I think I've heard somebody say it's for
portability.

But the vtable ABI isn't standardized either, is it? Do all compilers
just happen to implement it the same way?

Thanks,
- Kim

All compilers try to follow the itanium ABI, except msvc :slight_smile:

I was about to answer the same thing, but hesitated. I know COM avoids
use virtual inheritance, and I think I've heard somebody say it's for
portability.

But the vtable ABI isn't standardized either, is it? Do all compilers
just happen to implement it the same way?

All compilers that allow C++ to implement COM objects must implement
virtual tables (but not, for example, name mangling) in the same way
for COM ABI compatibility; I was wondering if Clang did so already or
not.

Stephen

Nikola Smiljanic <popizdeh@gmail.com>
writes:

But the vtable ABI isn't standardized either, is it? Do all compilers
just happen to implement it the same way?

All compilers try to follow the itanium ABI, except msvc :slight_smile:

I realize that you are saying this tongue-in-cheek, but anyways...

MSVC++, Borland C++, Watcom C++... all they existed much before the
Itanium existed. When the Itanium C++ ABI came into existence, they
(specially MSVC++) had no incentives for switching to it. In the closed
source world changing the C++ ABI is a big issue. And using an ABI hard
to duplicate (i.e. undocumented) has its advantages from the competitive
POV.

As for COM, AFAIK it is fairly simple to comply with (when compared with
the full MSVC++ ABI.) IIRC it is fully documented too. A quick web
search should provide plenty of material.

All compilers that allow C++ to implement COM objects must implement
virtual tables (but not, for example, name mangling) in the same way
for COM ABI compatibility; I was wondering if Clang did so already or
not.

Stephen

(To clarify, I mean they must implement the subset of virtual tables
needed to implement COM objects in the same way, which is actually
much easier than implementing all virtual tables in the same way...)

Personally, I've never tried and I don't have any test code for this handy.
Some things that are probably broken that would affect COM:

- Record layout. Warren has a patch for this. One of the big things is
the alignment of all the non-vfptr fields. These appear to be laid out as
though there is a parent struct with a vfptr and then an anonymous struct
containing all the fields. If the object doesn't contain any fields with
more than pointer alignment, this shouldn't matter.

- Virtual method calls with multiple inheritance. Timur has a patch for
this. The big change is that there are fewer thunks because the 'this'
pointer on entry is adjusted to point at the vfptr used to perform the
dispatch. If you don't implement multiple interfaces, this shouldn't
matter.

- Outside the scope of COM, things like virtual inheritance and virtual
destructors are broken still.

Those are some pretty big caveats, so I assume COM interop is broken until
tested.

Thanks for the color.

Just curious, where do we stand with straight Windows C ABI support?
It seems like, given straight C ABI support, COM interop would be
relatively easy just by reverse engineering the C headers generated by
Microsoft's IDL compiler, right?

I could be wrong and misunderstanding the complexity (also, just
knowing how it works doesn't imply knowing an easy way to implement it
within the structure of Clang's codebase, I understand.)

Stephen

I realize that you are saying this tongue-in-cheek, but anyways...

MSVC++, Borland C++, Watcom C++... all they existed much before the
Itanium existed. When the Itanium C++ ABI came into existence, they
(specially MSVC++) had no incentives for switching to it. In the closed
source world changing the C++ ABI is a big issue. And using an ABI hard
to duplicate (i.e. undocumented) has its advantages from the competitive
POV.

Well, independent of motives, relying on a subset of the C++ ABI (and
forcing others on your platform to do the same, by not making the full
C++ ABI documented) has some technical advantages, arguably: it means
that ABI compatibility between C++ and other languages can be achieved
(jn a subset of cases) without forcing the implementations of other
languages to understand something as esoteric as C++ name mangling.

Stephen

COM uses pure abstract base classes, but *not* virtual inheritance. Which
makes for a simpler vtable layout. And is the reason why you have to be
careful returning the correct pointer in IUnknown::QueryInterface (COM's
dynamic_cast on steroids) when inheriting from multiple interfaces.

-Nico

Thanks, I did not realize that (it's all hidden behind macros when you
use the IDL-generated files, so it's hard to see what is going on...).

Not relying on virtual inheritance does make a lot more sense in
keeping the ABI simple, but, as you say, does require care when
implementing objects.

Stephen

Hi,

Hi Nico,

But the vtable ABI isn't standardized either, is it? Do all compilers
just happen to implement it the same way?

Some don't. IBM's C/Set++ or the VisualAge C++ compiler for OS/2
didn't (the pointers in the vtable were 8 bytes apart, despite it
being a 32-bit compiler). Our (cross-platform: Windoes, OS/2, Mac,
Unix, NetWare, ...) product had a library with a COM wrapper on it.
All platforms implemented COM in C++, except OS/2, where we had to use
plain C to get the correct layout.

Csaba

Some don't. IBM's C/Set++ or the VisualAge C++ compiler for OS/2
didn't (the pointers in the vtable were 8 bytes apart, despite it
being a 32-bit compiler). Our (cross-platform: Windoes, OS/2, Mac,
Unix, NetWare, ...) product had a library with a COM wrapper on it.
All platforms implemented COM in C++, except OS/2, where we had to use
plain C to get the correct layout.

Out of curiosity, what were the extra 4 bytes in each vtable entry
for? Was this part of some implementation strategy to support
pointers-to-member-functions, or something like that?

Stephen

Hi Stephen,

a somewhat related thought that comes to my mind...

I have no idea if the following is feasible...it appears to me at a superficial level that the C++/CX reference counting extensions for WindowsRT development are pretty much the same as ARC in ObjC. One might be able to implement that functionality with the ARC infrastructure.

C++/CX extends the language a lot though, and syntax-wise (and in some features semantic-wise) it’s very similar to C++/CLI.

Has there been any talk of adding this stuff to the c++ stander. partial classes in particular look very useful to me.

This discussion seems to be wandering pretty far off-topic. There are
better mailing lists (such as the discussion lists on isocpp.org) that you
might try.