From 68902d1bedcc8c23f8907d023d325ce8a40196c1 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Fri, 6 Feb 2015 15:32:57 +0100 Subject: [PATCH 1/1] optimize frequent method calls --- php_http_client.c | 87 ++++++++++++++++++++++++++++++++-------------- php_http_client.h | 2 ++ php_http_message.c | 6 ++-- php_http_object.c | 73 +++++++++++++++++++++++++++++--------- php_http_object.h | 11 +++++- 5 files changed, 134 insertions(+), 45 deletions(-) diff --git a/php_http_client.c b/php_http_client.c index 2b4a31d..3050bd8 100644 --- a/php_http_client.c +++ b/php_http_client.c @@ -329,6 +329,8 @@ void php_http_client_object_free(void *object TSRMLS_DC) php_http_client_object_t *o = (php_http_client_object_t *) object; php_http_client_free(&o->client); + php_http_object_method_dtor(&o->notify); + php_http_object_method_free(&o->update); zend_object_std_dtor((zend_object *) o TSRMLS_CC); efree(o); } @@ -457,14 +459,18 @@ static STATUS handle_response(void *arg, php_http_client_t *client, php_http_cli static void handle_progress(void *arg, php_http_client_t *client, php_http_client_enqueue_t *e, php_http_client_progress_state_t *progress) { - zval *zrequest, *zprogress, *retval = NULL, *zclient; + zval *zrequest, *zprogress, *zclient, **args[2]; + php_http_client_object_t *client_obj = arg; zend_error_handling zeh; TSRMLS_FETCH_FROM_CTX(client->ts); MAKE_STD_ZVAL(zclient); - ZVAL_OBJVAL(zclient, ((php_http_client_object_t *) arg)->zv, 1); + ZVAL_OBJVAL(zclient, client_obj->zv, 1); + MAKE_STD_ZVAL(zrequest); ZVAL_OBJVAL(zrequest, ((php_http_message_object_t *) e->opaque)->zv, 1); + args[0] = &zrequest; + MAKE_STD_ZVAL(zprogress); object_init(zprogress); add_property_bool(zprogress, "started", progress->started); @@ -474,15 +480,15 @@ static void handle_progress(void *arg, php_http_client_t *client, php_http_clien add_property_double(zprogress, "dlnow", progress->dl.now); add_property_double(zprogress, "ultotal", progress->ul.total); add_property_double(zprogress, "ulnow", progress->ul.now); + args[1] = &zprogress; + zend_replace_error_handling(EH_NORMAL, NULL, &zeh TSRMLS_CC); - zend_call_method_with_2_params(&zclient, NULL, NULL, "notify", &retval, zrequest, zprogress); + php_http_object_method_call(&client_obj->notify, zclient, NULL, 2, args TSRMLS_CC); zend_restore_error_handling(&zeh TSRMLS_CC); + zval_ptr_dtor(&zclient); zval_ptr_dtor(&zrequest); zval_ptr_dtor(&zprogress); - if (retval) { - zval_ptr_dtor(&retval); - } } static void response_dtor(void *data) @@ -537,6 +543,8 @@ static PHP_METHOD(HttpClient, __construct) php_http_expect(obj->client = php_http_client_init(NULL, driver.client_ops, rf, NULL TSRMLS_CC), runtime, return); + php_http_object_method_init(&obj->notify, getThis(), ZEND_STRL("notify") TSRMLS_CC); + obj->client->callback.response.func = handle_response; obj->client->callback.response.arg = obj; obj->client->callback.progress.func = handle_progress; @@ -869,13 +877,20 @@ static PHP_METHOD(HttpClient, enableEvents) RETVAL_ZVAL(getThis(), 1, 0); } +struct notify_arg { + php_http_object_method_t *cb; + zval **args[3]; + int argc; +}; + static int notify(zend_object_iterator *iter, void *puser TSRMLS_DC) { - zval **observer = NULL, ***args = puser; + zval **observer = NULL; + struct notify_arg *arg = puser; iter->funcs->get_current_data(iter, &observer TSRMLS_CC); if (observer) { - return php_http_method_call(*observer, ZEND_STRL("update"), args[2]?3:args[1]?2:args[0]?1:0, args, NULL TSRMLS_CC); + return php_http_object_method_call(arg->cb, *observer, NULL, arg->argc, arg->args TSRMLS_CC); } return FAILURE; } @@ -885,10 +900,13 @@ ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_notify, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, notify) { - zval *request = NULL, *zprogress = NULL, *observers, **args[3]; + zval *request = NULL, *zprogress = NULL, *observers; + php_http_client_object_t *client_obj; + struct notify_arg arg = {NULL}; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|O!o!", &request, php_http_client_request_class_entry, &zprogress), invalid_arg, return); + client_obj = zend_object_store_get_object(getThis() TSRMLS_CC); observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0 TSRMLS_CC); if (Z_TYPE_P(observers) != IS_OBJECT) { @@ -896,23 +914,34 @@ static PHP_METHOD(HttpClient, notify) return; } - Z_ADDREF_P(getThis()); - args[0] = &getThis(); - if (request) { - Z_ADDREF_P(request); - } - args[1] = &request; - if (zprogress) { - Z_ADDREF_P(zprogress); - } - args[2] = &zprogress; - spl_iterator_apply(observers, notify, args TSRMLS_CC); - zval_ptr_dtor(&getThis()); - if (request) { - zval_ptr_dtor(&request); - } - if (zprogress) { - zval_ptr_dtor(&zprogress); + if (client_obj->update) { + arg.cb = client_obj->update; + + Z_ADDREF_P(getThis()); + arg.args[0] = &getThis(); + arg.argc = 1; + + if (request) { + Z_ADDREF_P(request); + arg.args[1] = &request; + arg.argc += 1; + } + + if (zprogress) { + Z_ADDREF_P(zprogress); + arg.args[2] = &zprogress; + arg.argc += 1; + } + + spl_iterator_apply(observers, notify, &arg TSRMLS_CC); + + zval_ptr_dtor(&getThis()); + if (request) { + zval_ptr_dtor(&request); + } + if (zprogress) { + zval_ptr_dtor(&zprogress); + } } RETVAL_ZVAL(getThis(), 1, 0); @@ -924,9 +953,11 @@ ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClient, attach) { zval *observers, *observer, *retval = NULL; + php_http_client_object_t *client_obj; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &observer, spl_ce_SplObserver), invalid_arg, return); + client_obj = zend_object_store_get_object(getThis() TSRMLS_CC); observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0 TSRMLS_CC); if (Z_TYPE_P(observers) != IS_OBJECT) { @@ -934,6 +965,10 @@ static PHP_METHOD(HttpClient, attach) return; } + if (!client_obj->update) { + client_obj->update = php_http_object_method_init(NULL, observer, ZEND_STRL("update") TSRMLS_CC); + } + zend_call_method_with_1_params(&observers, NULL, NULL, "attach", &retval, observer); if (retval) { zval_ptr_dtor(&retval); diff --git a/php_http_client.h b/php_http_client.h index c9768b9..b536753 100644 --- a/php_http_client.h +++ b/php_http_client.h @@ -118,6 +118,8 @@ typedef struct php_http_client_object { zend_object_value zv; php_http_client_t *client; long iterator; + php_http_object_method_t *update; + php_http_object_method_t notify; } php_http_client_object_t; PHP_HTTP_API php_http_client_t *php_http_client_init(php_http_client_t *h, php_http_client_ops_t *ops, php_resource_factory_t *rf, void *init_arg TSRMLS_DC); diff --git a/php_http_message.c b/php_http_message.c index 8a7e564..5a278f6 100644 --- a/php_http_message.c +++ b/php_http_message.c @@ -1161,17 +1161,19 @@ static PHP_METHOD(HttpMessage, getHeader) if (!header_ce) { RETURN_ZVAL(header, 1, 1); } else if (instanceof_function(header_ce, php_http_header_class_entry TSRMLS_CC)) { + php_http_object_method_t cb; zval *header_name, **argv[2]; MAKE_STD_ZVAL(header_name); ZVAL_STRINGL(header_name, header_str, header_len, 1); - Z_ADDREF_P(header); argv[0] = &header_name; argv[1] = &header; object_init_ex(return_value, header_ce); - php_http_method_call(return_value, ZEND_STRL("__construct"), 2, argv, NULL TSRMLS_CC); + php_http_object_method_init(&cb, return_value, ZEND_STRL("__construct") TSRMLS_CC); + php_http_object_method_call(&cb, return_value, NULL, 2, argv TSRMLS_CC); + php_http_object_method_dtor(&cb); zval_ptr_dtor(&header_name); zval_ptr_dtor(&header); diff --git a/php_http_object.c b/php_http_object.c index abf7229..7d902ea 100644 --- a/php_http_object.c +++ b/php_http_object.c @@ -53,30 +53,71 @@ STATUS php_http_new(zend_object_value *ovp, zend_class_entry *ce, php_http_new_t return SUCCESS; } -STATUS php_http_method_call(zval *object, const char *method_str, size_t method_len, int argc, zval **argv[], zval **retval_ptr TSRMLS_DC) +php_http_object_method_t *php_http_object_method_init(php_http_object_method_t *cb, zval *zobject, const char *method_str, size_t method_len TSRMLS_DC) +{ + zval *zfn; + + if (!cb) { + cb = ecalloc(1, sizeof(*cb)); + } else { + memset(cb, 0, sizeof(*cb)); + } + + MAKE_STD_ZVAL(zfn); + ZVAL_STRINGL(zfn, method_str, method_len, 1); + + cb->fci.size = sizeof(cb->fci); + cb->fci.function_name = zfn; + cb->fcc.initialized = 1; + cb->fcc.calling_scope = cb->fcc.called_scope = Z_OBJCE_P(zobject); + cb->fcc.function_handler = Z_OBJ_HT_P(zobject)->get_method(&zobject, Z_STRVAL_P(cb->fci.function_name), Z_STRLEN_P(cb->fci.function_name), NULL TSRMLS_CC); + + return cb; +} + +void php_http_object_method_dtor(php_http_object_method_t *cb) +{ + if (cb->fci.function_name) { + zval_ptr_dtor(&cb->fci.function_name); + cb->fci.function_name = NULL; + } +} + +void php_http_object_method_free(php_http_object_method_t **cb) +{ + if (*cb) { + php_http_object_method_dtor(*cb); + efree(*cb); + *cb = NULL; + } +} + +STATUS php_http_object_method_call(php_http_object_method_t *cb, zval *zobject, zval **retval_ptr, int argc, zval ***args TSRMLS_DC) { - zend_fcall_info fci; - zval zmethod; - zval *retval; STATUS rv; + zval *retval = NULL; - fci.size = sizeof(fci); - fci.object_ptr = object; - fci.function_name = &zmethod; - fci.retval_ptr_ptr = retval_ptr ? retval_ptr : &retval; - fci.param_count = argc; - fci.params = argv; - fci.no_separation = 1; - fci.symbol_table = NULL; - fci.function_table = NULL; + Z_ADDREF_P(zobject); + cb->fci.object_ptr = zobject; + cb->fcc.object_ptr = zobject; - INIT_PZVAL(&zmethod); - ZVAL_STRINGL(&zmethod, method_str, method_len, 0); - rv = zend_call_function(&fci, NULL TSRMLS_CC); + cb->fci.retval_ptr_ptr = retval_ptr ? retval_ptr : &retval; + cb->fci.param_count = argc; + cb->fci.params = args; + + if (cb->fcc.called_scope != Z_OBJCE_P(zobject)) { + cb->fcc.called_scope = Z_OBJCE_P(zobject); + cb->fcc.function_handler = Z_OBJ_HT_P(zobject)->get_method(&zobject, Z_STRVAL_P(cb->fci.function_name), Z_STRLEN_P(cb->fci.function_name), NULL TSRMLS_CC); + } + + rv = zend_call_function(&cb->fci, &cb->fcc TSRMLS_CC); + + zval_ptr_dtor(&zobject); if (!retval_ptr && retval) { zval_ptr_dtor(&retval); } + return rv; } diff --git a/php_http_object.h b/php_http_object.h index 63730b4..1fbd817 100644 --- a/php_http_object.h +++ b/php_http_object.h @@ -24,7 +24,16 @@ zend_object_value php_http_object_new_ex(zend_class_entry *ce, void *nothing, ph typedef zend_object_value (*php_http_new_t)(zend_class_entry *ce, void *, void ** TSRMLS_DC); STATUS php_http_new(zend_object_value *ov, zend_class_entry *ce, php_http_new_t create, zend_class_entry *parent_ce, void *intern_ptr, void **obj_ptr TSRMLS_DC); -STATUS php_http_method_call(zval *object, const char *method_str, size_t method_len, int argc, zval **argv[], zval **retval_ptr TSRMLS_DC); + +typedef struct php_http_method { + zend_fcall_info fci; + zend_fcall_info_cache fcc; +} php_http_object_method_t; + +php_http_object_method_t *php_http_object_method_init(php_http_object_method_t *cb, zval *zobject, const char *method_str, size_t method_len TSRMLS_DC); +STATUS php_http_object_method_call(php_http_object_method_t *cb, zval *zobject, zval **retval, int argc, zval ***args TSRMLS_DC); +void php_http_object_method_dtor(php_http_object_method_t *cb); +void php_http_object_method_free(php_http_object_method_t **cb); #endif -- 2.30.2