Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

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...
commit 453b49ed20a0d68173cfbe740eb8a3068f62121a 1 parent 0bba0bf
Dmitry Stogov authored
4 NEWS
@@ -4,6 +4,10 @@
4 4 - Upgraded bundled sqlite to version 3.6.23.1. (Ilia)
5 5 - Upgraded bundled PCRE to version 8.02. (Ilia)
6 6
  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
7 11 - Added concept of interned strings. All strings constants known at compile
8 12 time are allocated in a single copy and never changed. (Dmitry)
9 13 - Added an optimization which saves memory and emalloc/efree calls for empty
2  Zend/tests/isset_003.phpt
... ... @@ -1,5 +1,7 @@
1 1 --TEST--
2 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.3 or below needed'); ?>
3 5 --FILE--
4 6 <?php
5 7
42 Zend/tests/isset_003_2_4.phpt
... ... @@ -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)
57 Zend/zend.h
@@ -352,17 +352,21 @@ struct _zval_struct {
352 352 #if defined(__GNUC__)
353 353 #if __GNUC__ >= 3
354 354 #define zend_always_inline inline __attribute__((always_inline))
  355 +#define zend_never_inline __attribute__((noinline))
355 356 #else
356 357 #define zend_always_inline inline
  358 +#define zend_never_inline
357 359 #endif
358 360
359 361 #elif defined(_MSC_VER)
360 362 #define zend_always_inline __forceinline
  363 +#define zend_never_inline
361 364 #else
362 365 #define zend_always_inline inline
  366 +#define zend_never_inline
363 367 #endif
364 368
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)
366 370 # define EXPECTED(condition) __builtin_expect(condition, 1)
367 371 # define UNEXPECTED(condition) __builtin_expect(condition, 0)
368 372 #else
@@ -677,19 +681,30 @@ END_EXTERN_C()
677 681
678 682 #define PZVAL_IS_REF(z) Z_ISREF_P(z)
679 683
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)
693 708
694 709 #define SEPARATE_ZVAL_IF_NOT_REF(ppzv) \
695 710 if (!PZVAL_IS_REF(*ppzv)) { \
@@ -712,10 +727,9 @@ END_EXTERN_C()
712 727 } \
713 728 INIT_PZVAL(&(zv));
714 729
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));
719 733
720 734 #define REPLACE_ZVAL_VALUE(ppzv_dest, pzv_src, copy) { \
721 735 int is_ref, refcount; \
@@ -724,7 +738,7 @@ END_EXTERN_C()
724 738 is_ref = Z_ISREF_PP(ppzv_dest); \
725 739 refcount = Z_REFCOUNT_PP(ppzv_dest); \
726 740 zval_dtor(*ppzv_dest); \
727   - **ppzv_dest = *pzv_src; \
  741 + ZVAL_COPY_VALUE(*ppzv_dest, pzv_src); \
728 742 if (copy) { \
729 743 zval_copy_ctor(*ppzv_dest); \
730 744 } \
@@ -736,10 +750,7 @@ END_EXTERN_C()
736 750 if (PZVAL_IS_REF(varptr)) { \
737 751 zval *original_var = varptr; \
738 752 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); \
743 754 zval_copy_ctor(varptr); \
744 755 } else { \
745 756 Z_ADDREF_P(varptr); \
75 Zend/zend_API.h
@@ -488,8 +488,12 @@ ZEND_API int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci
488 488
489 489 ZEND_API int zend_set_hash_symbol(zval *symbol, const char *name, int name_length, zend_bool is_ref, int num_symbol_tables, ...);
490 490
  491 +ZEND_API void zend_delete_variable(zend_execute_data *ex, HashTable *ht, char *name, int name_len, ulong hash_value TSRMLS_DC);
  492 +
491 493 ZEND_API int zend_delete_global_variable(char *name, int name_len TSRMLS_DC);
492 494
  495 +ZEND_API int zend_delete_global_variable_ex(char *name, int name_len, ulong hash_value TSRMLS_DC);
  496 +
493 497 ZEND_API void zend_reset_all_cv(HashTable *symbol_table TSRMLS_DC);
494 498
495 499 ZEND_API void zend_rebuild_symbol_table(TSRMLS_D);
@@ -510,54 +514,61 @@ END_EXTERN_C()
510 514 #define CHECK_ZVAL_STRING_REL(z)
511 515 #endif
512 516
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)
517 522
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)
522 528
523 529 #define ZVAL_NULL(z) { \
524 530 Z_TYPE_P(z) = IS_NULL; \
525 531 }
526 532
527 533 #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; \
530 537 }
531 538
532 539 #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; \
535 543 }
536 544
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)
556 567
557 568 #define ZVAL_ZVAL(z, zv, copy, dtor) { \
558 569 zend_uchar is_ref = Z_ISREF_P(z); \
559 570 zend_uint refcount = Z_REFCOUNT_P(z); \
560   - *(z) = *(zv); \
  571 + ZVAL_COPY_VALUE(z, zv); \
561 572 if (copy) { \
562 573 zval_copy_ctor(z); \
563 574 } \
47 Zend/zend_compile.c
@@ -1571,10 +1571,11 @@ void zend_do_end_function_declaration(const znode *function_token TSRMLS_DC) /*
1571 1571 }
1572 1572 /* }}} */
1573 1573
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) /* {{{ */
1575 1575 {
1576 1576 zend_op *opline;
1577 1577 zend_arg_info *cur_arg_info;
  1578 + znode var;
1578 1579
1579 1580 if (class_type->op_type == IS_CONST &&
1580 1581 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
1585 1586 return;
1586 1587 }
1587 1588
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 + }
1599 1604 }
1600 1605
1601 1606 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1602 1607 CG(active_op_array)->num_args++;
1603 1608 opline->opcode = op;
1604   - SET_NODE(opline->result, var);
  1609 + SET_NODE(opline->result, &var);
