Skip to content

Commit 5ea6e25

Browse files
committed
Use a union to cache zend_function*
1 parent 591af29 commit 5ea6e25

16 files changed

+332
-174
lines changed

Zend/zend.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,8 +201,11 @@ struct _zend_class_entry {
201201
int (*serialize)(zval *object, unsigned char **buffer, size_t *buf_len, zend_serialize_data *data);
202202
int (*unserialize)(zval *object, zend_class_entry *ce, const unsigned char *buf, size_t buf_len, zend_unserialize_data *data);
203203

204-
/* dimension handler callbacks */
205-
zend_class_dimensions_functions *dimension_handlers;
204+
/* C dimension handler callbacks for internal classes, and zend_function* pointers for userland classes */
205+
union {
206+
zend_user_class_dimensions_functions *dimension_functions;
207+
zend_internal_class_dimensions_functions *dimension_handlers;
208+
};
206209

207210
uint32_t num_interfaces;
208211
uint32_t num_traits;

Zend/zend_dimension_handlers.h

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
#include "zend_types.h"
2626

27-
typedef struct _zend_class_dimensions_functions {
27+
typedef struct _zend_internal_class_dimensions_functions {
2828
/* rv is a slot provided by the callee that is returned */
2929
zval *(*/* const */ read_dimension)(zend_object *object, zval *offset, zval *rv);
3030
bool (*/* const */ has_dimension)(zend_object *object, zval *offset);
@@ -34,6 +34,27 @@ typedef struct _zend_class_dimensions_functions {
3434
void (*/* const */ append)(zend_object *object, zval *value);
3535
zval *(*/* const */ fetch_append)(zend_object *object, zval *rv);
3636
void (*/* const */ unset_dimension)(zend_object *object, zval *offset);
37-
} zend_class_dimensions_functions;
37+
} zend_internal_class_dimensions_functions;
38+
39+
typedef struct _zend_user_class_dimensions_functions {
40+
zend_function *read_dimension;
41+
zend_function *has_dimension;
42+
zend_function *fetch_dimension;
43+
zend_function *write_dimension;
44+
zend_function *append;
45+
zend_function *fetch_append;
46+
zend_function *unset_dimension;
47+
} zend_user_class_dimensions_functions;
48+
49+
ZEND_API zval* zend_class_read_dimension(zend_object *object, zval *offset, zval *rv);
50+
ZEND_API bool zend_class_has_dimension(zend_object *object, zval *offset);
51+
ZEND_API zval* zend_class_fetch_dimension(zend_object *object, zval *offset, zval *rv);
52+
ZEND_API void zend_class_write_dimension(zend_object *object, zval *offset, zval *value);
53+
ZEND_API void zend_class_append(zend_object *object, zval *value);
54+
ZEND_API zval *zend_class_fetch_append(zend_object *object, zval *rv);
55+
ZEND_API void zend_class_unset_dimension(zend_object *object, zval *offset);
56+
57+
/* VM and JIT Helper */
58+
ZEND_API bool zend_class_isset_empty_dimension(zend_object *object, zval *offset, bool is_empty);
3859

3960
#endif /* ZEND_DIMENSION_HANDLERS_H */

Zend/zend_execute.c

Lines changed: 20 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1612,7 +1612,7 @@ static zend_never_inline void zend_unset_object_dim(zend_object *obj, zval *offs
16121612
if (EXPECTED(obj->ce->dimension_handlers)) {
16131613
if (EXPECTED(obj->ce->dimension_handlers->unset_dimension)) {
16141614
ZVAL_DEREF(offset);
1615-
obj->ce->dimension_handlers->unset_dimension(obj, offset);
1615+
zend_class_unset_dimension(obj, offset);
16161616
} else {
16171617
zend_invalid_use_of_object_as_array(obj, /* has_offset */ true, BP_VAR_UNSET);
16181618
}
@@ -1629,12 +1629,12 @@ static zend_never_inline void zend_assign_to_object_dim(zend_object *obj, zval *
16291629
&& obj->ce->dimension_handlers->write_dimension
16301630
) {
16311631
ZVAL_DEREF(offset);
1632-
obj->ce->dimension_handlers->write_dimension(obj, offset, value);
1632+
zend_class_write_dimension(obj, offset, value);
16331633
} else if (
16341634
!offset
16351635
&& obj->ce->dimension_handlers->append
16361636
) {
1637-
obj->ce->dimension_handlers->append(obj, value);
1637+
zend_class_append(obj, value);
16381638
} else {
16391639
zend_invalid_use_of_object_as_array(obj, /* has_offset */ offset, BP_VAR_W);
16401640
}
@@ -1752,8 +1752,7 @@ static zend_never_inline void zend_binary_assign_op_obj_dim(zend_object *obj, zv
17521752
if (zend_binary_op(&res, &zref, value OPLINE_CC) == SUCCESS) {
17531753
zval tmp;
17541754
ZVAL_NULL(&tmp);
1755-
1756-
obj->ce->dimension_handlers->write_dimension(obj, &tmp, &res);
1755+
zend_class_write_dimension(obj, &tmp, &res);
17571756
}
17581757

17591758
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
@@ -1828,7 +1827,7 @@ static zend_never_inline void zend_binary_assign_op_obj_dim(zend_object *obj, zv
18281827
zval *z;
18291828
zval rv, res;
18301829

1831-
z = obj->ce->dimension_handlers->read_dimension(obj, dim, &rv);
1830+
z = zend_class_read_dimension(obj, dim, &rv);
18321831
if (UNEXPECTED(z == NULL)) {
18331832
ZEND_ASSERT(EG(exception) && "returned NULL without exception");
18341833
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
@@ -1837,7 +1836,7 @@ static zend_never_inline void zend_binary_assign_op_obj_dim(zend_object *obj, zv
18371836
goto clean_up;
18381837
} else {
18391838
if (zend_binary_op(&res, z, value OPLINE_CC) == SUCCESS) {
1840-
obj->ce->dimension_handlers->write_dimension(obj, dim, &res);
1839+
zend_class_write_dimension(obj, dim, &res);
18411840
}
18421841
}
18431842

@@ -3009,15 +3008,15 @@ static zend_never_inline void zend_fetch_object_dimension_address(zval *result,
30093008
if (UNEXPECTED(type == BP_VAR_IS)) {
30103009
ZEND_ASSERT(obj->ce->dimension_handlers->has_dimension);
30113010
/* The key does not exist */
3012-
if (!obj->ce->dimension_handlers->has_dimension(obj, offset)) {
3011+
if (!zend_class_has_dimension(obj, offset)) {
30133012
ZVAL_UNDEF(result);
30143013
goto clean_up;
30153014
}
30163015
} else if (UNEXPECTED(type == BP_VAR_RW)) {
30173016
/* RW semantics dictate that the offset must actually exists, otherwise a warning is emitted */
3018-
offset_exists = obj->ce->dimension_handlers->has_dimension(obj, offset);
3017+
offset_exists = zend_class_has_dimension(obj, offset);
30193018
}
3020-
retval = obj->ce->dimension_handlers->fetch_dimension(obj, offset, result);
3019+
retval = zend_class_fetch_dimension(obj, offset, result);
30213020
if (UNEXPECTED(type == BP_VAR_RW && !offset_exists && !EG(exception))) {
30223021
// TODO Better warning?
30233022
zend_error(E_WARNING, "Undefined offset");
@@ -3029,7 +3028,7 @@ static zend_never_inline void zend_fetch_object_dimension_address(zval *result,
30293028
} else if (!offset && obj->ce->dimension_handlers->fetch_append) {
30303029
ZEND_ASSERT(zend_check_dimension_interfaces_implemented(obj, /* has_offset */ false, BP_VAR_FETCH));
30313030
ZEND_ASSERT(type != BP_VAR_IS);
3032-
retval = obj->ce->dimension_handlers->fetch_append(obj, result);
3031+
retval = zend_class_fetch_append(obj, result);
30333032
} else {
30343033
zend_invalid_use_of_object_as_array(obj, /* has_offset */ offset, BP_VAR_FETCH);
30353034
ZVAL_UNDEF(result);
@@ -3235,15 +3234,16 @@ static zend_never_inline void zend_fetch_object_dimension_address_read(zval *res
32353234
ZEND_ASSERT(zend_check_dimension_interfaces_implemented(obj, /* has_offset */ true, BP_VAR_R));
32363235

32373236
ZVAL_DEREF(offset);
3237+
// TODO Same logic as isset() here?
32383238
if (UNEXPECTED(
32393239
is_bp_var_is
3240-
&& !obj->ce->dimension_handlers->has_dimension(obj, offset)
3240+
&& !zend_class_has_dimension(obj, offset)
32413241
)) {
32423242
ZVAL_NULL(result);
32433243
goto end;
32443244
}
32453245

3246-
retval = obj->ce->dimension_handlers->read_dimension(obj, offset, result);
3246+
retval = zend_class_read_dimension(obj, offset, result);
32473247

32483248
ZEND_ASSERT(result != NULL);
32493249
if (EXPECTED(retval)) {
@@ -3253,7 +3253,7 @@ static zend_never_inline void zend_fetch_object_dimension_address_read(zval *res
32533253
zend_unwrap_reference(result);
32543254
}
32553255
} else {
3256-
ZEND_ASSERT(EG(exception) && "read_dimension() returned NULL without exception");
3256+
ZEND_ASSERT(EG(exception) && "zend_class_read_dimension() returned NULL without exception");
32573257
ZVAL_NULL(result);
32583258
}
32593259
} else {
@@ -3423,29 +3423,10 @@ static zend_never_inline bool ZEND_FASTCALL zend_isset_dim_slow(zval *container,
34233423

34243424
ZVAL_DEREF(offset);
34253425

3426-
/* Object handler can modify the value of the object via globals; thus take a copy */
3427-
zval copy;
3428-
ZVAL_COPY(&copy, container);
3429-
const zend_class_entry *ce = obj->ce;
3430-
bool exists = ce->dimension_handlers->has_dimension(Z_OBJ(copy), offset);
3431-
if (!exists) {
3432-
zval_ptr_dtor(&copy);
3433-
return false;
3434-
}
3435-
3436-
zval *retval;
3437-
zval slot;
3438-
retval = ce->dimension_handlers->read_dimension(Z_OBJ(copy), offset, &slot);
3426+
GC_ADDREF(obj);
3427+
bool result = zend_class_isset_empty_dimension(obj, offset, /* is_empty */ false);
3428+
GC_DELREF(obj);
34393429

3440-
zval_ptr_dtor(&copy);
3441-
if (UNEXPECTED(!retval)) {
3442-
ZEND_ASSERT(EG(exception) && "read_dimension() returned NULL without exception");
3443-
return true;
3444-
}
3445-
ZEND_ASSERT(Z_TYPE_P(retval) != IS_UNDEF);
3446-
/* Check if value is null, if it is we consider it to not be set */
3447-
bool result = Z_TYPE_P(retval) != IS_NULL;
3448-
zval_ptr_dtor(retval);
34493430
return result;
34503431
} else {
34513432
zend_invalid_use_of_object_as_array(obj, /* has_offset */ true, BP_VAR_IS);
@@ -3497,29 +3478,10 @@ static zend_never_inline bool ZEND_FASTCALL zend_isempty_dim_slow(zval *containe
34973478

34983479
ZVAL_DEREF(offset);
34993480

3500-
/* Object handler can modify the value of the object via globals; thus take a copy */
3501-
zval copy;
3502-
ZVAL_COPY(&copy, container);
3503-
const zend_class_entry *ce = obj->ce;
3504-
bool exists = ce->dimension_handlers->has_dimension(Z_OBJ(copy), offset);
3505-
if (!exists) {
3506-
zval_ptr_dtor(&copy);
3507-
return true;
3508-
}
3509-
3510-
zval *retval;
3511-
zval slot;
3512-
retval = ce->dimension_handlers->read_dimension(Z_OBJ(copy), offset, &slot);
3481+
GC_ADDREF(obj);
3482+
bool result = zend_class_isset_empty_dimension(obj, offset, /* is_empty */ true);
3483+
GC_DELREF(obj);
35133484

3514-
zval_ptr_dtor(&copy);
3515-
if (UNEXPECTED(!retval)) {
3516-
ZEND_ASSERT(EG(exception) && "read_dimension() returned NULL without exception");
3517-
return true;
3518-
}
3519-
ZEND_ASSERT(Z_TYPE_P(retval) != IS_UNDEF);
3520-
/* Check if value is empty, which it is when it is falsy, i.e. not truthy */
3521-
bool result = !i_zend_is_true(retval);
3522-
zval_ptr_dtor(retval);
35233485
return result;
35243486
} else {
35253487
zend_invalid_use_of_object_as_array(obj, /* has_offset */ true, BP_VAR_IS);

0 commit comments

Comments
 (0)