Implement pass-ref semantics for NPObject and NPVariant

This will allow us to get rid of delayed NPN_ReleaseObject.
This commit is contained in:
David Benjamin 2011-04-20 11:13:23 -04:00
parent 94593ff660
commit 3791e265ab
4 changed files with 137 additions and 20 deletions

View File

@ -33,6 +33,7 @@ extern int npclass_add_method_descriptors(rpc_connection_t *connection) attribut
// Management of stubs, objects which live on the side that owns the
// NPObject and holds a reference to it on behalf of a proxy.
extern uint32_t npobject_create_stub(NPObject *npobj) attribute_hidden;
extern void npobject_destroy_stub(uint32_t id) attribute_hidden;
extern NPObject *npobject_lookup_local(uint32_t id) attribute_hidden;
// Create a proxy object. The received id must correspond to a live
@ -41,6 +42,7 @@ extern NPObject *npobject_lookup_local(uint32_t id) attribute_hidden;
// its stub.
extern NPObject *npobject_create_proxy(uint32_t id) attribute_hidden;
extern uint32_t npobject_get_proxy_id(NPObject *npobj) attribute_hidden;
extern void npobject_destroy_proxy(NPObject *npobj, bool release_stub);
struct _NPVariant;
extern void npvariant_clear(struct _NPVariant *variant) attribute_hidden;

View File

