]> granicus.if.org Git - php/commitdiff
Use COW to prevent unnecessary duplication of dynamic propertyes of stdClass (and...
authorDmitry Stogov <dmitry@zend.com>
Wed, 17 Jun 2015 09:50:16 +0000 (12:50 +0300)
committerDmitry Stogov <dmitry@zend.com>
Wed, 17 Jun 2015 09:50:16 +0000 (12:50 +0300)
Zend/zend_builtin_functions.c
Zend/zend_object_handlers.c
Zend/zend_objects.c
Zend/zend_operators.c

index 8989e93fa61f2b5c443e4e2ea7c948664f5c2185..8ea758adcc12244034c0e9615323dddb931b7322 100644 (file)
@@ -1151,6 +1151,12 @@ ZEND_FUNCTION(get_object_vars)
 
        if (!zobj->ce->default_properties_count && properties == zobj->properties) {
                /* fast copy */
+               if (EXPECTED(zobj->handlers == &std_object_handlers)) {
+                       if (EXPECTED(!(GC_FLAGS(properties) & IS_ARRAY_IMMUTABLE))) {
+                               GC_REFCOUNT(properties)++;
+                       }
+                       RETURN_ARR(properties);
+               }
                RETURN_ARR(zend_array_dup(properties));
        } else {
                array_init_size(return_value, zend_hash_num_elements(properties));
index 74ae382df4bb5280e9cc4cc758897deb61267b2d..f284ca4b31963b84b5b75ac3dccfcb960e98e095 100644 (file)
@@ -628,6 +628,12 @@ ZEND_API void zend_std_write_property(zval *object, zval *member, zval *value, v
                                goto found;
                        }
                } else if (EXPECTED(zobj->properties != NULL)) {
+                       if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) {
+                               if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) {
+                                       GC_REFCOUNT(zobj->properties)--;
+                               }
+                               zobj->properties = zend_array_dup(zobj->properties);
+                       }
                        if ((variable_ptr = zend_hash_find(zobj->properties, Z_STR_P(member))) != NULL) {
 found:
                                zend_assign_to_variable(variable_ptr, value, IS_CV);
@@ -815,20 +821,31 @@ static zval *zend_std_get_property_ptr_ptr(zval *object, zval *member, int type,
                                }
                        }
                } else {
-                       if (UNEXPECTED(!zobj->properties) ||
-                           UNEXPECTED((retval = zend_hash_find(zobj->properties, name)) == NULL)) {
-                               if (EXPECTED(!zobj->ce->__get) ||
-                                   UNEXPECTED((*zend_get_property_guard(zobj, name)) & IN_GET)) {
-                                       if (UNEXPECTED(!zobj->properties)) {
-                                               rebuild_object_properties(zobj);
+                       if (EXPECTED(zobj->properties)) {
+                               if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) {
+                                       if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) {
+                                               GC_REFCOUNT(zobj->properties)--;
                                        }
-                                       retval = zend_hash_update(zobj->properties, name, &EG(uninitialized_zval));
-                                       /* Notice is thrown after creation of the property, to avoid EG(std_property_info)
-                                        * being overwritten in an error handler. */
-                                       if (UNEXPECTED(type == BP_VAR_RW || type == BP_VAR_R)) {
-                                               zend_error(E_NOTICE, "Undefined property: %s::$%s", zobj->ce->name->val, name->val);
+                                       zobj->properties = zend_array_dup(zobj->properties);
+                               }
+                           if (EXPECTED((retval = zend_hash_find(zobj->properties, name)) != NULL)) {
+                                       if (UNEXPECTED(Z_TYPE_P(member) != IS_STRING)) {
+                                               zend_string_release(name);
                                        }
-                       }
+                                       return retval;
+                           }
+                       }
+                       if (EXPECTED(!zobj->ce->__get) ||
+                           UNEXPECTED((*zend_get_property_guard(zobj, name)) & IN_GET)) {
+                               if (UNEXPECTED(!zobj->properties)) {
+                                       rebuild_object_properties(zobj);
+                               }
+                               retval = zend_hash_update(zobj->properties, name, &EG(uninitialized_zval));
+                               /* Notice is thrown after creation of the property, to avoid EG(std_property_info)
+                                * being overwritten in an error handler. */
+                               if (UNEXPECTED(type == BP_VAR_RW || type == BP_VAR_R)) {
+                                       zend_error(E_NOTICE, "Undefined property: %s::$%s", zobj->ce->name->val, name->val);
+                               }
                        }
                }
        }
