Skip to content

Commit d3c798a

Browse files
committed
Change check for read/write handler overrides to use flags
1 parent 56504e7 commit d3c798a

File tree

1 file changed

+30
-32
lines changed

1 file changed

+30
-32
lines changed

ext/spl/spl_observer.c

Lines changed: 30 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -44,19 +44,20 @@ PHPAPI zend_class_entry *spl_ce_MultipleIterator;
4444

4545
PHPAPI zend_object_handlers spl_handler_SplObjectStorage;
4646

47-
typedef struct _spl_SplObjectStorage_fptrs {
48-
zend_function *get_hash;
49-
bool override_read_dimension;
50-
bool override_write_dimension;
51-
} spl_SplObjectStorage_fptrs;
47+
typedef enum {
48+
SOS_OVERRIDDEN_READ_DIMENSION = 1,
49+
SOS_OVERRIDDEN_WRITE_DIMENSION = 2,
50+
} SplObjectStorageBitFlags;
5251

5352
typedef struct _spl_SplObjectStorage { /* {{{ */
54-
HashTable storage;
55-
zend_long index;
56-
HashPosition pos;
57-
zend_long flags;
58-
spl_SplObjectStorage_fptrs *fptrs;
59-
zend_object std;
53+
HashTable storage;
54+
zend_long index;
55+
HashPosition pos;
56+
/* In SplObjectStorage, flags is a hidden implementation detail to optimize ArrayAccess handlers.
57+
* In MultipleIterator on a different class hierarchy, flags is a user settable value controlling iteration behavior. */
58+
zend_long flags;
59+
zend_function *fptr_get_hash;
60+
zend_object std;
6061
} spl_SplObjectStorage; /* }}} */
6162

6263
/* {{{ storage is an assoc array of [zend_object*]=>[zval *obj, zval *inf] */
@@ -79,19 +80,15 @@ void spl_SplObjectStorage_free_storage(zend_object *object) /* {{{ */
7980
zend_object_std_dtor(&intern->std);
8081

8182
zend_hash_destroy(&intern->storage);
82-
83-
if (UNEXPECTED(intern->fptrs)) {
84-
efree_size(intern->fptrs, sizeof(spl_SplObjectStorage_fptrs));
85-
}
8683
} /* }}} */
8784