@ -103,14 +103,21 @@ NPObject *npobject_lookup_local(uint32_t id)
return stub ? stub->npobject : NULL;
}
static void npobject_destroy_stub(NPObjectStub *stub)
static void npobject_destroy_stub_obj(NPObjectStub *stub)
{
D(bug("npobject_stub: id=0x%x\n", stub->id));
D(bug("npobject_destroy_stub: id=0x%x\n", stub->id));
g_hash_table_remove(g_stubs, GINT_TO_POINTER(stub->id));
NPN_ReleaseObject(stub->npobject);
g_free(stub);
}
void npobject_destroy_stub(uint32_t id)
{
NPObjectStub *stub = npobject_lookup_stub(id);
assert(stub != NULL);
npobject_destroy_stub_obj(stub);
}
/* ====================================================================== */
/* === NPObject proxies === */
/* ====================================================================== */
@ -154,6 +161,23 @@ uint32_t npobject_get_proxy_id(NPObject *npobj)
return proxy->id;
}
static void npclass_invoke_Deallocate(NPObjectProxy *proxy);
void npobject_destroy_proxy(NPObject *npobj, bool release_stub)
{
// Unregister the proxy.
D(bugiI("npobject_destroy_proxy: npobj=%p, release_stub=%d\n",
npobj, release_stub));
NPObjectProxy *proxy = npobject_get_proxy(npobj);
assert(proxy != NULL);
if (release_stub && proxy->is_valid) {
npclass_invoke_Deallocate(proxy);
g_hash_table_remove(g_proxies, GINT_TO_POINTER(proxy->id));
}
free(npobj);
D(bugiD("npobject_destroy_proxy done\n"));
}
static inline bool is_valid_npobject_proxy(NPObject *npobj)
{
if (npobj == NULL)
@ -228,7 +252,7 @@ int npclass_handle_Deallocate(rpc_connection_t *connection)
D(bugiI("NPClass:Deallocate: id=0x%x\n", id));
NPObjectStub *stub = npobject_lookup_stub(id);
if (stub != NULL) {
npobject_destroy_stub(stub);
npobject_destroy_stub_obj(stub);
}
D(bugiD("NPClass:Deallocate done\n"));
@ -260,15 +284,7 @@ static void npclass_invoke_Deallocate(NPObjectProxy *proxy)
void g_NPClass_Deallocate(NPObject *npobj)
{
// Unregister the proxy.
D(bugiI("NPClass::Deallocate: npobj=%p\n", npobj));
NPObjectProxy *proxy = npobject_get_proxy(npobj);
if (proxy && proxy->is_valid) {
npclass_invoke_Deallocate(proxy);
g_hash_table_remove(g_proxies, GINT_TO_POINTER(proxy->id));
}
D(bugiD("NPClass::Deallocate done\n"));
free(npobj);
npobject_destroy_proxy(npobj, true);
}
// NPClass::Invalidate
@ -1155,7 +1171,7 @@ static void proxy_deactivate_func(gpointer key, gpointer value, gpointer user_da
static void stub_destroy_func(gpointer key, gpointer value, gpointer user_data)
{
NPObjectStub *stub = (NPObjectStub *)value;
npobject_destroy_stub(stub);
npobject_destroy_stub_obj(stub);
}
void npruntime_deactivate(void)

View File

@ -1178,19 +1178,38 @@ static int do_recv_NPPrintData(rpc_message_t *message, void *p_value)
* Process NPObject objects
*/
static int do_send_NPObject(rpc_message_t *message, void *p_value)
static int do_send_NPObject_helper(rpc_message_t *message, void *p_value,
bool pass_ref)
{
uint32_t npobj_id = 0;
NPObject *npobj = (NPObject *)p_value;
bool release_stub = false;
if (npobj) {
npobj_id = npobject_get_proxy_id(npobj);
if (npobj_id == 0) {
// Sending an object on our side. Allocate a stub so the other
// side can make a proxy.
npobj_id = npobject_create_stub(npobj);
if (pass_ref) {
// Release our reference; the stub protects the object from
// deallocation.
NPN_ReleaseObject(npobj);
}
} else {
// This is a proxy for the object on the other side. Just pass
// the id along.
if (pass_ref) {
// As above, we release out reference. If this is not the last
// reference, we may just do so. Otherwise, we destroy it, but
// do /not/ send the corresponding RPC. That gets merged into
// this one.
if (npobj->referenceCount == 1) {
npobject_destroy_proxy(npobj, false);
release_stub = true;
} else {
NPN_ReleaseObject(npobj);
}
}
}
D(bug("sending id 0x%x\n", npobj_id));
assert(npobj_id != 0);
@ -1198,17 +1217,28 @@ static int do_send_NPObject(rpc_message_t *message, void *p_value)
int error = rpc_message_send_uint32(message, npobj_id);
if (error < 0)
return error;
// Tell the other side whether or not to destroy the stub.
if (pass_ref) {
if ((error = rpc_message_send_uint32(message, release_stub)) < 0)
return error;
}
return RPC_ERROR_NO_ERROR;
}
static int do_recv_NPObject(rpc_message_t *message, void *p_value)
static int do_recv_NPObject_helper(rpc_message_t *message, void *p_value,
bool pass_ref)
{
int error;
uint32_t npobj_id;
uint32_t release_stub = 0;
if ((error = rpc_message_recv_uint32(message, &npobj_id)) < 0)
return error;
if (pass_ref) {
if ((error = rpc_message_recv_uint32(message, &release_stub)) < 0)
return error;
}
NPObject *npobj = NULL;
if (npobj_id) {
@ -1217,11 +1247,17 @@ static int do_recv_NPObject(rpc_message_t *message, void *p_value)
// We got an id of a newly created remote stub. Create a proxy
// for it.
npobj = npobject_create_proxy(npobj_id);
if (release_stub)
npw_printf("ERROR: received release_stub for proxy NPObject.\n");
} else {
// This is an object on our side. Retain it; receiver must
// release all received NPObjects.
D(bug("local\n"));
NPN_RetainObject(npobj);
if (release_stub) {
// We just retained the object, so it won't be destroyed.
npobject_destroy_stub(npobj_id);
}
}
D(bug("recv id 0x%x, obj %p\n", npobj_id, npobj));
assert(npobj != NULL);
@ -1231,6 +1267,26 @@ static int do_recv_NPObject(rpc_message_t *message, void *p_value)
return RPC_ERROR_NO_ERROR;
}
static int do_send_NPObject(rpc_message_t *message, void *p_value)
{
return do_send_NPObject_helper(message, p_value, false);
}
static int do_recv_NPObject(rpc_message_t *message, void *p_value)
{
return do_recv_NPObject_helper(message, p_value, false);
}
static int do_send_NPObject_pass_ref(rpc_message_t *message, void *p_value)
{
return do_send_NPObject_helper(message, p_value, true);
}
static int do_recv_NPObject_pass_ref(rpc_message_t *message, void *p_value)
{
return do_recv_NPObject_helper(message, p_value, true);
}
/*
* Process NPIdentifier objects
@ -1371,7 +1427,8 @@ static int do_recv_NPString(rpc_message_t *message, void *p_value)
* Process NPVariant objects
*/
static int do_send_NPVariant(rpc_message_t *message, void *p_value)
static int do_send_NPVariant_helper(rpc_message_t *message, void *p_value,
bool pass_ref)
{
NPVariant *variant = (NPVariant *)p_value;
if (variant == NULL)
@ -1403,15 +1460,23 @@ static int do_send_NPVariant(rpc_message_t *message, void *p_value)
return error;
break;
case NPVariantType_Object:
if ((error = do_send_NPObject(message, variant->value.objectValue)) < 0)
if ((error = do_send_NPObject_helper(message, variant->value.objectValue,
pass_ref)) < 0)
return error;
break;
}
// Clean up local data. If we had an NPObject,
// do_send_NPObject_pass_ref took care of it.
if (pass_ref && variant->type != NPVariantType_Object) {
NPN_ReleaseVariantValue(variant);
}
return RPC_ERROR_NO_ERROR;
}
static int do_recv_NPVariant(rpc_message_t *message, void *p_value)
static int do_recv_NPVariant_helper(rpc_message_t *message, void *p_value,
bool pass_ref)
{
NPVariant *variant = (NPVariant *)p_value;
if (variant)
@ -1451,9 +1516,10 @@ static int do_recv_NPVariant(rpc_message_t *message, void *p_value)
return error;
break;
case NPVariantType_Object:
if ((error = do_recv_NPObject(message, &result.value.objectValue)) < 0)
if ((error = do_recv_NPObject_helper(message, &result.value.objectValue,
pass_ref)) < 0)
return error;
// NPVariant owns reference from do_recv_NPObject.
// NPVariant owns reference from do_recv_NPObject_helper.
break;
}
@ -1465,6 +1531,25 @@ static int do_recv_NPVariant(rpc_message_t *message, void *p_value)
return RPC_ERROR_NO_ERROR;
}
static int do_send_NPVariant(rpc_message_t *message, void *p_value)
{
return do_send_NPVariant_helper(message, p_value, false);
}
static int do_recv_NPVariant(rpc_message_t *message, void *p_value)
{
return do_recv_NPVariant_helper(message, p_value, false);
}
static int do_send_NPVariant_pass_ref(rpc_message_t *message, void *p_value)
{
return do_send_NPVariant_helper(message, p_value, true);
}
static int do_recv_NPVariant_pass_ref(rpc_message_t *message, void *p_value)
{
return do_recv_NPVariant_helper(message, p_value, true);
}
/*
* Initialize marshalers for NPAPI types
@ -1555,6 +1640,12 @@ static const rpc_message_descriptor_t message_descs[] = {
do_send_NPObject,
do_recv_NPObject
},
{
RPC_TYPE_NP_OBJECT_PASS_REF,
sizeof(NPObject *),
do_send_NPObject_pass_ref,
do_recv_NPObject_pass_ref
},
{
RPC_TYPE_NP_IDENTIFIER,
sizeof(NPIdentifier),
@ -1578,6 +1669,12 @@ static const rpc_message_descriptor_t message_descs[] = {
sizeof(NPVariant),
do_send_NPVariant,
do_recv_NPVariant
},
{
RPC_TYPE_NP_VARIANT_PASS_REF,
sizeof(NPVariant),
do_send_NPVariant_pass_ref,
do_recv_NPVariant_pass_ref
}
};

View File

@ -131,6 +131,8 @@ enum {
RPC_TYPE_NP_STRING, /* 15 */
RPC_TYPE_NP_VARIANT,
RPC_TYPE_NP_UTF8,
RPC_TYPE_NP_OBJECT_PASS_REF,
RPC_TYPE_NP_VARIANT_PASS_REF,
RPC_TYPE_NPW_PLUGIN_INSTANCE
};