1605 1610 SET_NODE(opline->op1, offset);
1606 1611 if (op == ZEND_RECV_INIT) {
1607 1612 SET_NODE(opline->op2, initialization);
@@ -2498,16 +2503,17 @@ void zend_do_begin_catch(znode *try_token, znode *class_name, znode *catch_var,
2498 2503 zend_op *opline;
2499 2504 znode catch_class;
2500 2505
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;
2502 2509
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");
2509 2514 }
2510 2515
  2516 + catch_op_number = get_next_op_number(CG(active_op_array));
2511 2517 if (first_catch) {
2512 2518 first_catch->u.op.opline_num = catch_op_number;
2513 2519 }
@@ -2515,6 +2521,7 @@ void zend_do_begin_catch(znode *try_token, znode *class_name, znode *catch_var,
2515 2521 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2516 2522 opline->opcode = ZEND_CATCH;
2517 2523 SET_NODE(opline->op1, &catch_class);
  2524 + add_lowercased_class_name(opline->op1.constant TSRMLS_CC);
2518 2525 opline->op2_type = IS_CV;
2519 2526 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);
2520 2527 catch_var->u.constant.value.str.val = CG(active_op_array)->vars[opline->op2.var].name;
3  Zend/zend_compile.h
@@ -342,7 +342,6 @@ struct _zend_execute_data {
342 342 zend_class_entry *current_called_scope;
343 343 zval *current_this;
344 344 zval *current_object;
345   - struct _zend_op *call_opline;
346 345 };
347 346
348 347 #define EX(element) execute_data.element
@@ -440,7 +439,7 @@ void zend_do_add_variable(znode *result, const znode *op1, const znode *op2 TSRM
440 439 int zend_do_verify_access_types(const znode *current_access_type, const znode *new_modifier);
441 440 void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, znode *fn_flags_znode TSRMLS_DC);
442 441 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);
444 443 int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace TSRMLS_DC);
445 444 void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC);
446 445 void zend_do_clone(znode *result, const znode *expr TSRMLS_DC);
444 Zend/zend_execute.c
@@ -60,8 +60,8 @@ static void zend_extension_fcall_end_handler(const zend_extension *extension, ze
60 60
61 61 #define RETURN_VALUE_USED(opline) (!((opline)->result_type & EXT_TYPE_UNUSED))
62 62
63   -#define EX_T(offset) (*(temp_variable *)((char *) EX(Ts) + offset))
64 63 #define T(offset) (*(temp_variable *)((char *) Ts + offset))
  64 +#define CV(var) CVs[var]
65 65
66 66 #define TEMP_VAR_STACK_LIMIT 2000
67 67
@@ -92,23 +92,37 @@ static zend_always_inline void zend_pzval_unlock_free_func(zval *z TSRMLS_DC)
92 92 }
93 93 }
94 94
  95 +static zend_never_inline void __zval_ptr_dtor(zval *zval_ptr ZEND_FILE_LINE_DC)
  96 +{
  97 + __zval_ptr_dtor(zval_ptr ZEND_FILE_LINE_RELAY_CC);
  98 +}
  99 +
  100 +#undef zval_ptr_dtor
  101 +#define zval_ptr_dtor(pzv) i_zval_ptr_dtor(*(pzv) ZEND_FILE_LINE_CC)
  102 +
95 103 #define PZVAL_UNLOCK(z, f) zend_pzval_unlock_func(z, f, 1 TSRMLS_CC)
96 104 #define PZVAL_UNLOCK_EX(z, f, u) zend_pzval_unlock_func(z, f, u TSRMLS_CC)
97 105 #define PZVAL_UNLOCK_FREE(z) zend_pzval_unlock_free_func(z TSRMLS_CC)
98 106 #define PZVAL_LOCK(z) Z_ADDREF_P((z))
99 107 #define SELECTIVE_PZVAL_LOCK(pzv, opline) if (RETURN_VALUE_USED(opline)) { PZVAL_LOCK(pzv); }
100 108
101   -#define AI_USE_PTR(ai) \
102   - if ((ai).ptr_ptr) { \
103   - (ai).ptr = *((ai).ptr_ptr); \
104   - (ai).ptr_ptr = &((ai).ptr); \
105   - } else { \
106   - (ai).ptr = NULL; \
107   - }
  109 +#define EXTRACT_ZVAL_PTR(t) do { \
  110 + temp_variable *__t = (t); \
  111 + if (__t->var.ptr_ptr) { \
  112 + __t->var.ptr = *__t->var.ptr_ptr; \
  113 + __t->var.ptr_ptr = &__t->var.ptr; \
  114 + if (!PZVAL_IS_REF(__t->var.ptr) && \
  115 + Z_REFCOUNT_P(__t->var.ptr) > 2) { \
  116 + SEPARATE_ZVAL(__t->var.ptr_ptr); \
  117 + } \
  118 + } \
  119 + } while (0)
108 120
109   -#define AI_SET_PTR(ai, val) \
110   - (ai).ptr = (val); \
111   - (ai).ptr_ptr = &((ai).ptr);
  121 +#define AI_SET_PTR(t, val) do { \
  122 + temp_variable *__t = (t); \
  123 + __t->var.ptr = (val); \
  124 + __t->var.ptr_ptr = &__t->var.ptr; \
  125 + } while (0)
112 126
113 127 #define FREE_OP(should_free) \
114 128 if (should_free.var) { \
@@ -133,21 +147,12 @@ static zend_always_inline void zend_pzval_unlock_free_func(zval *z TSRMLS_DC)
133 147
134 148 #define IS_TMP_FREE(should_free) ((zend_uintptr_t)should_free.var & 1L)
135 149
136   -#define INIT_PZVAL_COPY(z,v) \
137   - (z)->value = (v)->value; \
138   - Z_TYPE_P(z) = Z_TYPE_P(v); \
139   - Z_SET_REFCOUNT_P(z, 1); \
140   - Z_UNSET_ISREF_P(z);
141   -
142 150 #define MAKE_REAL_ZVAL_PTR(val) \
143 151 do { \
144 152 zval *_tmp; \
145 153 ALLOC_ZVAL(_tmp); \
146   - _tmp->value = (val)->value; \
147   - Z_TYPE_P(_tmp) = Z_TYPE_P(val); \
148   - Z_SET_REFCOUNT_P(_tmp, 1); \
149   - Z_UNSET_ISREF_P(_tmp); \
150   - val = _tmp; \
  154 + INIT_PZVAL_COPY(_tmp, (val)); \
  155 + (val) = _tmp; \
151 156 } while (0)
152 157
153 158 /* End of zend_execute_locks.h */
@@ -214,7 +219,7 @@ static zend_always_inline zval *_get_zval_ptr_var(zend_uint var, const temp_vari
214 219 }
215 220 }
216 221
217   -static zval **_get_zval_cv_lookup(zval ***ptr, zend_uint var, int type TSRMLS_DC)
  222 +static zend_never_inline zval **_get_zval_cv_lookup(zval ***ptr, zend_uint var, int type TSRMLS_DC)
