]> granicus.if.org Git - php/commitdiff
Use optimized zend_array_dup() function. convert zend_hash_num_elements() and zend_ha...
authorDmitry Stogov <dmitry@zend.com>
Fri, 23 May 2014 16:37:53 +0000 (20:37 +0400)
committerDmitry Stogov <dmitry@zend.com>
Fri, 23 May 2014 16:37:53 +0000 (20:37 +0400)
16 files changed:
Zend/zend.c
Zend/zend_builtin_functions.c
Zend/zend_closures.c
Zend/zend_compile.c
Zend/zend_hash.c
Zend/zend_hash.h
Zend/zend_operators.c
Zend/zend_variables.c
ext/dom/php_dom.c
ext/gmp/gmp.c
ext/soap/soap.c
ext/spl/spl_array.c
ext/spl/spl_directory.c
ext/spl/spl_observer.c
ext/standard/array.c
ext/standard/browscap.c

index eccd477f77857b6e93264ad2a5e86637f15ff73d..f7f78f30df16a4f4bf8bd2e7bcd8b907c70b2cb0 100644 (file)
@@ -1166,8 +1166,8 @@ ZEND_API void zend_error(int type, const char *format, ...) /* {{{ */
                        if (!EG(active_symbol_table)) {
                                ZVAL_NULL(&params[4]);
                        } else {
-                               array_init_size(&params[4], zend_hash_num_elements(&EG(active_symbol_table)->ht));
-                               zend_hash_copy(Z_ARRVAL(params[4]), &EG(active_symbol_table)->ht, zval_add_ref);
+                               ZVAL_NEW_ARR(&params[4]);
+                               zend_array_dup(Z_ARRVAL(params[4]), &EG(active_symbol_table)->ht);
                        }
 
                        ZVAL_COPY_VALUE(&orig_user_error_handler, &EG(user_error_handler));
index d8b828763fe29f54908cdb7b9d8164c7ea1ff0de..77743fbd329bb72810356a934d12a489712a073d 100644 (file)
@@ -1713,9 +1713,8 @@ ZEND_FUNCTION(get_defined_vars)
                zend_rebuild_symbol_table(TSRMLS_C);
        }
 
-       array_init_size(return_value, zend_hash_num_elements(&EG(active_symbol_table)->ht));
-
-       zend_hash_copy(Z_ARRVAL_P(return_value), &EG(active_symbol_table)->ht, zval_add_ref);
+       ZVAL_NEW_ARR(return_value);
+       zend_array_dup(Z_ARRVAL_P(return_value), &EG(active_symbol_table)->ht);
 }
 /* }}} */
 
