CEF3 ABI proposal

Do not post support requests, bug reports or feature requests. Discuss CEF here. Non-CEF related discussion goes in General Discussion!

CEF3 ABI proposal

Postby fddima » Thu Feb 16, 2012 7:24 am

Hi.

Based on my experience with CefGlue, - a .NET/Mono binding to CEF1 - i have some thoughts about CEF C API.
CEF-side it is code located in libcef (dll-side in cef c api docs).
Other-side it is same as in c api, i.e. it is client-side.
In CLR world: cef-side it is same as native-side, and other-side it is same as managed-side.

CEF API works with various types and objects.

Subject to revision for this proposal it is:

1. Primitive value types -- (currently i'm skip this, but for future - in some cases - some little restrictions must be applied).
2. Non-primitive types, which act as primitive value types -- it is a CefString (big question, but currently we also just skip it).
3. Complex value types (structs) -- (also currently skip this).

CEF1 now have two classes of objects with predefined interface/contract (class with virtual methods):
4. Objects that created by CEF-side: for example CefV8Value, CefBrowser and etc...
5. Objects that created by other-side: for example CefLifeSpanHandler.

6. Method invocation.


How it works in CEF1:
For example, we calling method [c]CefV8Context.GetGlobal();[/c] which return to us CefV8Value object.
Internally CEF1 for this do:
0. (real work)
1. creates CefV8ValueImpl object (which implements CefV8Value interface).
2. then create C++ proxy object (which internally object have cef_v8_value_t structure which initialized each time (per proxy object instance)).
3. then returns pointer to cef_v8_value_t structure.

Something like this happens when we needed pass object to CEF-side.
As result, for example, CefClient which returns pointer to cef_display_handler_t - require create proxy from C structure to cpp structure
on each interaction with display handler.


What problems with this methodology:

1. Heavy proxies
CEF creates proxy (i mean c struct) contains pointers to methods, for same methods, for each instance in most cases.
Of course it must fill it with pointers. Most big struct it is cef_v8value_t struct - it is about 150 bytes on x86.

2. Unstable object pointers
CEF always returns new proxies. I.e. CefBrowser.GetMainFrame() - it is one object, but we will got really new proxies after each call.
As result we can't do make equality comparisons.
As result some handlers which have first argument like CefBrowser or CefFrame *REALLY* can't be used one handler for many browsers,
'cause handler can't identify object.
In most cases it is not very big problem, using very little workaround - we can create many handlers and each handler know own browser.
But this is doesn't work with frames or any other objects (i know that frames resolved by names inside, so for frames it is no have sense).
But for browser objects i think that it is have real sense.
Also it is have sense to do not create client-side proxies, if binding require it.
For CefGlue i'm create proxies each time, but alternative way - it is map it to already created object.

3. Each proxy contains pointer to method. It require create dynamic delegates to invoke method via this raw pointers.
I see two problems: invoking via dynamic delegate it is really advanced technique (vs classic calling exported method).
And second it is that in most cases it is pointers to same methods - bindings require cache delegates, to prevent memory blow.
(managed delegates to native code generate special thunk in memory, for example in CLR thunks it is also subject to be GC-ed,
but what happens with others - i'm don't know).


Alternative way (all code it is pseudo code, not C/C++):

1. CefObject (struct)

Declare something like:
Code: Select all
struct CefObject
{
    intptr impl;
    intptr vtable;
    // note that it can be extended,
    // for example to introduce type-id or other useful stuff.
    // for example intptr binding_tag, which will be controlled by lang binding, to store associated object handle on other-side
}


2. CefV8Value (interface)
It is very like as cef_v8value_t, it is struct with pointers.
Code: Select all
struct CefV8ValueVtbl
{
    // refcounting stuff
    bool IsUndefined(CefV8Value self);
}




3. CEF ABI
All object calls must be available via dll exports, and this methods must call real methods using vtable.
It is just for simplifying.
Most languages already have this kind of invoking methods, and it can be much faster than invoking via delegates.
This is calling thunks must be defined for all methods to all objects. I.e. and for handlers too.

bool CefV8Value_IsUndefined(CefObject<CefV8Value> self)
{
return self->vtable->IsUndefined(self->impl);
}


4. CEF-side CefV8ValueImpl
Code: Select all
class CefV8ValueImpl
{
    private CefObject<CefV8ValueVtbl> obj;
   
    // construction of this class, must properly fill obj struct
    // impl field it is will set to 'this'
    // and vtable to corresponding vtable (CefV8ValueImpl_vtbl)
   
   static bool IsUndefined(CefV8ValueImpl* self)
   {
       return self->IsUndefined();
   }


    bool IsUndefined() { }   // no have sense to do it virtual, but it is possible
}


Code: Select all
    const CefV8ValueImpl_vtbl = new CefV8ValueVtbl { CefV8ValueImpl::IsUndefined };



5. Other-side object implementations very similar.
Note that each object can have different vtables, bindings must not assume that it is always one.


It is very like COM, but not a COM. :)
I very fast write this, may it is not enought, but i hope, it is enought starting point to discussion.
fddima
Master
 
