Skip to content

Commit 453b49e

Browse files
committed
Added a number of small performance tweaks and optimizations
. ZEND_RECV now always has IS_CV as its result . ZEND_CATCH now has to be used only with constant class names . ZEND_FETCH_DIM_? may fetch array and dimension operans in a different order
1 parent 0bba0bf commit 453b49e

21 files changed

+9944
-6993
lines changed

NEWS

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
- Upgraded bundled sqlite to version 3.6.23.1. (Ilia)
55
- Upgraded bundled PCRE to version 8.02. (Ilia)
66

7+
- Added a number of small performance tweaks and optimizations (Dmitry)
8+
. ZEND_RECV now always has IS_CV as its result
9+
. ZEND_CATCH now has to be used only with constant class names
10+
. ZEND_FETCH_DIM_? may fetch array and dimension operans in a different order
711
- Added concept of interned strings. All strings constants known at compile
812
time are allocated in a single copy and never changed. (Dmitry)
913
- Added an optimization which saves memory and emalloc/efree calls for empty

Zend/tests/isset_003.phpt

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
--TEST--
22
Testing isset accessing undefined array itens and properties
3+
--SKIPIF--
4+
<?php if (version_compare(zend_version(), '2.4.0', '>=')) die('skip ZendEngine 2.3 or below needed'); ?>
35
--FILE--
46
<?php
57

Zend/tests/isset_003_2_4.phpt

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
--TEST--
2+
Testing isset accessing undefined array itens and properties
3+
--SKIPIF--
4+
<?php if (version_compare(zend_version(), '2.4.0', '<')) die('skip ZendEngine 2.4 needed'); ?>
5+
--FILE--
6+
<?php
7+
8+
$a = 'foo';
9+
$b =& $a;
10+
11+
var_dump(isset($b));
12+
13+
var_dump(isset($a[0], $b[1]));
14+
15+
var_dump(isset($a[0]->a));
16+
17+
var_dump(isset($c[0][1][2]->a->b->c->d));
18+
19+
var_dump(isset(${$a}->{$b->$c[$d]}));
20+
21+
var_dump(isset($GLOBALS));
22+
23+
var_dump(isset($GLOBALS[1]));
24+
25+
var_dump(isset($GLOBALS[1]->$GLOBALS));
26+
27+
?>
28+
--EXPECTF--
29+
bool(true)
30+
bool(true)
31+
bool(false)
32+
bool(false)
33+
34+
Notice: Undefined variable: c in %s on line %d
35+
36+
Notice: Undefined variable: d in %s on line %d
37+
38+
Notice: Trying to get property of non-object in %s on line %d
39+
bool(false)
40+
bool(true)
41+
bool(false)
42+
bool(false)

Zend/zend.h

