]> granicus.if.org Git - php/commitdiff
Implement constant expression folding as a separate pass
authorNikita Popov <nikic@php.net>
Mon, 23 Jun 2014 19:30:57 +0000 (21:30 +0200)
committerNikita Popov <nikic@php.net>
Mon, 23 Jun 2014 19:59:14 +0000 (21:59 +0200)
Zend/zend_ast.c
Zend/zend_ast.h
Zend/zend_compile.c
Zend/zend_compile.h

index c2a9500feb057c3d364d2fcc562a9453bd16e6e1..c6f5ca8ccccfcef67e976b8ed02e91a79c213c55 100644 (file)
@@ -411,7 +411,7 @@ ZEND_API void zend_ast_destroy(zend_ast *ast)
        int i;
 
        if (ast->kind == ZEND_CONST) {
-               zval_dtor(zend_ast_get_zval(ast));
+               zval_ptr_dtor(zend_ast_get_zval(ast));
        } else if (ast->kind != ZEND_AST_ZNODE) {
                for (i = 0; i < ast->children; i++) {
                        if (ast->child[i]) {
index b1b9c17589d597545d5337337101957a231b9064..9806790841c5171856f85628a987c44c0faf3401 100644 (file)
@@ -155,6 +155,7 @@ static inline zend_ast *zend_ast_create_assign_op(zend_uint opcode, zend_ast *op
 /* Temporary, for porting */
 #define AST_COMPILE(res, ast) do { \
        zend_ast *_ast = (ast); \
+       zend_eval_const_expr(&_ast TSRMLS_CC); \
        zend_compile_expr((res), _ast TSRMLS_CC); \
        zend_ast_destroy(_ast); \
 } while (0)
index 60fe0af475a232820aa03705e8806f7cf22254a3..533341db6df1268d89d6718ea60b9dec8ac229b9 100644 (file)
@@ -7182,31 +7182,16 @@ void zend_compile_unset(zend_ast *ast TSRMLS_DC) {
        }
 }
 
-int zend_compile_binary_op_maybe_ct(znode *result, zend_ast *ast, zend_bool ct_required TSRMLS_DC) {
+void zend_compile_binary_op(znode *result, zend_ast *ast TSRMLS_DC) {
        zend_ast *left_ast = ast->child[0];
        zend_ast *right_ast = ast->child[1];
        zend_uint opcode = ast->attr;
 
        znode left_node, right_node;
-
-       int ct_left = zend_compile_expr_maybe_ct(&left_node, left_ast, ct_required TSRMLS_CC);
-       int ct_right = zend_compile_expr_maybe_ct(&right_node, right_ast, ct_required TSRMLS_CC);
-       if (ct_left == SUCCESS && ct_right == SUCCESS) {
-               binary_op_type op = get_binary_op(opcode);
-               op(&result->u.constant, &left_node.u.constant, &right_node.u.constant TSRMLS_CC);
-               zval_ptr_dtor(&left_node.u.constant);
-               zval_ptr_dtor(&right_node.u.constant);
-               result->op_type = IS_CONST;
-               return SUCCESS;
-       } else if (ct_required) {
-               if (ct_left == SUCCESS) zval_ptr_dtor(&left_node.u.constant);
-               if (ct_right == SUCCESS) zval_ptr_dtor(&right_node.u.constant);
-               return FAILURE;
-       }
+       zend_compile_expr(&left_node, left_ast TSRMLS_CC);
+       zend_compile_expr(&right_node, right_ast TSRMLS_CC);
 
        emit_op_tmp(result, opcode, &left_node, &right_node TSRMLS_CC);
-
-       return FAILURE;
 }
 
 /* We do not use zend_compile_binary_op for this because we want to retain the left-to-right
@@ -7590,96 +7575,11 @@ void zend_compile_shell_exec(znode *result, zend_ast *ast TSRMLS_DC) {
        zend_ast_destroy(name_ast);
 }
 
-int zend_try_ct_compile_array(zval *array, zend_ast *ast TSRMLS_DC) {
-       zend_uint i;
-
-       ZVAL_UNDEF(array);
-       for (i = 0; i < ast->children; ++i) {
-               zend_ast *elem_ast = ast->child[i];
-               zend_ast *value_ast = elem_ast->child[0];
-               zend_ast *key_ast = elem_ast->child[1];
-               zend_bool by_ref = elem_ast->attr;
-
-               znode key_node, value_node;
-               zval *key = &key_node.u.constant, *value = &value_node.u.constant;
-
-               if (by_ref) {
-                       goto failure;
-               }
-
-               if (FAILURE == zend_compile_expr_maybe_ct(&value_node, value_ast, 1 TSRMLS_CC)) {
-                       goto failure;
-               }
-
-               if (key_ast) {
-                       if (FAILURE == zend_compile_expr_maybe_ct(&key_node, key_ast, 1 TSRMLS_CC)) {
-                               zval_ptr_dtor(value);
-                               goto failure;
-                       }
-               }
-
-               if (Z_TYPE_P(array) == IS_UNDEF) {
-                       array_init_size(array, ast->children);
-               }
-
-               if (key_ast) {
-                       switch (Z_TYPE_P(key)) {
-                               case IS_LONG:
-                                       zend_hash_index_update(Z_ARRVAL_P(array), Z_LVAL_P(key), value);
-                                       break;
-                               case IS_STRING:
-                                       zend_symtable_update(Z_ARRVAL_P(array), Z_STR_P(key), value);
-                                       break;
-                               case IS_DOUBLE:
-                                       zend_hash_index_update(Z_ARRVAL_P(array),
-                                               zend_dval_to_lval(Z_DVAL_P(key)), value);
-                                       break;
-                               case IS_FALSE:
-                                       zend_hash_index_update(Z_ARRVAL_P(array), 0, value);
-                                       break;
-                               case IS_TRUE:
-                                       zend_hash_index_update(Z_ARRVAL_P(array), 1, value);
-                                       break;
-                               case IS_NULL:
-                                       zend_hash_update(Z_ARRVAL_P(array), STR_EMPTY_ALLOC(), value);
-                                       break;
-                               default:
-                                       zend_error(E_COMPILE_ERROR, "Illegal offset type");
-                                       break;
-                       }
-                       zval_ptr_dtor(key);
-               } else {
-                       zend_hash_next_index_insert(Z_ARRVAL_P(array), value);
-               }
-       }
-
-       if (!ast->children) {
-               array_init(array);
-       }
-
-       zend_make_immutable_array(array TSRMLS_CC);
-       return SUCCESS;
-
-failure:
-       zval_dtor(array);
-       return FAILURE;
-}
-
-int zend_compile_array_maybe_ct(znode *result, zend_ast *ast, zend_bool ct_required TSRMLS_DC) {
+void zend_compile_array(znode *result, zend_ast *ast TSRMLS_DC) {
        zend_op *opline;
        zend_uint i, opnum_init;
        zend_bool packed = 1;
 
-       zval array;
-
-       if (SUCCESS == zend_try_ct_compile_array(&array, ast TSRMLS_CC)) {
-               result->op_type = IS_CONST;
-               ZVAL_COPY_VALUE(&result->u.constant, &array);
-               return SUCCESS;
-       } else if (ct_required) {
-               return FAILURE;
-       }
-
        opnum_init = get_next_op_number(CG(active_op_array));
 
        for (i = 0; i < ast->children; ++i) {
@@ -7729,8 +7629,6 @@ int zend_compile_array_maybe_ct(znode *result, zend_ast *ast, zend_bool ct_requi
                opline = &CG(active_op_array)->opcodes[opnum_init];
                opline->extended_value |= ZEND_ARRAY_NOT_PACKED;
        }
-
-       return FAILURE;
 }
 
 void zend_compile_const(znode *result, zend_ast *ast TSRMLS_DC) {
@@ -7935,7 +7833,7 @@ void zend_compile_expr(znode *result, zend_ast *ast TSRMLS_DC) {
                        zend_compile_compound_assign(result, ast TSRMLS_CC);
                        return;
                case ZEND_AST_BINARY_OP:
-                       zend_compile_binary_op_maybe_ct(result, ast, 0 TSRMLS_CC);
+                       zend_compile_binary_op(result, ast TSRMLS_CC);
                        return;
                case ZEND_AST_GREATER:
                case ZEND_AST_GREATER_EQUAL:
@@ -7993,7 +7891,7 @@ void zend_compile_expr(znode *result, zend_ast *ast TSRMLS_DC) {
                        zend_compile_shell_exec(result, ast TSRMLS_CC);
                        return;
                case ZEND_AST_ARRAY:
-                       zend_compile_array_maybe_ct(result, ast, 0 TSRMLS_CC);
+                       zend_compile_array(result, ast TSRMLS_CC);
                        return;
                case ZEND_AST_CONST:
                        zend_compile_const(result, ast TSRMLS_CC);
@@ -8012,24 +7910,6 @@ void zend_compile_expr(znode *result, zend_ast *ast TSRMLS_DC) {
        }
 }
 
-int zend_compile_expr_maybe_ct(znode *result, zend_ast *ast, zend_bool ct_required TSRMLS_DC) {
-       switch (ast->kind) {
-               case ZEND_CONST:
-                       ZVAL_COPY(&result->u.constant, zend_ast_get_zval(ast));
-                       result->op_type = IS_CONST;
-                       return SUCCESS;
-               case ZEND_AST_BINARY_OP:
-                       return zend_compile_binary_op_maybe_ct(result, ast, ct_required TSRMLS_CC);
-               case ZEND_AST_ARRAY:
-                       return zend_compile_array_maybe_ct(result, ast, ct_required TSRMLS_CC);
-               default:
-                       if (!ct_required) {
-                               zend_compile_expr(result, ast TSRMLS_CC);
-                       }
-                       return FAILURE;
-       }
-}
-
 void zend_compile_var(znode *result, zend_ast *ast, int type TSRMLS_DC) {
        switch (ast->kind) {
                case ZEND_AST_VAR:
@@ -8069,6 +7949,106 @@ void zend_compile_var(znode *result, zend_ast *ast, int type TSRMLS_DC) {
        }
 }
 
+void zend_eval_const_binary_op(zend_ast **ast_ptr TSRMLS_DC) {
+       zend_ast *ast = *ast_ptr;
+       zend_ast *left_ast = ast->child[0];
+       zend_ast *right_ast = ast->child[1];
+       zend_uchar opcode = ast->attr;
+
+       if (left_ast->kind == ZEND_CONST && right_ast->kind == ZEND_CONST) {
+               binary_op_type op = get_binary_op(opcode);
+               zval result;
+               op(&result, zend_ast_get_zval(left_ast), zend_ast_get_zval(right_ast) TSRMLS_CC);
+               zend_ast_destroy(ast);
+               *ast_ptr = zend_ast_create_constant(&result);
+       }
+}
+
+void zend_eval_const_array(zend_ast **ast_ptr TSRMLS_DC) {
+       zend_ast *ast = *ast_ptr;
+       zend_uint i;
+       zval array;
+
+       /* First ensure that *all* child nodes are constant */
+       for (i = 0; i < ast->children; ++i) {
+               zend_ast *elem_ast = ast->child[i];
+               zend_ast *value_ast = elem_ast->child[0];
+               zend_ast *key_ast = elem_ast->child[1];
+               zend_bool by_ref = elem_ast->attr;
+
+               if (by_ref || (key_ast && key_ast->kind != ZEND_CONST) || value_ast->kind != ZEND_CONST) {
+                       return;
+               }
+       }
+
+       array_init_size(&array, ast->children);
+       for (i = 0; i < ast->children; ++i) {
+               zend_ast *elem_ast = ast->child[i];
+               zend_ast *value_ast = elem_ast->child[0];
+               zend_ast *key_ast = elem_ast->child[1];
+
+               zval *value = zend_ast_get_zval(value_ast);
+               if (Z_REFCOUNTED_P(value)) Z_ADDREF_P(value);
+
+               if (key_ast) {
+                       zval *key = zend_ast_get_zval(key_ast);
+                       switch (Z_TYPE_P(key)) {
+                               case IS_LONG:
+                                       zend_hash_index_update(Z_ARRVAL(array), Z_LVAL_P(key), value);
+                                       break;
+                               case IS_STRING:
+                                       zend_symtable_update(Z_ARRVAL(array), Z_STR_P(key), value);
+                                       break;
+                               case IS_DOUBLE:
+                                       zend_hash_index_update(Z_ARRVAL(array),
+                                               zend_dval_to_lval(Z_DVAL_P(key)), value);
+                                       break;
+                               case IS_FALSE:
+                                       zend_hash_index_update(Z_ARRVAL(array), 0, value);
+                                       break;
+                               case IS_TRUE:
+                                       zend_hash_index_update(Z_ARRVAL(array), 1, value);
+                                       break;
+                               case IS_NULL:
+                                       zend_hash_update(Z_ARRVAL(array), STR_EMPTY_ALLOC(), value);
+                                       break;
+                               default:
+                                       zend_error(E_COMPILE_ERROR, "Illegal offset type");
+                                       break;
+                       }
+               } else {
+                       zend_hash_next_index_insert(Z_ARRVAL(array), value);
+               }
+       }
+
+       zend_ast_destroy(ast);
+       zend_make_immutable_array(&array TSRMLS_CC);
+       *ast_ptr = zend_ast_create_constant(&array);
+}
+
+void zend_eval_const_expr(zend_ast **ast_ptr TSRMLS_DC) {
+       zend_ast *ast = *ast_ptr;
+       if (!ast || ast->kind == ZEND_CONST || ast->kind == ZEND_AST_ZNODE) {
+               return;
+       }
+
+       {
+               zend_uint i;
+               for (i = 0; i < ast->children; ++i) {
+                       zend_eval_const_expr(&ast->child[i] TSRMLS_CC);
+               }
+       }
+
+       switch (ast->kind) {
+               case ZEND_AST_BINARY_OP:
+                       zend_eval_const_binary_op(ast_ptr TSRMLS_CC);
+                       break;
+               case ZEND_AST_ARRAY:
+                       zend_eval_const_array(ast_ptr TSRMLS_CC);
+                       break;
+       }
+}
+
 /*
  * Local variables:
  * tab-width: 4
index 6e66b9e9d66be4e66908c5d8228b58f1723cb015..be6fca6c7c96479cad7e812f91d726c9127018d5 100644 (file)
@@ -104,6 +104,7 @@ void zend_compile_stmt(zend_ast *ast TSRMLS_DC);
 void zend_compile_expr(znode *node, zend_ast *ast TSRMLS_DC);
 int zend_compile_expr_maybe_ct(znode *node, zend_ast *ast, zend_bool ct_required TSRMLS_DC);
 void zend_compile_var(znode *node, zend_ast *ast, int type TSRMLS_DC);
+void zend_eval_const_expr(zend_ast **ast_ptr TSRMLS_DC);
 
 typedef struct _zend_execute_data zend_execute_data;