@@ -866,9 +883,16 @@ static void zend_std_unset_property(zval *object, zval *member, void **cache_slo
                                ZVAL_UNDEF(slot);
                                goto exit;
                        }
-               } else if (EXPECTED(zobj->properties != NULL) &&
-               EXPECTED(zend_hash_del(zobj->properties, Z_STR_P(member)) != FAILURE)) {
-                       goto exit;
+               } else if (EXPECTED(zobj->properties != NULL)) {
+                       if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) {
+                               if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) {
+                                       GC_REFCOUNT(zobj->properties)--;
+                               }
+                               zobj->properties = zend_array_dup(zobj->properties);
+                       }
+                       if (EXPECTED(zend_hash_del(zobj->properties, Z_STR_P(member)) != FAILURE)) {
+                               goto exit;
+                       }
                }
        } else if (UNEXPECTED(EG(exception))) {
                goto exit;
index 9007661f03b8fdee7cfd0730b8331332d2eeb389..2a0655b258fb2067e068b99bff0847f982b36dfd 100644 (file)
@@ -55,7 +55,11 @@ ZEND_API void zend_object_std_dtor(zend_object *object)
        zval *p, *end;
 
        if (object->properties) {
-               zend_array_destroy(object->properties);
+               if (EXPECTED(!(GC_FLAGS(object->properties) & IS_ARRAY_IMMUTABLE))) {
+                       if (EXPECTED(--GC_REFCOUNT(object->properties) == 0)) {
+                               zend_array_destroy(object->properties);
+                       }
+               }
        }
        p = object->properties_table;
        if (EXPECTED(object->ce->default_properties_count)) {
@@ -163,7 +167,17 @@ ZEND_API void zend_objects_clone_members(zend_object *new_object, zend_object *o
                        src++;
                        dst++;
                } while (src != end);
+       } else if (old_object->properties && !old_object->ce->clone) {
+               /* fast copy */
+               if (EXPECTED(old_object->handlers == &std_object_handlers)) {
+                       if (EXPECTED(!(GC_FLAGS(old_object->properties) & IS_ARRAY_IMMUTABLE))) {
+                               GC_REFCOUNT(old_object->properties)++;
+                       }
+                       new_object->properties = old_object->properties;
+                       return;
+               }
        }
+
        if (old_object->properties &&
            EXPECTED(zend_hash_num_elements(old_object->properties))) {
                zval *prop, new_prop;
index d7d25913823e21076c48d7255310b161e467696e..7e3b458bbed781b8b86c6efe64f6291bd9c74e64 100644 (file)
@@ -588,9 +588,24 @@ try_again:
                                        HashTable *obj_ht = Z_OBJ_HT_P(op)->get_properties(op);
                                        if (obj_ht) {
                                                zval arr;
-                                               ZVAL_ARR(&arr, zend_array_dup(obj_ht));
-                                               zval_dtor(op);
-                                               ZVAL_COPY_VALUE(op, &arr);
+
+                                               if (!Z_OBJCE_P(op)->default_properties_count && obj_ht == Z_OBJ_P(op)->properties) {
+                                                       /* fast copy */
+                                                       if (EXPECTED(Z_OBJ_P(op)->handlers == &std_object_handlers)) {
+                                                               ZVAL_ARR(&arr, obj_ht);
+                                                               if (EXPECTED(!(GC_FLAGS(Z_OBJ_P(op)->properties) & IS_ARRAY_IMMUTABLE))) {
+                                                                       GC_REFCOUNT(Z_OBJ_P(op)->properties)++;
+                                                               }
+                                                       } else {
+                                                               ZVAL_ARR(&arr, zend_array_dup(obj_ht));
+                                                       }
+                                                       zval_dtor(op);
+                                                       ZVAL_COPY_VALUE(op, &arr);
+                                               } else {
+                                                       ZVAL_ARR(&arr, zend_array_dup(obj_ht));
+                                                       zval_dtor(op);
+                                                       ZVAL_COPY_VALUE(op, &arr);
+                                               }
                                                return;
                                        }
                                } else {