index 1eae481829c9b450515c179eaa4994641d3f846f..96252e8be0527d7582804d02ff978f8aa48dd0f7 100644 (file)
@@ -297,8 +297,8 @@ static HashTable *zend_closure_get_debug_info(zval *object, int *is_temp TSRMLS_
        if (closure->debug_info->u.v.nApplyCount == 0) {
                if (closure->func.type == ZEND_USER_FUNCTION && closure->func.op_array.static_variables) {
                        HashTable *static_variables = closure->func.op_array.static_variables;
-                       array_init(&val);
-                       zend_hash_copy(Z_ARRVAL(val), static_variables, zval_add_ref);
+                       ZVAL_NEW_ARR(&val);
+                       zend_array_dup(Z_ARRVAL(val), static_variables);
                        zend_hash_str_update(closure->debug_info, "static", sizeof("static")-1, &val);
                }
 
index 5f2cbbfde4cb62e5402905650b276181b43e5342..20e4b5f341cbe15cf6c755180de2135d92b5e3d3 100644 (file)
@@ -3076,8 +3076,7 @@ ZEND_API void function_add_ref(zend_function *function) /* {{{ */
                        HashTable *static_variables = op_array->static_variables;
 
                        ALLOC_HASHTABLE(op_array->static_variables);
-                       zend_hash_init(op_array->static_variables, zend_hash_num_elements(static_variables), NULL, ZVAL_PTR_DTOR, 0);
-                       zend_hash_copy(op_array->static_variables, static_variables, zval_add_ref);
+                       zend_array_dup(op_array->static_variables, static_variables);
                }
                op_array->run_time_cache = NULL;
        } else if (function->type == ZEND_INTERNAL_FUNCTION) {
index 695f05d2251f3c8759523a0adff605b0923a1e85..ee1dcb2501af24f84cda97690cfb48fed4688095 100644 (file)
@@ -1070,6 +1070,131 @@ ZEND_API void zend_hash_copy(HashTable *target, HashTable *source, copy_ctor_fun
 }
 
 
+ZEND_API void zend_array_dup(HashTable *target, HashTable *source)
+{
+    uint idx, target_idx;
+       uint nIndex;
+       Bucket *p, *q;
+       zval *data;
+
+       IS_CONSISTENT(source);
+       
+       target->nTableMask = source->nTableMask;
+       target->nTableSize = source->nTableSize;
+       target->pDestructor = source->pDestructor;
+       target->nInternalPointer = INVALID_IDX;
+       target->u.flags = (source->u.flags & ~HASH_FLAG_PERSISTENT);
+
+       target_idx = 0;
+       if (target->nTableMask) {
+               if (target->u.flags & HASH_FLAG_PACKED) {
+                       target->nNumUsed = source->nNumUsed;
+                       target->nNumOfElements = source->nNumOfElements;
+                       target->nNextFreeElement = source->nNextFreeElement;
+                       target->arData = (Bucket *) safe_pemalloc(target->nTableSize, sizeof(Bucket), 0, 0);
+                       target->arHash = (zend_uint*)&uninitialized_bucket;
+                       target->nInternalPointer = source->nInternalPointer;
+
+                       for (idx = 0; idx < source->nNumUsed; idx++) {          
+                               p = source->arData + idx;
+                               q = target->arData + idx;
+                               if (Z_TYPE(p->val) == IS_UNDEF) {
+                                       q->h = 0;
+                                       q->key = NULL;
+                                       ZVAL_UNDEF(&q->val);
+                                       continue;
+                               }
+                               /* INDIRECT element may point to UNDEF-ined slots */
+                               data = &p->val;
+                               if (Z_TYPE_P(data) == IS_INDIRECT) {
+                                       data = Z_INDIRECT_P(data);
+                                       if (Z_TYPE_P(data) == IS_UNDEF) {
+                                               q->h = 0;
+                                               q->key = NULL;
+                                               ZVAL_UNDEF(&q->val);
+                                               continue;
+                                       }
+                               }
+
+                               q->h = p->h;
+                               q->key = NULL;
+                               if (Z_OPT_REFCOUNTED_P(data)) {
+                                       if (Z_ISREF_P(data) && Z_REFCOUNT_P(data) == 1) {
+                                               ZVAL_DUP(&q->val, Z_REFVAL_P(data));
+                                       } else {
+                                               ZVAL_COPY(&q->val, data);
+                                       }
+                               } else {
+                                       ZVAL_COPY_VALUE(&q->val, data);
+                               }
+                       }
+                       if (target->nNumOfElements > 0 &&
+                           target->nInternalPointer == INVALID_IDX) {
+                               idx = 0;
+                               while (Z_TYPE(target->arData[idx].val) == IS_UNDEF) {
+                                       idx++;
+                               }
+                               target->nInternalPointer = idx;
+                       }
+               } else {
+                       target->nNextFreeElement = source->nNextFreeElement;
+                       target->arData = (Bucket *) safe_pemalloc(target->nTableSize, sizeof(Bucket) + sizeof(zend_uint), 0, 0);
+                       target->arHash = (zend_uint*)(target->arData + target->nTableSize);
+                       memset(target->arHash, INVALID_IDX, target->nTableSize * sizeof(zend_uint));
+
+                       for (idx = 0; idx < source->nNumUsed; idx++) {          
+                               p = source->arData + idx;
+                               if (Z_TYPE(p->val) == IS_UNDEF) continue;
+                               /* INDIRECT element may point to UNDEF-ined slots */
+                               data = &p->val;
+                               if (Z_TYPE_P(data) == IS_INDIRECT) {
+                                       data = Z_INDIRECT_P(data);
+                                       if (Z_TYPE_P(data) == IS_UNDEF) {
+                                               continue;
+                                       }
+                               }
+
+                               if (source->nInternalPointer == idx) {
+                                       target->nInternalPointer = target_idx;
+                               }
+
+                               q = target->arData + target_idx;
+                               q->h = p->h;
+                               q->key = p->key;
+                               if (q->key) {
+                                       STR_ADDREF(q->key);
+                               }
+                               nIndex = q->h & target->nTableMask;
+                               Z_NEXT(q->val) = target->arHash[nIndex];
+                               target->arHash[nIndex] = target_idx;
+                               if (Z_OPT_REFCOUNTED_P(data)) {
+                                       if (Z_ISREF_P(data) && Z_REFCOUNT_P(data) == 1) {
+                                               ZVAL_DUP(&q->val, Z_REFVAL_P(data));
+                                       } else {
+                                               ZVAL_COPY(&q->val, data);
+                                       }
+                               } else {
+                                       ZVAL_COPY_VALUE(&q->val, data);
+                               }
+                               target_idx++;
+                       }
+                       target->nNumUsed = target_idx;
+                       target->nNumOfElements = target_idx;
+                       if (target->nNumOfElements > 0 &&
+                           target->nInternalPointer == INVALID_IDX) {
+                               target->nInternalPointer = 0;
+                       }
+               }
+       } else {
+               target->nNumUsed = 0;
+               target->nNumOfElements = 0;
+               target->nNextFreeElement = 0;
+               target->arData = NULL;
+               target->arHash = (zend_uint*)&uninitialized_bucket;
+       }
+}
+
+
 ZEND_API void _zend_hash_merge(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, int overwrite ZEND_FILE_LINE_DC)
 {
     uint idx;
@@ -1251,14 +1376,6 @@ ZEND_API int zend_hash_index_exists(const HashTable *ht, ulong h)
 }
 
 
-ZEND_API int zend_hash_num_elements(const HashTable *ht)
-{
-       IS_CONSISTENT(ht);
-
-       return ht->nNumOfElements;
-}
-
-
 ZEND_API int zend_hash_get_pointer(const HashTable *ht, HashPointer *ptr)
 {
        ptr->pos = ht->nInternalPointer;
@@ -1673,14 +1790,6 @@ ZEND_API zval *zend_hash_minmax(const HashTable *ht, compare_func_t compar, int
        return &res->val;
 }
 
-ZEND_API ulong zend_hash_next_free_element(const HashTable *ht)
-{
-       IS_CONSISTENT(ht);
-
-       return ht->nNextFreeElement;
-
-}
-
 /*
  * Local variables:
  * tab-width: 4
index 6f6d9f0ec7b2202f962a8e7ff83be3bcaafec76b..04fc311a52f9eb5382040ddffe810792cb5f8eba 100644 (file)
@@ -134,7 +134,6 @@ ZEND_API zval *zend_hash_index_find(const HashTable *ht, ulong h);
 ZEND_API int zend_hash_exists(const HashTable *ht, zend_string *key);
 ZEND_API int zend_hash_str_exists(const HashTable *ht, const char *str, int len);
 ZEND_API int zend_hash_index_exists(const HashTable *ht, ulong h);
-ZEND_API ulong zend_hash_next_free_element(const HashTable *ht);
 
 /* traversing */
 #define zend_hash_has_more_elements_ex(ht, pos) \
@@ -187,10 +186,16 @@ ZEND_API zval *zend_hash_minmax(const HashTable *ht, compare_func_t compar, int
 #define zend_hash_merge(target, source, pCopyConstructor, overwrite)                                   \
        _zend_hash_merge(target, source, pCopyConstructor, overwrite ZEND_FILE_LINE_CC)
 
-ZEND_API int zend_hash_num_elements(const HashTable *ht);
+#define zend_hash_num_elements(ht) \
+       (ht)->nNumOfElements
+
+#define zend_hash_next_free_element(ht) \
+       (ht)->nNextFreeElement
 
 ZEND_API int zend_hash_rehash(HashTable *ht);
 
+ZEND_API void zend_array_dup(HashTable *target, HashTable *source);
+
 #if ZEND_DEBUG
 /* debug */
 void zend_hash_display_pListTail(const HashTable *ht);
index b8ab22fc069b84abe879bbab8fd8b573ce32055f..a1554164a0b4fb32445976cc08bfbe225759ee86 100644 (file)
@@ -671,8 +671,7 @@ ZEND_API void convert_to_array(zval *op) /* {{{ */
                                        if (obj_ht) {
                                                zval arr;
                                                ZVAL_NEW_ARR(&arr);
-                                               zend_hash_init(Z_ARRVAL(arr), zend_hash_num_elements(obj_ht), NULL, ZVAL_PTR_DTOR, 0);
-                                               zend_hash_copy(Z_ARRVAL(arr), obj_ht, zval_add_ref);
+                                               zend_array_dup(Z_ARRVAL(arr), obj_ht);
                                                zval_dtor(op);
                                                ZVAL_COPY_VALUE(op, &arr);
                                                return;
index ccdef2246c574694963794c85b980981bdcbac6d..ac65d9d18c649a4fc42691eaff7871b62cb33079 100644 (file)
@@ -245,8 +245,7 @@ ZEND_API void _zval_copy_ctor_func(zval *zvalue ZEND_FILE_LINE_DC)
                                }
                                ht = Z_ARRVAL_P(zvalue);
                                ZVAL_NEW_ARR(zvalue);
-                               zend_hash_init(Z_ARRVAL_P(zvalue), zend_hash_num_elements(ht), NULL, ZVAL_PTR_DTOR, 0);
-                               zend_hash_copy(Z_ARRVAL_P(zvalue), ht, zval_add_ref);
+                               zend_array_dup(Z_ARRVAL_P(zvalue), ht);
                        }
                        break;
                case IS_CONSTANT_AST: {
index 77bf91920fa3fa3451aaee3fd9687b9c6a2c3b1b..7120a7ee08b05f1681255bcdb3c158c4202dc6c4 100644 (file)
@@ -425,10 +425,9 @@ static HashTable* dom_get_debug_info_helper(zval *object, int *is_temp TSRMLS_DC
        *is_temp = 1;
 
        ALLOC_HASHTABLE(debug_info);
-       ZEND_INIT_SYMTABLE_EX(debug_info, 32, 0);
 
        std_props = zend_std_get_properties(object TSRMLS_CC);
-       zend_hash_copy(debug_info, std_props, (copy_ctor_func_t) zval_add_ref);
+       zend_array_dup(debug_info, std_props);
 
        if (!prop_handlers) {
                return debug_info;
index e2ece55869cfcf33cddb1a0f1f6b3cf2452cbd9a..17ec39d0875c7fd07232a66dc57f1c3170b85c79 100644 (file)
@@ -429,8 +429,7 @@ static HashTable *gmp_get_debug_info(zval *obj, int *is_temp TSRMLS_DC) /* {{{ *
 
        *is_temp = 1;
        ALLOC_HASHTABLE(ht);
-       ZEND_INIT_SYMTABLE_EX(ht, zend_hash_num_elements(props) + 1, 0);
-       zend_hash_copy(ht, props, (copy_ctor_func_t) zval_add_ref);
+       zend_array_dup(ht, props);
 
        gmp_strval(&zv, gmpnum, 10);
        zend_hash_str_update(ht, "num", sizeof("num")-1, &zv);
index 9660c32e24e812b7eed4daa6831fcd6bd7bdd8d5..5d2eaae9aac20a6312263de2c3f29c22289bb364 100644 (file)
@@ -1178,8 +1178,7 @@ PHP_METHOD(SoapServer, SoapServer)
                if ((tmp = zend_hash_str_find(ht, "classmap", sizeof("classmap")-1)) != NULL &&
                        Z_TYPE_P(tmp) == IS_ARRAY) {
                        ALLOC_HASHTABLE(service->class_map);
-                       zend_hash_init(service->class_map, zend_hash_num_elements(Z_ARRVAL_P(tmp)), NULL, ZVAL_PTR_DTOR, 0);
-                       zend_hash_copy(service->class_map, Z_ARRVAL_P(tmp), zval_add_ref);
+                       zend_array_dup(service->class_map, Z_ARRVAL_P(tmp));
                }
 
                if ((tmp = zend_hash_str_find(ht, "typemap", sizeof("typemap")-1)) != NULL &&
@@ -2904,8 +2903,7 @@ PHP_METHOD(SoapClient, __call)
                if (soap_headers) {
                        if (!free_soap_headers) {
                                HashTable *t =  emalloc(sizeof(HashTable));
-                               zend_hash_init(t, 0, NULL, ZVAL_PTR_DTOR, 0);
-                               zend_hash_copy(t, soap_headers, zval_add_ref);
+                               zend_array_dup(t, soap_headers);
                                soap_headers = t;
                                free_soap_headers = 1;
                        }
index 5c873f36a48bd86c7e594104ca440f669fdef8f6..2fa7a53dd3b286844bf6e09e728b4792679bad4a 100644 (file)
@@ -198,8 +198,8 @@ static zend_object *spl_array_object_new_ex(zend_class_entry *class_type, zval *
                if (clone_orig) {
                        intern->array = other->array;
                        if (Z_OBJ_HT_P(orig) == &spl_handler_ArrayObject) {
-                               array_init(&intern->array);
-                               zend_hash_copy(HASH_OF(&intern->array), HASH_OF(&other->array), (copy_ctor_func_t) zval_add_ref);
+                               ZVAL_NEW_ARR(&intern->array);
+                               zend_array_dup(Z_ARRVAL(intern->array), HASH_OF(&other->array));
                        }
                        if (Z_OBJ_HT_P(orig) == &spl_handler_ArrayIterator) {
                                Z_ADDREF_P(&other->array);
@@ -824,8 +824,8 @@ SPL_METHOD(Array, getArrayCopy)
        zval *object = getThis();
        spl_array_object *intern = Z_SPLARRAY_P(object);
 
-    array_init(return_value);
-       zend_hash_copy(Z_ARRVAL_P(return_value), spl_array_get_hash_table(intern, 0 TSRMLS_CC), (copy_ctor_func_t) zval_add_ref);
+       ZVAL_NEW_ARR(return_value);
+       zend_array_dup(Z_ARRVAL_P(return_value), spl_array_get_hash_table(intern, 0 TSRMLS_CC));
 } /* }}} */
 
 static HashTable *spl_array_get_properties(zval *object TSRMLS_DC) /* {{{ */
@@ -1323,8 +1323,8 @@ SPL_METHOD(Array, exchangeArray)
        zval *object = getThis(), *array;
        spl_array_object *intern = Z_SPLARRAY_P(object);
 
-       array_init(return_value);
-       zend_hash_copy(HASH_OF(return_value), spl_array_get_hash_table(intern, 0 TSRMLS_CC), (copy_ctor_func_t)zval_add_ref);
+       ZVAL_NEW_ARR(return_value);
+       zend_array_dup(Z_ARRVAL_P(return_value), spl_array_get_hash_table(intern, 0 TSRMLS_CC));
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &array) == FAILURE) {
                return;
        }
@@ -1745,8 +1745,8 @@ SPL_METHOD(Array, serialize)
                rebuild_object_properties(&intern->std);
        }
 
-       array_init(&members);
-       zend_hash_copy(Z_ARRVAL(members), intern->std.properties, (copy_ctor_func_t)zval_add_ref);
+       ZVAL_NEW_ARR(&members);
+       zend_array_dup(Z_ARRVAL(members), intern->std.properties);
 
        php_var_serialize(&buf, &members, &var_hash TSRMLS_CC); /* finishes the string */
 
index ca7baf2226d672a5f33f9dc233f7b0c5b51d0179..9405dafa0dcf85025419c667264ca4c8c32a36fd 100644 (file)
@@ -589,9 +589,8 @@ static HashTable *spl_filesystem_object_get_debug_info(zval *object, int *is_tem
        }
 
        ALLOC_HASHTABLE(rv);
-       ZEND_INIT_SYMTABLE_EX(rv, zend_hash_num_elements(intern->std.properties) + 3, 0);
 
-       zend_hash_copy(rv, intern->std.properties, (copy_ctor_func_t) zval_add_ref);
+       zend_array_dup(rv, intern->std.properties);
 
        pnstr = spl_gen_private_prop_name(spl_ce_SplFileInfo, "pathName", sizeof("pathName")-1 TSRMLS_CC);
        path = spl_filesystem_object_get_pathname(intern, &path_len TSRMLS_CC);
index 52279c3429f10a6e83058e78edcc5dfac8bbcd3d..4ccd345df1acc07605a2974bd1b2e3661b186059 100644 (file)
@@ -772,8 +772,8 @@ SPL_METHOD(SplObjectStorage, serialize)
 
        /* members */
        smart_str_appendl(&buf, "m:", 2);
-       array_init(&members);
-       zend_hash_copy(Z_ARRVAL(members), zend_std_get_properties(getThis() TSRMLS_CC), (copy_ctor_func_t) zval_add_ref);
+       ZVAL_NEW_ARR(&members);
+       zend_array_dup(Z_ARRVAL(members), zend_std_get_properties(getThis() TSRMLS_CC));
        php_var_serialize(&buf, &members, &var_hash TSRMLS_CC); /* finishes the string */
        zval_ptr_dtor(&members);
 
index b8e0409d0619f40c43c03e150fe1976948c8ffa7..97ab2583f633774155246da1e487bc4e3c90eea0 100644 (file)
@@ -2811,8 +2811,8 @@ PHP_FUNCTION(array_unique)
 
        php_set_compare_func(sort_type TSRMLS_CC);
 
-       array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(array)));
-       zend_hash_copy(Z_ARRVAL_P(return_value), Z_ARRVAL_P(array), zval_add_ref);
+       ZVAL_NEW_ARR(return_value);
+       zend_array_dup(Z_ARRVAL_P(return_value), Z_ARRVAL_P(array));
 
        if (Z_ARRVAL_P(array)->nNumOfElements <= 1) {   /* nothing to do */
                return;
@@ -3164,8 +3164,7 @@ static void php_array_intersect(INTERNAL_FUNCTION_PARAMETERS, int behavior, int
                HashTable *old_ht = Z_ARRVAL_P(return_value);
 
                ZVAL_NEW_ARR(return_value);
-               zend_hash_init(Z_ARRVAL_P(return_value), zend_hash_num_elements(old_ht), NULL, ZVAL_PTR_DTOR, 0);
-               zend_hash_copy(Z_ARRVAL_P(return_value), old_ht, zval_add_ref);
+               zend_array_dup(Z_ARRVAL_P(return_value), old_ht);
        }
 
        /* go through the lists and look for common values */
@@ -3584,8 +3583,7 @@ static void php_array_diff(INTERNAL_FUNCTION_PARAMETERS, int behavior, int data_
                HashTable *old_ht = Z_ARRVAL_P(return_value);
 
                ZVAL_NEW_ARR(return_value);
-               zend_hash_init(Z_ARRVAL_P(return_value), zend_hash_num_elements(old_ht), NULL, ZVAL_PTR_DTOR, 0);
-               zend_hash_copy(Z_ARRVAL_P(return_value), old_ht, zval_add_ref);
+               zend_array_dup(Z_ARRVAL_P(return_value), old_ht);
        }
 
        /* go through the lists and look for values of ptr[0] that are not in the others */
@@ -3942,17 +3940,23 @@ PHP_FUNCTION(array_multisort)
        /* Restructure the arrays based on sorted indirect - this is mostly taken from zend_hash_sort() function. */
        HANDLE_BLOCK_INTERRUPTIONS();
        for (i = 0; i < num_arrays; i++) {
+               int repack;
+
                hash = Z_ARRVAL_P(arrays[i]);
                hash->nNumUsed = array_size;
                hash->nInternalPointer = 0;
+               repack = !(hash->u.flags & HASH_FLAG_PACKED);
 
                for (n = 0, k = 0; k < array_size; k++) {
                        hash->arData[k] = indirect[k][i];
-                       if (hash->arData[k].key == NULL)
+                       if (hash->arData[k].key == NULL) {
                                hash->arData[k].h = n++;
+                       } else {
+                               repack = 0;
+                       }
                }
                hash->nNextFreeElement = array_size;
-               if (!(hash->u.flags & HASH_FLAG_PACKED)) {
+               if (repack) {
                        zend_hash_to_packed(hash);
                }
        }
index 186c30cc902f584250c5d9520f1d606e2138bd5a..fc68a34f8c9bbc719237948883357c2c94fb5e6e 100644 (file)
@@ -494,8 +494,8 @@ PHP_FUNCTION(get_browser)
        }
 
        if (return_array) {
-               array_init(return_value);
-               zend_hash_copy(Z_ARRVAL_P(return_value), Z_ARRVAL_P(agent), (copy_ctor_func_t) browscap_zval_copy_ctor);
+               ZVAL_NEW_ARR(return_value);
+               zend_array_dup(Z_ARRVAL_P(return_value), Z_ARRVAL_P(agent));
        }
        else {
                object_init(return_value);