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);
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)
int nargs;
VARIANT v;
int ret = FAILURE;
-
+
obj = CDNO_FETCH(getThis());
if (V_VT(&obj->v) != VT_DISPATCH) {
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)
}
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);
}