From: Nikita Popov Date: Sat, 20 Sep 2014 19:58:06 +0000 (+0200) Subject: Merge branch 'PHP-5.6' X-Git-Tag: PRE_NATIVE_TLS_MERGE~158^2~82^2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6219a4e844e82f8eacd9ad6d24bb92739dcd6ff6;p=php Merge branch 'PHP-5.6' Conflicts: Zend/zend_compile.c --- 6219a4e844e82f8eacd9ad6d24bb92739dcd6ff6 diff --cc Zend/zend_compile.c index c5337595c5,19185dfb70..15902256db --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@@ -3380,99 -4737,131 +3380,103 @@@ void zend_compile_for(zend_ast *ast TSR } /* }}} */ -void zend_do_early_binding(TSRMLS_D) /* {{{ */ +void zend_compile_foreach(zend_ast *ast TSRMLS_DC) /* {{{ */ { - zend_op *opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1]; - HashTable *table; + zend_ast *expr_ast = ast->child[0]; + zend_ast *value_ast = ast->child[1]; + zend_ast *key_ast = ast->child[2]; + zend_ast *stmt_ast = ast->child[3]; + zend_bool by_ref = value_ast->kind == ZEND_AST_REF; + zend_bool is_variable = zend_is_variable(expr_ast) && !zend_is_call(expr_ast) + && zend_can_write_to_variable(expr_ast); - while (opline->opcode == ZEND_TICKS && opline > CG(active_op_array)->opcodes) { - opline--; - } + znode expr_node, reset_node, value_node, key_node, dummy_node; + zend_op *opline; + uint32_t opnum_reset, opnum_fetch; - switch (opline->opcode) { - case ZEND_DECLARE_FUNCTION: - if (do_bind_function(CG(active_op_array), opline, CG(function_table), 1) == FAILURE) { - return; - } - table = CG(function_table); - break; - case ZEND_DECLARE_CLASS: - if (do_bind_class(CG(active_op_array), opline, CG(class_table), 1 TSRMLS_CC) == NULL) { - return; - } - table = CG(class_table); - break; - case ZEND_DECLARE_INHERITED_CLASS: - { - zend_op *fetch_class_opline = opline-1; - zval *parent_name; - zend_class_entry **pce; + if (key_ast) { + if (key_ast->kind == ZEND_AST_REF) { + zend_error_noreturn(E_COMPILE_ERROR, "Key element cannot be a reference"); + } + if (key_ast->kind == ZEND_AST_LIST) { + zend_error_noreturn(E_COMPILE_ERROR, "Cannot use list as key element"); + } + } - parent_name = &CONSTANT(fetch_class_opline->op2.constant); - if ((zend_lookup_class(Z_STRVAL_P(parent_name), Z_STRLEN_P(parent_name), &pce TSRMLS_CC) == FAILURE) || - ((CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_CLASSES) && - ((*pce)->type == ZEND_INTERNAL_CLASS))) { - if (CG(compiler_options) & ZEND_COMPILE_DELAYED_BINDING) { - zend_uint *opline_num = &CG(active_op_array)->early_binding; + if (by_ref) { + value_ast = value_ast->child[0]; + } - while (*opline_num != -1) { - opline_num = &CG(active_op_array)->opcodes[*opline_num].result.opline_num; - } - *opline_num = opline - CG(active_op_array)->opcodes; - opline->opcode = ZEND_DECLARE_INHERITED_CLASS_DELAYED; - opline->result_type = IS_UNUSED; - opline->result.opline_num = -1; - } - return; - } - if (do_bind_inherited_class(CG(active_op_array), opline, CG(class_table), *pce, 1 TSRMLS_CC) == NULL) { - return; - } - /* clear unnecessary ZEND_FETCH_CLASS opcode */ - zend_del_literal(CG(active_op_array), fetch_class_opline->op2.constant); - MAKE_NOP(fetch_class_opline); + if (by_ref && is_variable) { + zend_compile_var(&expr_node, expr_ast, BP_VAR_W TSRMLS_CC); + } else { + zend_compile_expr(&expr_node, expr_ast TSRMLS_CC); + } - table = CG(class_table); - break; - } - case ZEND_VERIFY_ABSTRACT_CLASS: - case ZEND_ADD_INTERFACE: - case ZEND_ADD_TRAIT: - case ZEND_BIND_TRAITS: - /* We currently don't early-bind classes that implement interfaces */ - /* Classes with traits are handled exactly the same, no early-bind here */ - return; - default: - zend_error_noreturn(E_COMPILE_ERROR, "Invalid binding type"); - return; ++ if (by_ref) { ++ zend_separate_if_call_and_write(&expr_node, expr_ast, BP_VAR_W TSRMLS_CC); + } + - zend_hash_quick_del(table, Z_STRVAL(CONSTANT(opline->op1.constant)), Z_STRLEN(CONSTANT(opline->op1.constant)), Z_HASH_P(&CONSTANT(opline->op1.constant))); - zend_del_literal(CG(active_op_array), opline->op1.constant); - zend_del_literal(CG(active_op_array), opline->op2.constant); - MAKE_NOP(opline); -} -/* }}} */ + opnum_reset = get_next_op_number(CG(active_op_array)); + opline = zend_emit_op(&reset_node, ZEND_FE_RESET, &expr_node, NULL TSRMLS_CC); + if (by_ref && is_variable) { + opline->extended_value = ZEND_FE_FETCH_BYREF; + } -ZEND_API void zend_do_delayed_early_binding(const zend_op_array *op_array TSRMLS_DC) /* {{{ */ -{ - if (op_array->early_binding != -1) { - zend_bool orig_in_compilation = CG(in_compilation); - zend_uint opline_num = op_array->early_binding; - zend_class_entry **pce; + zend_stack_push(&CG(loop_var_stack), &reset_node); - CG(in_compilation) = 1; - while (opline_num != -1) { - if (zend_lookup_class(Z_STRVAL_P(op_array->opcodes[opline_num-1].op2.zv), Z_STRLEN_P(op_array->opcodes[opline_num-1].op2.zv), &pce TSRMLS_CC) == SUCCESS) { - do_bind_inherited_class(op_array, &op_array->opcodes[opline_num], EG(class_table), *pce, 0 TSRMLS_CC); - } - opline_num = op_array->opcodes[opline_num].result.opline_num; - } - CG(in_compilation) = orig_in_compilation; + opnum_fetch = get_next_op_number(CG(active_op_array)); + opline = zend_emit_op(&value_node, ZEND_FE_FETCH, &reset_node, NULL TSRMLS_CC); + if (by_ref) { + opline->extended_value |= ZEND_FE_FETCH_BYREF; + } + if (key_ast) { + opline->extended_value |= ZEND_FE_FETCH_WITH_KEY; } -} -/* }}} */ -void zend_do_boolean_or_begin(znode *expr1, znode *op_token TSRMLS_DC) /* {{{ */ -{ - int next_op_number = get_next_op_number(CG(active_op_array)); - zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); + opline = zend_emit_op(NULL, ZEND_OP_DATA, NULL, NULL TSRMLS_CC); + + /* Allocate enough space to keep HashPointer on VM stack */ + opline->op1_type = IS_TMP_VAR; + opline->op1.var = get_temporary_variable(CG(active_op_array)); + if (sizeof(HashPointer) > sizeof(zval)) { + /* Make sure 1 zval is enough for HashPointer (2 must be enough) */ + get_temporary_variable(CG(active_op_array)); + } - opline->opcode = ZEND_JMPNZ_EX; - if (expr1->op_type == IS_TMP_VAR) { - SET_NODE(opline->result, expr1); + if (key_ast) { + zend_make_tmp_result(&key_node, opline TSRMLS_CC); + } + + if (value_ast->attr == ZEND_AST_LIST) { + zend_compile_list_assign(&dummy_node, value_ast, &value_node TSRMLS_CC); + zend_do_free(&dummy_node TSRMLS_CC); + } else if (by_ref) { + zend_emit_assign_ref_znode(value_ast, &value_node TSRMLS_CC); } else { - opline->result.var = get_temporary_variable(CG(active_op_array)); - opline->result_type = IS_TMP_VAR; + zend_emit_assign_znode(value_ast, &value_node TSRMLS_CC); } - SET_NODE(opline->op1, expr1); - SET_UNUSED(opline->op2); - op_token->u.op.opline_num = next_op_number; + if (key_ast) { + zend_emit_assign_znode(key_ast, &key_node TSRMLS_CC); + } - GET_NODE(expr1, opline->result); -} -/* }}} */ + zend_begin_loop(TSRMLS_C); -void zend_do_boolean_or_end(znode *result, const znode *expr1, const znode *expr2, znode *op_token TSRMLS_DC) /* {{{ */ -{ - zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); + zend_compile_stmt(stmt_ast TSRMLS_CC); - *result = *expr1; /* we saved the original result in expr1 */ - opline->opcode = ZEND_BOOL; - SET_NODE(opline->result, result); - SET_NODE(opline->op1, expr2); - SET_UNUSED(opline->op2); + zend_emit_jump(opnum_fetch TSRMLS_CC); + + opline = &CG(active_op_array)->opcodes[opnum_reset]; + opline->op2.opline_num = get_next_op_number(CG(active_op_array)); + + opline = &CG(active_op_array)->opcodes[opnum_fetch]; + opline->op2.opline_num = get_next_op_number(CG(active_op_array)); + + zend_end_loop(opnum_fetch, 1 TSRMLS_CC); - CG(active_op_array)->opcodes[op_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array)); + generate_free_loop_var(&reset_node TSRMLS_CC); + zend_stack_del_top(&CG(loop_var_stack)); } /* }}} */