Saturday, September 03, 2005

Creating the public functions to allocate and deallocate proxy objects was straightforward enough; simply generate into the proxy header and source files code like the following:


extern "C" HelloClassProxy *
NewHelloClassProxy()
{
HelloClassProxy *ptr = new HelloClassProxy();
return ptr;
}

extern "C" void
DeleteHelloClassProxy(HelloClassProxy *ptr)
{
if (ptr)
delete ptr;
}

HelloClassProxy::HelloClassProxy()
{
m_impl = new HelloClass();
}

HelloClassProxy::~HelloClassProxy()
{
if (m_impl)
delete m_impl;
}


At runtime, the layout engine, when it goes to create the JavaScript object that represents an instance of the proxy class in response to a query by the user JavaScript code to obtain an instance of an object, constructs a string that consists of a concatenation of the strings "New", the class name (e.g., HelloClass), and "Proxy". It then calls the Library class object to query the shared library for a function with that name (in this case, NewHelloClassProxy). If it is returned a non-NULL value, it then can call that function to allocate a proxy object. Notice that allocating the proxy object also causes the concrete object (HelloClass) wrapped by the proxy to be instantiated (see the source for the HelloClassProxy constructor, above). Here's a snippet of that code taken from the layout engine:


PRStatus
Object::CreateJSObject()
{
PRStatus ret = PR_SUCCESS;
JSEngine *js = JSEngine::GetJSEngine();

if (!js)
return PR_FAILURE;

Component *comp = GetComponent();

if (!comp)
return PR_FAILURE;

Library *lib = comp->GetLibrary();

if (!lib)
return PR_FAILURE;

JSContext *ctx = js->GetContext();
JSObject *obj = js->GetGlobalObject();

string name = GetAttributeByName(string("name"))->GetValue();

// create an instance of the proxy class

string creator;

creator = "New" + name + "Proxy";

void *fptr = lib->FindSymbol(creator);


However, we have a problem, Houston. Once the layout engine has an instance of the proxy object (in fptr, above), it needs to create entry points in the JavaScript object for each method implemented by the proxy object. These entry points are what the JavaScript engine uses to map calls made by the user's JavaScript into C/C++ calls. For the HelloClassProxy class, this includes the methods Hello(), Get_age(), and Set_age(). With an instance of the object in hand, you say, the layout code can obtain the addresses of these objects, so what is the problem? The problem is that the best we can do (in my current design that is) is obtain effectively a void * when calling the shared library implementation of NewHelloClassProxy(). The layout engine cannot allocate a pointer to a HelloClassProxy object; to do otherwise would require the layout engine to anticipate the types of all proxy objects it is ever going to be expected to interface to. But with only a void *, I can't possible obtain addresses of functions in the object's vtable.

But there is a solution. We can generate into the proxy source an addition extern "C" interface, perhaps call it HelloClassProxyLookup(), that takes a string and a void * representing the proxy object, and then returns a pointer to the method in the object that pertains to that name. This pointer can then be stuffed into the JavaScript object. The code in the layout engine that generates the proxy source (and the lookup function) will be modified generate the code needed to support this functionality.

Another thing I need to concern myself with is passing "this" to the proxy functions from JavaScript. Currently, I am not accounting for this required argument.

0 Comments:

Post a Comment

<< Home