218 223 {
219 224 zend_compiled_variable *cv = &CV_DEF_OF(var);
220 225
@@ -245,6 +250,73 @@ static zval **_get_zval_cv_lookup(zval ***ptr, zend_uint var, int type TSRMLS_DC
245 250 return *ptr;
246 251 }
247 252
  253 +static zend_never_inline zval **_get_zval_cv_lookup_BP_VAR_R(zval ***ptr, zend_uint var TSRMLS_DC)
  254 +{
  255 + zend_compiled_variable *cv = &CV_DEF_OF(var);
  256 +
  257 + if (!EG(active_symbol_table) ||
  258 + zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void **)ptr)==FAILURE) {
  259 + zend_error(E_NOTICE, "Undefined variable: %s", cv->name);
  260 + return &EG(uninitialized_zval_ptr);
  261 + }
  262 + return *ptr;
  263 +}
  264 +
  265 +static zend_never_inline zval **_get_zval_cv_lookup_BP_VAR_UNSET(zval ***ptr, zend_uint var TSRMLS_DC)
  266 +{
  267 + zend_compiled_variable *cv = &CV_DEF_OF(var);
  268 +
  269 + if (!EG(active_symbol_table) ||
  270 + zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void **)ptr)==FAILURE) {
  271 + zend_error(E_NOTICE, "Undefined variable: %s", cv->name);
  272 + return &EG(uninitialized_zval_ptr);
  273 + }
  274 + return *ptr;
  275 +}
  276 +
  277 +static zend_never_inline zval **_get_zval_cv_lookup_BP_VAR_IS(zval ***ptr, zend_uint var TSRMLS_DC)
  278 +{
  279 + zend_compiled_variable *cv = &CV_DEF_OF(var);
  280 +
  281 + if (!EG(active_symbol_table) ||
  282 + zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void **)ptr)==FAILURE) {
  283 + return &EG(uninitialized_zval_ptr);
  284 + }
  285 + return *ptr;
  286 +}
  287 +
  288 +static zend_never_inline zval **_get_zval_cv_lookup_BP_VAR_RW(zval ***ptr, zend_uint var TSRMLS_DC)
  289 +{
  290 + zend_compiled_variable *cv = &CV_DEF_OF(var);
  291 +
  292 + if (!EG(active_symbol_table)) {
  293 + Z_ADDREF(EG(uninitialized_zval));
  294 + *ptr = (zval**)EG(current_execute_data)->CVs + (EG(active_op_array)->last_var + var);
  295 + **ptr = &EG(uninitialized_zval);
  296 + zend_error(E_NOTICE, "Undefined variable: %s", cv->name);
  297 + } else if (zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void **)ptr)==FAILURE) {
  298 + Z_ADDREF(EG(uninitialized_zval));
  299 + zend_hash_quick_update(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, &EG(uninitialized_zval_ptr), sizeof(zval *), (void **)ptr);
  300 + zend_error(E_NOTICE, "Undefined variable: %s", cv->name);
  301 + }
  302 + return *ptr;
  303 +}
  304 +
  305 +static zend_never_inline zval **_get_zval_cv_lookup_BP_VAR_W(zval ***ptr, zend_uint var TSRMLS_DC)
  306 +{
  307 + zend_compiled_variable *cv = &CV_DEF_OF(var);
  308 +
  309 + if (!EG(active_symbol_table)) {
  310 + Z_ADDREF(EG(uninitialized_zval));
  311 + *ptr = (zval**)EG(current_execute_data)->CVs + (EG(active_op_array)->last_var + var);
  312 + **ptr = &EG(uninitialized_zval);
  313 + } else if (zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void **)ptr)==FAILURE) {
  314 + Z_ADDREF(EG(uninitialized_zval));
  315 + zend_hash_quick_update(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, &EG(uninitialized_zval_ptr), sizeof(zval *), (void **)ptr);
  316 + }
  317 + return *ptr;
  318 +}
  319 +
