From: Nikita Popov Date: Mon, 7 Jul 2014 19:06:02 +0000 (+0200) Subject: Port return statement X-Git-Tag: POST_AST_MERGE^2~170 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=36c3cf3198a0ac9394af09c985fe71cfc0803cbf;p=php Port return statement --- diff --git a/Zend/zend_ast.h b/Zend/zend_ast.h index 2d12ed26bd..b3d6969867 100644 --- a/Zend/zend_ast.h +++ b/Zend/zend_ast.h @@ -37,17 +37,25 @@ enum _zend_ast_kind { ZEND_AST_CALL, ZEND_AST_METHOD_CALL, ZEND_AST_STATIC_CALL, + ZEND_AST_PARAMS, + ZEND_AST_UNPACK, + + ZEND_AST_CONST, + ZEND_AST_CLASS_CONST, + ZEND_AST_RESOLVE_CLASS_NAME, ZEND_AST_ASSIGN, ZEND_AST_ASSIGN_REF, + ZEND_AST_ASSIGN_OP, ZEND_AST_LIST, - ZEND_AST_GLOBAL, - ZEND_AST_UNSET, - ZEND_AST_PARAMS, - ZEND_AST_UNPACK, - - ZEND_AST_ASSIGN_OP, + ZEND_AST_UNARY_PLUS, + ZEND_AST_UNARY_MINUS, + ZEND_AST_CAST, + ZEND_AST_EMPTY, + ZEND_AST_ISSET, + ZEND_AST_SILENCE, + ZEND_AST_SHELL_EXEC, ZEND_AST_BINARY_OP, ZEND_AST_GREATER, @@ -55,25 +63,15 @@ enum _zend_ast_kind { ZEND_AST_AND, ZEND_AST_OR, - ZEND_AST_UNARY_PLUS, - ZEND_AST_UNARY_MINUS, - ZEND_AST_CAST, - ZEND_AST_CONDITIONAL, - ZEND_AST_EMPTY, - ZEND_AST_ISSET, - - ZEND_AST_SILENCE, - ZEND_AST_SHELL_EXEC, ZEND_AST_ARRAY, ZEND_AST_ARRAY_ELEM, - - ZEND_AST_CONST, - ZEND_AST_CLASS_CONST, - ZEND_AST_RESOLVE_CLASS_NAME, - ZEND_AST_ENCAPS_LIST, + + ZEND_AST_GLOBAL, + ZEND_AST_UNSET, + ZEND_AST_RETURN, }; typedef unsigned short zend_ast_kind; @@ -167,6 +165,7 @@ static inline zend_ast *zend_ast_create_assign_op(zend_uint opcode, zend_ast *op #define AST_ZVAL(znode) zend_ast_create_zval(&(znode)->u.constant) #define AC(znode) AST_COMPILE(&znode, znode.u.ast) +#define AS(znode) AST_COMPILE_STMT(znode.u.ast) #define AZ(znode) ((znode).u.ast = AST_ZNODE(&znode)) #endif diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index c407a744f8..e64ba51320 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -6886,7 +6886,6 @@ void zend_compile_global_var(zend_ast *ast TSRMLS_DC) { zend_ast *var_ast = ast->child[0]; znode var_node, result; - zend_op *opline; zend_compile_expr(&var_node, var_ast TSRMLS_CC); if (var_node.op_type == IS_CONST) { @@ -6895,7 +6894,7 @@ void zend_compile_global_var(zend_ast *ast TSRMLS_DC) { } } - opline = emit_op(&result, ZEND_FETCH_W, &var_node, NULL TSRMLS_CC); + emit_op(&result, ZEND_FETCH_W, &var_node, NULL TSRMLS_CC); // TODO.AST Avoid double fetch //opline->extended_value = ZEND_FETCH_GLOBAL_LOCK; @@ -6936,6 +6935,58 @@ void zend_compile_unset(zend_ast *ast TSRMLS_DC) { } } +static void zend_free_foreach_and_switch_variables(TSRMLS_D) { + zend_uint opnum_start, opnum_end, i; + + opnum_start = get_next_op_number(CG(active_op_array)); + +#ifdef ZTS + zend_stack_apply_with_argument(&CG(switch_cond_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element, void *)) generate_free_switch_expr TSRMLS_CC); + zend_stack_apply_with_argument(&CG(foreach_copy_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element, void *)) generate_free_foreach_copy TSRMLS_CC); +#else + zend_stack_apply(&CG(switch_cond_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element)) generate_free_switch_expr); + zend_stack_apply(&CG(foreach_copy_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element)) generate_free_foreach_copy); +#endif + + opnum_end = get_next_op_number(CG(active_op_array)); + + for (i = opnum_start; i < opnum_end; ++i) { + CG(active_op_array)->opcodes[i].extended_value |= EXT_TYPE_FREE_ON_RETURN; + } +} + +void zend_compile_return(zend_ast *ast TSRMLS_DC) { + zend_ast *expr_ast = ast->child[0]; + zend_bool by_ref = (CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0; + + znode expr_node; + zend_op *opline; + + if (!expr_ast) { + expr_node.op_type = IS_CONST; + ZVAL_NULL(&expr_node.u.constant); + } else if (by_ref && zend_is_variable(expr_ast) && !zend_is_call(expr_ast)) { + zend_compile_var(&expr_node, expr_ast, BP_VAR_REF TSRMLS_CC); + } else { + zend_compile_expr(&expr_node, expr_ast TSRMLS_CC); + } + + zend_free_foreach_and_switch_variables(TSRMLS_C); + + if (CG(context).in_finally) { + emit_op(NULL, ZEND_DISCARD_EXCEPTION, NULL, NULL TSRMLS_CC); + } + + opline = emit_op(NULL, by_ref ? ZEND_RETURN_BY_REF : ZEND_RETURN, &expr_node, NULL TSRMLS_CC); + if (expr_ast) { + if (zend_is_call(expr_ast)) { + opline->extended_value = ZEND_RETURNS_FUNCTION; + } else if (!zend_is_variable(expr_ast)) { + opline->extended_value = ZEND_RETURNS_VALUE; + } + } +} + 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]; @@ -7688,6 +7739,9 @@ void zend_compile_stmt(zend_ast *ast TSRMLS_DC) { case ZEND_AST_UNSET: zend_compile_unset(ast TSRMLS_CC); return; + case ZEND_AST_RETURN: + zend_compile_return(ast TSRMLS_CC); + return; EMPTY_SWITCH_DEFAULT_CASE() } } diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 2580c585bc..1ed1510136 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -341,9 +341,10 @@ unticked_statement: | T_BREAK expr ';' { AC($2); zend_do_brk_cont(ZEND_BRK, &$2 TSRMLS_CC); } | T_CONTINUE ';' { zend_do_brk_cont(ZEND_CONT, NULL TSRMLS_CC); } | T_CONTINUE expr ';' { AC($2); zend_do_brk_cont(ZEND_CONT, &$2 TSRMLS_CC); } - | T_RETURN ';' { zend_do_return(NULL, 0 TSRMLS_CC); } - | T_RETURN expr_without_variable ';' { AC($2); zend_do_return(&$2, 0 TSRMLS_CC); } - | T_RETURN variable ';' { zend_do_return(&$2, 1 TSRMLS_CC); } + | T_RETURN ';' + { $$.u.ast = zend_ast_create_unary(ZEND_AST_RETURN, NULL); AS($$); } + | T_RETURN expr ';' + { $$.u.ast = zend_ast_create_unary(ZEND_AST_RETURN, $2.u.ast); AS($$); } | T_GLOBAL global_var_list ';' | T_STATIC static_var_list ';' | T_ECHO echo_expr_list ';'