+34-23
Original file line numberDiff line numberDiff line change
@@ -352,17 +352,21 @@ struct _zval_struct {
352352
#if defined(__GNUC__)
353353
#if __GNUC__ >= 3
354354
#define zend_always_inline inline __attribute__((always_inline))
355+
#define zend_never_inline __attribute__((noinline))
355356
#else
356357
#define zend_always_inline inline
358+
#define zend_never_inline
357359
#endif
358360

359361
#elif defined(_MSC_VER)
360362
#define zend_always_inline __forceinline
363+
#define zend_never_inline
361364
#else
362365
#define zend_always_inline inline
366+
#define zend_never_inline
363367
#endif
364368

365-
#if (defined (__GNUC__) && __GNUC__ > 2 ) && !defined(__INTEL_COMPILER) && !defined(DARWIN) && !defined(__hpux) && !defined(_AIX)
369+
#if (defined (__GNUC__) && __GNUC__ > 2 ) && !defined(DARWIN) && !defined(__hpux) && !defined(_AIX)
366370
# define EXPECTED(condition) __builtin_expect(condition, 1)
367371
# define UNEXPECTED(condition) __builtin_expect(condition, 0)
368372
#else
@@ -677,19 +681,30 @@ END_EXTERN_C()
677681

678682
#define PZVAL_IS_REF(z) Z_ISREF_P(z)
679683

680-
#define SEPARATE_ZVAL(ppzv) \
681-
{ \
682-
zval *orig_ptr = *(ppzv); \
683-
\
684-
if (Z_REFCOUNT_P(orig_ptr) > 1) { \
685-
Z_DELREF_P(orig_ptr); \
686-
ALLOC_ZVAL(*(ppzv)); \
687-
**(ppzv) = *orig_ptr; \
688-
zval_copy_ctor(*(ppzv)); \
689-
Z_SET_REFCOUNT_PP(ppzv, 1); \
690-
Z_UNSET_ISREF_PP((ppzv)); \
691-
} \
692-
}
684+
#define ZVAL_COPY_VALUE(z, v) \
685+
do { \
686+
(z)->value = (v)->value; \
687+
Z_TYPE_P(z) = Z_TYPE_P(v); \
688+
} while (0)
689+
690+
#define INIT_PZVAL_COPY(z, v) \
691+
do { \
692+
ZVAL_COPY_VALUE(z, v); \
693+
Z_SET_REFCOUNT_P(z, 1); \
694+
Z_UNSET_ISREF_P(z); \
695+
} while (0)
696+
697+
#define SEPARATE_ZVAL(ppzv) \
698+
do { \
699+
if (Z_REFCOUNT_PP((ppzv)) > 1) { \
700+
zval *new_zv; \
701+
Z_DELREF_PP(ppzv); \
702+
ALLOC_ZVAL(new_zv); \
703+
INIT_PZVAL_COPY(new_zv, *(ppzv)); \
704+
*(ppzv) = new_zv; \
705+
zval_copy_ctor(new_zv); \
706+
} \
707+
} while (0)
693708

694709
#define SEPARATE_ZVAL_IF_NOT_REF(ppzv) \
695710
if (!PZVAL_IS_REF(*ppzv)) { \
@@ -712,10 +727,9 @@ END_EXTERN_C()
712727
} \
713728
INIT_PZVAL(&(zv));
714729

715-
#define MAKE_COPY_ZVAL(ppzv, pzv) \
716-
*(pzv) = **(ppzv); \
717-
zval_copy_ctor((pzv)); \
718-
INIT_PZVAL((pzv));
730+
#define MAKE_COPY_ZVAL(ppzv, pzv) \
731+
INIT_PZVAL_COPY(pzv, *(ppzv)); \
732+
zval_copy_ctor((pzv));
719733

720734
#define REPLACE_ZVAL_VALUE(ppzv_dest, pzv_src, copy) { \
721735
int is_ref, refcount; \
@@ -724,7 +738,7 @@ END_EXTERN_C()
724738
is_ref = Z_ISREF_PP(ppzv_dest); \
725739
refcount = Z_REFCOUNT_PP(ppzv_dest); \
726740
zval_dtor(*ppzv_dest); \
727-
**ppzv_dest = *pzv_src; \
741+
ZVAL_COPY_VALUE(*ppzv_dest, pzv_src); \
728742
if (copy) { \
729743
zval_copy_ctor(*ppzv_dest); \
730744
} \
@@ -736,10 +750,7 @@ END_EXTERN_C()
736750
if (PZVAL_IS_REF(varptr)) { \
737751
zval *original_var = varptr; \
738752
ALLOC_ZVAL(varptr); \
739-
varptr->value = original_var->value; \
740-
Z_TYPE_P(varptr) = Z_TYPE_P(original_var); \
741-
Z_UNSET_ISREF_P(varptr); \
742-
Z_SET_REFCOUNT_P(varptr, 1); \
753+
INIT_PZVAL_COPY(varptr, original_var); \
743754
zval_copy_ctor(varptr); \
744755
} else { \
745756
Z_ADDREF_P(varptr); \

Zend/zend_API.h

+43-32
Original file line numberDiff line numberDiff line change
@@ -488,8 +488,12 @@ ZEND_API int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci
488488

489489
ZEND_API int zend_set_hash_symbol(zval *symbol, const char *name, int name_length, zend_bool is_ref, int num_symbol_tables, ...);
490490

491+
ZEND_API void zend_delete_variable(zend_execute_data *ex, HashTable *ht, char *name, int name_len, ulong hash_value TSRMLS_DC);
492+
491493
ZEND_API int zend_delete_global_variable(char *name, int name_len TSRMLS_DC);
492494

495+
ZEND_API int zend_delete_global_variable_ex(char *name, int name_len, ulong hash_value TSRMLS_DC);
496+
493497
ZEND_API void zend_reset_all_cv(HashTable *symbol_table TSRMLS_DC);
494498

495499
ZEND_API void zend_rebuild_symbol_table(TSRMLS_D);
@@ -510,54 +514,61 @@ END_EXTERN_C()
510514
#define CHECK_ZVAL_STRING_REL(z)
511515
#endif
512516

513-
#define ZVAL_RESOURCE(z, l) { \
514-
Z_TYPE_P(z) = IS_RESOURCE; \
515-
Z_LVAL_P(z) = l; \
516-
}
517+
#define ZVAL_RESOURCE(z, l) do { \
518+
zval *__z = (z); \
519+
Z_LVAL_P(__z) = l; \
520+
Z_TYPE_P(__z) = IS_RESOURCE;\
521+
} while (0)
517522

