diff options
| -rw-r--r-- | Zend/zend.h | 20 | ||||
| -rw-r--r-- | Zend/zend_ast.c | 359 | ||||
| -rw-r--r-- | Zend/zend_ast.h | 47 | ||||
| -rw-r--r-- | Zend/zend_builtin_functions.c | 2 | ||||
| -rw-r--r-- | Zend/zend_compile.c | 17 | ||||
| -rw-r--r-- | Zend/zend_compile.h | 6 | ||||
| -rw-r--r-- | Zend/zend_execute_API.c | 341 | ||||
| -rw-r--r-- | Zend/zend_extensions.h | 2 | ||||
| -rw-r--r-- | Zend/zend_language_parser.y | 80 | ||||
| -rw-r--r-- | Zend/zend_operators.c | 62 | ||||
| -rw-r--r-- | Zend/zend_operators.h | 4 | ||||
| -rw-r--r-- | Zend/zend_variables.c | 8 | ||||
| -rw-r--r-- | Zend/zend_vm_def.h | 1 | ||||
| -rw-r--r-- | Zend/zend_vm_execute.h | 1 | ||||
| -rw-r--r-- | ext/opcache/zend_accelerator_util_funcs.c | 56 | ||||
| -rw-r--r-- | ext/opcache/zend_persist.c | 29 | ||||
| -rw-r--r-- | ext/opcache/zend_persist_calc.c | 27 |
17 files changed, 656 insertions, 406 deletions
diff --git a/Zend/zend.h b/Zend/zend.h index a949c5b0b6..a95473b76e 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -579,18 +579,18 @@ typedef int (*zend_write_func_t)(const char *str, uint str_length); /* data types */ /* All data types <= IS_BOOL have their constructor/destructors skipped */ -#define IS_NULL 0 -#define IS_LONG 1 -#define IS_DOUBLE 2 -#define IS_BOOL 3 -#define IS_ARRAY 4 -#define IS_OBJECT 5 -#define IS_STRING 6 -#define IS_RESOURCE 7 -#define IS_CONSTANT 8 +#define IS_NULL 0 +#define IS_LONG 1 +#define IS_DOUBLE 2 +#define IS_BOOL 3 +#define IS_ARRAY 4 +#define IS_OBJECT 5 +#define IS_STRING 6 +#define IS_RESOURCE 7 +#define IS_CONSTANT 8 #define IS_CONSTANT_ARRAY 9 #define IS_CONSTANT_AST 10 -#define IS_CALLABLE 11 +#define IS_CALLABLE 11 /* Ugly hack to support constants as static array indices */ #define IS_CONSTANT_TYPE_MASK 0x00f diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index 21c08da510..7ebb8d2796 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -13,118 +13,317 @@ | license@zend.com so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Bob Weinand <bwoebi@php.net> | + | Dmitry Stogov <dmitry@zend.com> | +----------------------------------------------------------------------+ */ /* $Id$ */ #include "zend_ast.h" -#include "zend_execute.h" +#include "zend_API.h" +#include "zend_operators.h" -#define COPY_ZVAL_TO_OP(nr) \ - if (op##nr) { \ - Z_AST_P(result)->ops[nr] = emalloc(sizeof(zval)); \ - *Z_AST_P(result)->ops[nr] = *op##nr; \ - } else { \ - Z_AST_P(result)->ops[nr] = NULL; \ - } - -void zend_ast_add(zval *result, intermediary_ast_function_type func, char op_count) { - zend_ast *ast = emalloc(sizeof(zend_ast) + op_count * sizeof(zval *)); - ast->op_count = op_count; - ast->ops = (zval **)(ast + 1); - ast->refcount = 1; - ast->func = func; - Z_AST_P(result) = ast; - Z_TYPE_P(result) = IS_CONSTANT_AST; +ZEND_API zend_ast *zend_ast_create_constant_node(zval *zv) +{ + zend_ast *node = emalloc(sizeof(zend_ast) + sizeof(zval)); + node->kind = ZEND_CONST; + node->children = 0; + node->u.val = (zval*)(node + 1); + INIT_PZVAL_COPY(node->u.val, zv); + return node; } -/* Do operations on constant operators at compile time (AST building time) */ - -void zend_ast_add_unary(zval *result, unary_ast_func func, zval *op0 TSRMLS_DC) { - if (!op0 || !IS_CONSTANT_TYPE(Z_TYPE_P(op0))) { - func(result, op0 TSRMLS_CC); - if (op0) zval_dtor(op0); - return; - } - - zend_ast_add(result, (intermediary_ast_function_type)func, 1); - COPY_ZVAL_TO_OP(0) +ZEND_API zend_ast* zend_ast_create_node1(uint kind, zend_ast *op0) +{ + zend_ast *node = emalloc(sizeof(zend_ast)); + node->kind = kind; + node->children = 1; + node->u.child[0] = op0; + return node; } -void zend_ast_add_binary(zval *result, binary_ast_func func, zval *op0, zval *op1 TSRMLS_DC) { - if ((!op0 || !IS_CONSTANT_TYPE(Z_TYPE_P(op0))) && (!op1 || !IS_CONSTANT_TYPE(Z_TYPE_P(op1)))) { - func(result, op0, op1 TSRMLS_CC); - if (op0) zval_dtor(op0); - if (op1) zval_dtor(op1); - return; - } - - zend_ast_add(result, (intermediary_ast_function_type)func, 2); - COPY_ZVAL_TO_OP(0) - COPY_ZVAL_TO_OP(1) +ZEND_API zend_ast* zend_ast_create_node2(uint kind, zend_ast *op0, zend_ast *op1) +{ + zend_ast *node = emalloc(sizeof(zend_ast) + sizeof(zend_ast*)); + node->kind = kind; + node->children = 2; + node->u.child[0] = op0; + node->u.child[1] = op1; + return node; } -void zend_ast_add_ternary(zval *result, ternary_ast_func func, zval *op0, zval *op1, zval *op2 TSRMLS_DC) { - if ((!op0 || !IS_CONSTANT_TYPE(Z_TYPE_P(op0))) && (!op1 || !IS_CONSTANT_TYPE(Z_TYPE_P(op1))) && (!op2 || !IS_CONSTANT_TYPE(Z_TYPE_P(op2)))) { - func(result, op0, op1, op2 TSRMLS_CC); - if (op0) zval_dtor(op0); - if (op1) zval_dtor(op1); - if (op2) zval_dtor(op2); - return; - } - - zend_ast_add(result, (intermediary_ast_function_type)func, 3); - COPY_ZVAL_TO_OP(0) - COPY_ZVAL_TO_OP(1) - COPY_ZVAL_TO_OP(2) +ZEND_API zend_ast* zend_ast_create_node3(uint kind, zend_ast *op0, zend_ast *op1, zend_ast *op2) +{ + zend_ast *node = emalloc(sizeof(zend_ast) + sizeof(zend_ast*) * 2); + node->kind = kind; + node->children = 3; + node->u.child[0] = op0; + node->u.child[1] = op1; + node->u.child[2] = op2; + return node; } -void zend_ast_evaluate(zval *result, zend_ast *ast TSRMLS_DC) { +ZEND_API int zend_ast_is_ct_constant(zend_ast *ast) +{ int i; - zval **ops = emalloc((sizeof(zval *) + sizeof(zval)) * ast->op_count); - for (i = ast->op_count; i--;) { - if (ast->ops[i] && IS_CONSTANT_TYPE(Z_TYPE_P(ast->ops[i]))) { - ops[i] = ((zval *)(ops + ast->op_count)) + i; - *ops[i] = *ast->ops[i]; - zval_copy_ctor(ops[i]); - zval_update_constant_ex(&ops[i], (void *)1, NULL TSRMLS_CC); - } else { - ops[i] = ast->ops[i]; + if (ast->kind == ZEND_CONST) { + return !IS_CONSTANT_TYPE(Z_TYPE_P(ast->u.val)); + } else { + for (i = 0; i < ast->children; i++) { + if (ast->u.child[i]) { + if (!zend_ast_is_ct_constant(ast->u.child[i])) { + return 0; + } + } } + return 1; } +} + +ZEND_API void zend_ast_evaluate(zval *result, zend_ast *ast TSRMLS_DC) +{ + zval op1, op2; - switch (ast->op_count) { - case 1: - ((unary_ast_func)ast->func)(result, ops[0] TSRMLS_CC); + switch (ast->kind) { + case ZEND_ADD: + zend_ast_evaluate(&op1, ast->u.child[0] TSRMLS_CC); + zend_ast_evaluate(&op2, ast->u.child[1] TSRMLS_CC); + add_function(result, &op1, &op2 TSRMLS_CC); + zval_dtor(&op1); + zval_dtor(&op2); + break; + case ZEND_SUB: + zend_ast_evaluate(&op1, ast->u.child[0] TSRMLS_CC); + zend_ast_evaluate(&op2, ast->u.child[1] TSRMLS_CC); + sub_function(result, &op1, &op2 TSRMLS_CC); + zval_dtor(&op1); + zval_dtor(&op2); + break; + case ZEND_MUL: + zend_ast_evaluate(&op1, ast->u.child[0] TSRMLS_CC); + zend_ast_evaluate(&op2, ast->u.child[1] TSRMLS_CC); + mul_function(result, &op1, &op2 TSRMLS_CC); + zval_dtor(&op1); + zval_dtor(&op2); + break; + case ZEND_DIV: + zend_ast_evaluate(&op1, ast->u.child[0] TSRMLS_CC); + zend_ast_evaluate(&op2, ast->u.child[1] TSRMLS_CC); + div_function(result, &op1, &op2 TSRMLS_CC); + zval_dtor(&op1); + zval_dtor(&op2); + break; + case ZEND_MOD: + zend_ast_evaluate(&op1, ast->u.child[0] TSRMLS_CC); + zend_ast_evaluate(&op2, ast->u.child[1] TSRMLS_CC); + mod_function(result, &op1, &op2 TSRMLS_CC); + zval_dtor(&op1); + zval_dtor(&op2); + break; + case ZEND_SL: + zend_ast_evaluate(&op1, ast->u.child[0] TSRMLS_CC); + zend_ast_evaluate(&op2, ast->u.child[1] TSRMLS_CC); + shift_left_function(result, &op1, &op2 TSRMLS_CC); + zval_dtor(&op1); + zval_dtor(&op2); + break; + case ZEND_SR: + zend_ast_evaluate(&op1, ast->u.child[0] TSRMLS_CC); + zend_ast_evaluate(&op2, ast->u.child[1] TSRMLS_CC); + shift_right_function(result, &op1, &op2 TSRMLS_CC); + zval_dtor(&op1); + zval_dtor(&op2); + break; + case ZEND_CONCAT: + zend_ast_evaluate(&op1, ast->u.child[0] TSRMLS_CC); + zend_ast_evaluate(&op2, ast->u.child[1] TSRMLS_CC); + concat_function(result, &op1, &op2 TSRMLS_CC); + zval_dtor(&op1); + zval_dtor(&op2); + break; + case ZEND_BW_OR: + zend_ast_evaluate(&op1, ast->u.child[0] TSRMLS_CC); + zend_ast_evaluate(&op2, ast->u.child[1] TSRMLS_CC); + bitwise_or_function(result, &op1, &op2 TSRMLS_CC); + zval_dtor(&op1); + zval_dtor(&op2); break; - case 2: - ((binary_ast_func)ast->func)(result, ops[0], ops[1] TSRMLS_CC); + case ZEND_BW_AND: + zend_ast_evaluate(&op1, ast->u.child[0] TSRMLS_CC); + zend_ast_evaluate(&op2, ast->u.child[1] TSRMLS_CC); + bitwise_and_function(result, &op1, &op2 TSRMLS_CC); + zval_dtor(&op1); + zval_dtor(&op2); break; - case 3: - ((ternary_ast_func)ast->func)(result, ops[0], ops[1], ops[2] TSRMLS_CC); + case ZEND_BW_XOR: + zend_ast_evaluate(&op1, ast->u.child[0] TSRMLS_CC); + zend_ast_evaluate(&op2, ast->u.child[1] TSRMLS_CC); + bitwise_xor_function(result, &op1, &op2 TSRMLS_CC); + zval_dtor(&op1); + zval_dtor(&op2); break; + case ZEND_BW_NOT: + zend_ast_evaluate(&op1, ast->u.child[0] TSRMLS_CC); + bitwise_not_function(result, &op1 TSRMLS_CC); + zval_dtor(&op1); + break; + case ZEND_BOOL_NOT: + zend_ast_evaluate(&op1, ast->u.child[0] TSRMLS_CC); + boolean_not_function(result, &op1 TSRMLS_CC); + zval_dtor(&op1); + break; + case ZEND_BOOL_XOR: + zend_ast_evaluate(&op1, ast->u.child[0] TSRMLS_CC); + zend_ast_evaluate(&op2, ast->u.child[1] TSRMLS_CC); + boolean_xor_function(result, &op1, &op2 TSRMLS_CC); + zval_dtor(&op1); + zval_dtor(&op2); + break; + case ZEND_IS_IDENTICAL: + zend_ast_evaluate(&op1, ast->u.child[0] TSRMLS_CC); + zend_ast_evaluate(&op2, ast->u.child[1] TSRMLS_CC); + is_identical_function(result, &op1, &op2 TSRMLS_CC); + zval_dtor(&op1); + zval_dtor(&op2); + break; + case ZEND_IS_NOT_IDENTICAL: + zend_ast_evaluate(&op1, ast->u.child[0] TSRMLS_CC); + zend_ast_evaluate(&op2, ast->u.child[1] TSRMLS_CC); + is_not_identical_function(result, &op1, &op2 TSRMLS_CC); + zval_dtor(&op1); + zval_dtor(&op2); + break; + case ZEND_IS_EQUAL: + zend_ast_evaluate(&op1, ast->u.child[0] TSRMLS_CC); + zend_ast_evaluate(&op2, ast->u.child[1] TSRMLS_CC); + is_equal_function(result, &op1, &op2 TSRMLS_CC); + zval_dtor(&op1); + zval_dtor(&op2); + break; + case ZEND_IS_NOT_EQUAL: + zend_ast_evaluate(&op1, ast->u.child[0] TSRMLS_CC); + zend_ast_evaluate(&op2, ast->u.child[1] TSRMLS_CC); + is_not_equal_function(result, &op1, &op2 TSRMLS_CC); + zval_dtor(&op1); + zval_dtor(&op2); + break; + case ZEND_IS_SMALLER: + zend_ast_evaluate(&op1, ast->u.child[0] TSRMLS_CC); + zend_ast_evaluate(&op2, ast->u.child[1] TSRMLS_CC); + is_smaller_function(result, &op1, &op2 TSRMLS_CC); + zval_dtor(&op1); + zval_dtor(&op2); + break; + case ZEND_IS_SMALLER_OR_EQUAL: + zend_ast_evaluate(&op1, ast->u.child[0] TSRMLS_CC); + zend_ast_evaluate(&op2, ast->u.child[1] TSRMLS_CC); + is_smaller_or_equal_function(result, &op1, &op2 TSRMLS_CC); + zval_dtor(&op1); + zval_dtor(&op2); + break; + case ZEND_CONST: + *result = *ast->u.val; + zval_copy_ctor(result); + if (IS_CONSTANT_TYPE(Z_TYPE_P(result))) { + zval_update_constant(&result, (void *) 1 TSRMLS_CC); + } + break; + case ZEND_BOOL_AND: + zend_ast_evaluate(&op1, ast->u.child[0] TSRMLS_CC); + if (zend_is_true(&op1)) { + zend_ast_evaluate(&op2, ast->u.child[1] TSRMLS_CC); + ZVAL_BOOL(result, zend_is_true(&op2)); + zval_dtor(&op2); + } else { + ZVAL_BOOL(result, 0); + } + zval_dtor(&op1); + break; + case ZEND_BOOL_OR: + zend_ast_evaluate(&op1, ast->u.child[0] TSRMLS_CC); + if (zend_is_true(&op1)) { + ZVAL_BOOL(result, 1); + } else { + zend_ast_evaluate(&op2, ast->u.child[1] TSRMLS_CC); + ZVAL_BOOL(result, zend_is_true(&op2)); + zval_dtor(&op2); + } + zval_dtor(&op1); + break; + case ZEND_TERNARY: + zend_ast_evaluate(&op1, ast->u.child[0] TSRMLS_CC); + if (zend_is_true(&op1)) { + if (!ast->u.child[1]) { + *result = op1; + } else { + zend_ast_evaluate(result, ast->u.child[1] TSRMLS_CC); + zval_dtor(&op1); + } + } else { + zend_ast_evaluate(result, ast->u.child[2] TSRMLS_CC); + zval_dtor(&op1); + } + break; + case ZEND_UNARY_PLUS: + ZVAL_LONG(&op1, 0); + zend_ast_evaluate(&op2, ast->u.child[0] TSRMLS_CC); + add_function(result, &op1, &op2 TSRMLS_CC); + zval_dtor(&op2); + break; + case ZEND_UNARY_MINUS: + ZVAL_LONG(&op1, 0); + zend_ast_evaluate(&op2, ast->u.child[0] TSRMLS_CC); + sub_function(result, &op1, &op2 TSRMLS_CC); + zval_dtor(&op2); + break; + default: + zend_error(E_ERROR, "Unsupported constant expression"); } +} - for (i = ast->op_count; i--;) { - if (ast->ops[i] != ops[i]) { - zval_dtor(ops[i]); +ZEND_API zend_ast *zend_ast_copy(zend_ast *ast) +{ + if (ast == NULL) { + return NULL; + } else if (ast->kind == ZEND_CONST) { + zend_ast *node = zend_ast_create_constant_node(ast->u.val); + zval_copy_ctor(node->u.val); + return node; + } else { + switch (ast->children) { + case 1: + return zend_ast_create_node1( + ast->kind, + zend_ast_copy(ast->u.child[0])); + case 2: + return zend_ast_create_node2( + ast->kind, + zend_ast_copy(ast->u.child[0]), + zend_ast_copy(ast->u.child[1])); + case 3: + return zend_ast_create_node3( + ast->kind, + zend_ast_copy(ast->u.child[0]), + zend_ast_copy(ast->u.child[1]), + zend_ast_copy(ast->u.child[2])); } } - - efree(ops); + return NULL; } -void zend_ast_destroy(zend_ast *ast TSRMLS_DC) { +ZEND_API void zend_ast_destroy(zend_ast *ast) +{ int i; - for (i = ast->op_count; i--;) { - if (ast->ops[i] && !Z_DELREF_P(ast->ops[i])) { - zval_dtor(ast->ops[i]); - efree(ast->ops[i]); + if (ast->kind == ZEND_CONST) { + zval_dtor(ast->u.val); + } else { + for (i = 0; i < ast->children; i++) { + if (ast->u.child[i]) { + zend_ast_destroy(ast->u.child[i]); + } } } - efree(ast); } diff --git a/Zend/zend_ast.h b/Zend/zend_ast.h index 218f2c02e0..4c94cf8ac2 100644 --- a/Zend/zend_ast.h +++ b/Zend/zend_ast.h @@ -13,6 +13,7 @@ | license@zend.com so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Bob Weinand <bwoebi@php.net> | + | Dmitry Stogov <dmitry@zend.com> | +----------------------------------------------------------------------+ */ @@ -25,36 +26,36 @@ typedef struct _zend_ast zend_ast; #include "zend.h" -typedef void(*intermediary_ast_function_type)(zval *, ...); -typedef int(*unary_ast_func)(zval *result, zval *op0 TSRMLS_DC); -typedef int(*binary_ast_func)(zval *result, zval *op0, zval *op1 TSRMLS_DC); -typedef int(*ternary_ast_func)(zval *result, zval *op0, zval *op1, zval *op2 TSRMLS_DC); +typedef enum _zend_ast_node_kind { + /* first 256 node kinds are reserved for opcodes */ + ZEND_CONST = 256, + ZEND_BOOL_AND, + ZEND_BOOL_OR, + ZEND_TERNARY, + ZEND_UNARY_PLUS, + ZEND_UNARY_MINUS, +} zend_ast_ode_kind; struct _zend_ast { - char op_count; - zval **ops; - intermediary_ast_function_type func; - int refcount; + unsigned short kind; + unsigned short children; + union { + zval *val; + zend_ast *child[1]; + } u; }; -void zend_ast_add_unary(zval *result, unary_ast_func func, zval *op0 TSRMLS_DC); -void zend_ast_add_binary(zval *result, binary_ast_func func, zval *op0, zval *op1 TSRMLS_DC); -void zend_ast_add_ternary(zval *result, ternary_ast_func func, zval *op0, zval *op1, zval *op2 TSRMLS_DC); +ZEND_API zend_ast *zend_ast_create_constant_node(zval *zv); -void zend_ast_evaluate(zval *result, zend_ast *ast TSRMLS_DC); +ZEND_API zend_ast *zend_ast_create_node1(uint kind, zend_ast *op0); +ZEND_API zend_ast *zend_ast_create_node2(uint kind, zend_ast *op0, zend_ast *op1); +ZEND_API zend_ast *zend_ast_create_node3(uint kind, zend_ast *op0, zend_ast *op1, zend_ast *op2); -void zend_ast_destroy(zend_ast *ast TSRMLS_DC); +ZEND_API int zend_ast_is_ct_constant(zend_ast *ast); -#define ZEND_AST_ADD_REF(ast) ++ast->refcount +ZEND_API void zend_ast_evaluate(zval *result, zend_ast *ast TSRMLS_DC); -static inline int ZEND_AST_DEL_REF(zend_ast *ast) { - if (ast->refcount == 1) { - TSRMLS_FETCH(); - - zend_ast_destroy(ast TSRMLS_CC); - return 0; - } - return --ast->refcount; -} +ZEND_API zend_ast *zend_ast_copy(zend_ast *ast); +ZEND_API void zend_ast_destroy(zend_ast *ast); #endif diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 049864c54a..d779e8a5ee 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -946,7 +946,7 @@ static void add_class_vars(zend_class_entry *ce, int statics, zval *return_value /* this is necessary to make it able to work with default array * properties, returned to user */ - switch (IS_CONSTANT_TYPE(Z_TYPE_P(prop_copy))) { + if (IS_CONSTANT_TYPE(Z_TYPE_P(prop_copy))) { zval_update_constant(&prop_copy, 0 TSRMLS_CC); } diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 77da945153..07a9ae88d0 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -5793,8 +5793,8 @@ void zend_do_add_static_array_element(znode *result, znode *offset, const znode key[len + 1] = 0; zend_symtable_update(Z_ARRVAL(result->u.constant), key, len + 2, &element, sizeof(zval *), NULL); efree(key); + break; } - break; case IS_STRING: zend_symtable_update(Z_ARRVAL(result->u.constant), Z_STRVAL(offset->u.constant), Z_STRLEN(offset->u.constant)+1, &element, sizeof(zval *), NULL); zval_dtor(&offset->u.constant); @@ -7133,6 +7133,21 @@ void zend_do_end_compilation(TSRMLS_D) /* {{{ */ } /* }}} */ +void zend_do_constant_expression(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */ +{ + if (ast->kind == ZEND_CONST) { + result->u.constant = *ast->u.val; + efree(ast); + } else if (zend_ast_is_ct_constant(ast)) { + zend_ast_evaluate(&result->u.constant, ast TSRMLS_CC); + zend_ast_destroy(ast); + } else { + Z_TYPE(result->u.constant) = IS_CONSTANT_AST; + Z_AST(result->u.constant) = ast; + } +} +/* }}} */ + /* {{{ zend_dirname Returns directory name component of path */ ZEND_API size_t zend_dirname(char *path, size_t len) diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index b80a7cb84f..76b5348e37 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -93,6 +93,7 @@ typedef struct _znode { /* used only during compilation */ znode_op op; zval constant; /* replaced by literal/zv */ zend_op_array *op_array; + zend_ast *ast; } u; zend_uint EA; /* extended attributes */ } znode; @@ -639,6 +640,7 @@ void zend_do_end_namespace(TSRMLS_D); void zend_verify_namespace(TSRMLS_D); void zend_do_use(znode *name, znode *new_name, int is_global TSRMLS_DC); void zend_do_end_compilation(TSRMLS_D); +void zend_do_constant_expression(znode *result, zend_ast *ast TSRMLS_DC); void zend_do_resolve_class_name(znode *result, znode *class_name, int is_static TSRMLS_DC); @@ -722,10 +724,6 @@ int zend_add_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC); #define ZEND_OP_DATA 137 -/* Pseudo-opcodes for internal object overloading */ -#define ZEND_BOOL_AND -1 -#define ZEND_BOOL_OR -2 - /* END: OPCODES */ /* class fetches */ diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 12047f0518..769b333d9d 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -478,205 +478,200 @@ ZEND_API int zval_update_constant_ex(zval **pp, void *arg, zend_class_entry *sco if (IS_CONSTANT_VISITED(p)) { zend_error(E_ERROR, "Cannot declare self-referencing constant '%s'", Z_STRVAL_P(p)); - return FAILURE; - } - switch (Z_TYPE_P(p) & IS_CONSTANT_TYPE_MASK) { - case IS_CONSTANT: { - int refcount; - zend_uchar is_ref; + } else if ((Z_TYPE_P(p) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT) { + int refcount; + zend_uchar is_ref; - SEPARATE_ZVAL_IF_NOT_REF(pp); - p = *pp; + SEPARATE_ZVAL_IF_NOT_REF(pp); + p = *pp; - MARK_CONSTANT_VISITED(p); + MARK_CONSTANT_VISITED(p); - refcount = Z_REFCOUNT_P(p); - is_ref = Z_ISREF_P(p); + refcount = Z_REFCOUNT_P(p); + is_ref = Z_ISREF_P(p); - if (!zend_get_constant_ex(p->value.str.val, p->value.str.len, &const_value, scope, Z_REAL_TYPE_P(p) TSRMLS_CC)) { - char *actual = Z_STRVAL_P(p); + if (!zend_get_constant_ex(p->value.str.val, p->value.str.len, &const_value, scope, Z_REAL_TYPE_P(p) TSRMLS_CC)) { + char *actual = Z_STRVAL_P(p); - if ((colon = (char*)zend_memrchr(Z_STRVAL_P(p), ':', Z_STRLEN_P(p)))) { - zend_error(E_ERROR, "Undefined class constant '%s'", Z_STRVAL_P(p)); - Z_STRLEN_P(p) -= ((colon - Z_STRVAL_P(p)) + 1); + if ((colon = (char*)zend_memrchr(Z_STRVAL_P(p), ':', Z_STRLEN_P(p)))) { + zend_error(E_ERROR, "Undefined class constant '%s'", Z_STRVAL_P(p)); + Z_STRLEN_P(p) -= ((colon - Z_STRVAL_P(p)) + 1); + if (inline_change) { + colon = estrndup(colon, Z_STRLEN_P(p)); + str_efree(Z_STRVAL_P(p)); + Z_STRVAL_P(p) = colon; + } else { + Z_STRVAL_P(p) = colon + 1; + } + } else { + char *save = actual, *slash; + int actual_len = Z_STRLEN_P(p); + if ((Z_TYPE_P(p) & IS_CONSTANT_UNQUALIFIED) && (slash = (char *)zend_memrchr(actual, '\\', actual_len))) { + actual = slash + 1; + actual_len -= (actual - Z_STRVAL_P(p)); if (inline_change) { - colon = estrndup(colon, Z_STRLEN_P(p)); - str_efree(Z_STRVAL_P(p)); - Z_STRVAL_P(p) = colon; - } else { - Z_STRVAL_P(p) = colon + 1; + actual = estrndup(actual, actual_len); + Z_STRVAL_P(p) = actual; + Z_STRLEN_P(p) = actual_len; } - } else { - char *save = actual, *slash; - int actual_len = Z_STRLEN_P(p); - if ((Z_TYPE_P(p) & IS_CONSTANT_UNQUALIFIED) && (slash = (char *)zend_memrchr(actual, '\\', actual_len))) { - actual = slash + 1; - actual_len -= (actual - Z_STRVAL_P(p)); - if (inline_change) { - actual = estrndup(actual, actual_len); - Z_STRVAL_P(p) = actual; - Z_STRLEN_P(p) = actual_len; - } + } + if (actual[0] == '\\') { + if (inline_change) { + memmove(Z_STRVAL_P(p), Z_STRVAL_P(p)+1, Z_STRLEN_P(p)); + --Z_STRLEN_P(p); + } else { + ++actual; } - if (actual[0] == '\\') { - if (inline_change) { - memmove(Z_STRVAL_P(p), Z_STRVAL_P(p)+1, Z_STRLEN_P(p)--); - } else { - ++actual; - } - --actual_len; + --actual_len; + } + if ((Z_TYPE_P(p) & IS_CONSTANT_UNQUALIFIED) == 0) { + int fix_save = 0; + if (save[0] == '\\') { + save++; + fix_save = 1; } - if ((Z_TYPE_P(p) & IS_CONSTANT_UNQUALIFIED) == 0) { - int fix_save = 0; - if (save[0] == '\\') { - save++; - fix_save = 1; - } - zend_error(E_ERROR, "Undefined constant '%s'", save); - if (fix_save) { - save--; - } - if (inline_change) { - str_efree(save); - } - save = NULL; + zend_error(E_ERROR, "Undefined constant '%s'", save); + if (fix_save) { + save--; } - if (inline_change && save && save != actual) { + if (inline_change) { str_efree(save); } - zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'", actual, actual); - p->type = IS_STRING; - if (!inline_change) { - Z_STRVAL_P(p) = actual; - Z_STRLEN_P(p) = actual_len; - zval_copy_ctor(p); - } + save = NULL; } - } else { - if (inline_change) { - str_efree(Z_STRVAL_P(p)); + if (inline_change && save && save != actual) { + str_efree(save); } - *p = const_value; + zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'", actual, actual); + p->type = IS_STRING; + if (!inline_change) { + Z_STRVAL_P(p) = actual; + Z_STRLEN_P(p) = actual_len; + zval_copy_ctor(p); + } + } + } else { + if (inline_change) { + str_efree(Z_STRVAL_P(p)); } + *p = const_value; + } - Z_SET_REFCOUNT_P(p, refcount); - Z_SET_ISREF_TO_P(p, is_ref); + Z_SET_REFCOUNT_P(p, refcount); + Z_SET_ISREF_TO_P(p, is_ref); + } else if (Z_TYPE_P(p) == IS_CONSTANT_ARRAY) { + zval **element, *new_val; + char *str_index; + uint str_index_len; + ulong num_index; + int ret; + + SEPARATE_ZVAL_IF_NOT_REF(pp); + p = *pp; + Z_TYPE_P(p) = IS_ARRAY; + + if (!inline_change) { + zval *tmp; + HashTable *tmp_ht = NULL; + + ALLOC_HASHTABLE(tmp_ht); + zend_hash_init(tmp_ht, zend_hash_num_elements(Z_ARRVAL_P(p)), NULL, ZVAL_PTR_DTOR, 0); + zend_hash_copy(tmp_ht, Z_ARRVAL_P(p), (copy_ctor_func_t) zval_deep_copy, (void *) &tmp, sizeof(zval *)); + Z_ARRVAL_P(p) = tmp_ht; } - break; - - case IS_CONSTANT_ARRAY: { - zval **element, *new_val; - char *str_index; - uint str_index_len; - ulong num_index; - int ret; - - SEPARATE_ZVAL_IF_NOT_REF(pp); - p = *pp; - Z_TYPE_P(p) = IS_ARRAY; - - if (!inline_change) { - zval *tmp; - HashTable *tmp_ht = NULL; - - ALLOC_HASHTABLE(tmp_ht); - zend_hash_init(tmp_ht, zend_hash_num_elements(Z_ARRVAL_P(p)), NULL, ZVAL_PTR_DTOR, 0); - zend_hash_copy(tmp_ht, Z_ARRVAL_P(p), (copy_ctor_func_t) zval_deep_copy, (void *) &tmp, sizeof(zval *)); - Z_ARRVAL_P(p) = tmp_ht; - } - /* First go over the array and see if there are any constant indices */ - zend_hash_internal_pointer_reset(Z_ARRVAL_P(p)); - while (zend_hash_get_current_data(Z_ARRVAL_P(p), (void **) &element) == SUCCESS) { - if (!(Z_TYPE_PP(element) & IS_CONSTANT_INDEX)) { - zend_hash_move_forward(Z_ARRVAL_P(p)); - continue; - } - Z_TYPE_PP(element) &= ~IS_CONSTANT_INDEX; - if (zend_hash_get_current_key_ex(Z_ARRVAL_P(p), &str_index, &str_index_len, &num_index, 0, NULL) != HASH_KEY_IS_STRING) { - zend_hash_move_forward(Z_ARRVAL_P(p)); - continue; - } - if (str_index[str_index_len - 2] == IS_CONSTANT_AST) { - zend_ast_evaluate(&const_value, *(zend_ast **)str_index TSRMLS_CC); - ZEND_AST_DEL_REF(*(zend_ast **)str_index); - } else if (!zend_get_constant_ex(str_index, str_index_len - 3, &const_value, scope, str_index[str_index_len - 2] TSRMLS_CC)) { - char *actual; - const char *save = str_index; - if ((colon = (char*)zend_memrchr(str_index, ':', str_index_len - 3))) { - zend_error(E_ERROR, "Undefined class constant '%s'", str_index); - str_index_len -= ((colon - str_index) + 1); - str_index = colon; - } else { - if (str_index[str_index_len - 2] & IS_CONSTANT_UNQUALIFIED) { - if ((actual = (char *)zend_memrchr(str_index, '\\', str_index_len - 3))) { - actual++; - str_index_len -= (actual - str_index); - str_index = actual; - } - } - if (str_index[0] == '\\') { - ++str_index; - --str_index_len; - } - if (save[0] == '\\') { - ++save; - } - if ((str_index[str_index_len - 2] & IS_CONSTANT_UNQUALIFIED) == 0) { - zend_error(E_ERROR, "Undefined constant '%s'", save); + /* First go over the array and see if there are any constant indices */ + zend_hash_internal_pointer_reset(Z_ARRVAL_P(p)); + while (zend_hash_get_current_data(Z_ARRVAL_P(p), (void **) &element) == SUCCESS) { + if (!(Z_TYPE_PP(element) & IS_CONSTANT_INDEX)) { + zend_hash_move_forward(Z_ARRVAL_P(p)); + continue; + } + Z_TYPE_PP(element) &= ~IS_CONSTANT_INDEX; + if (zend_hash_get_current_key_ex(Z_ARRVAL_P(p), &str_index, &str_index_len, &num_index, 0, NULL) != HASH_KEY_IS_STRING) { + zend_hash_move_forward(Z_ARRVAL_P(p)); + continue; + } + if (str_index[str_index_len - 2] == IS_CONSTANT_AST) { + zend_ast_evaluate(&const_value, *(zend_ast **)str_index TSRMLS_CC); + zend_ast_destroy(*(zend_ast **)str_index); + } else if (!zend_get_constant_ex(str_index, str_index_len - 3, &const_value, scope, str_index[str_index_len - 2] TSRMLS_CC)) { + char *actual; + const char *save = str_index; + if ((colon = (char*)zend_memrchr(str_index, ':', str_index_len - 3))) { + zend_error(E_ERROR, "Undefined class constant '%s'", str_index); + str_index_len -= ((colon - str_index) + 1); + str_index = colon; + } else { + if (str_index[str_index_len - 2] & IS_CONSTANT_UNQUALIFIED) { + if ((actual = (char *)zend_memrchr(str_index, '\\', str_index_len - 3))) { + actual++; + str_index_len -= (actual - str_index); + str_index = actual; } - zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'", str_index, str_index); } - ZVAL_STRINGL(&const_value, str_index, str_index_len-3, 1); + if (str_index[0] == '\\') { + ++str_index; + --str_index_len; + } + if (save[0] == '\\') { + ++save; + } + if ((str_index[str_index_len - 2] & IS_CONSTANT_UNQUALIFIED) == 0) { + zend_error(E_ERROR, "Undefined constant '%s'", save); + } + zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'", str_index, str_index); } + ZVAL_STRINGL(&const_value, str_index, str_index_len-3, 1); + } - if (Z_REFCOUNT_PP(element) > 1) { - ALLOC_ZVAL(new_val); - *new_val = **element; - zval_copy_ctor(new_val); - Z_SET_REFCOUNT_P(new_val, 1); - Z_UNSET_ISREF_P(new_val); - - /* preserve this bit for inheritance */ - Z_TYPE_PP(element) |= IS_CONSTANT_INDEX; - zval_ptr_dtor(element); - *element = new_val; - } + if (Z_REFCOUNT_PP(element) > 1) { + ALLOC_ZVAL(new_val); + *new_val = **element; + zval_copy_ctor(new_val); + Z_SET_REFCOUNT_P(new_val, 1); + Z_UNSET_ISREF_P(new_val); + + /* preserve this bit for inheritance */ + Z_TYPE_PP(element) |= IS_CONSTANT_INDEX; + zval_ptr_dtor(element); + *element = new_val; + } - switch (Z_TYPE(const_value)) { - case IS_STRING: - ret = zend_symtable_update_current_key(Z_ARRVAL_P(p), Z_STRVAL(const_value), Z_STRLEN(const_value) + 1, HASH_UPDATE_KEY_IF_BEFORE); - break; - case IS_BOOL: - case IS_LONG: - ret = zend_hash_update_current_key_ex(Z_ARRVAL_P(p), HASH_KEY_IS_LONG, NULL, 0, Z_LVAL(const_value), HASH_UPDATE_KEY_IF_BEFORE, NULL); - break; - case IS_DOUBLE: - ret = zend_hash_update_current_key_ex(Z_ARRVAL_P(p), HASH_KEY_IS_LONG, NULL, 0, zend_dval_to_lval(Z_DVAL(const_value)), HASH_UPDATE_KEY_IF_BEFORE, NULL); - break; - case IS_NULL: - ret = zend_hash_update_current_key_ex(Z_ARRVAL_P(p), HASH_KEY_IS_STRING, "", 1, 0, HASH_UPDATE_KEY_IF_BEFORE, NULL); - break; - default: - ret = SUCCESS; - break; - } - if (ret == SUCCESS) { - zend_hash_move_forward(Z_ARRVAL_P(p)); - } - zval_dtor(&const_value); + switch (Z_TYPE(const_value)) { + case IS_STRING: + ret = zend_symtable_update_current_key(Z_ARRVAL_P(p), Z_STRVAL(const_value), Z_STRLEN(const_value) + 1, HASH_UPDATE_KEY_IF_BEFORE); + break; + case IS_BOOL: + case IS_LONG: + ret = zend_hash_update_current_key_ex(Z_ARRVAL_P(p), HASH_KEY_IS_LONG, NULL, 0, Z_LVAL(const_value), HASH_UPDATE_KEY_IF_BEFORE, NULL); + break; + case IS_DOUBLE: + ret = zend_hash_update_current_key_ex(Z_ARRVAL_P(p), HASH_KEY_IS_LONG, NULL, 0, zend_dval_to_lval(Z_DVAL(const_value)), HASH_UPDATE_KEY_IF_BEFORE, NULL); + break; + case IS_NULL: + ret = zend_hash_update_current_key_ex(Z_ARRVAL_P(p), HASH_KEY_IS_STRING, "", 1, 0, HASH_UPDATE_KEY_IF_BEFORE, NULL); + break; + default: + ret = SUCCESS; + break; + } + if (ret == SUCCESS) { + zend_hash_move_forward(Z_ARRVAL_P(p)); } - zend_hash_apply_with_argument(Z_ARRVAL_P(p), (apply_func_arg_t) zval_update_constant_inline_change, (void *) scope TSRMLS_CC); - zend_hash_internal_pointer_reset(Z_ARRVAL_P(p)); + zval_dtor(&const_value); } - break; - - case IS_CONSTANT_AST: { - zend_ast *ast = Z_AST_P(p); - - zend_ast_evaluate(p, ast TSRMLS_CC); - ZEND_AST_DEL_REF(ast); + zend_hash_apply_with_argument(Z_ARRVAL_P(p), (apply_func_arg_t) zval_update_constant_inline_change, (void *) scope TSRMLS_CC); + zend_hash_internal_pointer_reset(Z_ARRVAL_P(p)); + } else if (Z_TYPE_P(p) == IS_CONSTANT_AST) { + SEPARATE_ZVAL_IF_NOT_REF(pp); + p = *pp; + + zend_ast_evaluate(&const_value, Z_AST_P(p) TSRMLS_CC); + if (inline_change) { + zend_ast_destroy(Z_AST_P(p)); } + ZVAL_COPY_VALUE(p, &const_value); } return 0; } diff --git a/Zend/zend_extensions.h b/Zend/zend_extensions.h index 83cad7f38d..e7f289a656 100644 --- a/Zend/zend_extensions.h +++ b/Zend/zend_extensions.h @@ -28,7 +28,7 @@ /* The first number is the engine version and the rest is the date. * This way engine 2/3 API no. is always greater than engine 1 API no.. */ -#define ZEND_EXTENSION_API_NO 220121212 +#define ZEND_EXTENSION_API_NO 220131106 typedef struct _zend_extension_version_info { int zend_extension_api_no; diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 19d6d839a2..b6926ea041 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -952,53 +952,53 @@ static_class_constant: ; static_scalar: /* compile-time evaluated scalars */ - static_scalar_value { $$ = $1; } - | T_ARRAY '(' static_array_pair_list ')' { $$ = $3; Z_TYPE($$.u.constant) = IS_CONSTANT_ARRAY; } - | '[' static_array_pair_list ']' { $$ = $2; Z_TYPE($$.u.constant) = IS_CONSTANT_ARRAY; } + static_scalar_value { zend_do_constant_expression(&$$, $1.u.ast TSRMLS_CC); } ; static_scalar_value: - common_scalar { $$ = $1; } - | static_class_name_scalar { $$ = $1; } - | namespace_name { zend_do_fetch_constant(&$$, NULL, &$1, ZEND_CT, 1 TSRMLS_CC); } - | T_NAMESPACE T_NS_SEPARATOR namespace_name { $$.op_type = IS_CONST; ZVAL_EMPTY_STRING(&$$.u.constant); zend_do_build_namespace_name(&$$, &$$, &$3 TSRMLS_CC); $3 = $$; zend_do_fetch_constant(&$$, NULL, &$3, ZEND_CT, 0 TSRMLS_CC); } - | T_NS_SEPARATOR namespace_name { char *tmp = estrndup(Z_STRVAL($2.u.constant), Z_STRLEN($2.u.constant)+1); memcpy(&(tmp[1]), Z_STRVAL($2.u.constant), Z_STRLEN($2.u.constant)+1); tmp[0] = '\\'; efree(Z_STRVAL($2.u.constant)); Z_STRVAL($2.u.constant) = tmp; ++Z_STRLEN($2.u.constant); zend_do_fetch_constant(&$$, NULL, &$2, ZEND_CT, 0 TSRMLS_CC); } - | static_class_constant { $$ = $1; } - | T_CLASS_C { $$ = $1; } + common_scalar { $$.u.ast = zend_ast_create_constant_node(&$1.u.constant); } + | static_class_name_scalar { $$.u.ast = zend_ast_create_constant_node(&$1.u.constant); } + | namespace_name { zend_do_fetch_constant(&$$, NULL, &$1, ZEND_CT, 1 TSRMLS_CC); $$.u.ast = zend_ast_create_constant_node(&$$.u.constant); } + | T_NAMESPACE T_NS_SEPARATOR namespace_name { $$.op_type = IS_CONST; ZVAL_EMPTY_STRING(&$$.u.constant); zend_do_build_namespace_name(&$$, &$$, &$3 TSRMLS_CC); $3 = $$; zend_do_fetch_constant(&$$, NULL, &$3, ZEND_CT, 0 TSRMLS_CC); $$.u.ast = zend_ast_create_constant_node(&$$.u.constant); } + | T_NS_SEPARATOR namespace_name { char *tmp = estrndup(Z_STRVAL($2.u.constant), Z_STRLEN($2.u.constant)+1); memcpy(&(tmp[1]), Z_STRVAL($2.u.constant), Z_STRLEN($2.u.constant)+1); tmp[0] = '\\'; efree(Z_STRVAL($2.u.constant)); Z_STRVAL($2.u.constant) = tmp; ++Z_STRLEN($2.u.constant); zend_do_fetch_constant(&$$, NULL, &$2, ZEND_CT, 0 TSRMLS_CC); $$.u.ast = zend_ast_create_constant_node(&$$.u.constant); } + | static_class_constant { $$.u.ast = zend_ast_create_constant_node(&$1.u.constant); } + | T_CLASS_C { $$.u.ast = zend_ast_create_constant_node(&$1.u.constant); } + | T_ARRAY '(' static_array_pair_list ')' { $$ = $3; Z_TYPE($$.u.constant) = IS_CONSTANT_ARRAY; $$.u.ast = zend_ast_create_constant_node(&$$.u.constant); } + | '[' static_array_pair_list ']' { $$ = $2; Z_TYPE($$.u.constant) = IS_CONSTANT_ARRAY; $$.u.ast = zend_ast_create_constant_node(&$$.u.constant); } | static_operation { $$ = $1; } ; static_operation: - static_scalar_value '+' static_scalar_value { zend_ast_add_binary(&$$.u.constant, add_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } - | static_scalar_value '-' static_scalar_value { zend_ast_add_binary(&$$.u.constant, sub_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } - | static_scalar_value '*' static_scalar_value { zend_ast_add_binary(&$$.u.constant, mul_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } - | static_scalar_value '/' static_scalar_value { zend_ast_add_binary(&$$.u.constant, div_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } - | static_scalar_value '%' static_scalar_value { zend_ast_add_binary(&$$.u.constant, mod_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } - | '!' static_scalar_value { zend_ast_add_unary(&$$.u.constant, boolean_not_function, &$2.u.constant TSRMLS_CC); } - | '~' static_scalar_value { zend_ast_add_unary(&$$.u.constant, bitwise_not_function, &$2.u.constant TSRMLS_CC); } - | static_scalar_value '|' static_scalar_value { zend_ast_add_binary(&$$.u.constant, bitwise_or_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } - | static_scalar_value '&' static_scalar_value { zend_ast_add_binary(&$$.u.constant, bitwise_and_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } - | static_scalar_value '^' static_scalar_value { zend_ast_add_binary(&$$.u.constant, bitwise_xor_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } - | static_scalar_value T_SL static_scalar_value { zend_ast_add_binary(&$$.u.constant, shift_left_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } - | static_scalar_value T_SR static_scalar_value { zend_ast_add_binary(&$$.u.constant, shift_right_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } - | static_scalar_value '.' static_scalar_value { zend_ast_add_binary(&$$.u.constant, concat_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } - | static_scalar_value T_LOGICAL_XOR static_scalar_value { zend_ast_add_binary(&$$.u.constant, boolean_xor_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } - | static_scalar_value T_LOGICAL_AND static_scalar_value { zend_ast_add_binary(&$$.u.constant, boolean_and_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } - | static_scalar_value T_LOGICAL_OR static_scalar_value { zend_ast_add_binary(&$$.u.constant, boolean_or_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } - | static_scalar_value T_BOOLEAN_AND static_scalar_value { zend_ast_add_binary(&$$.u.constant, boolean_and_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } - | static_scalar_value T_BOOLEAN_OR static_scalar_value { zend_ast_add_binary(&$$.u.constant, boolean_or_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } - | static_scalar_value T_IS_IDENTICAL static_scalar_value { zend_ast_add_binary(&$$.u.constant, is_identical_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } - | static_scalar_value T_IS_NOT_IDENTICAL static_scalar_value { zend_ast_add_binary(&$$.u.constant, is_not_identical_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } - | static_scalar_value T_IS_EQUAL static_scalar_value { zend_ast_add_binary(&$$.u.constant, is_equal_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } - | static_scalar_value T_IS_NOT_EQUAL static_scalar_value { zend_ast_add_binary(&$$.u.constant, is_not_equal_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } - | static_scalar_value '<' static_scalar_value { zend_ast_add_binary(&$$.u.constant, is_smaller_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } - | static_scalar_value '>' static_scalar_value { zend_ast_add_binary(&$$.u.constant, is_smaller_function, &$3.u.constant, &$1.u.constant TSRMLS_CC); } - | static_scalar_value T_IS_SMALLER_OR_EQUAL static_scalar_value { zend_ast_add_binary(&$$.u.constant, is_smaller_or_equal_function, &$1.u.constant, &$3.u.constant TSRMLS_CC); } - | static_scalar_value T_IS_GREATER_OR_EQUAL static_scalar_value { zend_ast_add_binary(&$$.u.constant, is_smaller_or_equal_function, &$3.u.constant, &$1.u.constant TSRMLS_CC); } - | static_scalar_value '?' ':' static_scalar_value { zend_ast_add_ternary(&$$.u.constant, ternary_function, &$1.u.constant, NULL, &$4.u.constant TSRMLS_CC); } - | static_scalar_value '?' static_scalar_value ':' static_scalar_value { zend_ast_add_ternary(&$$.u.constant, ternary_function, &$1.u.constant, &$3.u.constant, &$5.u.constant TSRMLS_CC); } - | '+' static_scalar_value { ZVAL_LONG(&$1.u.constant, 0); zend_ast_add_binary(&$$.u.constant, add_function, &$1.u.constant, &$2.u.constant TSRMLS_CC); } - | '-' static_scalar_value { ZVAL_LONG(&$1.u.constant, 0); zend_ast_add_binary(&$$.u.constant, sub_function, &$1.u.constant, &$2.u.constant TSRMLS_CC); } + static_scalar_value '+' static_scalar_value { $$.u.ast = zend_ast_create_node2(ZEND_ADD, $1.u.ast, $3.u.ast); } + | static_scalar_value '-' static_scalar_value { $$.u.ast = zend_ast_create_node2(ZEND_SUB, $1.u.ast, $3.u.ast); } + | static_scalar_value '*' static_scalar_value { $$.u.ast = zend_ast_create_node2(ZEND_MUL, $1.u.ast, $3.u.ast); } + | static_scalar_value '/' static_scalar_value { $$.u.ast = zend_ast_create_node2(ZEND_DIV, $1.u.ast, $3.u.ast); } + | static_scalar_value '%' static_scalar_value { $$.u.ast = zend_ast_create_node2(ZEND_MOD, $1.u.ast, $3.u.ast); } + | '!' static_scalar_value { $$.u.ast = zend_ast_create_node1(ZEND_BOOL_NOT, $2.u.ast); } + | '~' static_scalar_value { $$.u.ast = zend_ast_create_node1(ZEND_BW_NOT, $2.u.ast); } + | static_scalar_value '|' static_scalar_value { $$.u.ast = zend_ast_create_node2(ZEND_BW_OR, $1.u.ast, $3.u.ast); } + | static_scalar_value '&' static_scalar_value { $$.u.ast = zend_ast_create_node2(ZEND_BW_AND, $1.u.ast, $3.u.ast); } + | static_scalar_value '^' static_scalar_value { $$.u.ast = zend_ast_create_node2(ZEND_BW_XOR, $1.u.ast, $3.u.ast); } + | static_scalar_value T_SL static_scalar_value { $$.u.ast = zend_ast_create_node2(ZEND_SL, $1.u.ast, $3.u.ast); } + | static_scalar_value T_SR static_scalar_value { $$.u.ast = zend_ast_create_node2(ZEND_SR, $1.u.ast, $3.u.ast); } + | static_scalar_value '.' static_scalar_value { $$.u.ast = zend_ast_create_node2(ZEND_CONCAT, $1.u.ast, $3.u.ast); } + | static_scalar_value T_LOGICAL_XOR static_scalar_value { $$.u.ast = zend_ast_create_node2(ZEND_BOOL_XOR, $1.u.ast, $3.u.ast); } + | static_scalar_value T_LOGICAL_AND static_scalar_value { $$.u.ast = zend_ast_create_node2(ZEND_BOOL_AND, $1.u.ast, $3.u.ast); } + | static_scalar_value T_LOGICAL_OR static_scalar_value { $$.u.ast = zend_ast_create_node2(ZEND_BOOL_OR, $1.u.ast, $3.u.ast); } + | static_scalar_value T_BOOLEAN_AND static_scalar_value { $$.u.ast = zend_ast_create_node2(ZEND_BOOL_AND, $1.u.ast, $3.u.ast); } + | static_scalar_value T_BOOLEAN_OR static_scalar_value { $$.u.ast = zend_ast_create_node2(ZEND_BOOL_OR, $1.u.ast, $3.u.ast); } + | static_scalar_value T_IS_IDENTICAL static_scalar_value { $$.u.ast = zend_ast_create_node2(ZEND_IS_IDENTICAL, $1.u.ast, $3.u.ast); } + | static_scalar_value T_IS_NOT_IDENTICAL static_scalar_value { $$.u.ast = zend_ast_create_node2(ZEND_IS_NOT_IDENTICAL, $1.u.ast, $3.u.ast); } + | static_scalar_value T_IS_EQUAL static_scalar_value { $$.u.ast = zend_ast_create_node2(ZEND_IS_EQUAL, $1.u.ast, $3.u.ast); } + | static_scalar_value T_IS_NOT_EQUAL static_scalar_value { $$.u.ast = zend_ast_create_node2(ZEND_IS_NOT_EQUAL, $1.u.ast, $3.u.ast); } + | static_scalar_value '<' static_scalar_value { $$.u.ast = zend_ast_create_node2(ZEND_IS_SMALLER, $1.u.ast, $3.u.ast); } + | static_scalar_value '>' static_scalar_value { $$.u.ast = zend_ast_create_node2(ZEND_IS_SMALLER, $3.u.ast, $1.u.ast); } + | static_scalar_value T_IS_SMALLER_OR_EQUAL static_scalar_value { $$.u.ast = zend_ast_create_node2(ZEND_IS_SMALLER_OR_EQUAL, $1.u.ast, $3.u.ast); } + | static_scalar_value T_IS_GREATER_OR_EQUAL static_scalar_value { $$.u.ast = zend_ast_create_node2(ZEND_IS_SMALLER_OR_EQUAL, $3.u.ast, $1.u.ast); } + | static_scalar_value '?' ':' static_scalar_value { $$.u.ast = zend_ast_create_node3(ZEND_TERNARY, $1.u.ast, NULL, $4.u.ast); } + | static_scalar_value '?' static_scalar_value ':' static_scalar_value { $$.u.ast = zend_ast_create_node3(ZEND_TERNARY, $1.u.ast, $3.u.ast, $5.u.ast); } + | '+' static_scalar_value { $$.u.ast = zend_ast_create_node1(ZEND_UNARY_PLUS, $2.u.ast); } + | '-' static_scalar_value { $$.u.ast = zend_ast_create_node1(ZEND_UNARY_MINUS, $2.u.ast); } | '(' static_scalar_value ')' { $$ = $2; } ; diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index 8c083542f0..e8629291e5 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -1082,46 +1082,6 @@ ZEND_API int boolean_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) } /* }}} */ -ZEND_API int boolean_and_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ -{ - zval op1_copy, op2_copy; - long op1_lval; - - if (Z_TYPE_P(op1) != IS_BOOL || Z_TYPE_P(op2) != IS_BOOL) { - ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BOOL_AND); - - zendi_convert_to_boolean(op1, op1_copy, result); - op1_lval = Z_LVAL_P(op1); - zendi_convert_to_boolean(op2, op2_copy, result); - } else { - op1_lval = Z_LVAL_P(op1); - } - - ZVAL_BOOL(result, op1_lval & Z_LVAL_P(op2)); - return SUCCESS; -} -/* }}} */ - -ZEND_API int boolean_or_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ -{ - zval op1_copy, op2_copy; - long op1_lval; - - if (Z_TYPE_P(op1) != IS_BOOL || Z_TYPE_P(op2) != IS_BOOL) { - ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BOOL_OR); - - zendi_convert_to_boolean(op1, op1_copy, result); - op1_lval = Z_LVAL_P(op1); - zendi_convert_to_boolean(op2, op2_copy, result); - } else { - op1_lval = Z_LVAL_P(op1); - } - - ZVAL_BOOL(result, op1_lval | Z_LVAL_P(op2)); - return SUCCESS; -} -/* }}} */ - ZEND_API int boolean_not_function(zval *result, zval *op1 TSRMLS_DC) /* {{{ */ { zval op1_copy; @@ -2363,28 +2323,6 @@ ZEND_API void zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_DC) /* {{{ */ } /* }}} */ -#define PREVENT_DTOR_IF_REFCOUNT_1_AND_ASSIGN_TO_RESULT(var) \ - *result = *var; \ - if (Z_REFCOUNT_P(var) == 1) { \ - Z_TYPE_P(var) = IS_NULL; \ - } - -ZEND_API int ternary_function(zval *result, zval *condition, zval *then, zval *if_not TSRMLS_DC) /* {{{ */ -{ - if (i_zend_is_true(condition)) { - if (then) { - PREVENT_DTOR_IF_REFCOUNT_1_AND_ASSIGN_TO_RESULT(then); - } else { - PREVENT_DTOR_IF_REFCOUNT_1_AND_ASSIGN_TO_RESULT(condition); - } - } else { - PREVENT_DTOR_IF_REFCOUNT_1_AND_ASSIGN_TO_RESULT(if_not); - } - - return SUCCESS; -} -/* }}} */ - /* * Local variables: * tab-width: 4 diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h index 3f0fc2ef6a..ce21af3d2e 100644 --- a/Zend/zend_operators.h +++ b/Zend/zend_operators.h @@ -50,8 +50,6 @@ ZEND_API int mul_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); ZEND_API int div_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); ZEND_API int mod_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); ZEND_API int boolean_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); -ZEND_API int boolean_and_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); -ZEND_API int boolean_or_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); ZEND_API int boolean_not_function(zval *result, zval *op1 TSRMLS_DC); ZEND_API int bitwise_not_function(zval *result, zval *op1 TSRMLS_DC); ZEND_API int bitwise_or_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); @@ -378,8 +376,6 @@ ZEND_API int zend_atoi(const char *str, int str_len); ZEND_API long zend_atol(const char *str, int str_len); ZEND_API void zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_DC); - -ZEND_API int ternary_function(zval *result, zval *condition, zval *then, zval *if_not TSRMLS_DC); END_EXTERN_C() #define convert_to_ex_master(ppzv, lower_type, upper_type) \ diff --git a/Zend/zend_variables.c b/Zend/zend_variables.c index 095c16ca91..3fa1b063a1 100644 --- a/Zend/zend_variables.c +++ b/Zend/zend_variables.c @@ -49,7 +49,7 @@ ZEND_API void _zval_dtor_func(zval *zvalue ZEND_FILE_LINE_DC) } break; case IS_CONSTANT_AST: - ZEND_AST_DEL_REF(Z_AST_P(zvalue)); + zend_ast_destroy(Z_AST_P(zvalue)); break; case IS_OBJECT: { @@ -85,11 +85,9 @@ ZEND_API void _zval_internal_dtor(zval *zvalue ZEND_FILE_LINE_DC) CHECK_ZVAL_STRING_REL(zvalue); str_free(zvalue->value.str.val); break; - case IS_CONSTANT_AST: - ZEND_AST_DEL_REF(Z_AST_P(zvalue)); - break; case IS_ARRAY: case IS_CONSTANT_ARRAY: + case IS_CONSTANT_AST: case IS_OBJECT: case IS_RESOURCE: zend_error(E_CORE_ERROR, "Internal zval's can't be arrays, objects or resources"); @@ -147,7 +145,7 @@ ZEND_API void _zval_copy_ctor_func(zval *zvalue ZEND_FILE_LINE_DC) } break; case IS_CONSTANT_AST: - ZEND_AST_ADD_REF(Z_AST_P(zvalue)); + Z_AST_P(zvalue) = zend_ast_copy(Z_AST_P(zvalue)); break; case IS_OBJECT: { diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 006f2ec729..79719c8d7b 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -5200,7 +5200,6 @@ ZEND_VM_HANDLER(143, ZEND_DECLARE_CONST, CONST, CONST) INIT_PZVAL_COPY(&c.value, val); zval_copy_ctor(&c.value); } - c.flags = CONST_CS; /* non persistent, case sensetive */ c.name = str_strndup(Z_STRVAL_P(name), Z_STRLEN_P(name)); c.name_len = Z_STRLEN_P(name)+1; diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 4f850c2978..5a2c2cf993 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -4102,7 +4102,6 @@ static int ZEND_FASTCALL ZEND_DECLARE_CONST_SPEC_CONST_CONST_HANDLER(ZEND_OPCOD INIT_PZVAL_COPY(&c.value, val); zval_copy_ctor(&c.value); } - c.flags = CONST_CS; /* non persistent, case sensetive */ c.name = str_strndup(Z_STRVAL_P(name), Z_STRLEN_P(name)); c.name_len = Z_STRLEN_P(name)+1; diff --git a/ext/opcache/zend_accelerator_util_funcs.c b/ext/opcache/zend_accelerator_util_funcs.c index 894da63aaa..8ced274cb2 100644 --- a/ext/opcache/zend_accelerator_util_funcs.c +++ b/ext/opcache/zend_accelerator_util_funcs.c @@ -222,6 +222,52 @@ static void zend_destroy_property_info(zend_property_info *property_info) } } +#if ZEND_EXTENSION_API_NO > PHP_5_5_X_API_NO +static zend_ast *zend_ast_clone(zend_ast *ast TSRMLS_DC) +{ + int i; + zend_ast *node; + + if (ast->kind == ZEND_CONST) { + node = emalloc(sizeof(zend_ast) + sizeof(zval)); + node->kind = ZEND_CONST; + node->children = 0; + node->u.val = (zval*)(node + 1); + *node->u.val = *ast->u.val; + if ((Z_TYPE_P(ast->u.val) & IS_CONSTANT_TYPE_MASK) >= IS_ARRAY) { + switch ((Z_TYPE_P(ast->u.val) & IS_CONSTANT_TYPE_MASK)) { + case IS_STRING: + case IS_CONSTANT: + Z_STRVAL_P(node->u.val) = (char *) interned_estrndup(Z_STRVAL_P(ast->u.val), Z_STRLEN_P(ast->u.val)); + break; + case IS_ARRAY: + case IS_CONSTANT_ARRAY: + if (ast->u.val->value.ht && ast->u.val->value.ht != &EG(symbol_table)) { + ALLOC_HASHTABLE(node->u.val->value.ht); + zend_hash_clone_zval(node->u.val->value.ht, ast->u.val->value.ht, 0); + } + break; + case IS_CONSTANT_AST: + Z_AST_P(node->u.val) = zend_ast_clone(Z_AST_P(ast->u.val) TSRMLS_CC); + break; + } + } + } else { + node = emalloc(sizeof(zend_ast) + sizeof(zend_ast*) * (ast->children - 1)); + node->kind = ast->kind; + node->children = ast->children; + for (i = 0; i < ast->children; i++) { + if (ast->u.child[i]) { + node->u.child[i] = zend_ast_clone(ast->u.child[i] TSRMLS_CC); + } else { + node->u.child[i] = NULL; + } + } + } + return node; +} +#endif + static inline zval* zend_clone_zval(zval *src, int bind TSRMLS_DC) { zval *ret, **ret_ptr = NULL; @@ -259,6 +305,11 @@ static inline zval* zend_clone_zval(zval *src, int bind TSRMLS_DC) zend_hash_clone_zval(ret->value.ht, src->value.ht, 0); } break; +#if ZEND_EXTENSION_API_NO > PHP_5_5_X_API_NO + case IS_CONSTANT_AST: + Z_AST_P(ret) = zend_ast_clone(Z_AST_P(ret) TSRMLS_CC); + break; +#endif } } return ret; @@ -376,6 +427,11 @@ static void zend_hash_clone_zval(HashTable *ht, HashTable *source, int bind) zend_hash_clone_zval(ppz->value.ht, ((zval*)p->pDataPtr)->value.ht, 0); } break; +#if ZEND_EXTENSION_API_NO > PHP_5_5_X_API_NO + case IS_CONSTANT_AST: + Z_AST_P(ppz) = zend_ast_clone(Z_AST_P(ppz) TSRMLS_CC); + break; +#endif } } diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index 9f1940e061..bf13865666 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -51,6 +51,7 @@ typedef void (*zend_persist_func_t)(void * TSRMLS_DC); static void zend_persist_zval_ptr(zval **zp TSRMLS_DC); +static void zend_persist_zval(zval *z TSRMLS_DC); #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO static const Bucket *uninitialized_bucket = NULL; @@ -138,6 +139,29 @@ static void zend_hash_persist(HashTable *ht, void (*pPersistElement)(void *pElem #endif } +#if ZEND_EXTENSION_API_NO > PHP_5_5_X_API_NO +static zend_ast *zend_persist_ast(zend_ast *ast TSRMLS_DC) +{ + int i; + zend_ast *node; + + if (ast->kind == ZEND_CONST) { + node = zend_accel_memdup(ast, sizeof(zend_ast) + sizeof(zval)); + node->u.val = (zval*)(node + 1); + zend_persist_zval(node->u.val TSRMLS_CC); + } else { + node = zend_accel_memdup(ast, sizeof(zend_ast) + sizeof(zend_ast*) * (ast->children - 1)); + for (i = 0; i < ast->children; i++) { + if (node->u.child[i]) { + node->u.child[i] = zend_persist_ast(node->u.child[i] TSRMLS_CC); + } + } + } + efree(ast); + return node; +} +#endif + static void zend_persist_zval(zval *z TSRMLS_DC) { #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO @@ -154,6 +178,11 @@ static void zend_persist_zval(zval *z TSRMLS_DC) zend_accel_store(z->value.ht, sizeof(HashTable)); zend_hash_persist(z->value.ht, (zend_persist_func_t) zend_persist_zval_ptr, sizeof(zval**) TSRMLS_CC); break; +#if ZEND_EXTENSION_API_NO > PHP_5_5_X_API_NO + case IS_CONSTANT_AST: + Z_AST_P(z) = zend_persist_ast(Z_AST_P(z) TSRMLS_CC); + break; +#endif } } diff --git a/ext/opcache/zend_persist_calc.c b/ext/opcache/zend_persist_calc.c index 18af756f6e..91438132d0 100644 --- a/ext/opcache/zend_persist_calc.c +++ b/ext/opcache/zend_persist_calc.c @@ -45,6 +45,7 @@ #endif static uint zend_persist_zval_ptr_calc(zval **zp TSRMLS_DC); +static uint zend_persist_zval_calc(zval *z TSRMLS_DC); static uint zend_hash_persist_calc(HashTable *ht, int (*pPersistElement)(void *pElement TSRMLS_DC), size_t el_size TSRMLS_DC) { @@ -91,6 +92,27 @@ static uint zend_hash_persist_calc(HashTable *ht, int (*pPersistElement)(void *p RETURN_SIZE(); } +#if ZEND_EXTENSION_API_NO > PHP_5_5_X_API_NO +static uint zend_persist_ast_calc(zend_ast *ast TSRMLS_DC) +{ + int i; + START_SIZE(); + + if (ast->kind == ZEND_CONST) { + ADD_SIZE(sizeof(zend_ast) + sizeof(zval)); + ADD_SIZE(zend_persist_zval_calc(ast->u.val TSRMLS_CC)); + } else { + ADD_SIZE(sizeof(zend_ast) + sizeof(zend_ast*) * (ast->children - 1)); + for (i = 0; i < ast->children; i++) { + if (ast->u.child[i]) { + ADD_SIZE(zend_persist_ast_calc(ast->u.child[i] TSRMLS_CC)); + } + } + } + RETURN_SIZE(); +} +#endif + static uint zend_persist_zval_calc(zval *z TSRMLS_DC) { START_SIZE(); @@ -109,6 +131,11 @@ static uint zend_persist_zval_calc(zval *z TSRMLS_DC) ADD_DUP_SIZE(z->value.ht, sizeof(HashTable)); ADD_SIZE(zend_hash_persist_calc(z->value.ht, (int (*)(void* TSRMLS_DC)) zend_persist_zval_ptr_calc, sizeof(zval**) TSRMLS_CC)); break; +#if ZEND_EXTENSION_API_NO > PHP_5_5_X_API_NO + case IS_CONSTANT_AST: + ADD_SIZE(zend_persist_ast_calc(Z_AST_P(z) TSRMLS_CC)); + break; +#endif } RETURN_SIZE(); } |