Posts: 788
Joined: Tue Dec 07, 2010 6:10 am

Re: CEF3 ABI proposal

Postby magreenblatt » Thu Feb 16, 2012 2:01 pm

Your vtable idea is interesting and I mostly follow how it would work for library-side interfaces (exported by the DLL). However, I'm not sure I follow how it would work for client-side interfaces (implemented by the client and passed to the DLL). Let's use a simple example. With the current ABI the C++ interface looks like this:

Code: Select all
class CefSomeHandler : public virtual CefBase {
 public:
  virtual void OnFirst() =0;
  virtual void OnSecond() =0;
};

void CefDoSomething(CefRefPtr<CefSomeHandler> handler);

And the C API interface looks like this:

Code: Select all
typedef struct _cef_some_handler_t {
  cef_base_t base;
  void (CEF_CALLBACK *on_first)(struct _cef_some_handler_t* self);
  void (CEF_CALLBACK *on_second)(struct _cef_some_handler_t* self);
} cef_some_handler_t;

void cef_do_something(cef_some_handler_t* handler);

How would this code change with your suggested vtable approach?

EDIT: Also, the client C++ implementation looks like this:

Code: Select all
class MySomeHandler : public CefSomeHandler {
 public:
  MySomeHandler() {}
  virtual void OnFirst() {}
  virtual void OnSecond() {}
  IMPLEMENT_REFCOUNTING(MySomeHandler);
};

How would that need to change?
magreenblatt
Site Admin
 
Posts: 12408
Joined: Fri May 29, 2009 6:57 pm

Re: CEF3 ABI proposal

Postby fddima » Thu Feb 16, 2012 3:39 pm

Okay, i trying to explain:

CefObject<T> -- it is something from generic type. May be it is can be implemented via C++ templates, or may be no.
In any case it is just a pointer to a plain spectial struct which contains a) pointer to implementation b) pointer to vtable. It is subject to exchange between dll/other-sides.