518-
#define ZVAL_BOOL(z, b) { \
519-
Z_TYPE_P(z) = IS_BOOL; \
520-
Z_LVAL_P(z) = ((b) != 0); \
521-
}
523+
#define ZVAL_BOOL(z, b) do { \
524+
zval *__z = (z); \
525+
Z_LVAL_P(__z) = ((b) != 0); \
526+
Z_TYPE_P(__z) = IS_BOOL; \
527+
} while (0)
522528

523529
#define ZVAL_NULL(z) { \
524530
Z_TYPE_P(z) = IS_NULL; \
525531
}
526532

527533
#define ZVAL_LONG(z, l) { \
528-
Z_TYPE_P(z) = IS_LONG; \
529-
Z_LVAL_P(z) = l; \
534+
zval *__z = (z); \
535+
Z_LVAL_P(__z) = l; \
536+
Z_TYPE_P(__z) = IS_LONG; \
530537
}
531538

532539
#define ZVAL_DOUBLE(z, d) { \
533-
Z_TYPE_P(z) = IS_DOUBLE; \
534-
Z_DVAL_P(z) = d; \
540+
zval *__z = (z); \
541+
Z_DVAL_P(__z) = d; \
542+
Z_TYPE_P(__z) = IS_DOUBLE; \
535543
}
536544

537-
#define ZVAL_STRING(z, s, duplicate) { \
538-
const char *__s=(s); \
539-
Z_STRLEN_P(z) = strlen(__s); \
540-
Z_STRVAL_P(z) = (duplicate?estrndup(__s, Z_STRLEN_P(z)):(char*)__s);\
541-
Z_TYPE_P(z) = IS_STRING; \
542-
}
543-
544-
#define ZVAL_STRINGL(z, s, l, duplicate) { \
545-
const char *__s=(s); int __l=l; \
546-
Z_STRLEN_P(z) = __l; \
547-
Z_STRVAL_P(z) = (duplicate?estrndup(__s, __l):(char*)__s);\
548-
Z_TYPE_P(z) = IS_STRING; \
549-
}
550-
551-
#define ZVAL_EMPTY_STRING(z) { \
552-
Z_STRLEN_P(z) = 0; \
553-
Z_STRVAL_P(z) = STR_EMPTY_ALLOC();\
554-
Z_TYPE_P(z) = IS_STRING; \
555-
}
545+
#define ZVAL_STRING(z, s, duplicate) do { \
546+
const char *__s=(s); \
547+
zval *__z = (z); \
548+
Z_STRLEN_P(__z) = strlen(__s); \
549+
Z_STRVAL_P(__z) = (duplicate?estrndup(__s, Z_STRLEN_P(__z)):(char*)__s);\
550+
Z_TYPE_P(__z) = IS_STRING; \
551+
} while (0)
552+
553+
#define ZVAL_STRINGL(z, s, l, duplicate) do { \
554+
const char *__s=(s); int __l=l; \
555+
zval *__z = (z); \
556+
Z_STRLEN_P(__z) = __l; \
557+
Z_STRVAL_P(__z) = (duplicate?estrndup(__s, __l):(char*)__s);\
558+
Z_TYPE_P(__z) = IS_STRING; \
559+
} while (0)
560+
561+
#define ZVAL_EMPTY_STRING(z) do { \
562+
zval *__z = (z); \
563+
Z_STRLEN_P(__z) = 0; \
564+
Z_STRVAL_P(__z) = STR_EMPTY_ALLOC();\
565+
Z_TYPE_P(__z) = IS_STRING; \
566+
} while (0)
556567