8885
static int spl_object_storage_get_hash(zend_hash_key *key, spl_SplObjectStorage *intern, zend_object *obj) {
89-
if (UNEXPECTED(intern->fptrs) && intern->fptrs->get_hash) {
86+
if (UNEXPECTED(intern->fptr_get_hash)) {
9087
zval param;
9188
zval rv;
9289
ZVAL_OBJ(&param, obj);
9390
zend_call_method_with_1_params(
94-
&intern->std, intern->std.ce, &intern->fptrs->get_hash, "getHash", &rv, &param);
91+
&intern->std, intern->std.ce, &intern->fptr_get_hash, "getHash", &rv, &param);
9592
if (!Z_ISUNDEF(rv)) {
9693
if (Z_TYPE(rv) == IS_STRING) {
9794
key->key = Z_STR(rv);
@@ -154,7 +151,7 @@ static spl_SplObjectStorageElement *spl_object_storage_attach_handle(spl_SplObje
154151
zval *entry_zv;
155152
spl_SplObjectStorageElement *pelement;
156153
entry_zv = zend_hash_index_lookup(&intern->storage, handle);
157-
ZEND_ASSERT(intern->fptrs == NULL || !intern->fptrs->override_write_dimension);
154+
ZEND_ASSERT(!(intern->flags & SOS_OVERRIDDEN_WRITE_DIMENSION));
158155

159156
if (Z_TYPE_P(entry_zv) != IS_NULL) {
160157
zval zv_inf;
@@ -179,7 +176,7 @@ static spl_SplObjectStorageElement *spl_object_storage_attach_handle(spl_SplObje
179176

180177
spl_SplObjectStorageElement *spl_object_storage_attach(spl_SplObjectStorage *intern, zend_object *obj, zval *inf) /* {{{ */
181178
{
182-
if (EXPECTED(intern->fptrs == NULL || !intern->fptrs->override_write_dimension)) {
179+
if (EXPECTED(!(intern->flags & SOS_OVERRIDDEN_WRITE_DIMENSION))) {
183180
return spl_object_storage_attach_handle(intern, obj, inf);
184181
}
185182

@@ -269,21 +266,22 @@ static zend_object *spl_object_storage_new_ex(zend_class_entry *class_type, zend
269266

270267
while (parent) {
271268
if (parent == spl_ce_SplObjectStorage) {
272-
/* TODO: Make these singletons with a map from class entry to IS_NULL/IS_PTR */
269+
/* Possible optimization: Cache these results with a map from class entry to IS_NULL/IS_PTR.
270+
* Or maybe just a single item with the result for the most recently loaded subclass. */
273271
if (class_type != spl_ce_SplObjectStorage) {
274-
spl_SplObjectStorage_fptrs fptrs;
275-
fptrs.get_hash = zend_hash_str_find_ptr(&class_type->function_table, "gethash", sizeof("gethash") - 1);
276-
if (fptrs.get_hash->common.scope == spl_ce_SplObjectStorage) {
277-
fptrs.get_hash = NULL;
272+
zend_function *get_hash = zend_hash_str_find_ptr(&class_type->function_table, "gethash", sizeof("gethash") - 1);
273+
if (get_hash->common.scope != spl_ce_SplObjectStorage) {
274+
intern->fptr_get_hash = get_hash;
278275
}
279-
fptrs.override_read_dimension = fptrs.get_hash != NULL ||
276+
if (get_hash != NULL ||
280277
SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE(class_type, "offsetget") ||
281-
SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE(class_type, "offsetexists");
278+
SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE(class_type, "offsetexists")) {
279+
intern->flags |= SOS_OVERRIDDEN_READ_DIMENSION;
280+
}
282281

283-
fptrs.override_write_dimension = fptrs.get_hash != NULL || SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE(class_type, "offsetset");
284-
if (fptrs.get_hash || fptrs.override_read_dimension || fptrs.override_write_dimension) {
285-
intern->fptrs = emalloc(sizeof(spl_SplObjectStorage_fptrs));
286-
*intern->fptrs = fptrs;
282+
if (get_hash != NULL ||
283+
SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE(class_type, "offsetset")) {
284+
intern->flags |= SOS_OVERRIDDEN_WRITE_DIMENSION;
287285
}
288286
}
289287
break;
@@ -437,7 +435,7 @@ PHP_METHOD(SplObjectStorage, attach)
437435
static zval *spl_object_storage_read_dimension(zend_object *object, zval *offset, int type, zval *rv)
438436
{
439437
spl_SplObjectStorage *intern = spl_object_storage_from_obj(object);
440-
if (UNEXPECTED(offset == NULL || Z_TYPE_P(offset) != IS_OBJECT || (intern->fptrs && intern->fptrs->override_read_dimension))) {
438+
if (UNEXPECTED(offset == NULL || Z_TYPE_P(offset) != IS_OBJECT || (intern->flags & SOS_OVERRIDDEN_READ_DIMENSION))) {
441439
/* Can't optimize it if getHash, offsetExists, or offsetGet is overridden */
442440
return zend_std_read_dimension(object, offset, type, rv);
443441
}
@@ -460,7 +458,7 @@ static zval *spl_object_storage_read_dimension(zend_object *object, zval *offset
460458
static void spl_object_storage_write_dimension(zend_object *object, zval *offset, zval *inf)
461459
{
462460
spl_SplObjectStorage *intern = spl_object_storage_from_obj(object);
463-
if (UNEXPECTED(offset == NULL || Z_TYPE_P(offset) != IS_OBJECT || (intern->fptrs && intern->fptrs->override_write_dimension))) {
461+
if (UNEXPECTED(offset == NULL || Z_TYPE_P(offset) != IS_OBJECT || (intern->flags & SOS_OVERRIDDEN_WRITE_DIMENSION))) {
464462
zend_std_write_dimension(object, offset, inf);
465463
return;
466464
}

0 commit comments

Comments
 (0)