I.e. CefSomeHandler it is interface. All interface methods defined by vtable.
Each method of vtable it is static method, with first argument (intptr) is 'implementation' (we can don't any assumptions about that it is exact pointer or no - it is just raw intptr data, which can be reinterpreted different on CEF side, or on client side, i.e. for CEF it is pointer to C++ object, but for abstract .net binding it is can be GCHandle, for example).

So plain vtable for CefSomeHandler by layout it is same as in C API:
Code: Select all
struct CefSomeHandler {
  void (CEF_CALLBACK *AddRef)(CefSomeHandlerImplRef self);
  void (CEF_CALLBACK *Release)(CefSomeHandlerImplRef self);
  void (CEF_CALLBACK *GetRefCt)(CefSomeHandlerImplRef self);
  void (CEF_CALLBACK *OnFirst)(CefSomeHandlerImplRef self);
  void (CEF_CALLBACK *OnSecond)(CefSomeHandlerImplRef self);
}

void CefDoSomething(CefSomeHandlerRef handler);

CefSomeHandlerImplRef - it is pointer to implementation.
CefSomeHandlerRef === CefObject<CefSomeHandler> === iplain intptr.
I.e. static methods just remains static.

Of course all of this stuff must be good wrapped via something like CefRefPtr<>.

About client side:
Code: Select all
class MySomeHandler : public CefSomeHandler {
public:
  MySomeHandler() {}
  virtual void OnFirst() {}
  virtual void OnSecond() {}
  // IMPLEMENT_REFCOUNTING(MySomeHandler);  // << i hope it is becomes no more needed, 'cause will be implemented in base class
};


I think that it is possible, to stay about remains unchanged.
In fact client must create CefObject and provide vtable for own object (it can provide one vtable per class, or per object instance). I don't know how it implement in C++, but both of this are possible in .net. So client's CefSomeHandler (base class of MySomeHandler, not interface declared above!) will be very similar as CefV8ValueImpl in first topic.
I think that for C++ may be have sense to introduce XxxRef types (CefSomeHandlerRef) as smarty pointers to allow implicit convertions between MySomeHandler to CefObject<MySomeHandlerInterface> and etc.

Main idea, that C++ - it is also platfrom & language to which we will generate bindings. I think that 99% of bindings must be auto-generated. In any way it is happens in latest CEF, and it is happens in CefGlue. For handlers in CefGlue i'm generate absolutely different class impls, which act as simple abstract base classes with overridable methods. I.e. it is will be look in any case very similar. If someone want achieve more fine-grained control about creating objects - it always can provide own plain vtables.

May be have sense to create little prototype project to trying this concepts?
fddima
Master
 
Posts: 788
Joined: Tue Dec 07, 2010 6:10 am

Re: CEF3 ABI proposal

Postby magreenblatt » Thu Feb 16, 2012 7:17 pm

fddima wrote:May be have sense to create little prototype project to trying this concepts?

Sounds good. Will you do this?
magreenblatt
Site Admin
 
Posts: 12408
Joined: Fri May 29, 2009 6:57 pm

Re: CEF3 ABI proposal

Postby fddima » Fri Feb 17, 2012 2:52 am

magreenblatt wrote:
fddima wrote:May be have sense to create little prototype project to trying this concepts?

Sounds good. Will you do this?

Yes, i will try do it on weekend or next week.
fddima
Master
 
Posts: 788
Joined: Tue Dec 07, 2010 6:10 am

Re: CEF3 ABI proposal

Postby fddima » Sun Mar 11, 2012 3:52 am

Sorry, no have time at last weeks for this. But i hope i finish sample on this week.
fddima
Master
 
Posts: 788
Joined: Tue Dec 07, 2010 6:10 am

Re: CEF3 ABI proposal

Postby fddima » Thu Mar 15, 2012 4:09 am

Anyone really interested in this, or no?
fddima
Master
 
Posts: 788
Joined: Tue Dec 07, 2010 6:10 am

Re: CEF3 ABI proposal

Postby Benvie » Tue Mar 20, 2012 4:27 am

I absolutely am, but from an odd angle. I've been working on being able to creating bindings from in Node.js itself, so directly from javascript. I've been working on generating automated bindings for C level apis, https://gist.github.com/1973743, https://github.com/Benvie/chrome-nodium https://github.com/Benvie/chrome-nodium ... indings.js https://github.com/Benvie/node-ffi-tool ... indings.js. And I'm wrapping up work on a better foundation for translating and marshalling data to and from memory https://github.com/Benvie/reified. I had anticipated simply having to deal with the difficult API that CEF presents but would very much love to have it simplified!
Last edited by Benvie on Tue Mar 20, 2012 4:29 am, edited 1 time in total.
Benvie
Techie
 
Posts: 20
Joined: Wed Aug 10, 2011 2:58 pm

Re: CEF3 ABI proposal

Postby fddima » Tue Mar 20, 2012 4:28 am

Benvie wrote:I absolutely am, but from an odd angle. I've been working on being able to creating bindings from in Node.js itself, so directly from javascript. I've been working on generating automated bindings for C level apis, https://gist.github.com/1973743, https://github.com/Benvie/chrome-nodium https://github.com/Benvie/node-ffi-tool ... indings.js. And I'm wrapping up work on a better foundation for translating and marshalling data to and from memory https://github.com/Benvie/reified. I had anticipated simply having to deal with the difficult API that CEF presents but would very much love to have it simplified!

Thanks. Interesting.
fddima
Master
 
Posts: 788
Joined: Tue Dec 07, 2010 6:10 am

Re: CEF3 ABI proposal

Postby magreenblatt » Tue Mar 20, 2012 1:53 pm

fddima wrote:Anyone really interested in this, or no?

It's hard to judge at this point. Are you having problems with the prototype?
magreenblatt
Site Admin
 
Posts: 12408
Joined: Fri May 29, 2009 6:57 pm

Next

Return to CEF Discussion

Who is online

Users browsing this forum: No registered users and 33 guests