557568
#define ZVAL_ZVAL(z, zv, copy, dtor) { \
558569
zend_uchar is_ref = Z_ISREF_P(z); \
559570
zend_uint refcount = Z_REFCOUNT_P(z); \
560-
*(z) = *(zv); \
571+
ZVAL_COPY_VALUE(z, zv); \
561572
if (copy) { \
562573
zval_copy_ctor(z); \
563574
} \

Zend/zend_compile.c

+27-20
Original file line numberDiff line numberDiff line change
@@ -1571,10 +1571,11 @@ void zend_do_end_function_declaration(const znode *function_token TSRMLS_DC) /*
15711571
}
15721572
/* }}} */
15731573

1574-
void zend_do_receive_arg(zend_uchar op, const znode *var, const znode *offset, const znode *initialization, znode *class_type, const znode *varname, zend_uchar pass_by_reference TSRMLS_DC) /* {{{ */
1574+
void zend_do_receive_arg(zend_uchar op, znode *varname, const znode *offset, const znode *initialization, znode *class_type, zend_uchar pass_by_reference TSRMLS_DC) /* {{{ */
15751575
{
15761576
zend_op *opline;
15771577
zend_arg_info *cur_arg_info;
1578+
znode var;
15781579

15791580
if (class_type->op_type == IS_CONST &&
15801581
Z_TYPE(class_type->u.constant) == IS_STRING &&
@@ -1585,23 +1586,27 @@ void zend_do_receive_arg(zend_uchar op, const znode *var, const znode *offset, c
15851586
return;
15861587
}
15871588

1588-
if (var->op_type == IS_CV &&
1589-
var->u.op.var == CG(active_op_array)->this_var &&
1590-
(CG(active_op_array)->fn_flags & ZEND_ACC_STATIC) == 0) {
1591-
zend_error(E_COMPILE_ERROR, "Cannot re-assign $this");
1592-
} else if (var->op_type == IS_VAR &&
1593-
CG(active_op_array)->scope &&
1594-
((CG(active_op_array)->fn_flags & ZEND_ACC_STATIC) == 0) &&
1595-
(Z_TYPE(varname->u.constant) == IS_STRING) &&
1596-
(Z_STRLEN(varname->u.constant) == sizeof("this")-1) &&
1597-
(memcmp(Z_STRVAL(varname->u.constant), "this", sizeof("this")) == 0)) {
1598-
zend_error(E_COMPILE_ERROR, "Cannot re-assign $this");
1589+
if (zend_is_auto_global(Z_STRVAL(varname->u.constant), Z_STRLEN(varname->u.constant) TSRMLS_CC)) {
1590+
zend_error(E_COMPILE_ERROR, "Cannot re-assign auto-global variable %s", Z_STRVAL(varname->u.constant));
1591+
} else {
1592+
var.op_type = IS_CV;
1593+
var.u.op.var = lookup_cv(CG(active_op_array), varname->u.constant.value.str.val, varname->u.constant.value.str.len TSRMLS_CC);
1594+
varname->u.constant.value.str.val = CG(active_op_array)->vars[var.u.op.var].name;
1595+
var.EA = 0;
1596+
if (Z_STRLEN(varname->u.constant) == sizeof("this")-1 &&
1597+
!memcmp(Z_STRVAL(varname->u.constant), "this", sizeof("this")-1)) {
1598+
if (CG(active_op_array)->scope &&
1599+
(CG(active_op_array)->fn_flags & ZEND_ACC_STATIC) == 0) {
1600+
zend_error(E_COMPILE_ERROR, "Cannot re-assign $this");
1601+
}
1602+
CG(active_op_array)->this_var = var.u.op.var;
1603+
}
15991604
}
16001605

16011606
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
16021607
CG(active_op_array)->num_args++;
16031608
opline->opcode = op;
1604-
SET_NODE(opline->result, var);
1609+
SET_NODE(opline->result, &var);
16051610
SET_NODE(opline->op1, offset);
16061611
if (op == ZEND_RECV_INIT) {
16071612
SET_NODE(opline->op2, initialization);
@@ -2498,23 +2503,25 @@ void zend_do_begin_catch(znode *try_token, znode *class_name, znode *catch_var,
24982503
zend_op *opline;
24992504
znode catch_class;
25002505

2501-
zend_do_fetch_class(&catch_class, class_name TSRMLS_CC);
2506+
if (class_name->op_type == IS_CONST &&
2507+
ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant))) {
2508+
ulong fetch_type = ZEND_FETCH_CLASS_GLOBAL;
25022509

2503-
catch_op_number = get_next_op_number(CG(active_op_array));
2504-
if (catch_op_number > 0) {
2505-
opline = &CG(active_op_array)->opcodes[catch_op_number-1];
2506-
if (opline->opcode == ZEND_FETCH_CLASS) {
2507-
opline->extended_value |= ZEND_FETCH_CLASS_NO_AUTOLOAD;
2508-
}
2510+
zend_resolve_class_name(class_name, &fetch_type, 1 TSRMLS_CC);
2511+
catch_class = *class_name;
2512+
} else {
2513+
zend_error(E_COMPILE_ERROR, "Bad class name in the catch statement");
25092514
}
25102515

2516+
catch_op_number = get_next_op_number(CG(active_op_array));
25112517
if (first_catch) {
25122518
first_catch->u.op.opline_num = catch_op_number;
25132519
}
25142520

25152521
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
25162522
opline->opcode = ZEND_CATCH;
25172523
SET_NODE(opline->op1, &catch_class);
2524+
add_lowercased_class_name(opline->op1.constant TSRMLS_CC);
25182525
opline->op2_type = IS_CV;
25192526
opline->op2.var = lookup_cv(CG(active_op_array), catch_var->u.constant.value.str.val, catch_var->u.constant.value.str.len TSRMLS_CC);
25202527
catch_var->u.constant.value.str.val = CG(active_op_array)->vars[opline->op2.var].name;

Zend/zend_compile.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,6 @@ struct _zend_execute_data {
342342
zend_class_entry *current_called_scope;
343343
zval *current_this;
344344
zval *current_object;
345-
struct _zend_op *call_opline;
346345
};
347346

348347
#define EX(element) execute_data.element
@@ -440,7 +439,7 @@ void zend_do_add_variable(znode *result, const znode *op1, const znode *op2 TSRM
440439
int zend_do_verify_access_types(const znode *current_access_type, const znode *new_modifier);
441440
void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, znode *fn_flags_znode TSRMLS_DC);
442441
void zend_do_end_function_declaration(const znode *function_token TSRMLS_DC);
443-
void zend_do_receive_arg(zend_uchar op, const znode *var, const znode *offset, const znode *initialization, znode *class_type, const znode *varname, zend_bool pass_by_reference TSRMLS_DC);
442+
void zend_do_receive_arg(zend_uchar op, znode *varname, const znode *offset, const znode *initialization, znode *class_type, zend_bool pass_by_reference TSRMLS_DC);
444443
int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace TSRMLS_DC);
445444
void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC);
446445
void zend_do_clone(znode *result, const znode *expr TSRMLS_DC);

0 commit comments

Comments
 (0)