]> granicus.if.org Git - php/commitdiff
Fix leaking constructors.
authorWez Furlong <wez@php.net>
Tue, 13 Jan 2004 13:38:11 +0000 (13:38 +0000)
committerWez Furlong <wez@php.net>
Tue, 13 Jan 2004 13:38:11 +0000 (13:38 +0000)
Implement a cache for method signatures and DISPID's to
greatly improve performance when repeatedly accessing
members with the same names.

ext/com_dotnet/com_com.c
ext/com_dotnet/com_extension.c
ext/com_dotnet/com_handlers.c
ext/com_dotnet/php_com_dotnet_internal.h

index 135d1c98ba6a4ebea98ed6950ace446a4a3b7448..b63458481f14cea9006dfefd48aca8569476cfe6 100644 (file)
@@ -355,7 +355,17 @@ HRESULT php_com_get_id_of_name(php_com_dotnet_object *obj, char *name,
 {
        OLECHAR *olename;
        HRESULT hr;
+       DISPID *dispid_ptr;
 
+       if (namelen == -1) {
+               namelen = strlen(name);
+       }
+
+       if (obj->id_of_name_cache && SUCCESS == zend_hash_find(obj->id_of_name_cache, name, namelen, (void**)&dispid_ptr)) {
+               *dispid = *dispid_ptr;
+               return S_OK;
+       }
+       
        olename = php_com_string_to_olestring(name, namelen, obj->code_page TSRMLS_CC);
 
        if (obj->typeinfo) {
@@ -373,6 +383,15 @@ HRESULT php_com_get_id_of_name(php_com_dotnet_object *obj, char *name,
        }
        efree(olename);
 
+       if (SUCCEEDED(hr)) {
+               /* cache the mapping */
+               if (!obj->id_of_name_cache) {
+                       ALLOC_HASHTABLE(obj->id_of_name_cache);
+                       zend_hash_init(obj->id_of_name_cache, 2, NULL, NULL, 0);
+               }
+               zend_hash_update(obj->id_of_name_cache, name, namelen, dispid, sizeof(*dispid), NULL);
+       }
+       
        return hr;
 }
 
@@ -388,7 +407,7 @@ int php_com_do_invoke_byref(php_com_dotnet_object *obj, char *name, int namelen,
        zend_internal_function *f = (zend_internal_function*)EG(function_state_ptr)->function;
 
        /* assumption: that the active function (f) is the function we generated for the engine */
-       if (!f || f->type != ZEND_OVERLOADED_FUNCTION_TEMPORARY || f->arg_info == NULL) {
+       if (!f || f->arg_info == NULL) {
           f = NULL;
        }
        
index fc01903f707bf6d2a46431bb39bef7828f16c477..50c665dbba76e036544af8b2bc8b3cf9b8c32d43 100644 (file)
@@ -31,6 +31,7 @@
 
 ZEND_DECLARE_MODULE_GLOBALS(com_dotnet)
 TsHashTable php_com_typelibraries;
+
 zend_class_entry
        *php_com_variant_class_entry,
        *php_com_exception_class_entry,
index 5cb69b5ec37c312f512de3e9829b00b2be97cf30..f9f29e04d524d15c0d3082fc8bde242997e07b8d 100644 (file)
@@ -231,12 +231,21 @@ static HashTable *com_properties_get(zval *object TSRMLS_DC)
        return NULL;
 }
 
+static void function_dtor(void *pDest)
+{
+       zend_internal_function *f = (zend_internal_function*)pDest;
+
+       efree(f->function_name);
+       if (f->arg_info) {
+               efree(f->arg_info);
+       }
+}
+
 static union _zend_function *com_method_get(zval *object, char *name, int len TSRMLS_DC)
 {
-       zend_internal_function *f;
+       zend_internal_function f, *fptr = NULL;
        php_com_dotnet_object *obj;
-
-       /* TODO: cache this */
+       union _zend_function *func;
 
        obj = CDNO_FETCH(object);
 
@@ -244,64 +253,79 @@ static union _zend_function *com_method_get(zval *object, char *name, int len TS
                return NULL;
        }
 
-       f = emalloc(sizeof(zend_internal_function));
-       f->type = ZEND_OVERLOADED_FUNCTION_TEMPORARY;
-       f->num_args = 0;
-       f->arg_info = NULL;
-       f->scope = obj->ce;
-       f->fn_flags = 0;
-       f->function_name = estrndup(name, len);
-
-       if (obj->typeinfo) {
-               /* look for byref params */
-               ITypeComp *comp;
-               ITypeInfo *TI = NULL;
-               DESCKIND kind;
-               BINDPTR bindptr;
-               OLECHAR *olename;
-               ULONG lhash;
-               int i;
-
-               if (SUCCEEDED(ITypeInfo_GetTypeComp(obj->typeinfo, &comp))) {
-                       olename = php_com_string_to_olestring(name, len, obj->code_page TSRMLS_CC);
-                       lhash = LHashValOfNameSys(SYS_WIN32, LOCALE_SYSTEM_DEFAULT, olename);
-
-                       if (SUCCEEDED(ITypeComp_Bind(comp, olename, lhash, INVOKE_FUNC, &TI, &kind, &bindptr))) {
-                               switch (kind) {
-                                       case DESCKIND_FUNCDESC:
-                                               f->arg_info = ecalloc(bindptr.lpfuncdesc->cParams, sizeof(zend_arg_info));
-
-                                               for (i = 0; i < bindptr.lpfuncdesc->cParams; i++) {
-                                                       f->arg_info[i].allow_null = 1;
-                                                       if (bindptr.lpfuncdesc->lprgelemdescParam[i].paramdesc.wParamFlags & PARAMFLAG_FOUT) {
-                                                               f->arg_info[i].pass_by_reference = 1;
+       /* check cache */
+       if (obj->method_cache == NULL || FAILURE == zend_hash_find(obj->method_cache, name, len, (void**)&fptr)) {
+               f.type = ZEND_OVERLOADED_FUNCTION;
+               f.num_args = 0;
+               f.arg_info = NULL;
+               f.scope = obj->ce;
+               f.fn_flags = 0;
+               f.function_name = estrndup(name, len);
+
+               if (obj->typeinfo) {
+                       /* look for byref params */
+                       ITypeComp *comp;
+                       ITypeInfo *TI = NULL;
+                       DESCKIND kind;
+                       BINDPTR bindptr;
+                       OLECHAR *olename;
+                       ULONG lhash;
+                       int i;
+
+                       if (SUCCEEDED(ITypeInfo_GetTypeComp(obj->typeinfo, &comp))) {
+                               olename = php_com_string_to_olestring(name, len, obj->code_page TSRMLS_CC);
+                               lhash = LHashValOfNameSys(SYS_WIN32, LOCALE_SYSTEM_DEFAULT, olename);
+
+                               if (SUCCEEDED(ITypeComp_Bind(comp, olename, lhash, INVOKE_FUNC, &TI, &kind, &bindptr))) {
+                                       switch (kind) {
+                                               case DESCKIND_FUNCDESC:
+                                                       f.arg_info = ecalloc(bindptr.lpfuncdesc->cParams, sizeof(zend_arg_info));
+
+                                                       for (i = 0; i < bindptr.lpfuncdesc->cParams; i++) {
+                                                               f.arg_info[i].allow_null = 1;
+                                                               if (bindptr.lpfuncdesc->lprgelemdescParam[i].paramdesc.wParamFlags & PARAMFLAG_FOUT) {
+                                                                       f.arg_info[i].pass_by_reference = 1;
+                                                               }
                                                        }
-                                               }
-
-                                               f->num_args = bindptr.lpfuncdesc->cParams;
 
-                                               ITypeInfo_ReleaseFuncDesc(TI, bindptr.lpfuncdesc);
-                                               break;
-
-                                       /* these should not happen, but *might* happen if the user
-                                        * screws up; lets avoid a leak in that case */
-                                       case DESCKIND_VARDESC:
-                                               ITypeInfo_ReleaseVarDesc(TI, bindptr.lpvardesc);
-                                               break;
-                                       case DESCKIND_TYPECOMP:
-                                               ITypeComp_Release(bindptr.lptcomp);
-                                               break;
-                               }
-                               if (TI) {
-                                       ITypeInfo_Release(TI);
+                                                       f.num_args = bindptr.lpfuncdesc->cParams;
+
+                                                       ITypeInfo_ReleaseFuncDesc(TI, bindptr.lpfuncdesc);
+                                                       break;
+
+                                                       /* these should not happen, but *might* happen if the user
+                                                        * screws up; lets avoid a leak in that case */
+                                               case DESCKIND_VARDESC:
+                                                       ITypeInfo_ReleaseVarDesc(TI, bindptr.lpvardesc);
+                                                       break;
+                                               case DESCKIND_TYPECOMP:
+                                                       ITypeComp_Release(bindptr.lptcomp);
+                                                       break;
+                                       }
+                                       if (TI) {
+                                               ITypeInfo_Release(TI);
+                                       }
                                }
+                               ITypeComp_Release(comp);
+                               efree(olename);
                        }
-                       ITypeComp_Release(comp);
-                       efree(olename);
                }
+
+               /* save this method in the cache */
+               if (!obj->method_cache) {
+                       ALLOC_HASHTABLE(obj->method_cache);
+                       zend_hash_init(obj->method_cache, 2, NULL, function_dtor, 0);
+               }
+
+               zend_hash_update(obj->method_cache, name, len, &f, sizeof(f), (void**)&fptr);
        }
 
-       return (union _zend_function*)f;
+       /* duplicate this into a new chunk of emalloc'd memory,
+        * since the engine will efree it */
+       func = emalloc(sizeof(*fptr));
+       memcpy(func, fptr, sizeof(*fptr));
+
+       return func;
 }
 
 static int com_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS)
@@ -311,7 +335,7 @@ static int com_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS)
        int nargs;
        VARIANT v;
        int ret = FAILURE;
-
+       
        obj = CDNO_FETCH(getThis());
 
        if (V_VT(&obj->v) != VT_DISPATCH) {
@@ -343,31 +367,33 @@ static int com_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS)
 static union _zend_function *com_constructor_get(zval *object TSRMLS_DC)
 {
        php_com_dotnet_object *obj;
-       zend_internal_function *f;
+       static zend_internal_function c, d, v;
 
        obj = CDNO_FETCH(object);
 
-       /* TODO: this leaks */
-       f = emalloc(sizeof(zend_internal_function));
-       f->type = ZEND_INTERNAL_FUNCTION;
-
-       f->function_name = obj->ce->name;
-       f->scope = obj->ce;
-       f->arg_info = NULL;
-       f->num_args = 0;
-       f->fn_flags = 0;
-#if HAVE_MSCOREE_H
-       if (f->function_name[0] == 'd') { /* 'd'otnet */
-               f->handler = ZEND_FN(com_dotnet_create_instance);
-       } else 
-#endif
-       if (f->function_name[0] == 'c') { /* 'c'om */
-               f->handler = ZEND_FN(com_create_instance);
-       } else { /* 'v'ariant */
-               f->handler = ZEND_FN(com_variant_create_instance);
+#define POPULATE_CTOR(f, fn)   \
+       f.type = ZEND_INTERNAL_FUNCTION; \
+       f.function_name = obj->ce->name; \
+       f.scope = obj->ce; \
+       f.arg_info = NULL; \
+       f.num_args = 0; \
+       f.fn_flags = 0; \
+       f.handler = ZEND_FN(fn); \
+       return (union _zend_function*)&f;
+       
+       switch (obj->ce->name[0]) {
+               case 'd':
+                       POPULATE_CTOR(d, com_dotnet_create_instance);
+               
+               case 'c':
+                       POPULATE_CTOR(d, com_create_instance);
+               
+               case 'v':
+                       POPULATE_CTOR(d, com_variant_create_instance);
+                       
+               default:
+                       return NULL;
        }
-
-       return (union _zend_function*)f;
 }
 
 static zend_class_entry *com_class_entry_get(zval *object TSRMLS_DC)
@@ -538,6 +564,13 @@ void php_com_object_dtor(void *object, zend_object_handle handle TSRMLS_DC)
        }
 
        VariantClear(&obj->v);
+
+       if (obj->method_cache) {
+               FREE_HASHTABLE(obj->method_cache);
+       }
+       if (obj->id_of_name_cache) {
+               FREE_HASHTABLE(obj->id_of_name_cache);
+       }
        efree(obj);
 }
 
index 131a9180592c7bcebdafd7cd6d3118fad470ea3b..762972ec434f5221fe7db697d35fb3c4cc984bc3 100644 (file)
@@ -46,6 +46,11 @@ typedef struct _php_com_dotnet_object {
        IDispatch *sink_dispatch;
        GUID sink_id;
        DWORD sink_cookie;
+
+       /* cache for method signatures */
+       HashTable *method_cache;
+       /* cache for name -> DISPID */
+       HashTable *id_of_name_cache;
 } php_com_dotnet_object;
 
 static inline int php_com_is_valid_object(zval *zv TSRMLS_DC)