248 320 static zend_always_inline zval *_get_zval_ptr_cv(zend_uint var, int type TSRMLS_DC)
249 321 {
250 322 zval ***ptr = &CV_OF(var);
@@ -255,6 +327,56 @@ static zend_always_inline zval *_get_zval_ptr_cv(zend_uint var, int type TSRMLS_
255 327 return **ptr;
256 328 }
257 329
  330 +static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_R(zval ***CVs, zend_uint var TSRMLS_DC)
  331 +{
  332 + zval ***ptr = &CV(var);
  333 +
  334 + if (UNEXPECTED(*ptr == NULL)) {
  335 + return *_get_zval_cv_lookup_BP_VAR_R(ptr, var TSRMLS_CC);
  336 + }
  337 + return **ptr;
  338 +}
  339 +
  340 +static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_UNSET(zval ***CVs, zend_uint var TSRMLS_DC)
  341 +{
  342 + zval ***ptr = &CV(var);
  343 +
  344 + if (UNEXPECTED(*ptr == NULL)) {
  345 + return *_get_zval_cv_lookup_BP_VAR_UNSET(ptr, var TSRMLS_CC);
  346 + }
  347 + return **ptr;
  348 +}
  349 +
  350 +static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_IS(zval ***CVs, zend_uint var TSRMLS_DC)
  351 +{
  352 + zval ***ptr = &CV(var);
  353 +
  354 + if (UNEXPECTED(*ptr == NULL)) {
  355 + return *_get_zval_cv_lookup_BP_VAR_IS(ptr, var TSRMLS_CC);
  356 + }
  357 + return **ptr;
  358 +}
  359 +
  360 +static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_RW(zval ***CVs, zend_uint var TSRMLS_DC)
  361 +{
  362 + zval ***ptr = &CV(var);
  363 +
  364 + if (UNEXPECTED(*ptr == NULL)) {
  365 + return *_get_zval_cv_lookup_BP_VAR_RW(ptr, var TSRMLS_CC);
  366 + }
  367 + return **ptr;
  368 +}
  369 +
  370 +static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_W(zval ***CVs, zend_uint var TSRMLS_DC)
  371 +{
  372 + zval ***ptr = &CV(var);
  373 +
  374 + if (UNEXPECTED(*ptr == NULL)) {
  375 + return *_get_zval_cv_lookup_BP_VAR_W(ptr, var TSRMLS_CC);
  376 + }
  377 + return **ptr;
  378 +}
  379 +
258 380 static inline zval *_get_zval_ptr(int op_type, const znode_op *node, const temp_variable *Ts, zend_free_op *should_free, int type TSRMLS_DC)
259 381 {
260 382 /* should_free->is_var = 0; */
@@ -306,6 +428,56 @@ static zend_always_inline zval **_get_zval_ptr_ptr_cv(zend_uint var, int type TS
306 428 return *ptr;
307 429 }
308 430
  431 +static zend_always_inline zval **_get_zval_ptr_ptr_cv_BP_VAR_R(zval ***CVs, zend_uint var TSRMLS_DC)
  432 +{
  433 + zval ***ptr = &CV(var);
  434 +
  435 + if (UNEXPECTED(*ptr == NULL)) {
  436 + return _get_zval_cv_lookup_BP_VAR_R(ptr, var TSRMLS_CC);
  437 + }
  438 + return *ptr;
  439 +}
  440 +
  441 +static zend_always_inline zval **_get_zval_ptr_ptr_cv_BP_VAR_UNSET(zval ***CVs, zend_uint var TSRMLS_DC)
  442 +{
  443 + zval ***ptr = &CV(var);
  444 +
  445 + if (UNEXPECTED(*ptr == NULL)) {
  446 + return _get_zval_cv_lookup_BP_VAR_UNSET(ptr, var TSRMLS_CC);
  447 + }
  448 + return *ptr;
  449 +}
  450 +
  451 +static zend_always_inline zval **_get_zval_ptr_ptr_cv_BP_VAR_IS(zval ***CVs, zend_uint var TSRMLS_DC)
  452 +{
  453 + zval ***ptr = &CV(var);
  454 +
  455 + if (UNEXPECTED(*ptr == NULL)) {
  456 + return _get_zval_cv_lookup_BP_VAR_IS(ptr, var TSRMLS_CC);
  457 + }
  458 + return *ptr;
  459 +}
  460 +
  461 +static zend_always_inline zval **_get_zval_ptr_ptr_cv_BP_VAR_RW(zval ***CVs, zend_uint var TSRMLS_DC)
  462 +{
  463 + zval ***ptr = &CV(var);
  464 +
  465 + if (UNEXPECTED(*ptr == NULL)) {
  466 + return _get_zval_cv_lookup_BP_VAR_RW(ptr, var TSRMLS_CC);
  467 + }
  468 + return *ptr;
  469 +}
  470 +
  471 +static zend_always_inline zval **_get_zval_ptr_ptr_cv_BP_VAR_W(zval ***CVs, zend_uint var TSRMLS_DC)
  472 +{
  473 + zval ***ptr = &CV(var);
  474 +
  475 + if (UNEXPECTED(*ptr == NULL)) {
  476 + return _get_zval_cv_lookup_BP_VAR_W(ptr, var TSRMLS_CC);
  477 + }
  478 + return *ptr;
  479 +}
  480 +
309 481 static inline zval **_get_zval_ptr_ptr(int op_type, const znode_op *node, const temp_variable *Ts, zend_free_op *should_free, int type TSRMLS_DC)
310 482 {
311 483 if (op_type == IS_CV) {
@@ -387,7 +559,7 @@ static void zend_assign_to_variable_reference(zval **variable_ptr_ptr, zval **va
387 559 zval *variable_ptr = *variable_ptr_ptr;
388 560 zval *value_ptr = *value_ptr_ptr;
389 561
390   - if (variable_ptr == EG(error_zval_ptr) || value_ptr==EG(error_zval_ptr)) {
  562 + if (variable_ptr == &EG(error_zval) || value_ptr == &EG(error_zval)) {
391 563 variable_ptr_ptr = &EG(uninitialized_zval_ptr);
392 564 } else if (variable_ptr != value_ptr) {
393 565 if (!PZVAL_IS_REF(value_ptr)) {
@@ -395,7 +567,7 @@ static void zend_assign_to_variable_reference(zval **variable_ptr_ptr, zval **va
395 567 Z_DELREF_P(value_ptr);
396 568 if (Z_REFCOUNT_P(value_ptr)>0) {
397 569 ALLOC_ZVAL(*value_ptr_ptr);
398   - **value_ptr_ptr = *value_ptr;
  570 + ZVAL_COPY_VALUE(*value_ptr_ptr, value_ptr);
399 571 value_ptr = *value_ptr_ptr;
400 572 zendi_zval_copy_ctor(*value_ptr);
401 573 }
@@ -410,12 +582,12 @@ static void zend_assign_to_variable_reference(zval **variable_ptr_ptr, zval **va
410 582 } else if (!Z_ISREF_P(variable_ptr)) {
411 583 if (variable_ptr_ptr == value_ptr_ptr) {
412 584 SEPARATE_ZVAL(variable_ptr_ptr);
413   - } else if (variable_ptr==EG(uninitialized_zval_ptr)
  585 + } else if (variable_ptr==&EG(uninitialized_zval)
414 586 || Z_REFCOUNT_P(variable_ptr)>2) {
415 587 /* we need to separate */
416 588 Z_SET_REFCOUNT_P(variable_ptr, Z_REFCOUNT_P(variable_ptr) - 2);
417 589 ALLOC_ZVAL(*variable_ptr_ptr);
418   - **variable_ptr_ptr = *variable_ptr;
  590 + ZVAL_COPY_VALUE(*variable_ptr_ptr, variable_ptr);
419 591 zval_copy_ctor(*variable_ptr_ptr);
420 592 *value_ptr_ptr = *variable_ptr_ptr;
421 593 Z_SET_REFCOUNT_PP(variable_ptr_ptr, 2);
@@ -451,7 +623,7 @@ static inline char * zend_verify_arg_class_kind(const zend_arg_info *cur_arg_inf
451 623 }
452 624 }
453 625
454   -static inline int zend_verify_arg_error(const zend_function *zf, zend_uint arg_num, const zend_arg_info *cur_arg_info, const char *need_msg, const char *need_kind, const char *given_msg, char *given_kind TSRMLS_DC)
  626 +static inline int zend_verify_arg_error(const zend_function *zf, zend_uint arg_num, const char *need_msg, const char *need_kind, const char *given_msg, char *given_kind TSRMLS_DC)
455 627 {
456 628 zend_execute_data *ptr = EG(current_execute_data)->prev_execute_data;
457 629 char *fname = zf->common.function_name;
@@ -492,23 +664,23 @@ static inline int zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zva
492 664
493 665 if (!arg) {
494 666 need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC);
495   - return zend_verify_arg_error(zf, arg_num, cur_arg_info, need_msg, class_name, "none", "" TSRMLS_CC);
  667 + return zend_verify_arg_error(zf, arg_num, need_msg, class_name, "none", "" TSRMLS_CC);
496 668 }
497 669 if (Z_TYPE_P(arg) == IS_OBJECT) {
498 670 need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC);
499 671 if (!ce || !instanceof_function(Z_OBJCE_P(arg), ce TSRMLS_CC)) {
500   - return zend_verify_arg_error(zf, arg_num, cur_arg_info, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name TSRMLS_CC);
  672 + return zend_verify_arg_error(zf, arg_num, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name TSRMLS_CC);
501 673 }
502 674 } else if (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null) {
503 675 need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC);
504   - return zend_verify_arg_error(zf, arg_num, cur_arg_info, need_msg, class_name, zend_zval_type_name(arg), "" TSRMLS_CC);
  676 + return zend_verify_arg_error(zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "" TSRMLS_CC);
505 677 }
506 678 } else if (cur_arg_info->array_type_hint) {
507 679 if (!arg) {
508   - return zend_verify_arg_error(zf, arg_num, cur_arg_info, "be an array", "", "none", "" TSRMLS_CC);
  680 + return zend_verify_arg_error(zf, arg_num, "be an array", "", "none", "" TSRMLS_CC);
509 681 }
510 682 if (Z_TYPE_P(arg) != IS_ARRAY && (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null)) {
511   - return zend_verify_arg_error(zf, arg_num, cur_arg_info, "be an array", "", zend_zval_type_name(arg), "" TSRMLS_CC);
  683 + return zend_verify_arg_error(zf, arg_num, "be an array", "", zend_zval_type_name(arg), "" TSRMLS_CC);
512 684 }
513 685 }
514 686 return 1;
@@ -521,9 +693,9 @@ static inline void zend_assign_to_object(zval **retval, zval **object_ptr, zval
521 693 zval *value = get_zval_ptr(value_type, value_op, Ts, &free_value, BP_VAR_R);
522 694
523 695 if (Z_TYPE_P(object) != IS_OBJECT) {
524   - if (object == EG(error_zval_ptr)) {
  696 + if (object == &EG(error_zval)) {
525 697 if (retval) {
526   - *retval = EG(uninitialized_zval_ptr);
  698 + *retval = &EG(uninitialized_zval);
527 699 PZVAL_LOCK(*retval);
528 700 }
529 701 FREE_OP(free_value);
@@ -540,7 +712,7 @@ static inline void zend_assign_to_object(zval **retval, zval **object_ptr, zval
540 712 } else {
541 713 zend_error(E_WARNING, "Attempt to assign property of non-object");
542 714 if (retval) {
543   - *retval = EG(uninitialized_zval_ptr);
  715 + *retval = &EG(uninitialized_zval);
544 716 PZVAL_LOCK(*retval);
545 717 }
546 718 FREE_OP(free_value);
@@ -553,14 +725,14 @@ static inline void zend_assign_to_object(zval **retval, zval **object_ptr, zval
553 725 zval *orig_value = value;
554 726
555 727 ALLOC_ZVAL(value);
556   - *value = *orig_value;
  728 + ZVAL_COPY_VALUE(value, orig_value);
557 729 Z_UNSET_ISREF_P(value);
558 730 Z_SET_REFCOUNT_P(value, 0);
559 731 } else if (value_type == IS_CONST) {
560 732 zval *orig_value = value;
561 733
562 734 ALLOC_ZVAL(value);
563   - *value = *orig_value;
  735 + ZVAL_COPY_VALUE(value, orig_value);
564 736 Z_UNSET_ISREF_P(value);
565 737 Z_SET_REFCOUNT_P(value, 0);
566 738 zval_copy_ctor(value);
@@ -572,8 +744,8 @@ static inline void zend_assign_to_object(zval **retval, zval **object_ptr, zval
572 744 if (!Z_OBJ_HT_P(object)->write_property) {
573 745 zend_error(E_WARNING, "Attempt to assign property of non-object");
574 746 if (retval) {
575   - *retval = EG(uninitialized_zval_ptr);
576   - PZVAL_LOCK(*retval);
  747 + *retval = &EG(uninitialized_zval);
  748 + PZVAL_LOCK(&EG(uninitialized_zval));
577 749 }
578 750 if (value_type == IS_TMP_VAR) {
579 751 FREE_ZVAL(value);
@@ -631,8 +803,9 @@ static inline int zend_assign_to_string_offset(const temp_variable *T, const zva
631 803 }
632 804
633 805 if (Z_TYPE_P(value) != IS_STRING) {
634   - zval tmp = *value;
635   -
  806 + zval tmp;
  807 +
  808 + ZVAL_COPY_VALUE(&tmp, value);
636 809 if (value_type != IS_TMP_VAR) {
637 810 zval_copy_ctor(&tmp);
638 811 }
@@ -656,88 +829,104 @@ static inline int zend_assign_to_string_offset(const temp_variable *T, const zva
656 829 return 1;
657 830 }
658 831
659   -static inline zval* zend_assign_to_variable(zval **variable_ptr_ptr, zval *value, int is_tmp_var TSRMLS_DC)
  832 +
  833 +static inline zval* zend_assign_tmp_to_variable(zval **variable_ptr_ptr, zval *value TSRMLS_DC)
660 834 {
661 835 zval *variable_ptr = *variable_ptr_ptr;
662 836 zval garbage;
663 837
664   - if (variable_ptr == EG(error_zval_ptr)) {
665   - if (is_tmp_var) {
666   - zval_dtor(value);
667   - }
668   - return EG(uninitialized_zval_ptr);
669   - }
670   -
671   - if (Z_TYPE_P(variable_ptr) == IS_OBJECT && Z_OBJ_HANDLER_P(variable_ptr, set)) {
  838 + if (Z_TYPE_P(variable_ptr) == IS_OBJECT &&
  839 + UNEXPECTED(Z_OBJ_HANDLER_P(variable_ptr, set) != NULL)) {
672 840 Z_OBJ_HANDLER_P(variable_ptr, set)(variable_ptr_ptr, value TSRMLS_CC);
673 841 return variable_ptr;
674 842 }
675 843
676   - if (PZVAL_IS_REF(variable_ptr)) {
677   - if (variable_ptr!=value) {
  844 + if (EXPECTED(!PZVAL_IS_REF(variable_ptr))) {
  845 + if (Z_DELREF_P(variable_ptr)==0) {
  846 + ZVAL_COPY_VALUE(&garbage, variable_ptr);
  847 + INIT_PZVAL_COPY(variable_ptr, value);
  848 + zendi_zval_dtor(garbage);
  849 + return variable_ptr;
  850 + } else { /* we need to split */
  851 + ALLOC_ZVAL(variable_ptr);
  852 + INIT_PZVAL_COPY(variable_ptr, value);
  853 + *variable_ptr_ptr = variable_ptr;
  854 + return variable_ptr;
  855 + }
  856 + } else {
  857 + if (EXPECTED(variable_ptr != value)) {
678 858 zend_uint refcount = Z_REFCOUNT_P(variable_ptr);
679 859
680   - garbage = *variable_ptr;
681   - *variable_ptr = *value;
  860 + ZVAL_COPY_VALUE(&garbage, variable_ptr);
  861 + ZVAL_COPY_VALUE(variable_ptr, value);
682 862 Z_SET_REFCOUNT_P(variable_ptr, refcount);
683 863 Z_SET_ISREF_P(variable_ptr);
684   - if (!is_tmp_var) {
685   - zendi_zval_copy_ctor(*variable_ptr);
686   - }
687 864 zendi_zval_dtor(garbage);
688   - return variable_ptr;
689 865 }
690   - } else {
  866 + return variable_ptr;
  867 + }
  868 +}
  869 +
  870 +
  871 +static inline zval* zend_assign_to_variable(zval **variable_ptr_ptr, zval *value TSRMLS_DC)
  872 +{
  873 + zval *variable_ptr = *variable_ptr_ptr;
  874 + zval garbage;
  875 +
  876 + if (Z_TYPE_P(variable_ptr) == IS_OBJECT &&
  877 + UNEXPECTED(Z_OBJ_HANDLER_P(variable_ptr, set) != NULL)) {
  878 + Z_OBJ_HANDLER_P(variable_ptr, set)(variable_ptr_ptr, value TSRMLS_CC);
  879 + return variable_ptr;
  880 + }
  881 +
  882 + if (EXPECTED(!PZVAL_IS_REF(variable_ptr))) {
691 883 if (Z_DELREF_P(variable_ptr)==0) {
692   - if (!is_tmp_var) {
693   - if (variable_ptr==value) {
694   - Z_ADDREF_P(variable_ptr);
695   - } else if (PZVAL_IS_REF(value)) {
696   - garbage = *variable_ptr;
697   - *variable_ptr = *value;
698   - INIT_PZVAL(variable_ptr);
699   - zval_copy_ctor(variable_ptr);
700   - zendi_zval_dtor(garbage);
701   - return variable_ptr;
702   - } else {
703   - Z_ADDREF_P(value);
704   - *variable_ptr_ptr = value;
705   - if (variable_ptr != &EG(uninitialized_zval)) {
706   - GC_REMOVE_ZVAL_FROM_BUFFER(variable_ptr);
707   - zval_dtor(variable_ptr);
708   - efree(variable_ptr);
709   - }
710   - return value;
711   - }
712   - } else {
713   - garbage = *variable_ptr;
714   - *variable_ptr = *value;
715   - INIT_PZVAL(variable_ptr);
  884 + if (variable_ptr==value) {
  885 + Z_ADDREF_P(variable_ptr);
  886 + return variable_ptr;
  887 + } else if (PZVAL_IS_REF(value)) {
  888 + ZVAL_COPY_VALUE(&garbage, variable_ptr);
  889 + INIT_PZVAL_COPY(variable_ptr, value);
  890 + zval_copy_ctor(variable_ptr);
716 891 zendi_zval_dtor(garbage);
717 892 return variable_ptr;
  893 + } else {
  894 + Z_ADDREF_P(value);
  895 + *variable_ptr_ptr = value;
  896 + if (variable_ptr != &EG(uninitialized_zval)) {
  897 + GC_REMOVE_ZVAL_FROM_BUFFER(variable_ptr);
  898 + zval_dtor(variable_ptr);
  899 + efree(variable_ptr);
  900 + }
  901 + return value;
718 902 }
719 903 } else { /* we need to split */
720   - if (!is_tmp_var) {
721   - if (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0) {
722   - ALLOC_ZVAL(variable_ptr);
723   - *variable_ptr_ptr = variable_ptr;
724   - *variable_ptr = *value;
725   - zval_copy_ctor(variable_ptr);
726   - Z_SET_REFCOUNT_P(variable_ptr, 1);
727   - } else {
728   - *variable_ptr_ptr = value;
729   - Z_ADDREF_P(value);
730   - }
  904 + if (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0) {
  905 + ALLOC_ZVAL(variable_ptr);
  906 + INIT_PZVAL_COPY(variable_ptr, value);
  907 + zval_copy_ctor(variable_ptr);
  908 + *variable_ptr_ptr = variable_ptr;
  909 + return variable_ptr;
731 910 } else {
732   - ALLOC_ZVAL(*variable_ptr_ptr);
733   - Z_SET_REFCOUNT_P(value, 1);
734   - **variable_ptr_ptr = *value;
  911 + *variable_ptr_ptr = value;
  912 + Z_ADDREF_P(value);
  913 + Z_UNSET_ISREF_P(value);
  914 + return value;
735 915 }
736 916 }
737   - Z_UNSET_ISREF_PP(variable_ptr_ptr);
738   - }
  917 + } else {
  918 + if (EXPECTED(variable_ptr != value)) {
  919 + zend_uint refcount = Z_REFCOUNT_P(variable_ptr);
739 920
740   - return *variable_ptr_ptr;
  921 + ZVAL_COPY_VALUE(&garbage, variable_ptr);
  922 + ZVAL_COPY_VALUE(variable_ptr, value);
  923 + Z_SET_REFCOUNT_P(variable_ptr, refcount);
  924 + Z_SET_ISREF_P(variable_ptr);
  925 + zendi_zval_copy_ctor(*variable_ptr);
  926 + zendi_zval_dtor(garbage);
  927 + }
  928 + return variable_ptr;
  929 + }
741 930 }
742 931
743 932
@@ -916,7 +1105,7 @@ static void zend_fetch_dimension_address(temp_variable *result, zval **container
916 1105 break;
917 1106
918 1107 case IS_NULL:
919   - if (container == EG(error_zval_ptr)) {
  1108 + if (container == &EG(error_zval)) {
920 1109 result->var.ptr_ptr = &EG(error_zval_ptr);
921 1110 PZVAL_LOCK(EG(error_zval_ptr));
922 1111 } else if (type != BP_VAR_UNSET) {
@@ -997,7 +1186,7 @@ static void zend_fetch_dimension_address(temp_variable *result, zval **container
997 1186 zval *tmp = overloaded_result;
998 1187
999 1188 ALLOC_ZVAL(overloaded_result);
1000   - *overloaded_result = *tmp;
  1189 + ZVAL_COPY_VALUE(overloaded_result, tmp);
1001 1190 zval_copy_ctor(overloaded_result);
1002 1191 Z_UNSET_ISREF_P(overloaded_result);
1003 1192 Z_SET_REFCOUNT_P(overloaded_result, 0);
@@ -1011,7 +1200,7 @@ static void zend_fetch_dimension_address(temp_variable *result, zval **container
1011 1200 } else {
1012 1201 retval = &EG(error_zval_ptr);
1013 1202 }
1014   - AI_SET_PTR(result->var, *retval);
  1203 + AI_SET_PTR(result, *retval);
1015 1204 PZVAL_LOCK(*retval);
1016 1205 if (dim_type == IS_TMP_VAR) {
1017 1206 zval_ptr_dtor(&dim);
@@ -1029,8 +1218,8 @@ static void zend_fetch_dimension_address(temp_variable *result, zval **container
1029 1218 default:
1030 1219 if (type == BP_VAR_UNSET) {
1031 1220 zend_error(E_WARNING, "Cannot unset offset in a non-array variable");
1032   - AI_SET_PTR(result->var, EG(uninitialized_zval_ptr));
1033   - PZVAL_LOCK(EG(uninitialized_zval_ptr));
  1221 + AI_SET_PTR(result, &EG(uninitialized_zval));
  1222 + PZVAL_LOCK(&EG(uninitialized_zval));
1034 1223 } else {
1035 1224 zend_error(E_WARNING, "Cannot use a scalar value as an array");
1036 1225 result->var.ptr_ptr = &EG(error_zval_ptr);
@@ -1050,7 +1239,7 @@ static void zend_fetch_dimension_address_read(temp_variable *result, zval **cont
1050 1239 case IS_ARRAY:
1051 1240 retval = zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, dim_type, type TSRMLS_CC);
1052 1241 if (result) {
1053   - AI_SET_PTR(result->var, *retval);
  1242 + AI_SET_PTR(result, *retval);
1054 1243 PZVAL_LOCK(*retval);
1055 1244 }
1056 1245 return;
@@ -1058,8 +1247,8 @@ static void zend_fetch_dimension_address_read(temp_variable *result, zval **cont
1058 1247
1059 1248 case IS_NULL:
1060 1249 if (result) {
1061   - AI_SET_PTR(result->var, EG(uninitialized_zval_ptr));
1062   - PZVAL_LOCK(EG(uninitialized_zval_ptr));
  1250 + AI_SET_PTR(result, &EG(uninitialized_zval));
  1251 + PZVAL_LOCK(&EG(uninitialized_zval));
1063 1252 }
1064 1253 return;
1065 1254 break;
@@ -1081,7 +1270,7 @@ static void zend_fetch_dimension_address_read(temp_variable *result, zval **cont
1081 1270 break;
1082 1271 }
1083 1272
1084   - tmp = *dim;
  1273 + ZVAL_COPY_VALUE(&tmp, dim);
1085 1274 zval_copy_ctor(&tmp);
1086 1275 convert_to_long(&tmp);
1087 1276 dim = &tmp;
@@ -1115,7 +1304,7 @@ static void zend_fetch_dimension_address_read(temp_variable *result, zval **cont
1115 1304
1116 1305 if (overloaded_result) {
1117 1306 if (result) {
1118   - AI_SET_PTR(result->var, overloaded_result);
  1307 + AI_SET_PTR(result, overloaded_result);
1119 1308 PZVAL_LOCK(overloaded_result);
1120 1309 } else if (Z_REFCOUNT_P(overloaded_result) == 0) {
1121 1310 /* Destroy unused result from offsetGet() magic method */
@@ -1123,8 +1312,8 @@ static void zend_fetch_dimension_address_read(temp_variable *result, zval **cont
1123 1312 zval_ptr_dtor(&overloaded_result);
1124 1313 }
1125 1314 } else if (result) {
1126   - AI_SET_PTR(result->var, EG(uninitialized_zval_ptr));
1127   - PZVAL_LOCK(EG(uninitialized_zval_ptr));
  1315 + AI_SET_PTR(result, &EG(uninitialized_zval));
  1316 + PZVAL_LOCK(&EG(uninitialized_zval));
1128 1317 }
1129 1318 if (dim_type == IS_TMP_VAR) {
1130 1319 zval_ptr_dtor(&dim);
@@ -1135,8 +1324,8 @@ static void zend_fetch_dimension_address_read(temp_variable *result, zval **cont
1135 1324
1136 1325 default:
1137 1326 if (result) {
1138   - AI_SET_PTR(result->var, EG(uninitialized_zval_ptr));
1139   - PZVAL_LOCK(EG(uninitialized_zval_ptr));
  1327 + AI_SET_PTR(result, &EG(uninitialized_zval));
  1328 + PZVAL_LOCK(&EG(uninitialized_zval));
1140 1329 }
1141 1330 return;
1142 1331 break;
@@ -1148,9 +1337,9 @@ static void zend_fetch_property_address(temp_variable *result, zval **container_
1148 1337 zval *container = *container_ptr;;
1149 1338
1150 1339 if (Z_TYPE_P(container) != IS_OBJECT) {
1151   - if (container == EG(error_zval_ptr)) {
  1340 + if (container == &EG(error_zval)) {
1152 1341 result->var.ptr_ptr = &EG(error_zval_ptr);
1153   - PZVAL_LOCK(*result->var.ptr_ptr);
  1342 + PZVAL_LOCK(EG(error_zval_ptr));
1154 1343 return;
1155 1344 }
1156 1345
@@ -1179,7 +1368,7 @@ static void zend_fetch_property_address(temp_variable *result, zval **container_
1179 1368
1180 1369 if (Z_OBJ_HT_P(container)->read_property &&
1181 1370 (ptr = Z_OBJ_HT_P(container)->read_property(container, prop_ptr, type, key TSRMLS_CC)) != NULL) {
1182   - AI_SET_PTR(result->var, ptr);
  1371 + AI_SET_PTR(result, ptr);
1183 1372 PZVAL_LOCK(ptr);
1184 1373 } else {
1185 1374 zend_error_noreturn(E_ERROR, "Cannot access undefined property for object with overloaded property access");
@@ -1191,7 +1380,7 @@ static void zend_fetch_property_address(temp_variable *result, zval **container_
1191 1380 } else if (Z_OBJ_HT_P(container)->read_property) {
1192 1381 zval *ptr = Z_OBJ_HT_P(container)->read_property(container, prop_ptr, type, key TSRMLS_CC);
1193 1382
1194   - AI_SET_PTR(result->var, ptr);
  1383 + AI_SET_PTR(result, ptr);
1195 1384 PZVAL_LOCK(ptr);
1196 1385 } else {
1197 1386 zend_error(E_WARNING, "This object doesn't support property references");
@@ -1283,22 +1472,29 @@ ZEND_API void execute_internal(zend_execute_data *execute_data_ptr, int return_v
1283 1472
1284 1473 #define ZEND_VM_NEXT_OPCODE() \
1285 1474 CHECK_SYMBOL_TABLES() \
1286   - EX(opline)++; \
  1475 + ZEND_VM_INC_OPCODE(); \
1287 1476 ZEND_VM_CONTINUE()
1288 1477
1289 1478 #define ZEND_VM_SET_OPCODE(new_op) \
1290 1479 CHECK_SYMBOL_TABLES() \
1291   - EX(opline) = new_op
  1480 + OPLINE = new_op
1292 1481
1293 1482 #define ZEND_VM_JMP(new_op) \
1294   - CHECK_SYMBOL_TABLES() \
1295 1483 if (EXPECTED(!EG(exception))) { \
1296   - EX(opline) = new_op; \
  1484 + ZEND_VM_SET_OPCODE(new_op); \
  1485 + } else { \
  1486 + LOAD_OPLINE(); \
1297 1487 } \
1298 1488 ZEND_VM_CONTINUE()
1299 1489
1300 1490 #define ZEND_VM_INC_OPCODE() \
1301   - EX(opline)++
  1491 + OPLINE++
  1492 +
  1493 +#ifdef __GNUC__
  1494 +# define ZEND_VM_GUARD(name) __asm__("#" #name)
  1495 +#else
  1496 +# define ZEND_VM_GUARD(name)
  1497 +#endif
1302 1498
1303 1499 #include "zend_vm_execute.h"
1304 1500
59 Zend/zend_execute.h
@@ -62,7 +62,7 @@ ZEND_API void execute(zend_op_array *op_array TSRMLS_DC);
62 62 ZEND_API void execute_internal(zend_execute_data *execute_data_ptr, int return_value_used TSRMLS_DC);
63 63 ZEND_API int zend_is_true(zval *op);
64 64 #define safe_free_zval_ptr(p) safe_free_zval_ptr_rel(p ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
65   -static inline void safe_free_zval_ptr_rel(zval *p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
  65 +static zend_always_inline void safe_free_zval_ptr_rel(zval *p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
66 66 {
67 67 TSRMLS_FETCH();
68 68
@@ -77,7 +77,28 @@ ZEND_API int zend_eval_stringl(char *str, int str_len, zval *retval_ptr, char *s
77 77 ZEND_API int zend_eval_string_ex(char *str, zval *retval_ptr, char *string_name, int handle_exceptions TSRMLS_DC);
78 78 ZEND_API int zend_eval_stringl_ex(char *str, int str_len, zval *retval_ptr, char *string_name, int handle_exceptions TSRMLS_DC);
79 79
80   -static inline int i_zend_is_true(zval *op)
  80 +static zend_always_inline void i_zval_ptr_dtor(zval *zval_ptr ZEND_FILE_LINE_DC)
  81 +{
  82 + if (!Z_DELREF_P(zval_ptr)) {
  83 + TSRMLS_FETCH();
  84 +
  85 + if (zval_ptr != &EG(uninitialized_zval)) {
  86 + GC_REMOVE_ZVAL_FROM_BUFFER(zval_ptr);
  87 + zval_dtor(zval_ptr);
  88 + efree_rel(zval_ptr);
  89 + }
  90 + } else {
  91 + TSRMLS_FETCH();
  92 +
  93 + if (Z_REFCOUNT_P(zval_ptr) == 1) {
  94 + Z_UNSET_ISREF_P(zval_ptr);
  95 + }
  96 +
  97 + GC_ZVAL_CHECK_POSSIBLE_ROOT(zval_ptr);
  98 + }
  99 +}
  100 +
  101 +static zend_always_inline int i_zend_is_true(zval *op)
81 102 {
82 103 int result;
83 104
@@ -157,7 +178,7 @@ struct _zend_vm_stack {
157 178 } \
158 179 } while (0)
159 180
160   -static inline zend_vm_stack zend_vm_stack_new_page(int count) {
  181 +static zend_always_inline zend_vm_stack zend_vm_stack_new_page(int count) {
161 182 zend_vm_stack page = (zend_vm_stack)emalloc(ZEND_MM_ALIGNED_SIZE(sizeof(*page)) + sizeof(void*) * count);
162 183
163 184 page->top = ZEND_VM_STACK_ELEMETS(page);
@@ -166,12 +187,12 @@ static inline zend_vm_stack zend_vm_stack_new_page(int count) {
166 187 return page;
167 188 }
168 189
169   -static inline void zend_vm_stack_init(TSRMLS_D)
  190 +static zend_always_inline void zend_vm_stack_init(TSRMLS_D)
170 191 {
171 192 EG(argument_stack) = zend_vm_stack_new_page(ZEND_VM_STACK_PAGE_SIZE);
172 193 }
173 194
174   -static inline void zend_vm_stack_destroy(TSRMLS_D)
  195 +static zend_always_inline void zend_vm_stack_destroy(TSRMLS_D)
175 196 {
176 197 zend_vm_stack stack = EG(argument_stack);
177 198
@@ -182,30 +203,30 @@ static inline void zend_vm_stack_destroy(TSRMLS_D)
182 203 }
183 204 }
184 205
185   -static inline void zend_vm_stack_extend(int count TSRMLS_DC)
  206 +static zend_always_inline void zend_vm_stack_extend(int count TSRMLS_DC)
186 207 {
187 208 zend_vm_stack p = zend_vm_stack_new_page(count >= ZEND_VM_STACK_PAGE_SIZE ? count : ZEND_VM_STACK_PAGE_SIZE);
188 209 p->prev = EG(argument_stack);
189 210 EG(argument_stack) = p;
190 211 }
191 212
192   -static inline void **zend_vm_stack_top(TSRMLS_D)
  213 +static zend_always_inline void **zend_vm_stack_top(TSRMLS_D)