Permalink
Browse files

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
  • Loading branch information...
1 parent 0bba0bf commit 453b49ed20a0d68173cfbe740eb8a3068f62121a Dmitry Stogov committed Apr 20, 2010
View
@@ -4,6 +4,10 @@
- Upgraded bundled sqlite to version 3.6.23.1. (Ilia)
- Upgraded bundled PCRE to version 8.02. (Ilia)
+- Added a number of small performance tweaks and optimizations (Dmitry)
+ . 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
- Added concept of interned strings. All strings constants known at compile
time are allocated in a single copy and never changed. (Dmitry)
- Added an optimization which saves memory and emalloc/efree calls for empty
@@ -1,5 +1,7 @@
--TEST--
Testing isset accessing undefined array itens and properties
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.4.0', '>=')) die('skip ZendEngine 2.3 or below needed'); ?>
--FILE--
<?php
@@ -0,0 +1,42 @@
+--TEST--
+Testing isset accessing undefined array itens and properties
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.4.0', '<')) die('skip ZendEngine 2.4 needed'); ?>
+--FILE--
+<?php
+
+$a = 'foo';
+$b =& $a;
+
+var_dump(isset($b));
+
+var_dump(isset($a[0], $b[1]));
+
+var_dump(isset($a[0]->a));
+
+var_dump(isset($c[0][1][2]->a->b->c->d));
+
+var_dump(isset(${$a}->{$b->$c[$d]}));
+
+var_dump(isset($GLOBALS));
+
+var_dump(isset($GLOBALS[1]));
+
+var_dump(isset($GLOBALS[1]->$GLOBALS));
+
+?>
+--EXPECTF--
+bool(true)
+bool(true)
+bool(false)
+bool(false)
+
+Notice: Undefined variable: c in %s on line %d
+
+Notice: Undefined variable: d in %s on line %d
+
+Notice: Trying to get property of non-object in %s on line %d
+bool(false)
+bool(true)
+bool(false)
+bool(false)
View
@@ -352,17 +352,21 @@ struct _zval_struct {
#if defined(__GNUC__)
#if __GNUC__ >= 3
#define zend_always_inline inline __attribute__((always_inline))
+#define zend_never_inline __attribute__((noinline))
#else
#define zend_always_inline inline
+#define zend_never_inline
#endif
#elif defined(_MSC_VER)
#define zend_always_inline __forceinline
+#define zend_never_inline
#else
#define zend_always_inline inline
+#define zend_never_inline
#endif
-#if (defined (__GNUC__) && __GNUC__ > 2 ) && !defined(__INTEL_COMPILER) && !defined(DARWIN) && !defined(__hpux) && !defined(_AIX)
+#if (defined (__GNUC__) && __GNUC__ > 2 ) && !defined(DARWIN) && !defined(__hpux) && !defined(_AIX)
# define EXPECTED(condition) __builtin_expect(condition, 1)
# define UNEXPECTED(condition) __builtin_expect(condition, 0)
#else
@@ -677,19 +681,30 @@ END_EXTERN_C()
#define PZVAL_IS_REF(z) Z_ISREF_P(z)
-#define SEPARATE_ZVAL(ppzv) \
- { \
- zval *orig_ptr = *(ppzv); \
- \
- if (Z_REFCOUNT_P(orig_ptr) > 1) { \
- Z_DELREF_P(orig_ptr); \
- ALLOC_ZVAL(*(ppzv)); \
- **(ppzv) = *orig_ptr; \
- zval_copy_ctor(*(ppzv)); \
- Z_SET_REFCOUNT_PP(ppzv, 1); \
- Z_UNSET_ISREF_PP((ppzv)); \
- } \
- }
+#define ZVAL_COPY_VALUE(z, v) \
+ do { \
+ (z)->value = (v)->value; \
+ Z_TYPE_P(z) = Z_TYPE_P(v); \
+ } while (0)
+
+#define INIT_PZVAL_COPY(z, v) \
+ do { \
+ ZVAL_COPY_VALUE(z, v); \
+ Z_SET_REFCOUNT_P(z, 1); \
+ Z_UNSET_ISREF_P(z); \
+ } while (0)
+
+#define SEPARATE_ZVAL(ppzv) \
+ do { \
+ if (Z_REFCOUNT_PP((ppzv)) > 1) { \
+ zval *new_zv; \
+ Z_DELREF_PP(ppzv); \
+ ALLOC_ZVAL(new_zv); \
+ INIT_PZVAL_COPY(new_zv, *(ppzv)); \
+ *(ppzv) = new_zv; \
+ zval_copy_ctor(new_zv); \
+ } \
+ } while (0)
#define SEPARATE_ZVAL_IF_NOT_REF(ppzv) \
if (!PZVAL_IS_REF(*ppzv)) { \
@@ -712,10 +727,9 @@ END_EXTERN_C()
} \
INIT_PZVAL(&(zv));
-#define MAKE_COPY_ZVAL(ppzv, pzv) \
- *(pzv) = **(ppzv); \
- zval_copy_ctor((pzv)); \
- INIT_PZVAL((pzv));
+#define MAKE_COPY_ZVAL(ppzv, pzv) \
+ INIT_PZVAL_COPY(pzv, *(ppzv)); \
+ zval_copy_ctor((pzv));
#define REPLACE_ZVAL_VALUE(ppzv_dest, pzv_src, copy) { \
int is_ref, refcount; \
@@ -724,7 +738,7 @@ END_EXTERN_C()
is_ref = Z_ISREF_PP(ppzv_dest); \
refcount = Z_REFCOUNT_PP(ppzv_dest); \
zval_dtor(*ppzv_dest); \
- **ppzv_dest = *pzv_src; \
+ ZVAL_COPY_VALUE(*ppzv_dest, pzv_src); \
if (copy) { \
zval_copy_ctor(*ppzv_dest); \
} \
@@ -736,10 +750,7 @@ END_EXTERN_C()
if (PZVAL_IS_REF(varptr)) { \
zval *original_var = varptr; \
ALLOC_ZVAL(varptr); \
- varptr->value = original_var->value; \
- Z_TYPE_P(varptr) = Z_TYPE_P(original_var); \
- Z_UNSET_ISREF_P(varptr); \
- Z_SET_REFCOUNT_P(varptr, 1); \
+ INIT_PZVAL_COPY(varptr, original_var); \
zval_copy_ctor(varptr); \
} else { \
Z_ADDREF_P(varptr); \
View
@@ -488,8 +488,12 @@ ZEND_API int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci
ZEND_API int zend_set_hash_symbol(zval *symbol, const char *name, int name_length, zend_bool is_ref, int num_symbol_tables, ...);
+ZEND_API void zend_delete_variable(zend_execute_data *ex, HashTable *ht, char *name, int name_len, ulong hash_value TSRMLS_DC);
+
ZEND_API int zend_delete_global_variable(char *name, int name_len TSRMLS_DC);
+ZEND_API int zend_delete_global_variable_ex(char *name, int name_len, ulong hash_value TSRMLS_DC);
+
ZEND_API void zend_reset_all_cv(HashTable *symbol_table TSRMLS_DC);
ZEND_API void zend_rebuild_symbol_table(TSRMLS_D);
@@ -510,54 +514,61 @@ END_EXTERN_C()
#define CHECK_ZVAL_STRING_REL(z)
#endif
-#define ZVAL_RESOURCE(z, l) { \
- Z_TYPE_P(z) = IS_RESOURCE; \
- Z_LVAL_P(z) = l; \
- }
+#define ZVAL_RESOURCE(z, l) do { \
+ zval *__z = (z); \
+ Z_LVAL_P(__z) = l; \
+ Z_TYPE_P(__z) = IS_RESOURCE;\
+ } while (0)
-#define ZVAL_BOOL(z, b) { \
- Z_TYPE_P(z) = IS_BOOL; \
- Z_LVAL_P(z) = ((b) != 0); \
- }
+#define ZVAL_BOOL(z, b) do { \
+ zval *__z = (z); \
+ Z_LVAL_P(__z) = ((b) != 0); \
+ Z_TYPE_P(__z) = IS_BOOL; \
+ } while (0)
#define ZVAL_NULL(z) { \
Z_TYPE_P(z) = IS_NULL; \
}
#define ZVAL_LONG(z, l) { \
- Z_TYPE_P(z) = IS_LONG; \
- Z_LVAL_P(z) = l; \
+ zval *__z = (z); \
+ Z_LVAL_P(__z) = l; \
+ Z_TYPE_P(__z) = IS_LONG; \
}
#define ZVAL_DOUBLE(z, d) { \
- Z_TYPE_P(z) = IS_DOUBLE; \
- Z_DVAL_P(z) = d; \
+ zval *__z = (z); \
+ Z_DVAL_P(__z) = d; \
+ Z_TYPE_P(__z) = IS_DOUBLE; \
}
-#define ZVAL_STRING(z, s, duplicate) { \
- const char *__s=(s); \
- Z_STRLEN_P(z) = strlen(__s); \
- Z_STRVAL_P(z) = (duplicate?estrndup(__s, Z_STRLEN_P(z)):(char*)__s);\
- Z_TYPE_P(z) = IS_STRING; \
- }
-
-#define ZVAL_STRINGL(z, s, l, duplicate) { \
- const char *__s=(s); int __l=l; \
- Z_STRLEN_P(z) = __l; \
- Z_STRVAL_P(z) = (duplicate?estrndup(__s, __l):(char*)__s);\
- Z_TYPE_P(z) = IS_STRING; \
- }
-
-#define ZVAL_EMPTY_STRING(z) { \
- Z_STRLEN_P(z) = 0; \
- Z_STRVAL_P(z) = STR_EMPTY_ALLOC();\
- Z_TYPE_P(z) = IS_STRING; \
- }
+#define ZVAL_STRING(z, s, duplicate) do { \
+ const char *__s=(s); \
+ zval *__z = (z); \
+ Z_STRLEN_P(__z) = strlen(__s); \
+ Z_STRVAL_P(__z) = (duplicate?estrndup(__s, Z_STRLEN_P(__z)):(char*)__s);\
+ Z_TYPE_P(__z) = IS_STRING; \
+ } while (0)
+
+#define ZVAL_STRINGL(z, s, l, duplicate) do { \
+ const char *__s=(s); int __l=l; \
+ zval *__z = (z); \
+ Z_STRLEN_P(__z) = __l; \
+ Z_STRVAL_P(__z) = (duplicate?estrndup(__s, __l):(char*)__s);\
+ Z_TYPE_P(__z) = IS_STRING; \
+ } while (0)
+
+#define ZVAL_EMPTY_STRING(z) do { \
+ zval *__z = (z); \
+ Z_STRLEN_P(__z) = 0; \
+ Z_STRVAL_P(__z) = STR_EMPTY_ALLOC();\
+ Z_TYPE_P(__z) = IS_STRING; \
+ } while (0)
#define ZVAL_ZVAL(z, zv, copy, dtor) { \
zend_uchar is_ref = Z_ISREF_P(z); \
zend_uint refcount = Z_REFCOUNT_P(z); \
- *(z) = *(zv); \
+ ZVAL_COPY_VALUE(z, zv); \
if (copy) { \
zval_copy_ctor(z); \
} \
View
@@ -1571,10 +1571,11 @@ void zend_do_end_function_declaration(const znode *function_token TSRMLS_DC) /*
}
/* }}} */
-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) /* {{{ */
+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) /* {{{ */
{
zend_op *opline;
zend_arg_info *cur_arg_info;
+ znode var;
if (class_type->op_type == IS_CONST &&
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
return;
}
- if (var->op_type == IS_CV &&
- var->u.op.var == CG(active_op_array)->this_var &&
- (CG(active_op_array)->fn_flags & ZEND_ACC_STATIC) == 0) {
- zend_error(E_COMPILE_ERROR, "Cannot re-assign $this");
- } else if (var->op_type == IS_VAR &&
- CG(active_op_array)->scope &&
- ((CG(active_op_array)->fn_flags & ZEND_ACC_STATIC) == 0) &&
- (Z_TYPE(varname->u.constant) == IS_STRING) &&
- (Z_STRLEN(varname->u.constant) == sizeof("this")-1) &&
- (memcmp(Z_STRVAL(varname->u.constant), "this", sizeof("this")) == 0)) {
- zend_error(E_COMPILE_ERROR, "Cannot re-assign $this");
+ if (zend_is_auto_global(Z_STRVAL(varname->u.constant), Z_STRLEN(varname->u.constant) TSRMLS_CC)) {
+ zend_error(E_COMPILE_ERROR, "Cannot re-assign auto-global variable %s", Z_STRVAL(varname->u.constant));
+ } else {
+ var.op_type = IS_CV;
+ var.u.op.var = lookup_cv(CG(active_op_array), varname->u.constant.value.str.val, varname->u.constant.value.str.len TSRMLS_CC);
+ varname->u.constant.value.str.val = CG(active_op_array)->vars[var.u.op.var].name;
+ var.EA = 0;
+ if (Z_STRLEN(varname->u.constant) == sizeof("this")-1 &&
+ !memcmp(Z_STRVAL(varname->u.constant), "this", sizeof("this")-1)) {
+ if (CG(active_op_array)->scope &&
+ (CG(active_op_array)->fn_flags & ZEND_ACC_STATIC) == 0) {
+ zend_error(E_COMPILE_ERROR, "Cannot re-assign $this");
+ }
+ CG(active_op_array)->this_var = var.u.op.var;
+ }
}
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
CG(active_op_array)->num_args++;
opline->opcode = op;
- SET_NODE(opline->result, var);
+ SET_NODE(opline->result, &var);
SET_NODE(opline->op1, offset);
if (op == ZEND_RECV_INIT) {
SET_NODE(opline->op2, initialization);
@@ -2498,23 +2503,25 @@ void zend_do_begin_catch(znode *try_token, znode *class_name, znode *catch_var,
zend_op *opline;
znode catch_class;
- zend_do_fetch_class(&catch_class, class_name TSRMLS_CC);
+ if (class_name->op_type == IS_CONST &&
+ ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant))) {
+ ulong fetch_type = ZEND_FETCH_CLASS_GLOBAL;
- catch_op_number = get_next_op_number(CG(active_op_array));
- if (catch_op_number > 0) {
- opline = &CG(active_op_array)->opcodes[catch_op_number-1];
- if (opline->opcode == ZEND_FETCH_CLASS) {
- opline->extended_value |= ZEND_FETCH_CLASS_NO_AUTOLOAD;
- }
+ zend_resolve_class_name(class_name, &fetch_type, 1 TSRMLS_CC);
+ catch_class = *class_name;
+ } else {
+ zend_error(E_COMPILE_ERROR, "Bad class name in the catch statement");
}
+ catch_op_number = get_next_op_number(CG(active_op_array));
if (first_catch) {
first_catch->u.op.opline_num = catch_op_number;
}
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
opline->opcode = ZEND_CATCH;
SET_NODE(opline->op1, &catch_class);
+ add_lowercased_class_name(opline->op1.constant TSRMLS_CC);
opline->op2_type = IS_CV;
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);
catch_var->u.constant.value.str.val = CG(active_op_array)->vars[opline->op2.var].name;
View
@@ -342,7 +342,6 @@ struct _zend_execute_data {
zend_class_entry *current_called_scope;
zval *current_this;
zval *current_object;
- struct _zend_op *call_opline;
};
#define EX(element) execute_data.element
@@ -440,7 +439,7 @@ void zend_do_add_variable(znode *result, const znode *op1, const znode *op2 TSRM
int zend_do_verify_access_types(const znode *current_access_type, const znode *new_modifier);
void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, znode *fn_flags_znode TSRMLS_DC);
void zend_do_end_function_declaration(const znode *function_token TSRMLS_DC);
-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);
+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);
int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace TSRMLS_DC);
void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC);
void zend_do_clone(znode *result, const znode *expr TSRMLS_DC);
Oops, something went wrong.

0 comments on commit 453b49e

Please sign in to comment.