com php-src: Merge remote-tracking branch 'php-src/phpng' into ast: Zend/zend.c Zend/zend.h Zend/zend_ast.c Zend/zend_compi le.c Zend/zend_compile.h
Zend/zend_execute_API. c Zend/zend_vm_def.h Zend/zend_vm_execute.h e xt/opcache/zend_accelerator_util_funcs.c ext/opcache/ zend_persist.c
ext/opcache/zend_persist_calc.c
| From: | Nikita Popov | Date: | Sat, 16 Aug 2014 19:55:08 +0000 |
| Subject: | com php-src: Merge remote-tracking branch 'php-src/phpng' into ast: Zend/zend.c Zend/zend.h Zend/zend_ast.c Zend/zend_compi le.c Zend/zend_compile.h Zend/zend_execute_API. c Zend/zend_vm_def.h Zend/zend_vm_execute.h e xt/opcache/zend_accelerator_util_funcs.c ext/opcache/ zend_persist.c ext/opcache/zend_persist_calc.c |
||
| Groups: | php.cvs | ||
| Request: | Send a blank email to php-cvs+get-80879@lists.php.net to get a copy of this message | ||
Commit: 71675a4bf830d7b9400663275fe48275480d34f4
Author: Nikita Popov <nikic@php.net> Sat, 16 Aug 2014 21:55:08 +0200
Parents: f72d6f97ecf976f00abc0dc21b5d1ef4838de60a 8b66d64b2343bc4fd8aeabb690024edb850a0155
Branches: master
Link: http://git.php.net/?p=php-src.git;a=commitdiff;h=71675a4bf830d7b9400663275fe48275480d34f4
Log:
Merge remote-tracking branch 'php-src/phpng' into ast
Conflicts:
Zend/zend_ast.c
Zend/zend_compile.c
Zend/zend_language_parser.y
Incomplete merge!
Changed paths:
MM Zend/zend.c
MM Zend/zend.h
MM Zend/zend_ast.c
MM Zend/zend_compile.c
MM Zend/zend_compile.h
MM Zend/zend_execute_API.c
MM Zend/zend_vm_def.h
MM Zend/zend_vm_execute.h
MM ext/opcache/zend_accelerator_util_funcs.c
MM ext/opcache/zend_persist.c
MM ext/opcache/zend_persist_calc.c
diff --cc Zend/zend_ast.c index 2dd5b16,810b9b1..8e1d970 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@@ -224,25 -273,31 +223,36 @@@ ZEND_API void zend_ast_evaluate(zval *r zval_dtor(&op1); zval_dtor(&op2); break; - case ZEND_IS_SMALLER_OR_EQUAL: - zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC); - zend_ast_evaluate(&op2, (&ast->u.child)[1], scope TSRMLS_CC); - is_smaller_or_equal_function(result, &op1, &op2 TSRMLS_CC); + } + case ZEND_AST_UNARY_OP: + { + unary_op_type op = get_unary_op(ast->attr); + zend_ast_evaluate(&op1, ast->child[0], scope TSRMLS_CC); + op(result, &op1 TSRMLS_CC); zval_dtor(&op1); - zval_dtor(&op2); break; - case ZEND_CONST: - /* class constants may be updated in-place */ + } + case ZEND_AST_ZVAL: - ZVAL_DUP(result, zend_ast_get_zval(ast)); - if (Z_OPT_CONSTANT_P(result)) { - zval_update_constant_ex(result, 1, scope TSRMLS_CC); ++ { ++ zval *zv = zend_ast_get_zval(ast); + if (scope) { - if (Z_OPT_CONSTANT(ast->u.val)) { - zval_update_constant_ex(&ast->u.val, 1, scope TSRMLS_CC); ++ /* class constants may be updated in-place */ ++ if (Z_OPT_CONSTANT_P(zv)) { ++ zval_update_constant_ex(zv, 1, scope TSRMLS_CC); + } - ZVAL_DUP(result, &ast->u.val); ++ ZVAL_DUP(result, zv); + } else { - ZVAL_DUP(result, &ast->u.val); ++ ZVAL_DUP(result, zv); + if (Z_OPT_CONSTANT_P(result)) { + zval_update_constant_ex(result, 1, scope TSRMLS_CC); + } } break; - case ZEND_BOOL_AND: - zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC); ++ } + case ZEND_AST_AND: + zend_ast_evaluate(&op1, ast->child[0], scope TSRMLS_CC); if (zend_is_true(&op1 TSRMLS_CC)) { - zend_ast_evaluate(&op2, (&ast->u.child)[1], scope TSRMLS_CC); + zend_ast_evaluate(&op2, ast->child[1], scope TSRMLS_CC); ZVAL_BOOL(result, zend_is_true(&op2 TSRMLS_CC)); zval_dtor(&op2); } else { @@@ -304,15 -357,13 +314,13 @@@ } } break; - //??? - #if 0 case ZEND_FETCH_DIM_R: -- zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC); -- zend_ast_evaluate(&op2, (&ast->u.child)[1], scope TSRMLS_CC); ++ zend_ast_evaluate(&op1, ast->child[0], scope TSRMLS_CC); ++ zend_ast_evaluate(&op2, ast->child[1], scope TSRMLS_CC); { - zval *tmp; + zval tmp; zend_fetch_dimension_by_zval(&tmp, &op1, &op2 TSRMLS_CC); - ZVAL_ZVAL(result, tmp, 1, 1); + ZVAL_ZVAL(result, &tmp, 1, 1); } zval_dtor(&op1); zval_dtor(&op2); diff --cc Zend/zend_compile.c index 5a3359e,ae26733..5e0ed6c --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@@ -3055,476 -3721,246 +3055,438 @@@ ZEND_API void zend_initialize_class_dat } /* }}} */ -#define REALLOC_BUF_IF_EXCEED(buf, offset, length, size) \ - if (UNEXPECTED(offset - buf + size >= length)) { \ - length += size + 1; \ - buf = erealloc(buf, length); \ +zend_uint zend_get_class_fetch_type(zend_string *name) { + if (name->len == sizeof("self") - 1 && + !strncasecmp(name->val, "self", sizeof("self") - 1)) { + return ZEND_FETCH_CLASS_SELF; + } else if (name->len == sizeof("parent") - 1 && + !strncasecmp(name->val, "parent", sizeof("parent") - 1)) { + return ZEND_FETCH_CLASS_PARENT; + } else if (name->len == sizeof("static") - 1 && + !strncasecmp(name->val, "static", sizeof("static") - 1)) { + return ZEND_FETCH_CLASS_STATIC; + } else { + return ZEND_FETCH_CLASS_DEFAULT; } +} -static char * zend_get_function_declaration(zend_function *fptr TSRMLS_DC) /* {{{ */ +ZEND_API zend_string *zend_get_compiled_variable_name(const zend_op_array *op_array, zend_uint var) /* {{{ */ { - char *offset, *buf; - zend_uint length = 1024; + return op_array->vars[EX_VAR_TO_NUM(var)]; +} +/* }}} */ - offset = buf = (char *)emalloc(length * sizeof(char)); - if (fptr->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { - *(offset++) = '&'; - *(offset++) = ' '; +zend_ast *zend_ast_append_str(zend_ast *left_ast, zend_ast *right_ast) { + zval *left_zv = zend_ast_get_zval(left_ast); + zend_string *left = Z_STR_P(left_zv); + zend_string *right = zend_ast_get_str(right_ast); + + zend_string *result; + size_t left_len = left->len; + size_t len = left_len + right->len + 1; /* left\right */ + + result = STR_REALLOC(left, len, 0); + result->val[left_len] = '\\'; + memcpy(&result->val[left_len + 1], right->val, right->len); + result->val[len] = '\0'; + STR_RELEASE(right); + + ZVAL_STR(left_zv, result); + return left_ast; +} + +/* A hacky way that is used to store the doc comment for properties */ +zend_ast_list *zend_ast_append_doc_comment(zend_ast_list *list TSRMLS_DC) { + if (CG(doc_comment)) { + list = zend_ast_list_add(list, zend_ast_create_zval_from_str(CG(doc_comment))); + CG(doc_comment) = NULL; } - if (fptr->common.scope) { - memcpy(offset, fptr->common.scope->name->val, fptr->common.scope->name->len); - offset += fptr->common.scope->name->len; - *(offset++) = ':'; - *(offset++) = ':'; + return list; +} + +void zend_verify_namespace(TSRMLS_D) /* {{{ */ +{ + if (CG(has_bracketed_namespaces) && !CG(in_namespace)) { + zend_error_noreturn(E_COMPILE_ERROR, "No code may exist outside of namespace {}"); } +} +/* }}} */ - { - size_t name_len = fptr->common.function_name->len; - REALLOC_BUF_IF_EXCEED(buf, offset, length, name_len); - memcpy(offset, fptr->common.function_name->val, name_len); - offset += name_len; +static void zend_reset_import_tables(TSRMLS_D) { + if (CG(current_import)) { + zend_hash_destroy(CG(current_import)); + efree(CG(current_import)); + CG(current_import) = NULL; } - *(offset++) = '('; - if (fptr->common.arg_info) { - zend_uint i, required; - zend_arg_info *arg_info = fptr->common.arg_info; + if (CG(current_import_function)) { + zend_hash_destroy(CG(current_import_function)); + efree(CG(current_import_function)); + CG(current_import_function) = NULL; + } - required = fptr->common.required_num_args; - for (i = 0; i < fptr->common.num_args;) { - if (arg_info->class_name) { - const char *class_name; - zend_uint class_name_len; - if (!strcasecmp(arg_info->class_name, "self") && fptr->common.scope ) { - class_name = fptr->common.scope->name->val; - class_name_len = fptr->common.scope->name->len; - } else if (!strcasecmp(arg_info->class_name, "parent") && fptr->common.scope->parent) { - class_name = fptr->common.scope->parent->name->val; - class_name_len = fptr->common.scope->parent->name->len; - } else { - class_name = arg_info->class_name; - class_name_len = arg_info->class_name_len; - } - REALLOC_BUF_IF_EXCEED(buf, offset, length, class_name_len); - memcpy(offset, class_name, class_name_len); - offset += class_name_len; - *(offset++) = ' '; - } else if (arg_info->type_hint) { - zend_uint type_name_len; - char *type_name = zend_get_type_by_const(arg_info->type_hint); - type_name_len = strlen(type_name); - REALLOC_BUF_IF_EXCEED(buf, offset, length, type_name_len); - memcpy(offset, type_name, type_name_len); - offset += type_name_len; - *(offset++) = ' '; - } + if (CG(current_import_const)) { + zend_hash_destroy(CG(current_import_const)); + efree(CG(current_import_const)); + CG(current_import_const) = NULL; + } +} + +static void zend_end_namespace(TSRMLS_D) { + CG(in_namespace) = 0; + zend_reset_import_tables(TSRMLS_C); + if (CG(current_namespace)) { + STR_RELEASE(CG(current_namespace)); + CG(current_namespace) = NULL; + } +} + +void zend_do_end_compilation(TSRMLS_D) /* {{{ */ +{ + CG(has_bracketed_namespaces) = 0; + zend_end_namespace(TSRMLS_C); +} +/* }}} */ + - ZEND_API void zend_make_immutable_array(zval *zv TSRMLS_DC) /* {{{ */ - { - zend_constant *c; - - if (Z_IMMUTABLE_P(zv)) { - return; - } - - Z_TYPE_FLAGS_P(zv) = IS_TYPE_IMMUTABLE; - GC_REFCOUNT(Z_COUNTED_P(zv)) = 2; - Z_ARRVAL_P(zv)->u.flags &= ~HASH_FLAG_APPLY_PROTECTION; - - /* store as an anonymous constant */ - c = emalloc(sizeof(zend_constant)); - ZVAL_COPY_VALUE(&c->value, zv); - c->flags = 0; - c->name = NULL; - c->module_number = PHP_USER_CONSTANT; - zend_hash_next_index_insert_ptr(EG(zend_constants), c); - } - /* }}} */ - - void zend_make_immutable_array_r(zval *zv TSRMLS_DC) /* {{{ */ - { - zval *el; - - if (Z_IMMUTABLE_P(zv)) { - return; - } - zend_make_immutable_array(zv TSRMLS_CC); - ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zv), el) { - if (Z_TYPE_P(el) == IS_ARRAY) { - zend_make_immutable_array_r(el TSRMLS_CC); - } - } ZEND_HASH_FOREACH_END(); - } - /* }}} */ - +/* {{{ zend_dirname + Returns directory name component of path */ +ZEND_API size_t zend_dirname(char *path, size_t len) +{ + register char *end = path + len - 1; + unsigned int len_adjust = 0; + +#ifdef PHP_WIN32 + /* Note that on Win32 CWD is per drive (heritage from CP/M). + * This means dirname("c:foo") maps to "c:." or "c:" - which means CWD on C: drive. + */ + if ((2 <= len) && isalpha((int)((unsigned char *)path)[0]) && (':' == path[1])) { + /* Skip over the drive spec (if any) so as not to change */ + path += 2; + len_adjust += 2; + if (2 == len) { + /* Return "c:" on Win32 for dirname("c:"). + * It would be more consistent to return "c:." + * but that would require making the string *longer*. + */ + return len; + } + } +#elif defined(NETWARE) + /* + * Find the first occurrence of : from the left + * move the path pointer to the position just after : + * increment the len_adjust to the length of path till colon character(inclusive) + * If there is no character beyond : simple return len + */ + char *colonpos = NULL; + colonpos = strchr(path, ':'); + if (colonpos != NULL) { + len_adjust = ((colonpos - path) + 1); + path += len_adjust; + if (len_adjust == len) { + return len; + } + } +#endif + + if (len == 0) { + /* Illegal use of this function */ + return 0; + } + + /* Strip trailing slashes */ + while (end >= path && IS_SLASH_P(end)) { + end--; + } + if (end < path) { + /* The path only contained slashes */ + path[0] = DEFAULT_SLASH; + path[1] = '\0'; + return 1 + len_adjust; + } + + /* Strip filename */ + while (end >= path && !IS_SLASH_P(end)) { + end--; + } + if (end < path) { + /* No slash found, therefore return '.' */ +#ifdef NETWARE + if (len_adjust == 0) { + path[0] = '.'; + path[1] = '\0'; + return 1; /* only one character */ + } else { + path[0] = '\0'; + return len_adjust; + } +#else + path[0] = '.'; + path[1] = '\0'; + return 1 + len_adjust; +#endif + } + + /* Strip slashes which came before the file name */ + while (end >= path && IS_SLASH_P(end)) { + end--; + } + if (end < path) { + path[0] = DEFAULT_SLASH; + path[1] = '\0'; + return 1 + len_adjust; + } + *(end+1) = '\0'; + + return (size_t)(end + 1 - path) + len_adjust; +} +/* }}} */ + +static inline zend_bool zend_str_equals_str(zend_string *str1, zend_string *str2) { + return str1->len == str2->len && !memcmp(str1->val, str2->val, str2->len); +} +static inline zend_bool zend_str_equals_str_ci(zend_string *str1, zend_string *str2) { + return str1->len == str2->len + && !zend_binary_strcasecmp(str1->val, str1->len, str2->val, str2->len); +} + +#define zend_str_equals_literal(str, c) \ + ((str)->len == sizeof(c) - 1 && !memcmp((str)->val, (c), sizeof(c) - 1)) +#define zend_str_equals_literal_ci(str, c) \ + ((str)->len == sizeof(c) - 1 \ + && !zend_binary_strcasecmp((str)->val, (str)->len, (c), sizeof(c) - 1)) + +static void zend_adjust_for_fetch_type(zend_op *opline, zend_uint type) { + switch (type & BP_VAR_MASK) { + case BP_VAR_R: + return; + case BP_VAR_W: + opline->opcode += 3; + return; + case BP_VAR_REF: + opline->opcode += 3; + opline->extended_value |= ZEND_FETCH_MAKE_REF; + return; + case BP_VAR_RW: + opline->opcode += 6; + return; + case BP_VAR_IS: + opline->opcode += 9; + return; + case BP_VAR_FUNC_ARG: + opline->opcode += 12; + opline->extended_value |= type >> BP_VAR_SHIFT; + return; + case BP_VAR_UNSET: + opline->opcode += 15; + return; + EMPTY_SWITCH_DEFAULT_CASE() + } +} + +static inline void zend_make_var_result(znode *result, zend_op *opline TSRMLS_DC) { + opline->result_type = IS_VAR; + opline->result.var = get_temporary_variable(CG(active_op_array)); + GET_NODE(result, opline->result); +} + +static inline void zend_make_tmp_result(znode *result, zend_op *opline TSRMLS_DC) { + opline->result_type = IS_TMP_VAR; + opline->result.var = get_temporary_variable(CG(active_op_array)); + GET_NODE(result, opline->result); +} + +static zend_op *zend_emit_op(znode *result, zend_uchar opcode, znode *op1, znode *op2 TSRMLS_DC) { + zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); + opline->opcode = opcode; + + if (op1 == NULL) { + SET_UNUSED(opline->op1); + } else { + SET_NODE(opline->op1, op1); + } + + if (op2 == NULL) { + SET_UNUSED(opline->op2); + } else { + SET_NODE(opline->op2, op2); + } + + if (result) { + zend_make_var_result(result, opline TSRMLS_CC); + } + return opline; +} + +static zend_op *zend_emit_op_tmp( + znode *result, zend_uchar opcode, znode *op1, znode *op2 TSRMLS_DC +) { + zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); + opline->opcode = opcode; + + if (op1 == NULL) { + SET_UNUSED(opline->op1); + } else { + SET_NODE(opline->op1, op1); + } - if (arg_info->pass_by_reference) { - *(offset++) = '&'; - } + if (op2 == NULL) { + SET_UNUSED(opline->op2); + } else { + SET_NODE(opline->op2, op2); + } - if (arg_info->is_variadic) { - *(offset++) = '.'; - *(offset++) = '.'; - *(offset++) = '.'; - } + zend_make_tmp_result(result, opline TSRMLS_CC); - *(offset++) = '$'; + return opline; +} - if (arg_info->name) { - REALLOC_BUF_IF_EXCEED(buf, offset, length, arg_info->name_len); - memcpy(offset, arg_info->name, arg_info->name_len); - offset += arg_info->name_len; - } else { - zend_uint idx = i; - memcpy(offset, "param", 5); - offset += 5; - do { - *(offset++) = (char) (idx % 10) + '0'; - idx /= 10; - } while (idx > 0); - } - if (i >= required && !arg_info->is_variadic) { - *(offset++) = ' '; - *(offset++) = '='; - *(offset++) = ' '; - if (fptr->type == ZEND_USER_FUNCTION) { - zend_op *precv = NULL; - { - zend_uint idx = i; - zend_op *op = ((zend_op_array *)fptr)->opcodes; - zend_op *end = op + ((zend_op_array *)fptr)->last; +static void zend_emit_tick(TSRMLS_D) { + zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); - ++idx; - while (op < end) { - if ((op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT) - && op->op1.num == (long)idx) - { - precv = op; - } - ++op; - } - } - if (precv && precv->opcode == ZEND_RECV_INIT && precv->op2_type != IS_UNUSED) { - zval *zv = precv->op2.zv; + opline->opcode = ZEND_TICKS; + SET_UNUSED(opline->op1); + SET_UNUSED(opline->op2); + opline->extended_value = Z_LVAL(CG(declarables).ticks); +} - if (Z_TYPE_P(zv) == IS_CONSTANT) { - REALLOC_BUF_IF_EXCEED(buf, offset, length, Z_STRLEN_P(zv)); - memcpy(offset, Z_STRVAL_P(zv), Z_STRLEN_P(zv)); - offset += Z_STRLEN_P(zv); - } else if (Z_TYPE_P(zv) == IS_FALSE) { - memcpy(offset, "false", 5); - offset += 5; - } else if (Z_TYPE_P(zv) == IS_TRUE) { - memcpy(offset, "true", 4); - offset += 4; - } else if (Z_TYPE_P(zv) == IS_NULL) { - memcpy(offset, "NULL", 4); - offset += 4; - } else if (Z_TYPE_P(zv) == IS_STRING) { - *(offset++) = '\''; - REALLOC_BUF_IF_EXCEED(buf, offset, length, MIN(Z_STRLEN_P(zv), 10)); - memcpy(offset, Z_STRVAL_P(zv), MIN(Z_STRLEN_P(zv), 10)); - offset += MIN(Z_STRLEN_P(zv), 10); - if (Z_STRLEN_P(zv) > 10) { - *(offset++) = '.'; - *(offset++) = '.'; - *(offset++) = '.'; - } - *(offset++) = '\''; - } else if (Z_TYPE_P(zv) == IS_ARRAY) { - memcpy(offset, "Array", 5); - offset += 5; - } else if (Z_TYPE_P(zv) == IS_CONSTANT_AST) { - memcpy(offset, "<expression>", 12); - offset += 12; - } else { - zend_string *str = zval_get_string(zv); - REALLOC_BUF_IF_EXCEED(buf, offset, length, str->len); - memcpy(offset, str->val, str->len); - offset += str->len; - STR_RELEASE(str); - } - } - } else { - memcpy(offset, "NULL", 4); - offset += 4; - } - } +static inline zend_op *zend_emit_op_data(znode *value TSRMLS_DC) { + return zend_emit_op(NULL, ZEND_OP_DATA, value, NULL TSRMLS_CC); +} - if (++i < fptr->common.num_args) { - *(offset++) = ','; - *(offset++) = ' '; - } - arg_info++; - REALLOC_BUF_IF_EXCEED(buf, offset, length, 32); - } - } - *(offset++) = ')'; - *offset = '\0'; +static inline zend_uint zend_emit_jump(zend_uint opnum_target TSRMLS_DC) { + zend_uint opnum = get_next_op_number(CG(active_op_array)); + zend_op *opline = zend_emit_op(NULL, ZEND_JMP, NULL, NULL TSRMLS_CC); + opline->op1.opline_num = opnum_target; + return opnum; +} - return buf; +static inline zend_uint zend_emit_cond_jump( + zend_uchar opcode, znode *cond, zend_uint opnum_target TSRMLS_DC +) { + zend_uint opnum = get_next_op_number(CG(active_op_array)); + zend_op *opline = zend_emit_op(NULL, opcode, cond, NULL TSRMLS_CC); + opline->op2.opline_num = opnum_target; + return opnum; } -/* }}} */ -static void do_inheritance_check_on_method(zend_function *child, zend_function *parent TSRMLS_DC) /* {{{ */ -{ - zend_uint child_flags; - zend_uint parent_flags = parent->common.fn_flags; +static inline void zend_update_jump_target(zend_uint opnum_jump, zend_uint opnum_target TSRMLS_DC) { + zend_op *opline = &CG(active_op_array)->opcodes[opnum_jump]; + switch (opline->opcode) { + case ZEND_JMP: + opline->op1.opline_num = opnum_target; + break; + case ZEND_JMPZ: + case ZEND_JMPNZ: + case ZEND_JMPZ_EX: + case ZEND_JMPNZ_EX: + opline->op2.opline_num = opnum_target; + break; + EMPTY_SWITCH_DEFAULT_CASE() + } +} - if ((parent->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0 - && parent->common.fn_flags & ZEND_ACC_ABSTRACT - && parent->common.scope != (child->common.prototype ? child->common.prototype->common.scope : child->common.scope) - && child->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_IMPLEMENTED_ABSTRACT)) { - zend_error_noreturn(E_COMPILE_ERROR, "Can't inherit abstract function %s::%s() (previously declared abstract in %s)", - parent->common.scope->name->val, - child->common.function_name->val, - child->common.prototype ? child->common.prototype->common.scope->name->val : child->common.scope->name->val); +static inline void zend_update_jump_target_to_next(zend_uint opnum_jump TSRMLS_DC) { + zend_update_jump_target(opnum_jump, get_next_op_number(CG(active_op_array)) TSRMLS_CC); +} + +static inline zend_op *zend_delayed_emit_op( + znode *result, zend_uchar opcode, znode *op1, znode *op2 TSRMLS_DC +) { + zend_op tmp_opline; + init_op(&tmp_opline TSRMLS_CC); + tmp_opline.opcode = opcode; + SET_NODE(tmp_opline.op1, op1); + SET_NODE(tmp_opline.op2, op2); + if (result) { + zend_make_var_result(result, &tmp_opline TSRMLS_CC); } - if (parent_flags & ZEND_ACC_FINAL) { - zend_error_noreturn(E_COMPILE_ERROR, "Cannot override final method %s::%s()", ZEND_FN_SCOPE_NAME(parent), child->common.function_name->val); + zend_stack_push(&CG(delayed_oplines_stack), &tmp_opline); + return zend_stack_top(&CG(delayed_oplines_stack)); +} + +static inline zend_uint zend_delayed_compile_begin(TSRMLS_D) { + return zend_stack_count(&CG(delayed_oplines_stack)); +} + +static zend_op *zend_delayed_compile_end(zend_uint offset TSRMLS_DC) { + zend_op *opline, *oplines = zend_stack_base(&CG(delayed_oplines_stack)); + zend_uint i, count = zend_stack_count(&CG(delayed_oplines_stack)); + + ZEND_ASSERT(count > offset); + for (i = offset; i < count; ++i) { + opline = get_next_op(CG(active_op_array) TSRMLS_CC); + memcpy(opline, &oplines[i], sizeof(zend_op)); } + CG(delayed_oplines_stack).top = offset; + return opline; +} - child_flags = child->common.fn_flags; - /* You cannot change from static to non static and vice versa. - */ - if ((child_flags & ZEND_ACC_STATIC) != (parent_flags & ZEND_ACC_STATIC)) { - if (child->common.fn_flags & ZEND_ACC_STATIC) { - zend_error_noreturn(E_COMPILE_ERROR, "Cannot make non static method %s::%s() static in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name->val, ZEND_FN_SCOPE_NAME(child)); - } else { - zend_error_noreturn(E_COMPILE_ERROR, "Cannot make static method %s::%s() non static in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name->val, ZEND_FN_SCOPE_NAME(child)); - } +void zend_emit_final_return(zval *zv TSRMLS_DC) { + znode zn; + zend_bool returns_reference = (CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0; + + zn.op_type = IS_CONST; + if (zv) { + ZVAL_COPY_VALUE(&zn.u.constant, zv); + } else { + ZVAL_NULL(&zn.u.constant); } - /* Disallow making an inherited method abstract. */ - if ((child_flags & ZEND_ACC_ABSTRACT) && !(parent_flags & ZEND_ACC_ABSTRACT)) { - zend_error_noreturn(E_COMPILE_ERROR, "Cannot make non abstract method %s::%s() abstract in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name->val, ZEND_FN_SCOPE_NAME(child)); + zend_emit_op(NULL, returns_reference ? ZEND_RETURN_BY_REF : ZEND_RETURN, &zn, NULL TSRMLS_CC); +} + + +static inline zend_bool zend_is_variable(zend_ast *ast) { + return ast->kind == ZEND_AST_VAR || ast->kind == ZEND_AST_DIM + || ast->kind == ZEND_AST_PROP || ast->kind == ZEND_AST_STATIC_PROP + || ast->kind == ZEND_AST_CALL || ast->kind == ZEND_AST_METHOD_CALL + || ast->kind == ZEND_AST_STATIC_CALL; +} + +static inline zend_bool zend_is_call(zend_ast *ast) { + return ast->kind == ZEND_AST_CALL + || ast->kind == ZEND_AST_METHOD_CALL + || ast->kind == ZEND_AST_STATIC_CALL; +} + +static inline zend_bool zend_is_unticked_stmt(zend_ast *ast) { + return ast->kind == ZEND_AST_STMT_LIST || ast->kind == ZEND_AST_LABEL; +} + +static inline zend_bool zend_can_write_to_variable(zend_ast *ast) { + while (ast->kind == ZEND_AST_DIM || ast->kind == ZEND_AST_PROP) { + ast = ast->child[0]; } - if (parent_flags & ZEND_ACC_CHANGED) { - child->common.fn_flags |= ZEND_ACC_CHANGED; - } else { - /* Prevent derived classes from restricting access that was available in parent classes - */ - if ((child_flags & ZEND_ACC_PPP_MASK) > (parent_flags & ZEND_ACC_PPP_MASK)) { - zend_error_noreturn(E_COMPILE_ERROR, "Access level to %s::%s() must be %s (as in class %s)%s", ZEND_FN_SCOPE_NAME(child), child->common.function_name->val, zend_visibility_string(parent_flags), ZEND_FN_SCOPE_NAME(parent), (parent_flags&ZEND_ACC_PUBLIC) ? "" : " or weaker"); - } else if (((child_flags & ZEND_ACC_PPP_MASK) < (parent_flags & ZEND_ACC_PPP_MASK)) - && ((parent_flags & ZEND_ACC_PPP_MASK) & ZEND_ACC_PRIVATE)) { - child->common.fn_flags |= ZEND_ACC_CHANGED; - } + return zend_is_variable(ast); +} + +static inline zend_bool zend_is_const_default_class_ref(zend_ast *name_ast) { + zend_string *name; + + if (name_ast->kind != ZEND_AST_ZVAL) { + return 0; } - if (parent_flags & ZEND_ACC_PRIVATE) { - child->common.prototype = NULL; - } else if (parent_flags & ZEND_ACC_ABSTRACT) { - child->common.fn_flags |= ZEND_ACC_IMPLEMENTED_ABSTRACT; - child->common.prototype = parent; - } else if (!(parent->common.fn_flags & ZEND_ACC_CTOR) || (parent->common.prototype && (parent->common.prototype->common.scope->ce_flags & ZEND_ACC_INTERFACE))) { - /* ctors only have a prototype if it comes from an interface */ - child->common.prototype = parent->common.prototype ? parent->common.prototype : parent; + /* Fully qualified names are always default refs */ + if (!name_ast->attr) { + return 1; } - if (child->common.prototype && (child->common.prototype->common.fn_flags & ZEND_ACC_ABSTRACT)) { - if (!zend_do_perform_implementation_check(child, child->common.prototype TSRMLS_CC)) { - zend_error_noreturn(E_COMPILE_ERROR, "Declaration of %s::%s() must be compatible with %s", ZEND_FN_SCOPE_NAME(child), child->common.function_name->val, zend_get_function_declaration(child->common.prototype TSRMLS_CC)); - } - } else if (EG(error_reporting) & E_STRICT || Z_TYPE(EG(user_error_handler)) != IS_UNDEF) { /* Check E_STRICT (or custom error handler) before the check so that we save some time */ - if (!zend_do_perform_implementation_check(child, parent TSRMLS_CC)) { - char *method_prototype = zend_get_function_declaration(parent TSRMLS_CC); - zend_error(E_STRICT, "Declaration of %s::%s() should be compatible with %s", ZEND_FN_SCOPE_NAME(child), child->common.function_name->val, method_prototype); - efree(method_prototype); + name = zend_ast_get_str(name_ast); + return ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(name); +} + +static inline void zend_handle_numeric_op(znode *node TSRMLS_DC) { + if (node->op_type == IS_CONST && Z_TYPE(node->u.constant) == IS_STRING) { + zend_ulong index; + + if (ZEND_HANDLE_NUMERIC(Z_STR(node->u.constant), index)) { + zval_ptr_dtor(&node->u.constant); + ZVAL_LONG(&node->u.constant, index); } } } @@@ -6542,463 -6949,606 +6504,462 @@@ static zend_bool zend_try_ct_eval_array } } - zend_make_immutable_array(result TSRMLS_CC); - if (key->op_type != IS_UNUSED) { - znode key_node; + return 1; +} - opline = &CG(active_op_array)->opcodes[as_token->u.op.opline_num+1]; - opline->result_type = IS_TMP_VAR; - opline->result.opline_num = get_temporary_variable(CG(active_op_array)); - GET_NODE(&key_node, opline->result); +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; - zend_do_assign(&dummy, key, &key_node TSRMLS_CC); - zend_do_free(&dummy TSRMLS_CC); + znode left_node, right_node; + zend_compile_expr(&left_node, left_ast TSRMLS_CC); + zend_compile_expr(&right_node, right_ast TSRMLS_CC); + + if (left_node.op_type == IS_CONST && right_node.op_type == IS_CONST) { + result->op_type = IS_CONST; + zend_ct_eval_binary_op(&result->u.constant, opcode, + &left_node.u.constant, &right_node.u.constant TSRMLS_CC); + zval_ptr_dtor(&left_node.u.constant); + zval_ptr_dtor(&right_node.u.constant); + return; } - do_begin_loop(TSRMLS_C); - INC_BPC(CG(active_op_array)); + zend_emit_op_tmp(result, opcode, &left_node, &right_node TSRMLS_CC); } -/* }}} */ - -void zend_do_foreach_end(const znode *foreach_token, const znode *as_token TSRMLS_DC) /* {{{ */ -{ - zend_op *container_ptr; - zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); - opline->opcode = ZEND_JMP; - opline->op1.opline_num = as_token->u.op.opline_num; - SET_UNUSED(opline->op1); - SET_UNUSED(opline->op2); +/* We do not use zend_compile_binary_op for this because we want to retain the left-to-right + * evaluation order. */ +void zend_compile_greater(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast *left_ast = ast->child[0]; + zend_ast *right_ast = ast->child[1]; + znode left_node, right_node; - CG(active_op_array)->opcodes[foreach_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array)); /* FE_RESET */ - CG(active_op_array)->opcodes[as_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array)); /* FE_FETCH */ + ZEND_ASSERT(ast->kind == ZEND_AST_GREATER || ast->kind == ZEND_AST_GREATER_EQUAL); - do_end_loop(as_token->u.op.opline_num, 1 TSRMLS_CC); + zend_compile_expr(&left_node, left_ast TSRMLS_CC); + zend_compile_expr(&right_node, right_ast TSRMLS_CC); - container_ptr = zend_stack_top(&CG(foreach_copy_stack)); - generate_free_foreach_copy(container_ptr TSRMLS_CC); - zend_stack_del_top(&CG(foreach_copy_stack)); + if (left_node.op_type == IS_CONST && right_node.op_type == IS_CONST) { + result->op_type = IS_CONST; + zend_ct_eval_greater(&result->u.constant, ast->kind, + &left_node.u.constant, &right_node.u.constant TSRMLS_CC); + zval_ptr_dtor(&left_node.u.constant); + zval_ptr_dtor(&right_node.u.constant); + return; + } - DEC_BPC(CG(active_op_array)); + zend_emit_op_tmp(result, + ast->kind == ZEND_AST_GREATER ? ZEND_IS_SMALLER : ZEND_IS_SMALLER_OR_EQUAL, + &right_node, &left_node TSRMLS_CC); } -/* }}} */ -void zend_do_declare_begin(TSRMLS_D) /* {{{ */ -{ - zend_stack_push(&CG(declare_stack), &CG(declarables)); -} -/* }}} */ +void zend_compile_unary_op(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast *expr_ast = ast->child[0]; + zend_uint opcode = ast->attr; -void zend_do_declare_stmt(znode *var, znode *val TSRMLS_DC) /* {{{ */ -{ - if (!zend_binary_strcasecmp(Z_STRVAL(var->u.constant), Z_STRLEN(var->u.constant), "ticks", sizeof("ticks")-1)) { - convert_to_long(&val->u.constant); - CG(declarables).ticks = val->u.constant; - } else if (!zend_binary_strcasecmp(Z_STRVAL(var->u.constant), Z_STRLEN(var->u.constant), "encoding", sizeof("encoding")-1)) { - if (Z_TYPE(val->u.constant) == IS_CONSTANT) { - zend_error_noreturn(E_COMPILE_ERROR, "Cannot use constants as encoding"); - } - - /* - * Check that the pragma comes before any opcodes. If the compilation - * got as far as this, the previous portion of the script must have been - * parseable according to the .ini script_encoding setting. We still - * want to tell them to put declare() at the top. - */ - { - int num = CG(active_op_array)->last; - /* ignore ZEND_EXT_STMT and ZEND_TICKS */ - while (num > 0 && - (CG(active_op_array)->opcodes[num-1].opcode == ZEND_EXT_STMT || - CG(active_op_array)->opcodes[num-1].opcode == ZEND_TICKS)) { - --num; - } + znode expr_node; + zend_compile_expr(&expr_node, expr_ast TSRMLS_CC); - if (num > 0) { - zend_error_noreturn(E_COMPILE_ERROR, "Encoding declaration pragma must be the very first statement in the script"); - } - } + zend_emit_op_tmp(result, opcode, &expr_node, NULL TSRMLS_CC); +} - if (CG(multibyte)) { - const zend_encoding *new_encoding, *old_encoding; - zend_encoding_filter old_input_filter; +void zend_compile_unary_pm(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast *expr_ast = ast->child[0]; + znode zero_node, expr_node; - CG(encoding_declared) = 1; + ZEND_ASSERT(ast->kind == ZEND_AST_UNARY_PLUS || ast->kind == ZEND_AST_UNARY_MINUS); - convert_to_string(&val->u.constant); - new_encoding = zend_multibyte_fetch_encoding(Z_STRVAL(val->u.constant) TSRMLS_CC); - if (!new_encoding) { - zend_error(E_COMPILE_WARNING, "Unsupported encoding [%s]", Z_STRVAL(val->u.constant)); - } else { - old_input_filter = LANG_SCNG(input_filter); - old_encoding = LANG_SCNG(script_encoding); - zend_multibyte_set_filter(new_encoding TSRMLS_CC); - - /* need to re-scan if input filter changed */ - if (old_input_filter != LANG_SCNG(input_filter) || - (old_input_filter && new_encoding != old_encoding)) { - zend_multibyte_yyinput_again(old_input_filter, old_encoding TSRMLS_CC); - } - } - } else { - zend_error(E_COMPILE_WARNING, "declare(encoding=...) ignored because Zend multibyte feature is turned off by settings"); - } - zval_dtor(&val->u.constant); - } else { - zend_error(E_COMPILE_WARNING, "Unsupported declare '%s'", Z_STRVAL(var->u.constant)); - zval_dtor(&val->u.constant); - } - zval_dtor(&var->u.constant); -} -/* }}} */ + zend_compile_expr(&expr_node, expr_ast TSRMLS_CC); -void zend_do_declare_end(const znode *declare_token TSRMLS_DC) /* {{{ */ -{ - zend_declarables *declarables = zend_stack_top(&CG(declare_stack)); - /* We should restore if there was more than (current - start) - (ticks?1:0) opcodes */ - if ((get_next_op_number(CG(active_op_array)) - declare_token->u.op.opline_num) - ((Z_LVAL(CG(declarables).ticks))?1:0)) { - CG(declarables) = *declarables; + if (expr_node.op_type == IS_CONST) { + result->op_type = IS_CONST; + zend_ct_eval_unary_pm(&result->u.constant, ast->kind, &expr_node.u.constant TSRMLS_CC); + zval_ptr_dtor(&expr_node.u.constant); + return; } -} -/* }}} */ -void zend_do_exit(znode *result, znode *message TSRMLS_DC) /* {{{ */ -{ - zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); - - opline->opcode = ZEND_EXIT; - SET_NODE(opline->op1, message); - SET_UNUSED(opline->op2); + zero_node.op_type = IS_CONST; + ZVAL_LONG(&zero_node.u.constant, 0); - result->op_type = IS_CONST; - ZVAL_BOOL(&result->u.constant, 1); + zend_emit_op_tmp(result, ast->kind == ZEND_AST_UNARY_PLUS ? ZEND_ADD : ZEND_SUB, + &zero_node, &expr_node TSRMLS_CC); } -/* }}} */ -void zend_do_begin_silence(znode *strudel_token TSRMLS_DC) /* {{{ */ -{ - zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); +void zend_compile_short_circuiting(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast *left_ast = ast->child[0]; + zend_ast *right_ast = ast->child[1]; - opline->opcode = ZEND_BEGIN_SILENCE; - opline->result_type = IS_TMP_VAR; - opline->result.var = get_temporary_variable(CG(active_op_array)); - SET_UNUSED(opline->op1); - SET_UNUSED(opline->op2); - GET_NODE(strudel_token, opline->result); -} -/* }}} */ + znode left_node, right_node; + zend_op *opline_jmpz, *opline_bool; + zend_uint opnum_jmpz; -void zend_do_end_silence(znode *strudel_token TSRMLS_DC) /* {{{ */ -{ - zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); + ZEND_ASSERT(ast->kind == ZEND_AST_AND || ast->kind == ZEND_AST_OR); - opline->opcode = ZEND_END_SILENCE; - SET_NODE(opline->op1, strudel_token); - SET_UNUSED(opline->op2); -} -/* }}} */ + zend_compile_expr(&left_node, left_ast TSRMLS_CC); -void zend_do_jmp_set(znode *value, znode *jmp_token, znode *colon_token TSRMLS_DC) /* {{{ */ -{ - int op_number = get_next_op_number(CG(active_op_array)); - zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); + opnum_jmpz = get_next_op_number(CG(active_op_array)); + opline_jmpz = zend_emit_op(NULL, ast->kind == ZEND_AST_AND ? ZEND_JMPZ_EX : ZEND_JMPNZ_EX, + &left_node, NULL TSRMLS_CC); - if (value->op_type == IS_VAR || value->op_type == IS_CV) { - opline->opcode = ZEND_JMP_SET_VAR; - opline->result_type = IS_VAR; + if (left_node.op_type == IS_TMP_VAR) { + SET_NODE(opline_jmpz->result, &left_node); } else { - opline->opcode = ZEND_JMP_SET; - opline->result_type = IS_TMP_VAR; + opline_jmpz->result.var = get_temporary_variable(CG(active_op_array)); + opline_jmpz->result_type = IS_TMP_VAR; } - opline->result.var = get_temporary_variable(CG(active_op_array)); - SET_NODE(opline->op1, value); - SET_UNUSED(opline->op2); + GET_NODE(result, opline_jmpz->result); - GET_NODE(colon_token, opline->result); + zend_compile_expr(&right_node, right_ast TSRMLS_CC); - jmp_token->u.op.opline_num = op_number; + opline_bool = zend_emit_op(NULL, ZEND_BOOL, &right_node, NULL TSRMLS_CC); + SET_NODE(opline_bool->result, result); - INC_BPC(CG(active_op_array)); + zend_update_jump_target_to_next(opnum_jmpz TSRMLS_CC); } -/* }}} */ -void zend_do_jmp_set_else(znode *result, znode *false_value, const znode *jmp_token, znode *colon_token TSRMLS_DC) /* {{{ */ -{ - zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); +void zend_compile_post_incdec(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast *var_ast = ast->child[0]; + ZEND_ASSERT(ast->kind == ZEND_AST_POST_INC || ast->kind == ZEND_AST_POST_DEC); - SET_NODE(opline->result, colon_token); - if (colon_token->op_type == IS_TMP_VAR) { - if (false_value->op_type == IS_VAR || false_value->op_type == IS_CV) { - CG(active_op_array)->opcodes[jmp_token->u.op.opline_num].opcode = ZEND_JMP_SET_VAR; - CG(active_op_array)->opcodes[jmp_token->u.op.opline_num].result_type = IS_VAR; - opline->opcode = ZEND_QM_ASSIGN_VAR; - opline->result_type = IS_VAR; - } else { - opline->opcode = ZEND_QM_ASSIGN; - } + if (var_ast->kind == ZEND_AST_PROP) { + zend_op *opline = zend_compile_prop_common(NULL, var_ast, BP_VAR_RW TSRMLS_CC); + opline->opcode = ast->kind == ZEND_AST_POST_INC ? ZEND_POST_INC_OBJ : ZEND_POST_DEC_OBJ; + zend_make_tmp_result(result, opline TSRMLS_CC); } else { - opline->opcode = ZEND_QM_ASSIGN_VAR; + znode var_node; + zend_compile_var(&var_node, var_ast, BP_VAR_RW TSRMLS_CC); + zend_emit_op_tmp(result, ast->kind == ZEND_AST_POST_INC ? ZEND_POST_INC : ZEND_POST_DEC, + &var_node, NULL TSRMLS_CC); } - opline->extended_value = 0; - SET_NODE(opline->op1, false_value); - SET_UNUSED(opline->op2); - - GET_NODE(result, opline->result); +} - CG(active_op_array)->opcodes[jmp_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array)); +void zend_compile_pre_incdec(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast *var_ast = ast->child[0]; + ZEND_ASSERT(ast->kind == ZEND_AST_PRE_INC || ast->kind == ZEND_AST_PRE_DEC); - DEC_BPC(CG(active_op_array)); + if (var_ast->kind == ZEND_AST_PROP) { + zend_op *opline = zend_compile_prop_common(result, var_ast, BP_VAR_RW TSRMLS_CC); + opline->opcode = ast->kind == ZEND_AST_PRE_INC ? ZEND_PRE_INC_OBJ : ZEND_PRE_DEC_OBJ; + } else { + znode var_node; + zend_compile_var(&var_node, var_ast, BP_VAR_RW TSRMLS_CC); + zend_emit_op(result, ast->kind == ZEND_AST_PRE_INC ? ZEND_PRE_INC : ZEND_PRE_DEC, + &var_node, NULL TSRMLS_CC); + } } -/* }}} */ -void zend_do_begin_qm_op(znode *cond, znode *qm_token TSRMLS_DC) /* {{{ */ -{ - int jmpz_op_number = get_next_op_number(CG(active_op_array)); +void zend_compile_cast(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast *expr_ast = ast->child[0]; + znode expr_node; zend_op *opline; - opline = get_next_op(CG(active_op_array) TSRMLS_CC); - - opline->opcode = ZEND_JMPZ; - SET_NODE(opline->op1, cond); - SET_UNUSED(opline->op2); - opline->op2.opline_num = jmpz_op_number; - GET_NODE(qm_token, opline->op2); + zend_compile_expr(&expr_node, expr_ast TSRMLS_CC); - INC_BPC(CG(active_op_array)); + opline = zend_emit_op(result, ZEND_CAST, &expr_node, NULL TSRMLS_CC); + opline->extended_value = ast->attr; } -/* }}} */ -void zend_do_qm_true(znode *true_value, znode *qm_token, znode *colon_token TSRMLS_DC) /* {{{ */ -{ - zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); +static void zend_compile_shorthand_conditional(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast *cond_ast = ast->child[0]; + zend_ast *false_ast = ast->child[2]; - CG(active_op_array)->opcodes[qm_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array))+1; /* jmp over the ZEND_JMP */ + znode cond_node, false_node; + zend_op *opline_jmp_set, *opline_qm_assign; + zend_uint opnum_jmp_set; - if (true_value->op_type == IS_VAR || true_value->op_type == IS_CV) { - opline->opcode = ZEND_QM_ASSIGN_VAR; - opline->result_type = IS_VAR; - } else { - opline->opcode = ZEND_QM_ASSIGN; - opline->result_type = IS_TMP_VAR; - } - opline->result.var = get_temporary_variable(CG(active_op_array)); - SET_NODE(opline->op1, true_value); - SET_UNUSED(opline->op2); + ZEND_ASSERT(ast->child[1] == NULL); - GET_NODE(qm_token, opline->result); - colon_token->u.op.opline_num = get_next_op_number(CG(active_op_array)); + zend_compile_expr(&cond_node, cond_ast TSRMLS_CC); - opline = get_next_op(CG(active_op_array) TSRMLS_CC); - opline->opcode = ZEND_JMP; - SET_UNUSED(opline->op1); - SET_UNUSED(opline->op2); -} -/* }}} */ + opnum_jmp_set = get_next_op_number(CG(active_op_array)); + zend_emit_op_tmp(result, ZEND_JMP_SET, &cond_node, NULL TSRMLS_CC); -void zend_do_qm_false(znode *result, znode *false_value, znode *qm_token, const znode *colon_token TSRMLS_DC) /* {{{ */ -{ - zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); + zend_compile_expr(&false_node, false_ast TSRMLS_CC); - SET_NODE(opline->result, qm_token); - if (qm_token->op_type == IS_TMP_VAR) { - if (false_value->op_type == IS_VAR || false_value->op_type == IS_CV) { - CG(active_op_array)->opcodes[colon_token->u.op.opline_num - 1].opcode = ZEND_QM_ASSIGN_VAR; - CG(active_op_array)->opcodes[colon_token->u.op.opline_num - 1].result_type = IS_VAR; - opline->opcode = ZEND_QM_ASSIGN_VAR; - opline->result_type = IS_VAR; - } else { - opline->opcode = ZEND_QM_ASSIGN; - } + opline_jmp_set = &CG(active_op_array)->opcodes[opnum_jmp_set]; + opline_jmp_set->op2.opline_num = get_next_op_number(CG(active_op_array)) + 1; + if (cond_node.op_type == IS_VAR || cond_node.op_type == IS_CV + || false_node.op_type == IS_VAR || false_node.op_type == IS_CV + ) { + opline_jmp_set->opcode = ZEND_JMP_SET_VAR; + opline_jmp_set->result_type = IS_VAR; + GET_NODE(result, opline_jmp_set->result); + + opline_qm_assign = zend_emit_op(NULL, ZEND_QM_ASSIGN_VAR, &false_node, NULL TSRMLS_CC); } else { - opline->opcode = ZEND_QM_ASSIGN_VAR; + opline_qm_assign = zend_emit_op(NULL, ZEND_QM_ASSIGN, &false_node, NULL TSRMLS_CC); } - SET_NODE(opline->op1, false_value); - SET_UNUSED(opline->op2); - - CG(active_op_array)->opcodes[colon_token->u.op.opline_num].op1.opline_num = get_next_op_number(CG(active_op_array)); - - GET_NODE(result, opline->result); - - DEC_BPC(CG(active_op_array)); + SET_NODE(opline_qm_assign->result, result); } -/* }}} */ -void zend_do_extended_info(TSRMLS_D) /* {{{ */ -{ - zend_op *opline; +void zend_compile_conditional(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast *cond_ast = ast->child[0]; + zend_ast *true_ast = ast->child[1]; + zend_ast *false_ast = ast->child[2]; - if (!(CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO)) { + znode cond_node, true_node, false_node; + zend_op *opline_qm_assign1, *opline_qm_assign2; + zend_uint opnum_jmpz, opnum_jmp, opnum_qm_assign1; + + if (!true_ast) { + zend_compile_shorthand_conditional(result, ast TSRMLS_CC); return; } + + zend_compile_expr(&cond_node, cond_ast TSRMLS_CC); - opline = get_next_op(CG(active_op_array) TSRMLS_CC); - - opline->opcode = ZEND_EXT_STMT; - SET_UNUSED(opline->op1); - SET_UNUSED(opline->op2); -} -/* }}} */ + opnum_jmpz = zend_emit_cond_jump(ZEND_JMPZ, &cond_node, 0 TSRMLS_CC); -void zend_do_extended_fcall_begin(TSRMLS_D) /* {{{ */ -{ - zend_op *opline; + zend_compile_expr(&true_node, true_ast TSRMLS_CC); - if (!(CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO)) { - return; - } + opnum_qm_assign1 = get_next_op_number(CG(active_op_array)); + zend_emit_op(result, ZEND_QM_ASSIGN, &true_node, NULL TSRMLS_CC); - opline = get_next_op(CG(active_op_array) TSRMLS_CC); + opnum_jmp = zend_emit_jump(0 TSRMLS_CC); - opline->opcode = ZEND_EXT_FCALL_BEGIN; - SET_UNUSED(opline->op1); - SET_UNUSED(opline->op2); -} -/* }}} */ + zend_update_jump_target_to_next(opnum_jmpz TSRMLS_CC); -void zend_do_extended_fcall_end(TSRMLS_D) /* {{{ */ -{ - zend_op *opline; + zend_compile_expr(&false_node, false_ast TSRMLS_CC); - if (!(CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO)) { - return; + opline_qm_assign1 = &CG(active_op_array)->opcodes[opnum_qm_assign1]; + if (true_node.op_type == IS_VAR || true_node.op_type == IS_CV + || false_node.op_type == IS_VAR || false_node.op_type == IS_CV + ) { + opline_qm_assign1->opcode = ZEND_QM_ASSIGN_VAR; + opline_qm_assign1->result_type = IS_VAR; + GET_NODE(result, opline_qm_assign1->result); } - opline = get_next_op(CG(active_op_array) TSRMLS_CC); + opline_qm_assign2 = zend_emit_op(NULL, opline_qm_assign1->opcode, &false_node, NULL TSRMLS_CC); + SET_NODE(opline_qm_assign2->result, result); - opline->opcode = ZEND_EXT_FCALL_END; - SET_UNUSED(opline->op1); - SET_UNUSED(opline->op2); + zend_update_jump_target_to_next(opnum_jmp TSRMLS_CC); } -/* }}} */ -void zend_do_ticks(TSRMLS_D) /* {{{ */ -{ - zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); +void zend_compile_print(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast *expr_ast = ast->child[0]; - opline->opcode = ZEND_TICKS; - SET_UNUSED(opline->op1); - SET_UNUSED(opline->op2); - opline->extended_value = Z_LVAL(CG(declarables).ticks); + znode expr_node; + zend_compile_expr(&expr_node, expr_ast TSRMLS_CC); + + zend_emit_op_tmp(result, ZEND_PRINT, &expr_node, NULL TSRMLS_CC); } -/* }}} */ -zend_bool zend_is_auto_global(zend_string *name TSRMLS_DC) /* {{{ */ -{ - zend_auto_global *auto_global; +void zend_compile_exit(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast *expr_ast = ast->child[0]; - if ((auto_global = zend_hash_find_ptr(CG(auto_globals), name)) != NULL) { - if (auto_global->armed) { - auto_global->armed = auto_global->auto_global_callback(auto_global->name TSRMLS_CC); - } - return 1; + if (expr_ast) { + znode expr_node; + zend_compile_expr(&expr_node, expr_ast TSRMLS_CC); + zend_emit_op(NULL, ZEND_EXIT, &expr_node, NULL TSRMLS_CC); + } else { + zend_emit_op(NULL, ZEND_EXIT, NULL, NULL TSRMLS_CC); } - return 0; + + result->op_type = IS_CONST; + ZVAL_BOOL(&result->u.constant, 1); } -/* }}} */ -int zend_register_auto_global(zend_string *name, zend_bool jit, zend_auto_global_callback auto_global_callback TSRMLS_DC) /* {{{ */ -{ - zend_auto_global auto_global; - int retval; +void zend_compile_yield(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast *value_ast = ast->child[0]; + zend_ast *key_ast = ast->child[1]; - auto_global.name = zend_new_interned_string(name TSRMLS_CC); - auto_global.auto_global_callback = auto_global_callback; - auto_global.jit = jit; + znode value_node, key_node; + znode *value_node_ptr = NULL, *key_node_ptr = NULL; + zend_op *opline; + zend_bool returns_by_ref = (CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0; - retval = zend_hash_add_mem(CG(auto_globals), name, &auto_global, sizeof(zend_auto_global)) != NULL ? SUCCESS : FAILURE; + if (!CG(active_op_array)->function_name) { + zend_error_noreturn(E_COMPILE_ERROR, + "The \"yield\" expression can only be used inside a function"); + } - STR_RELEASE(auto_global.name); - return retval; -} -/* }}} */ + CG(active_op_array)->fn_flags |= ZEND_ACC_GENERATOR; -ZEND_API void zend_activate_auto_globals(TSRMLS_D) /* {{{ */ -{ - zend_auto_global *auto_global; + if (key_ast) { + zend_compile_expr(&key_node, key_ast TSRMLS_CC); + key_node_ptr = &key_node; + } - ZEND_HASH_FOREACH_PTR(CG(auto_globals), auto_global) { - if (auto_global->jit) { - auto_global->armed = 1; - } else if (auto_global->auto_global_callback) { - auto_global->armed = auto_global->auto_global_callback(auto_global->name TSRMLS_CC); + if (value_ast) { + if (returns_by_ref && zend_is_variable(value_ast) && !zend_is_call(value_ast)) { + zend_compile_var(&value_node, value_ast, BP_VAR_REF TSRMLS_CC); } else { - auto_global->armed = 0; + zend_compile_expr(&value_node, value_ast TSRMLS_CC); } - } ZEND_HASH_FOREACH_END(); + value_node_ptr = &value_node; + } + + opline = zend_emit_op(result, ZEND_YIELD, value_node_ptr, key_node_ptr TSRMLS_CC); + + if (value_ast && returns_by_ref && zend_is_call(value_ast)) { + opline->extended_value = ZEND_RETURNS_FUNCTION; + } } -/* }}} */ -int zendlex(znode *zendlval TSRMLS_DC) /* {{{ */ -{ - int retval; +void zend_compile_instanceof(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast *obj_ast = ast->child[0]; + zend_ast *class_ast = ast->child[1]; - if (CG(increment_lineno)) { - CG(zend_lineno)++; - CG(increment_lineno) = 0; + znode obj_node, class_node; + zend_op *opline; + + zend_compile_expr(&obj_node, obj_ast TSRMLS_CC); + if (obj_node.op_type == IS_CONST) { + zend_error_noreturn(E_COMPILE_ERROR, + "instanceof expects an object instance, constant given"); } -again: - Z_TYPE_INFO(zendlval->u.constant) = IS_LONG; - retval = lex_scan(&zendlval->u.constant TSRMLS_CC); - switch (retval) { - case T_COMMENT: - case T_DOC_COMMENT: - case T_OPEN_TAG: - case T_WHITESPACE: - goto again; + opline = zend_compile_class_ref(&class_node, class_ast TSRMLS_CC); + opline->extended_value |= ZEND_FETCH_CLASS_NO_AUTOLOAD; - case T_CLOSE_TAG: - if (LANG_SCNG(yy_text)[LANG_SCNG(yy_leng)-1] != '>') { - CG(increment_lineno) = 1; - } - if (CG(has_bracketed_namespaces) && !CG(in_namespace)) { - goto again; + zend_emit_op_tmp(result, ZEND_INSTANCEOF, &obj_node, &class_node TSRMLS_CC); +} + +void zend_compile_include_or_eval(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast *expr_ast = ast->child[0]; + znode expr_node; + zend_op *opline; + + zend_do_extended_fcall_begin(TSRMLS_C); + zend_compile_expr(&expr_node, expr_ast TSRMLS_CC); + + opline = zend_emit_op(result, ZEND_INCLUDE_OR_EVAL, &expr_node, NULL TSRMLS_CC); + opline->extended_value = ast->attr; + + zend_do_extended_fcall_end(TSRMLS_C); +} + +void zend_compile_isset_or_empty(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast *var_ast = ast->child[0]; + + znode var_node; + zend_op *opline; + + ZEND_ASSERT(ast->kind == ZEND_AST_ISSET || ast->kind == ZEND_AST_EMPTY); + + if (!zend_is_variable(var_ast) || zend_is_call(var_ast)) { + if (ast->kind == ZEND_AST_EMPTY) { + /* empty(expr) can be transformed to !expr */ + zend_ast *not_ast = zend_ast_create_ex(ZEND_AST_UNARY_OP, ZEND_BOOL_NOT, var_ast); + zend_compile_expr(result, not_ast TSRMLS_CC); + return; + } else { + zend_error_noreturn(E_COMPILE_ERROR, + "Cannot use isset() on the result of an expression " + "(you can use \"null !== expression\" instead)"); + } + } + + switch (var_ast->kind) { + case ZEND_AST_VAR: + if (zend_try_compile_cv(&var_node, var_ast TSRMLS_CC) == SUCCESS) { + opline = zend_emit_op(result, ZEND_ISSET_ISEMPTY_VAR, &var_node, NULL TSRMLS_CC); + opline->extended_value = ZEND_FETCH_LOCAL | ZEND_QUICK_SET; + } else { + opline = zend_compile_simple_var_no_cv(result, var_ast, BP_VAR_IS TSRMLS_CC); + opline->opcode = ZEND_ISSET_ISEMPTY_VAR; } - retval = ';'; /* implicit ; */ break; - case T_OPEN_TAG_WITH_ECHO: - retval = T_ECHO; + case ZEND_AST_DIM: + opline = zend_compile_dim_common(result, var_ast, BP_VAR_IS TSRMLS_CC); + opline->opcode = ZEND_ISSET_ISEMPTY_DIM_OBJ; + break; + case ZEND_AST_PROP: + opline = zend_compile_prop_common(result, var_ast, BP_VAR_IS TSRMLS_CC); + opline->opcode = ZEND_ISSET_ISEMPTY_PROP_OBJ; break; + case ZEND_AST_STATIC_PROP: + opline = zend_compile_static_prop_common(result, var_ast, BP_VAR_IS TSRMLS_CC); + opline->opcode = ZEND_ISSET_ISEMPTY_VAR; + break; + EMPTY_SWITCH_DEFAULT_CASE() } - zendlval->op_type = IS_CONST; - return retval; + opline->result_type = IS_TMP_VAR; + opline->extended_value |= ast->kind == ZEND_AST_ISSET ? ZEND_ISSET : ZEND_ISEMPTY; } -/* }}} */ - -ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify_handlers TSRMLS_DC) /* {{{ */ -{ - zend_bool persistent_hashes = (ce->type == ZEND_INTERNAL_CLASS) ? 1 : 0; - dtor_func_t zval_ptr_dtor_func = ((persistent_hashes) ? ZVAL_INTERNAL_PTR_DTOR : ZVAL_PTR_DTOR); - - ce->refcount = 1; - ce->ce_flags = ZEND_ACC_CONSTANTS_UPDATED; - ce->default_properties_table = NULL; - ce->default_static_members_table = NULL; - zend_hash_init_ex(&ce->properties_info, 8, NULL, (persistent_hashes ? zend_destroy_property_info_internal : zend_destroy_property_info), persistent_hashes, 0); - zend_hash_init_ex(&ce->constants_table, 8, NULL, zval_ptr_dtor_func, persistent_hashes, 0); - zend_hash_init_ex(&ce->function_table, 8, NULL, ZEND_FUNCTION_DTOR, persistent_hashes, 0); +void zend_compile_silence(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast *expr_ast = ast->child[0]; + znode silence_node; - if (ce->type == ZEND_INTERNAL_CLASS) { -#ifdef ZTS - int n = zend_hash_num_elements(CG(class_table)); + zend_emit_op_tmp(&silence_node, ZEND_BEGIN_SILENCE, NULL, NULL TSRMLS_CC); - if (CG(static_members_table) && n >= CG(last_static_member)) { - /* Support for run-time declaration: dl() */ - CG(last_static_member) = n+1; - CG(static_members_table) = realloc(CG(static_members_table), (n+1)*sizeof(zval*)); - CG(static_members_table)[n] = NULL; - } - ce->static_members_table = (zval*)(zend_intptr_t)n; -#else - ce->static_members_table = NULL; -#endif + if (expr_ast->kind == ZEND_AST_VAR) { + /* For @$var we need to force a FETCH instruction, otherwise the CV access will + * happen outside the silenced section. */ + zend_compile_simple_var_no_cv(result, expr_ast, BP_VAR_R TSRMLS_CC); } else { - ce->static_members_table = ce->default_static_members_table; - ce->info.user.doc_comment = NULL; + zend_compile_expr(result, expr_ast TSRMLS_CC); } - ce->default_properties_count = 0; - ce->default_static_members_count = 0; - - if (nullify_handlers) { - ce->constructor = NULL; - ce->destructor = NULL; - ce->clone = NULL; - ce->__get = NULL; - ce->__set = NULL; - ce->__unset = NULL; - ce->__isset = NULL; - ce->__call = NULL; - ce->__callstatic = NULL; - ce->__tostring = NULL; - ce->create_object = NULL; - ce->get_iterator = NULL; - ce->iterator_funcs.funcs = NULL; - ce->interface_gets_implemented = NULL; - ce->get_static_method = NULL; - ce->parent = NULL; - ce->num_interfaces = 0; - ce->interfaces = NULL; - ce->num_traits = 0; - ce->traits = NULL; - ce->trait_aliases = NULL; - ce->trait_precedences = NULL; - ce->serialize = NULL; - ce->unserialize = NULL; - ce->serialize_func = NULL; - ce->unserialize_func = NULL; - ce->__debugInfo = NULL; - if (ce->type == ZEND_INTERNAL_CLASS) { - ce->info.internal.module = NULL; - ce->info.internal.builtin_functions = NULL; - } - } + zend_emit_op(NULL, ZEND_END_SILENCE, &silence_node, NULL TSRMLS_CC); } -/* }}} */ -int zend_get_class_fetch_type(const char *class_name, uint class_name_len) /* {{{ */ -{ - if ((class_name_len == sizeof("self")-1) && - !strncasecmp(class_name, "self", sizeof("self")-1)) { - return ZEND_FETCH_CLASS_SELF; - } else if ((class_name_len == sizeof("parent")-1) && - !strncasecmp(class_name, "parent", sizeof("parent")-1)) { - return ZEND_FETCH_CLASS_PARENT; - } else if ((class_name_len == sizeof("static")-1) && - !strncasecmp(class_name, "static", sizeof("static")-1)) { - return ZEND_FETCH_CLASS_STATIC; - } else { - return ZEND_FETCH_CLASS_DEFAULT; - } -} -/* }}} */ +void zend_compile_shell_exec(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast *expr_ast = ast->child[0]; -ZEND_API zend_string *zend_get_compiled_variable_name(const zend_op_array *op_array, zend_uint var) /* {{{ */ -{ - return op_array->vars[EX_VAR_TO_NUM(var)]; + zval fn_name; + zend_ast *name_ast, *args_ast, *call_ast; + + ZVAL_STRING(&fn_name, "shell_exec"); + name_ast = zend_ast_create_zval(&fn_name); + args_ast = (zend_ast *) zend_ast_create_list(1, ZEND_AST_ARG_LIST, expr_ast); + call_ast = zend_ast_create(ZEND_AST_CALL, name_ast, args_ast); + + zend_compile_expr(result, call_ast TSRMLS_CC); + + zval_ptr_dtor(&fn_name); } -/* }}} */ -void zend_do_build_namespace_name(znode *result, znode *prefix, znode *name TSRMLS_DC) /* {{{ */ -{ - if (prefix) { - *result = *prefix; - if (Z_TYPE(result->u.constant) == IS_STRING && - Z_STRLEN(result->u.constant) == 0) { - /* namespace\ */ - if (Z_TYPE(CG(current_namespace)) != IS_UNDEF) { - znode tmp; - - zval_dtor(&result->u.constant); - tmp.op_type = IS_CONST; - ZVAL_DUP(&tmp.u.constant, &CG(current_namespace)); - zend_do_build_namespace_name(result, NULL, &tmp TSRMLS_CC); - } - } - } else { +void zend_compile_array(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast_list *list = zend_ast_get_list(ast); + zend_op *opline; + zend_uint i, opnum_init; + zend_bool packed = 1; + + if (zend_try_ct_eval_array(&result->u.constant, ast TSRMLS_CC)) { result->op_type = IS_CONST; - ZVAL_EMPTY_STRING(&result->u.constant); + return; } - /* prefix = result */ - zend_do_build_full_name(NULL, result, name, 0 TSRMLS_CC); -} -/* }}} */ -void zend_do_begin_namespace(znode *name, zend_bool with_bracket TSRMLS_DC) /* {{{ */ -{ - char *lcname; + opnum_init = get_next_op_number(CG(active_op_array)); - /* handle mixed syntax declaration or nested namespaces */ - if (!CG(has_bracketed_namespaces)) { - if (Z_TYPE(CG(current_namespace)) != IS_UNDEF) { - /* previous namespace declarations were unbracketed */ - if (with_bracket) { - zend_error_noreturn(E_COMPILE_ERROR, "Cannot mix bracketed namespace declarations with unbracketed namespace declarations"); - } - } - } else { - /* previous namespace declarations were bracketed */ - if (!with_bracket) { - zend_error_noreturn(E_COMPILE_ERROR, "Cannot mix bracketed namespace declarations with unbracketed namespace declarations"); - } else if (Z_TYPE(CG(current_namespace)) != IS_UNDEF || CG(in_namespace)) { - zend_error_noreturn(E_COMPILE_ERROR, "Namespace declarations cannot be nested"); - } - } + for (i = 0; i < list->children; ++i) { + zend_ast *elem_ast = list->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 (((!with_bracket && Z_TYPE(CG(current_namespace)) == IS_UNDEF) || (with_bracket && !CG(has_bracketed_namespaces))) && CG(active_op_array)->last > 0) { - /* ignore ZEND_EXT_STMT and ZEND_TICKS */ - int num = CG(active_op_array)->last; - while (num > 0 && - (CG(active_op_array)->opcodes[num-1].opcode == ZEND_EXT_STMT || - CG(active_op_array)->opcodes[num-1].opcode == ZEND_TICKS)) { - --num; - } - if (num > 0) { - zend_error_noreturn(E_COMPILE_ERROR, "Namespace declaration statement has to be the very first statement in the script"); - } - } + znode value_node, key_node, *key_node_ptr = NULL; - CG(in_namespace) = 1; - if (with_bracket) { - CG(has_bracketed_namespaces) = 1; - } + if (key_ast) { + zend_compile_expr(&key_node, key_ast TSRMLS_CC); + zend_handle_numeric_op(&key_node TSRMLS_CC); + key_node_ptr = &key_node; + } - if (name) { - lcname = zend_str_tolower_dup(Z_STRVAL(name->u.constant), Z_STRLEN(name->u.constant)); - if (((Z_STRLEN(name->u.constant) == sizeof("self")-1) && - !memcmp(lcname, "self", sizeof("self")-1)) || - ((Z_STRLEN(name->u.constant) == sizeof("parent")-1) && - !memcmp(lcname, "parent", sizeof("parent")-1))) { - zend_error_noreturn(E_COMPILE_ERROR, "Cannot use '%s' as namespace name", Z_STRVAL(name->u.constant)); + if (by_ref) { + zend_ensure_writable_variable(value_ast); + zend_compile_var(&value_node, value_ast, BP_VAR_W TSRMLS_CC); + } else { + zend_compile_expr(&value_node, value_ast TSRMLS_CC); } - efree(lcname); - if (Z_TYPE(CG(current_namespace)) != IS_UNDEF) { - zval_dtor(&CG(current_namespace)); + if (i == 0) { + opline = zend_emit_op_tmp(result, ZEND_INIT_ARRAY, &value_node, key_node_ptr TSRMLS_CC); + opline->extended_value = list->children << ZEND_ARRAY_SIZE_SHIFT; + } else { + opline = zend_emit_op(NULL, ZEND_ADD_ARRAY_ELEMENT, + &value_node, key_node_ptr TSRMLS_CC); + SET_NODE(opline->result, result); } - ZVAL_COPY_VALUE(&CG(current_namespace), &name->u.constant); - } else { - if (Z_TYPE(CG(current_namespace)) != IS_UNDEF) { - zval_dtor(&CG(current_namespace)); - ZVAL_UNDEF(&CG(current_namespace)); + opline->extended_value |= by_ref; + + if (key_ast && key_node.op_type == IS_CONST && Z_TYPE(key_node.u.constant) == IS_STRING) { + packed = 0; } } diff --cc Zend/zend_compile.h index d3d81d0,fa33354..0d343f0 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@@ -450,17 -461,61 +450,16 @@@ typedef int (*unary_op_type)(zval *, zv typedef int (*binary_op_type)(zval *, zval *, zval * TSRMLS_DC); ZEND_API unary_op_type get_unary_op(int opcode); ZEND_API binary_op_type get_binary_op(int opcode); - ZEND_API void zend_make_immutable_array(zval *zv TSRMLS_DC); -void zend_do_while_cond(znode *expr, znode *close_bracket_token TSRMLS_DC); -void zend_do_while_end(const znode *while_token, const znode *close_bracket_token TSRMLS_DC); -void zend_do_do_while_begin(TSRMLS_D); -void zend_do_do_while_end(const znode *do_token, const znode *expr_open_bracket, znode *expr TSRMLS_DC); - - -void zend_do_if_cond(znode *cond, znode *closing_bracket_token TSRMLS_DC); -void zend_do_if_after_statement(const znode *closing_bracket_token, unsigned char initialize TSRMLS_DC); -void zend_do_if_end(TSRMLS_D); - -void zend_do_for_cond(znode *expr, znode *second_semicolon_token TSRMLS_DC); -void zend_do_for_before_statement(const znode *cond_start, const znode *second_semicolon_token TSRMLS_DC); -void zend_do_for_end(const znode *second_semicolon_token TSRMLS_DC); - -void zend_do_pre_incdec(znode *result, znode *op1, zend_uchar op TSRMLS_DC); -void zend_do_post_incdec(znode *result, znode *op1, zend_uchar op TSRMLS_DC); - -void zend_do_begin_variable_parse(TSRMLS_D); -void zend_do_end_variable_parse(znode *variable, int type, int arg_offset TSRMLS_DC); - -void zend_check_writable_variable(const znode *variable); +void zend_stop_lexing(TSRMLS_D); +void zend_emit_final_return(zval *zv TSRMLS_DC); +zend_ast *zend_ast_append_str(zend_ast *left, zend_ast *right); +zend_uint zend_add_member_modifier(zend_uint flags, zend_uint new_flag); +zend_ast_list *zend_ast_append_doc_comment(zend_ast_list *list TSRMLS_DC); +/* parser-driven code generators */ void zend_do_free(znode *op1 TSRMLS_DC); -void zend_do_add_string(znode *result, znode *op1, znode *op2 TSRMLS_DC); -void zend_do_add_variable(znode *result, znode *op1, znode *op2 TSRMLS_DC); - -int zend_do_verify_access_types(const znode *current_access_type, const znode *new_modifier); -void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, znode *fn_flags_znode TSRMLS_DC); -void zend_do_end_function_declaration(const znode *function_token TSRMLS_DC); -void zend_do_receive_param(zend_uchar op, znode *varname, znode *initialization, znode *class_type, zend_bool pass_by_reference, zend_bool is_variadic TSRMLS_DC); -int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace TSRMLS_DC); -void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC); -void zend_do_clone(znode *result, znode *expr TSRMLS_DC); -void zend_do_begin_dynamic_function_call(znode *function_name, int prefix_len TSRMLS_DC); -void zend_do_fetch_class(znode *result, znode *class_name TSRMLS_DC); -void zend_do_build_full_name(znode *result, znode *prefix, znode *name, int is_class_member TSRMLS_DC); -int zend_do_begin_class_member_function_call(znode *class_name, znode *method_name TSRMLS_DC); -void zend_do_end_function_call(znode *function_name, znode *result, int is_method, int is_dynamic_fcall TSRMLS_DC); -void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC); -void zend_do_yield(znode *result, znode *value, znode *key, zend_bool is_variable TSRMLS_DC); -void zend_do_handle_exception(TSRMLS_D); - -void zend_do_begin_lambda_function_declaration(znode *result, znode *function_token, int return_reference, int is_static TSRMLS_DC); -void zend_do_fetch_lexical_variable(znode *varname, zend_bool is_ref TSRMLS_DC); - -void zend_do_try(znode *try_token TSRMLS_DC); -void zend_do_begin_catch(znode *try_token, znode *catch_class, znode *catch_var, znode *first_catch TSRMLS_DC); -void zend_do_bind_catch(znode *try_token, znode *catch_token TSRMLS_DC); -void zend_do_end_catch(znode *catch_token TSRMLS_DC); -void zend_do_finally(znode *finally_token TSRMLS_DC); -void zend_do_end_finally(znode *try_token, znode* catch_token, znode *finally_token TSRMLS_DC); -void zend_do_throw(znode *expr TSRMLS_DC); - ZEND_API int do_bind_function(const zend_op_array *op_array, zend_op *opline, HashTable *function_table, zend_bool compile_time TSRMLS_DC); ZEND_API zend_class_entry *do_bind_class(const zend_op_array *op_array, const zend_op *opline, HashTable *class_table, zend_bool compile_time TSRMLS_DC); ZEND_API zend_class_entry *do_bind_inherited_class(const zend_op_array *op_array, const zend_op *opline, HashTable *class_table, zend_class_entry *parent_ce, zend_bool compile_time TSRMLS_DC);
diff --cc Zend/zend_ast.c index 2dd5b16,810b9b1..8e1d970 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@@ -224,25 -273,31 +223,36 @@@ ZEND_API void zend_ast_evaluate(zval *r zval_dtor(&op1); zval_dtor(&op2); break; - case ZEND_IS_SMALLER_OR_EQUAL: - zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC); - zend_ast_evaluate(&op2, (&ast->u.child)[1], scope TSRMLS_CC); - is_smaller_or_equal_function(result, &op1, &op2 TSRMLS_CC); + } + case ZEND_AST_UNARY_OP: + { + unary_op_type op = get_unary_op(ast->attr); + zend_ast_evaluate(&op1, ast->child[0], scope TSRMLS_CC); + op(result, &op1 TSRMLS_CC); zval_dtor(&op1); - zval_dtor(&op2); break; - case ZEND_CONST: - /* class constants may be updated in-place */ + } + case ZEND_AST_ZVAL: - ZVAL_DUP(result, zend_ast_get_zval(ast)); - if (Z_OPT_CONSTANT_P(result)) { - zval_update_constant_ex(result, 1, scope TSRMLS_CC); ++ { ++ zval *zv = zend_ast_get_zval(ast); + if (scope) { - if (Z_OPT_CONSTANT(ast->u.val)) { - zval_update_constant_ex(&ast->u.val, 1, scope TSRMLS_CC); ++ /* class constants may be updated in-place */ ++ if (Z_OPT_CONSTANT_P(zv)) { ++ zval_update_constant_ex(zv, 1, scope TSRMLS_CC); + } - ZVAL_DUP(result, &ast->u.val); ++ ZVAL_DUP(result, zv); + } else { - ZVAL_DUP(result, &ast->u.val); ++ ZVAL_DUP(result, zv); + if (Z_OPT_CONSTANT_P(result)) { + zval_update_constant_ex(result, 1, scope TSRMLS_CC); + } } break; - case ZEND_BOOL_AND: - zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC); ++ } + case ZEND_AST_AND: + zend_ast_evaluate(&op1, ast->child[0], scope TSRMLS_CC); if (zend_is_true(&op1 TSRMLS_CC)) { - zend_ast_evaluate(&op2, (&ast->u.child)[1], scope TSRMLS_CC); + zend_ast_evaluate(&op2, ast->child[1], scope TSRMLS_CC); ZVAL_BOOL(result, zend_is_true(&op2 TSRMLS_CC)); zval_dtor(&op2); } else { @@@ -304,15 -357,13 +314,13 @@@ } } break; - //??? - #if 0 case ZEND_FETCH_DIM_R: -- zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC); -- zend_ast_evaluate(&op2, (&ast->u.child)[1], scope TSRMLS_CC); ++ zend_ast_evaluate(&op1, ast->child[0], scope TSRMLS_CC); ++ zend_ast_evaluate(&op2, ast->child[1], scope TSRMLS_CC); { - zval *tmp; + zval tmp; zend_fetch_dimension_by_zval(&tmp, &op1, &op2 TSRMLS_CC); - ZVAL_ZVAL(result, tmp, 1, 1); + ZVAL_ZVAL(result, &tmp, 1, 1); } zval_dtor(&op1); zval_dtor(&op2); diff --cc Zend/zend_compile.c index 5a3359e,ae26733..5e0ed6c --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@@ -3055,476 -3721,246 +3055,438 @@@ ZEND_API void zend_initialize_class_dat } /* }}} */ -#define REALLOC_BUF_IF_EXCEED(buf, offset, length, size) \ - if (UNEXPECTED(offset - buf + size >= length)) { \ - length += size + 1; \ - buf = erealloc(buf, length); \ +zend_uint zend_get_class_fetch_type(zend_string *name) { + if (name->len == sizeof("self") - 1 && + !strncasecmp(name->val, "self", sizeof("self") - 1)) { + return ZEND_FETCH_CLASS_SELF; + } else if (name->len == sizeof("parent") - 1 && + !strncasecmp(name->val, "parent", sizeof("parent") - 1)) { + return ZEND_FETCH_CLASS_PARENT; + } else if (name->len == sizeof("static") - 1 && + !strncasecmp(name->val, "static", sizeof("static") - 1)) { + return ZEND_FETCH_CLASS_STATIC; + } else { + return ZEND_FETCH_CLASS_DEFAULT; } +} -static char * zend_get_function_declaration(zend_function *fptr TSRMLS_DC) /* {{{ */ +ZEND_API zend_string *zend_get_compiled_variable_name(const zend_op_array *op_array, zend_uint var) /* {{{ */ { - char *offset, *buf; - zend_uint length = 1024; + return op_array->vars[EX_VAR_TO_NUM(var)]; +} +/* }}} */ - offset = buf = (char *)emalloc(length * sizeof(char)); - if (fptr->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { - *(offset++) = '&'; - *(offset++) = ' '; +zend_ast *zend_ast_append_str(zend_ast *left_ast, zend_ast *right_ast) { + zval *left_zv = zend_ast_get_zval(left_ast); + zend_string *left = Z_STR_P(left_zv); + zend_string *right = zend_ast_get_str(right_ast); + + zend_string *result; + size_t left_len = left->len; + size_t len = left_len + right->len + 1; /* left\right */ + + result = STR_REALLOC(left, len, 0); + result->val[left_len] = '\\'; + memcpy(&result->val[left_len + 1], right->val, right->len); + result->val[len] = '\0'; + STR_RELEASE(right); + + ZVAL_STR(left_zv, result); + return left_ast; +} + +/* A hacky way that is used to store the doc comment for properties */ +zend_ast_list *zend_ast_append_doc_comment(zend_ast_list *list TSRMLS_DC) { + if (CG(doc_comment)) { + list = zend_ast_list_add(list, zend_ast_create_zval_from_str(CG(doc_comment))); + CG(doc_comment) = NULL; } - if (fptr->common.scope) { - memcpy(offset, fptr->common.scope->name->val, fptr->common.scope->name->len); - offset += fptr->common.scope->name->len; - *(offset++) = ':'; - *(offset++) = ':'; + return list; +} + +void zend_verify_namespace(TSRMLS_D) /* {{{ */ +{ + if (CG(has_bracketed_namespaces) && !CG(in_namespace)) { + zend_error_noreturn(E_COMPILE_ERROR, "No code may exist outside of namespace {}"); } +} +/* }}} */ - { - size_t name_len = fptr->common.function_name->len; - REALLOC_BUF_IF_EXCEED(buf, offset, length, name_len); - memcpy(offset, fptr->common.function_name->val, name_len); - offset += name_len; +static void zend_reset_import_tables(TSRMLS_D) { + if (CG(current_import)) { + zend_hash_destroy(CG(current_import)); + efree(CG(current_import)); + CG(current_import) = NULL; } - *(offset++) = '('; - if (fptr->common.arg_info) { - zend_uint i, required; - zend_arg_info *arg_info = fptr->common.arg_info; + if (CG(current_import_function)) { + zend_hash_destroy(CG(current_import_function)); + efree(CG(current_import_function)); + CG(current_import_function) = NULL; + } - required = fptr->common.required_num_args; - for (i = 0; i < fptr->common.num_args;) { - if (arg_info->class_name) { - const char *class_name; - zend_uint class_name_len; - if (!strcasecmp(arg_info->class_name, "self") && fptr->common.scope ) { - class_name = fptr->common.scope->name->val; - class_name_len = fptr->common.scope->name->len; - } else if (!strcasecmp(arg_info->class_name, "parent") && fptr->common.scope->parent) { - class_name = fptr->common.scope->parent->name->val; - class_name_len = fptr->common.scope->parent->name->len; - } else { - class_name = arg_info->class_name; - class_name_len = arg_info->class_name_len; - } - REALLOC_BUF_IF_EXCEED(buf, offset, length, class_name_len); - memcpy(offset, class_name, class_name_len); - offset += class_name_len; - *(offset++) = ' '; - } else if (arg_info->type_hint) { - zend_uint type_name_len; - char *type_name = zend_get_type_by_const(arg_info->type_hint); - type_name_len = strlen(type_name); - REALLOC_BUF_IF_EXCEED(buf, offset, length, type_name_len); - memcpy(offset, type_name, type_name_len); - offset += type_name_len; - *(offset++) = ' '; - } + if (CG(current_import_const)) { + zend_hash_destroy(CG(current_import_const)); + efree(CG(current_import_const)); + CG(current_import_const) = NULL; + } +} + +static void zend_end_namespace(TSRMLS_D) { + CG(in_namespace) = 0; + zend_reset_import_tables(TSRMLS_C); + if (CG(current_namespace)) { + STR_RELEASE(CG(current_namespace)); + CG(current_namespace) = NULL; + } +} + +void zend_do_end_compilation(TSRMLS_D) /* {{{ */ +{ + CG(has_bracketed_namespaces) = 0; + zend_end_namespace(TSRMLS_C); +} +/* }}} */ + - ZEND_API void zend_make_immutable_array(zval *zv TSRMLS_DC) /* {{{ */ - { - zend_constant *c; - - if (Z_IMMUTABLE_P(zv)) { - return; - } - - Z_TYPE_FLAGS_P(zv) = IS_TYPE_IMMUTABLE; - GC_REFCOUNT(Z_COUNTED_P(zv)) = 2; - Z_ARRVAL_P(zv)->u.flags &= ~HASH_FLAG_APPLY_PROTECTION; - - /* store as an anonymous constant */ - c = emalloc(sizeof(zend_constant)); - ZVAL_COPY_VALUE(&c->value, zv); - c->flags = 0; - c->name = NULL; - c->module_number = PHP_USER_CONSTANT; - zend_hash_next_index_insert_ptr(EG(zend_constants), c); - } - /* }}} */ - - void zend_make_immutable_array_r(zval *zv TSRMLS_DC) /* {{{ */ - { - zval *el; - - if (Z_IMMUTABLE_P(zv)) { - return; - } - zend_make_immutable_array(zv TSRMLS_CC); - ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zv), el) { - if (Z_TYPE_P(el) == IS_ARRAY) { - zend_make_immutable_array_r(el TSRMLS_CC); - } - } ZEND_HASH_FOREACH_END(); - } - /* }}} */ - +/* {{{ zend_dirname + Returns directory name component of path */ +ZEND_API size_t zend_dirname(char *path, size_t len) +{ + register char *end = path + len - 1; + unsigned int len_adjust = 0; + +#ifdef PHP_WIN32 + /* Note that on Win32 CWD is per drive (heritage from CP/M). + * This means dirname("c:foo") maps to "c:." or "c:" - which means CWD on C: drive. + */ + if ((2 <= len) && isalpha((int)((unsigned char *)path)[0]) && (':' == path[1])) { + /* Skip over the drive spec (if any) so as not to change */ + path += 2; + len_adjust += 2; + if (2 == len) { + /* Return "c:" on Win32 for dirname("c:"). + * It would be more consistent to return "c:." + * but that would require making the string *longer*. + */ + return len; + } + } +#elif defined(NETWARE) + /* + * Find the first occurrence of : from the left + * move the path pointer to the position just after : + * increment the len_adjust to the length of path till colon character(inclusive) + * If there is no character beyond : simple return len + */ + char *colonpos = NULL; + colonpos = strchr(path, ':'); + if (colonpos != NULL) { + len_adjust = ((colonpos - path) + 1); + path += len_adjust; + if (len_adjust == len) { + return len; + } + } +#endif + + if (len == 0) { + /* Illegal use of this function */ + return 0; + } + + /* Strip trailing slashes */ + while (end >= path && IS_SLASH_P(end)) { + end--; + } + if (end < path) { + /* The path only contained slashes */ + path[0] = DEFAULT_SLASH; + path[1] = '\0'; + return 1 + len_adjust; + } + + /* Strip filename */ + while (end >= path && !IS_SLASH_P(end)) { + end--; + } + if (end < path) { + /* No slash found, therefore return '.' */ +#ifdef NETWARE + if (len_adjust == 0) { + path[0] = '.'; + path[1] = '\0'; + return 1; /* only one character */ + } else { + path[0] = '\0'; + return len_adjust; + } +#else + path[0] = '.'; + path[1] = '\0'; + return 1 + len_adjust; +#endif + } + + /* Strip slashes which came before the file name */ + while (end >= path && IS_SLASH_P(end)) { + end--; + } + if (end < path) { + path[0] = DEFAULT_SLASH; + path[1] = '\0'; + return 1 + len_adjust; + } + *(end+1) = '\0'; + + return (size_t)(end + 1 - path) + len_adjust; +} +/* }}} */ + +static inline zend_bool zend_str_equals_str(zend_string *str1, zend_string *str2) { + return str1->len == str2->len && !memcmp(str1->val, str2->val, str2->len); +} +static inline zend_bool zend_str_equals_str_ci(zend_string *str1, zend_string *str2) { + return str1->len == str2->len + && !zend_binary_strcasecmp(str1->val, str1->len, str2->val, str2->len); +} + +#define zend_str_equals_literal(str, c) \ + ((str)->len == sizeof(c) - 1 && !memcmp((str)->val, (c), sizeof(c) - 1)) +#define zend_str_equals_literal_ci(str, c) \ + ((str)->len == sizeof(c) - 1 \ + && !zend_binary_strcasecmp((str)->val, (str)->len, (c), sizeof(c) - 1)) + +static void zend_adjust_for_fetch_type(zend_op *opline, zend_uint type) { + switch (type & BP_VAR_MASK) { + case BP_VAR_R: + return; + case BP_VAR_W: + opline->opcode += 3; + return; + case BP_VAR_REF: + opline->opcode += 3; + opline->extended_value |= ZEND_FETCH_MAKE_REF; + return; + case BP_VAR_RW: + opline->opcode += 6; + return; + case BP_VAR_IS: + opline->opcode += 9; + return; + case BP_VAR_FUNC_ARG: + opline->opcode += 12; + opline->extended_value |= type >> BP_VAR_SHIFT; + return; + case BP_VAR_UNSET: + opline->opcode += 15; + return; + EMPTY_SWITCH_DEFAULT_CASE() + } +} + +static inline void zend_make_var_result(znode *result, zend_op *opline TSRMLS_DC) { + opline->result_type = IS_VAR; + opline->result.var = get_temporary_variable(CG(active_op_array)); + GET_NODE(result, opline->result); +} + +static inline void zend_make_tmp_result(znode *result, zend_op *opline TSRMLS_DC) { + opline->result_type = IS_TMP_VAR; + opline->result.var = get_temporary_variable(CG(active_op_array)); + GET_NODE(result, opline->result); +} + +static zend_op *zend_emit_op(znode *result, zend_uchar opcode, znode *op1, znode *op2 TSRMLS_DC) { + zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); + opline->opcode = opcode; + + if (op1 == NULL) { + SET_UNUSED(opline->op1); + } else { + SET_NODE(opline->op1, op1); + } + + if (op2 == NULL) { + SET_UNUSED(opline->op2); + } else { + SET_NODE(opline->op2, op2); + } + + if (result) { + zend_make_var_result(result, opline TSRMLS_CC); + } + return opline; +} + +static zend_op *zend_emit_op_tmp( + znode *result, zend_uchar opcode, znode *op1, znode *op2 TSRMLS_DC +) { + zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); + opline->opcode = opcode; + + if (op1 == NULL) { + SET_UNUSED(opline->op1); + } else { + SET_NODE(opline->op1, op1); + } - if (arg_info->pass_by_reference) { - *(offset++) = '&'; - } + if (op2 == NULL) { + SET_UNUSED(opline->op2); + } else { + SET_NODE(opline->op2, op2); + } - if (arg_info->is_variadic) { - *(offset++) = '.'; - *(offset++) = '.'; - *(offset++) = '.'; - } + zend_make_tmp_result(result, opline TSRMLS_CC); - *(offset++) = '$'; + return opline; +} - if (arg_info->name) { - REALLOC_BUF_IF_EXCEED(buf, offset, length, arg_info->name_len); - memcpy(offset, arg_info->name, arg_info->name_len); - offset += arg_info->name_len; - } else { - zend_uint idx = i; - memcpy(offset, "param", 5); - offset += 5; - do { - *(offset++) = (char) (idx % 10) + '0'; - idx /= 10; - } while (idx > 0); - } - if (i >= required && !arg_info->is_variadic) { - *(offset++) = ' '; - *(offset++) = '='; - *(offset++) = ' '; - if (fptr->type == ZEND_USER_FUNCTION) { - zend_op *precv = NULL; - { - zend_uint idx = i; - zend_op *op = ((zend_op_array *)fptr)->opcodes; - zend_op *end = op + ((zend_op_array *)fptr)->last; +static void zend_emit_tick(TSRMLS_D) { + zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); - ++idx; - while (op < end) { - if ((op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT) - && op->op1.num == (long)idx) - { - precv = op; - } - ++op; - } - } - if (precv && precv->opcode == ZEND_RECV_INIT && precv->op2_type != IS_UNUSED) { - zval *zv = precv->op2.zv; + opline->opcode = ZEND_TICKS; + SET_UNUSED(opline->op1); + SET_UNUSED(opline->op2); + opline->extended_value = Z_LVAL(CG(declarables).ticks); +} - if (Z_TYPE_P(zv) == IS_CONSTANT) { - REALLOC_BUF_IF_EXCEED(buf, offset, length, Z_STRLEN_P(zv)); - memcpy(offset, Z_STRVAL_P(zv), Z_STRLEN_P(zv)); - offset += Z_STRLEN_P(zv); - } else if (Z_TYPE_P(zv) == IS_FALSE) { - memcpy(offset, "false", 5); - offset += 5; - } else if (Z_TYPE_P(zv) == IS_TRUE) { - memcpy(offset, "true", 4); - offset += 4; - } else if (Z_TYPE_P(zv) == IS_NULL) { - memcpy(offset, "NULL", 4); - offset += 4; - } else if (Z_TYPE_P(zv) == IS_STRING) { - *(offset++) = '\''; - REALLOC_BUF_IF_EXCEED(buf, offset, length, MIN(Z_STRLEN_P(zv), 10)); - memcpy(offset, Z_STRVAL_P(zv), MIN(Z_STRLEN_P(zv), 10)); - offset += MIN(Z_STRLEN_P(zv), 10); - if (Z_STRLEN_P(zv) > 10) { - *(offset++) = '.'; - *(offset++) = '.'; - *(offset++) = '.'; - } - *(offset++) = '\''; - } else if (Z_TYPE_P(zv) == IS_ARRAY) { - memcpy(offset, "Array", 5); - offset += 5; - } else if (Z_TYPE_P(zv) == IS_CONSTANT_AST) { - memcpy(offset, "<expression>", 12); - offset += 12; - } else { - zend_string *str = zval_get_string(zv); - REALLOC_BUF_IF_EXCEED(buf, offset, length, str->len); - memcpy(offset, str->val, str->len); - offset += str->len; - STR_RELEASE(str); - } - } - } else { - memcpy(offset, "NULL", 4); - offset += 4; - } - } +static inline zend_op *zend_emit_op_data(znode *value TSRMLS_DC) { + return zend_emit_op(NULL, ZEND_OP_DATA, value, NULL TSRMLS_CC); +} - if (++i < fptr->common.num_args) { - *(offset++) = ','; - *(offset++) = ' '; - } - arg_info++; - REALLOC_BUF_IF_EXCEED(buf, offset, length, 32); - } - } - *(offset++) = ')'; - *offset = '\0'; +static inline zend_uint zend_emit_jump(zend_uint opnum_target TSRMLS_DC) { + zend_uint opnum = get_next_op_number(CG(active_op_array)); + zend_op *opline = zend_emit_op(NULL, ZEND_JMP, NULL, NULL TSRMLS_CC); + opline->op1.opline_num = opnum_target; + return opnum; +} - return buf; +static inline zend_uint zend_emit_cond_jump( + zend_uchar opcode, znode *cond, zend_uint opnum_target TSRMLS_DC +) { + zend_uint opnum = get_next_op_number(CG(active_op_array)); + zend_op *opline = zend_emit_op(NULL, opcode, cond, NULL TSRMLS_CC); + opline->op2.opline_num = opnum_target; + return opnum; } -/* }}} */ -static void do_inheritance_check_on_method(zend_function *child, zend_function *parent TSRMLS_DC) /* {{{ */ -{ - zend_uint child_flags; - zend_uint parent_flags = parent->common.fn_flags; +static inline void zend_update_jump_target(zend_uint opnum_jump, zend_uint opnum_target TSRMLS_DC) { + zend_op *opline = &CG(active_op_array)->opcodes[opnum_jump]; + switch (opline->opcode) { + case ZEND_JMP: + opline->op1.opline_num = opnum_target; + break; + case ZEND_JMPZ: + case ZEND_JMPNZ: + case ZEND_JMPZ_EX: + case ZEND_JMPNZ_EX: + opline->op2.opline_num = opnum_target; + break; + EMPTY_SWITCH_DEFAULT_CASE() + } +} - if ((parent->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0 - && parent->common.fn_flags & ZEND_ACC_ABSTRACT - && parent->common.scope != (child->common.prototype ? child->common.prototype->common.scope : child->common.scope) - && child->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_IMPLEMENTED_ABSTRACT)) { - zend_error_noreturn(E_COMPILE_ERROR, "Can't inherit abstract function %s::%s() (previously declared abstract in %s)", - parent->common.scope->name->val, - child->common.function_name->val, - child->common.prototype ? child->common.prototype->common.scope->name->val : child->common.scope->name->val); +static inline void zend_update_jump_target_to_next(zend_uint opnum_jump TSRMLS_DC) { + zend_update_jump_target(opnum_jump, get_next_op_number(CG(active_op_array)) TSRMLS_CC); +} + +static inline zend_op *zend_delayed_emit_op( + znode *result, zend_uchar opcode, znode *op1, znode *op2 TSRMLS_DC +) { + zend_op tmp_opline; + init_op(&tmp_opline TSRMLS_CC); + tmp_opline.opcode = opcode; + SET_NODE(tmp_opline.op1, op1); + SET_NODE(tmp_opline.op2, op2); + if (result) { + zend_make_var_result(result, &tmp_opline TSRMLS_CC); } - if (parent_flags & ZEND_ACC_FINAL) { - zend_error_noreturn(E_COMPILE_ERROR, "Cannot override final method %s::%s()", ZEND_FN_SCOPE_NAME(parent), child->common.function_name->val); + zend_stack_push(&CG(delayed_oplines_stack), &tmp_opline); + return zend_stack_top(&CG(delayed_oplines_stack)); +} + +static inline zend_uint zend_delayed_compile_begin(TSRMLS_D) { + return zend_stack_count(&CG(delayed_oplines_stack)); +} + +static zend_op *zend_delayed_compile_end(zend_uint offset TSRMLS_DC) { + zend_op *opline, *oplines = zend_stack_base(&CG(delayed_oplines_stack)); + zend_uint i, count = zend_stack_count(&CG(delayed_oplines_stack)); + + ZEND_ASSERT(count > offset); + for (i = offset; i < count; ++i) { + opline = get_next_op(CG(active_op_array) TSRMLS_CC); + memcpy(opline, &oplines[i], sizeof(zend_op)); } + CG(delayed_oplines_stack).top = offset; + return opline; +} - child_flags = child->common.fn_flags; - /* You cannot change from static to non static and vice versa. - */ - if ((child_flags & ZEND_ACC_STATIC) != (parent_flags & ZEND_ACC_STATIC)) { - if (child->common.fn_flags & ZEND_ACC_STATIC) { - zend_error_noreturn(E_COMPILE_ERROR, "Cannot make non static method %s::%s() static in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name->val, ZEND_FN_SCOPE_NAME(child)); - } else { - zend_error_noreturn(E_COMPILE_ERROR, "Cannot make static method %s::%s() non static in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name->val, ZEND_FN_SCOPE_NAME(child)); - } +void zend_emit_final_return(zval *zv TSRMLS_DC) { + znode zn; + zend_bool returns_reference = (CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0; + + zn.op_type = IS_CONST; + if (zv) { + ZVAL_COPY_VALUE(&zn.u.constant, zv); + } else { + ZVAL_NULL(&zn.u.constant); } - /* Disallow making an inherited method abstract. */ - if ((child_flags & ZEND_ACC_ABSTRACT) && !(parent_flags & ZEND_ACC_ABSTRACT)) { - zend_error_noreturn(E_COMPILE_ERROR, "Cannot make non abstract method %s::%s() abstract in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name->val, ZEND_FN_SCOPE_NAME(child)); + zend_emit_op(NULL, returns_reference ? ZEND_RETURN_BY_REF : ZEND_RETURN, &zn, NULL TSRMLS_CC); +} + + +static inline zend_bool zend_is_variable(zend_ast *ast) { + return ast->kind == ZEND_AST_VAR || ast->kind == ZEND_AST_DIM + || ast->kind == ZEND_AST_PROP || ast->kind == ZEND_AST_STATIC_PROP + || ast->kind == ZEND_AST_CALL || ast->kind == ZEND_AST_METHOD_CALL + || ast->kind == ZEND_AST_STATIC_CALL; +} + +static inline zend_bool zend_is_call(zend_ast *ast) { + return ast->kind == ZEND_AST_CALL + || ast->kind == ZEND_AST_METHOD_CALL + || ast->kind == ZEND_AST_STATIC_CALL; +} + +static inline zend_bool zend_is_unticked_stmt(zend_ast *ast) { + return ast->kind == ZEND_AST_STMT_LIST || ast->kind == ZEND_AST_LABEL; +} + +static inline zend_bool zend_can_write_to_variable(zend_ast *ast) { + while (ast->kind == ZEND_AST_DIM || ast->kind == ZEND_AST_PROP) { + ast = ast->child[0]; } - if (parent_flags & ZEND_ACC_CHANGED) { - child->common.fn_flags |= ZEND_ACC_CHANGED; - } else { - /* Prevent derived classes from restricting access that was available in parent classes - */ - if ((child_flags & ZEND_ACC_PPP_MASK) > (parent_flags & ZEND_ACC_PPP_MASK)) { - zend_error_noreturn(E_COMPILE_ERROR, "Access level to %s::%s() must be %s (as in class %s)%s", ZEND_FN_SCOPE_NAME(child), child->common.function_name->val, zend_visibility_string(parent_flags), ZEND_FN_SCOPE_NAME(parent), (parent_flags&ZEND_ACC_PUBLIC) ? "" : " or weaker"); - } else if (((child_flags & ZEND_ACC_PPP_MASK) < (parent_flags & ZEND_ACC_PPP_MASK)) - && ((parent_flags & ZEND_ACC_PPP_MASK) & ZEND_ACC_PRIVATE)) { - child->common.fn_flags |= ZEND_ACC_CHANGED; - } + return zend_is_variable(ast); +} + +static inline zend_bool zend_is_const_default_class_ref(zend_ast *name_ast) { + zend_string *name; + + if (name_ast->kind != ZEND_AST_ZVAL) { + return 0; } - if (parent_flags & ZEND_ACC_PRIVATE) { - child->common.prototype = NULL; - } else if (parent_flags & ZEND_ACC_ABSTRACT) { - child->common.fn_flags |= ZEND_ACC_IMPLEMENTED_ABSTRACT; - child->common.prototype = parent; - } else if (!(parent->common.fn_flags & ZEND_ACC_CTOR) || (parent->common.prototype && (parent->common.prototype->common.scope->ce_flags & ZEND_ACC_INTERFACE))) { - /* ctors only have a prototype if it comes from an interface */ - child->common.prototype = parent->common.prototype ? parent->common.prototype : parent; + /* Fully qualified names are always default refs */ + if (!name_ast->attr) { + return 1; } - if (child->common.prototype && (child->common.prototype->common.fn_flags & ZEND_ACC_ABSTRACT)) { - if (!zend_do_perform_implementation_check(child, child->common.prototype TSRMLS_CC)) { - zend_error_noreturn(E_COMPILE_ERROR, "Declaration of %s::%s() must be compatible with %s", ZEND_FN_SCOPE_NAME(child), child->common.function_name->val, zend_get_function_declaration(child->common.prototype TSRMLS_CC)); - } - } else if (EG(error_reporting) & E_STRICT || Z_TYPE(EG(user_error_handler)) != IS_UNDEF) { /* Check E_STRICT (or custom error handler) before the check so that we save some time */ - if (!zend_do_perform_implementation_check(child, parent TSRMLS_CC)) { - char *method_prototype = zend_get_function_declaration(parent TSRMLS_CC); - zend_error(E_STRICT, "Declaration of %s::%s() should be compatible with %s", ZEND_FN_SCOPE_NAME(child), child->common.function_name->val, method_prototype); - efree(method_prototype); + name = zend_ast_get_str(name_ast); + return ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(name); +} + +static inline void zend_handle_numeric_op(znode *node TSRMLS_DC) { + if (node->op_type == IS_CONST && Z_TYPE(node->u.constant) == IS_STRING) { + zend_ulong index; + + if (ZEND_HANDLE_NUMERIC(Z_STR(node->u.constant), index)) { + zval_ptr_dtor(&node->u.constant); + ZVAL_LONG(&node->u.constant, index); } } } @@@ -6542,463 -6949,606 +6504,462 @@@ static zend_bool zend_try_ct_eval_array } } - zend_make_immutable_array(result TSRMLS_CC); - if (key->op_type != IS_UNUSED) { - znode key_node; + return 1; +} - opline = &CG(active_op_array)->opcodes[as_token->u.op.opline_num+1]; - opline->result_type = IS_TMP_VAR; - opline->result.opline_num = get_temporary_variable(CG(active_op_array)); - GET_NODE(&key_node, opline->result); +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; - zend_do_assign(&dummy, key, &key_node TSRMLS_CC); - zend_do_free(&dummy TSRMLS_CC); + znode left_node, right_node; + zend_compile_expr(&left_node, left_ast TSRMLS_CC); + zend_compile_expr(&right_node, right_ast TSRMLS_CC); + + if (left_node.op_type == IS_CONST && right_node.op_type == IS_CONST) { + result->op_type = IS_CONST; + zend_ct_eval_binary_op(&result->u.constant, opcode, + &left_node.u.constant, &right_node.u.constant TSRMLS_CC); + zval_ptr_dtor(&left_node.u.constant); + zval_ptr_dtor(&right_node.u.constant); + return; } - do_begin_loop(TSRMLS_C); - INC_BPC(CG(active_op_array)); + zend_emit_op_tmp(result, opcode, &left_node, &right_node TSRMLS_CC); } -/* }}} */ - -void zend_do_foreach_end(const znode *foreach_token, const znode *as_token TSRMLS_DC) /* {{{ */ -{ - zend_op *container_ptr; - zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); - opline->opcode = ZEND_JMP; - opline->op1.opline_num = as_token->u.op.opline_num; - SET_UNUSED(opline->op1); - SET_UNUSED(opline->op2); +/* We do not use zend_compile_binary_op for this because we want to retain the left-to-right + * evaluation order. */ +void zend_compile_greater(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast *left_ast = ast->child[0]; + zend_ast *right_ast = ast->child[1]; + znode left_node, right_node; - CG(active_op_array)->opcodes[foreach_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array)); /* FE_RESET */ - CG(active_op_array)->opcodes[as_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array)); /* FE_FETCH */ + ZEND_ASSERT(ast->kind == ZEND_AST_GREATER || ast->kind == ZEND_AST_GREATER_EQUAL); - do_end_loop(as_token->u.op.opline_num, 1 TSRMLS_CC); + zend_compile_expr(&left_node, left_ast TSRMLS_CC); + zend_compile_expr(&right_node, right_ast TSRMLS_CC); - container_ptr = zend_stack_top(&CG(foreach_copy_stack)); - generate_free_foreach_copy(container_ptr TSRMLS_CC); - zend_stack_del_top(&CG(foreach_copy_stack)); + if (left_node.op_type == IS_CONST && right_node.op_type == IS_CONST) { + result->op_type = IS_CONST; + zend_ct_eval_greater(&result->u.constant, ast->kind, + &left_node.u.constant, &right_node.u.constant TSRMLS_CC); + zval_ptr_dtor(&left_node.u.constant); + zval_ptr_dtor(&right_node.u.constant); + return; + } - DEC_BPC(CG(active_op_array)); + zend_emit_op_tmp(result, + ast->kind == ZEND_AST_GREATER ? ZEND_IS_SMALLER : ZEND_IS_SMALLER_OR_EQUAL, + &right_node, &left_node TSRMLS_CC); } -/* }}} */ -void zend_do_declare_begin(TSRMLS_D) /* {{{ */ -{ - zend_stack_push(&CG(declare_stack), &CG(declarables)); -} -/* }}} */ +void zend_compile_unary_op(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast *expr_ast = ast->child[0]; + zend_uint opcode = ast->attr; -void zend_do_declare_stmt(znode *var, znode *val TSRMLS_DC) /* {{{ */ -{ - if (!zend_binary_strcasecmp(Z_STRVAL(var->u.constant), Z_STRLEN(var->u.constant), "ticks", sizeof("ticks")-1)) { - convert_to_long(&val->u.constant); - CG(declarables).ticks = val->u.constant; - } else if (!zend_binary_strcasecmp(Z_STRVAL(var->u.constant), Z_STRLEN(var->u.constant), "encoding", sizeof("encoding")-1)) { - if (Z_TYPE(val->u.constant) == IS_CONSTANT) { - zend_error_noreturn(E_COMPILE_ERROR, "Cannot use constants as encoding"); - } - - /* - * Check that the pragma comes before any opcodes. If the compilation - * got as far as this, the previous portion of the script must have been - * parseable according to the .ini script_encoding setting. We still - * want to tell them to put declare() at the top. - */ - { - int num = CG(active_op_array)->last; - /* ignore ZEND_EXT_STMT and ZEND_TICKS */ - while (num > 0 && - (CG(active_op_array)->opcodes[num-1].opcode == ZEND_EXT_STMT || - CG(active_op_array)->opcodes[num-1].opcode == ZEND_TICKS)) { - --num; - } + znode expr_node; + zend_compile_expr(&expr_node, expr_ast TSRMLS_CC); - if (num > 0) { - zend_error_noreturn(E_COMPILE_ERROR, "Encoding declaration pragma must be the very first statement in the script"); - } - } + zend_emit_op_tmp(result, opcode, &expr_node, NULL TSRMLS_CC); +} - if (CG(multibyte)) { - const zend_encoding *new_encoding, *old_encoding; - zend_encoding_filter old_input_filter; +void zend_compile_unary_pm(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast *expr_ast = ast->child[0]; + znode zero_node, expr_node; - CG(encoding_declared) = 1; + ZEND_ASSERT(ast->kind == ZEND_AST_UNARY_PLUS || ast->kind == ZEND_AST_UNARY_MINUS); - convert_to_string(&val->u.constant); - new_encoding = zend_multibyte_fetch_encoding(Z_STRVAL(val->u.constant) TSRMLS_CC); - if (!new_encoding) { - zend_error(E_COMPILE_WARNING, "Unsupported encoding [%s]", Z_STRVAL(val->u.constant)); - } else { - old_input_filter = LANG_SCNG(input_filter); - old_encoding = LANG_SCNG(script_encoding); - zend_multibyte_set_filter(new_encoding TSRMLS_CC); - - /* need to re-scan if input filter changed */ - if (old_input_filter != LANG_SCNG(input_filter) || - (old_input_filter && new_encoding != old_encoding)) { - zend_multibyte_yyinput_again(old_input_filter, old_encoding TSRMLS_CC); - } - } - } else { - zend_error(E_COMPILE_WARNING, "declare(encoding=...) ignored because Zend multibyte feature is turned off by settings"); - } - zval_dtor(&val->u.constant); - } else { - zend_error(E_COMPILE_WARNING, "Unsupported declare '%s'", Z_STRVAL(var->u.constant)); - zval_dtor(&val->u.constant); - } - zval_dtor(&var->u.constant); -} -/* }}} */ + zend_compile_expr(&expr_node, expr_ast TSRMLS_CC); -void zend_do_declare_end(const znode *declare_token TSRMLS_DC) /* {{{ */ -{ - zend_declarables *declarables = zend_stack_top(&CG(declare_stack)); - /* We should restore if there was more than (current - start) - (ticks?1:0) opcodes */ - if ((get_next_op_number(CG(active_op_array)) - declare_token->u.op.opline_num) - ((Z_LVAL(CG(declarables).ticks))?1:0)) { - CG(declarables) = *declarables; + if (expr_node.op_type == IS_CONST) { + result->op_type = IS_CONST; + zend_ct_eval_unary_pm(&result->u.constant, ast->kind, &expr_node.u.constant TSRMLS_CC); + zval_ptr_dtor(&expr_node.u.constant); + return; } -} -/* }}} */ -void zend_do_exit(znode *result, znode *message TSRMLS_DC) /* {{{ */ -{ - zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); - - opline->opcode = ZEND_EXIT; - SET_NODE(opline->op1, message); - SET_UNUSED(opline->op2); + zero_node.op_type = IS_CONST; + ZVAL_LONG(&zero_node.u.constant, 0); - result->op_type = IS_CONST; - ZVAL_BOOL(&result->u.constant, 1); + zend_emit_op_tmp(result, ast->kind == ZEND_AST_UNARY_PLUS ? ZEND_ADD : ZEND_SUB, + &zero_node, &expr_node TSRMLS_CC); } -/* }}} */ -void zend_do_begin_silence(znode *strudel_token TSRMLS_DC) /* {{{ */ -{ - zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); +void zend_compile_short_circuiting(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast *left_ast = ast->child[0]; + zend_ast *right_ast = ast->child[1]; - opline->opcode = ZEND_BEGIN_SILENCE; - opline->result_type = IS_TMP_VAR; - opline->result.var = get_temporary_variable(CG(active_op_array)); - SET_UNUSED(opline->op1); - SET_UNUSED(opline->op2); - GET_NODE(strudel_token, opline->result); -} -/* }}} */ + znode left_node, right_node; + zend_op *opline_jmpz, *opline_bool; + zend_uint opnum_jmpz; -void zend_do_end_silence(znode *strudel_token TSRMLS_DC) /* {{{ */ -{ - zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); + ZEND_ASSERT(ast->kind == ZEND_AST_AND || ast->kind == ZEND_AST_OR); - opline->opcode = ZEND_END_SILENCE; - SET_NODE(opline->op1, strudel_token); - SET_UNUSED(opline->op2); -} -/* }}} */ + zend_compile_expr(&left_node, left_ast TSRMLS_CC); -void zend_do_jmp_set(znode *value, znode *jmp_token, znode *colon_token TSRMLS_DC) /* {{{ */ -{ - int op_number = get_next_op_number(CG(active_op_array)); - zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); + opnum_jmpz = get_next_op_number(CG(active_op_array)); + opline_jmpz = zend_emit_op(NULL, ast->kind == ZEND_AST_AND ? ZEND_JMPZ_EX : ZEND_JMPNZ_EX, + &left_node, NULL TSRMLS_CC); - if (value->op_type == IS_VAR || value->op_type == IS_CV) { - opline->opcode = ZEND_JMP_SET_VAR; - opline->result_type = IS_VAR; + if (left_node.op_type == IS_TMP_VAR) { + SET_NODE(opline_jmpz->result, &left_node); } else { - opline->opcode = ZEND_JMP_SET; - opline->result_type = IS_TMP_VAR; + opline_jmpz->result.var = get_temporary_variable(CG(active_op_array)); + opline_jmpz->result_type = IS_TMP_VAR; } - opline->result.var = get_temporary_variable(CG(active_op_array)); - SET_NODE(opline->op1, value); - SET_UNUSED(opline->op2); + GET_NODE(result, opline_jmpz->result); - GET_NODE(colon_token, opline->result); + zend_compile_expr(&right_node, right_ast TSRMLS_CC); - jmp_token->u.op.opline_num = op_number; + opline_bool = zend_emit_op(NULL, ZEND_BOOL, &right_node, NULL TSRMLS_CC); + SET_NODE(opline_bool->result, result); - INC_BPC(CG(active_op_array)); + zend_update_jump_target_to_next(opnum_jmpz TSRMLS_CC); } -/* }}} */ -void zend_do_jmp_set_else(znode *result, znode *false_value, const znode *jmp_token, znode *colon_token TSRMLS_DC) /* {{{ */ -{ - zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); +void zend_compile_post_incdec(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast *var_ast = ast->child[0]; + ZEND_ASSERT(ast->kind == ZEND_AST_POST_INC || ast->kind == ZEND_AST_POST_DEC); - SET_NODE(opline->result, colon_token); - if (colon_token->op_type == IS_TMP_VAR) { - if (false_value->op_type == IS_VAR || false_value->op_type == IS_CV) { - CG(active_op_array)->opcodes[jmp_token->u.op.opline_num].opcode = ZEND_JMP_SET_VAR; - CG(active_op_array)->opcodes[jmp_token->u.op.opline_num].result_type = IS_VAR; - opline->opcode = ZEND_QM_ASSIGN_VAR; - opline->result_type = IS_VAR; - } else { - opline->opcode = ZEND_QM_ASSIGN; - } + if (var_ast->kind == ZEND_AST_PROP) { + zend_op *opline = zend_compile_prop_common(NULL, var_ast, BP_VAR_RW TSRMLS_CC); + opline->opcode = ast->kind == ZEND_AST_POST_INC ? ZEND_POST_INC_OBJ : ZEND_POST_DEC_OBJ; + zend_make_tmp_result(result, opline TSRMLS_CC); } else { - opline->opcode = ZEND_QM_ASSIGN_VAR; + znode var_node; + zend_compile_var(&var_node, var_ast, BP_VAR_RW TSRMLS_CC); + zend_emit_op_tmp(result, ast->kind == ZEND_AST_POST_INC ? ZEND_POST_INC : ZEND_POST_DEC, + &var_node, NULL TSRMLS_CC); } - opline->extended_value = 0; - SET_NODE(opline->op1, false_value); - SET_UNUSED(opline->op2); - - GET_NODE(result, opline->result); +} - CG(active_op_array)->opcodes[jmp_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array)); +void zend_compile_pre_incdec(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast *var_ast = ast->child[0]; + ZEND_ASSERT(ast->kind == ZEND_AST_PRE_INC || ast->kind == ZEND_AST_PRE_DEC); - DEC_BPC(CG(active_op_array)); + if (var_ast->kind == ZEND_AST_PROP) { + zend_op *opline = zend_compile_prop_common(result, var_ast, BP_VAR_RW TSRMLS_CC); + opline->opcode = ast->kind == ZEND_AST_PRE_INC ? ZEND_PRE_INC_OBJ : ZEND_PRE_DEC_OBJ; + } else { + znode var_node; + zend_compile_var(&var_node, var_ast, BP_VAR_RW TSRMLS_CC); + zend_emit_op(result, ast->kind == ZEND_AST_PRE_INC ? ZEND_PRE_INC : ZEND_PRE_DEC, + &var_node, NULL TSRMLS_CC); + } } -/* }}} */ -void zend_do_begin_qm_op(znode *cond, znode *qm_token TSRMLS_DC) /* {{{ */ -{ - int jmpz_op_number = get_next_op_number(CG(active_op_array)); +void zend_compile_cast(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast *expr_ast = ast->child[0]; + znode expr_node; zend_op *opline; - opline = get_next_op(CG(active_op_array) TSRMLS_CC); - - opline->opcode = ZEND_JMPZ; - SET_NODE(opline->op1, cond); - SET_UNUSED(opline->op2); - opline->op2.opline_num = jmpz_op_number; - GET_NODE(qm_token, opline->op2); + zend_compile_expr(&expr_node, expr_ast TSRMLS_CC); - INC_BPC(CG(active_op_array)); + opline = zend_emit_op(result, ZEND_CAST, &expr_node, NULL TSRMLS_CC); + opline->extended_value = ast->attr; } -/* }}} */ -void zend_do_qm_true(znode *true_value, znode *qm_token, znode *colon_token TSRMLS_DC) /* {{{ */ -{ - zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); +static void zend_compile_shorthand_conditional(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast *cond_ast = ast->child[0]; + zend_ast *false_ast = ast->child[2]; - CG(active_op_array)->opcodes[qm_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array))+1; /* jmp over the ZEND_JMP */ + znode cond_node, false_node; + zend_op *opline_jmp_set, *opline_qm_assign; + zend_uint opnum_jmp_set; - if (true_value->op_type == IS_VAR || true_value->op_type == IS_CV) { - opline->opcode = ZEND_QM_ASSIGN_VAR; - opline->result_type = IS_VAR; - } else { - opline->opcode = ZEND_QM_ASSIGN; - opline->result_type = IS_TMP_VAR; - } - opline->result.var = get_temporary_variable(CG(active_op_array)); - SET_NODE(opline->op1, true_value); - SET_UNUSED(opline->op2); + ZEND_ASSERT(ast->child[1] == NULL); - GET_NODE(qm_token, opline->result); - colon_token->u.op.opline_num = get_next_op_number(CG(active_op_array)); + zend_compile_expr(&cond_node, cond_ast TSRMLS_CC); - opline = get_next_op(CG(active_op_array) TSRMLS_CC); - opline->opcode = ZEND_JMP; - SET_UNUSED(opline->op1); - SET_UNUSED(opline->op2); -} -/* }}} */ + opnum_jmp_set = get_next_op_number(CG(active_op_array)); + zend_emit_op_tmp(result, ZEND_JMP_SET, &cond_node, NULL TSRMLS_CC); -void zend_do_qm_false(znode *result, znode *false_value, znode *qm_token, const znode *colon_token TSRMLS_DC) /* {{{ */ -{ - zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); + zend_compile_expr(&false_node, false_ast TSRMLS_CC); - SET_NODE(opline->result, qm_token); - if (qm_token->op_type == IS_TMP_VAR) { - if (false_value->op_type == IS_VAR || false_value->op_type == IS_CV) { - CG(active_op_array)->opcodes[colon_token->u.op.opline_num - 1].opcode = ZEND_QM_ASSIGN_VAR; - CG(active_op_array)->opcodes[colon_token->u.op.opline_num - 1].result_type = IS_VAR; - opline->opcode = ZEND_QM_ASSIGN_VAR; - opline->result_type = IS_VAR; - } else { - opline->opcode = ZEND_QM_ASSIGN; - } + opline_jmp_set = &CG(active_op_array)->opcodes[opnum_jmp_set]; + opline_jmp_set->op2.opline_num = get_next_op_number(CG(active_op_array)) + 1; + if (cond_node.op_type == IS_VAR || cond_node.op_type == IS_CV + || false_node.op_type == IS_VAR || false_node.op_type == IS_CV + ) { + opline_jmp_set->opcode = ZEND_JMP_SET_VAR; + opline_jmp_set->result_type = IS_VAR; + GET_NODE(result, opline_jmp_set->result); + + opline_qm_assign = zend_emit_op(NULL, ZEND_QM_ASSIGN_VAR, &false_node, NULL TSRMLS_CC); } else { - opline->opcode = ZEND_QM_ASSIGN_VAR; + opline_qm_assign = zend_emit_op(NULL, ZEND_QM_ASSIGN, &false_node, NULL TSRMLS_CC); } - SET_NODE(opline->op1, false_value); - SET_UNUSED(opline->op2); - - CG(active_op_array)->opcodes[colon_token->u.op.opline_num].op1.opline_num = get_next_op_number(CG(active_op_array)); - - GET_NODE(result, opline->result); - - DEC_BPC(CG(active_op_array)); + SET_NODE(opline_qm_assign->result, result); } -/* }}} */ -void zend_do_extended_info(TSRMLS_D) /* {{{ */ -{ - zend_op *opline; +void zend_compile_conditional(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast *cond_ast = ast->child[0]; + zend_ast *true_ast = ast->child[1]; + zend_ast *false_ast = ast->child[2]; - if (!(CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO)) { + znode cond_node, true_node, false_node; + zend_op *opline_qm_assign1, *opline_qm_assign2; + zend_uint opnum_jmpz, opnum_jmp, opnum_qm_assign1; + + if (!true_ast) { + zend_compile_shorthand_conditional(result, ast TSRMLS_CC); return; } + + zend_compile_expr(&cond_node, cond_ast TSRMLS_CC); - opline = get_next_op(CG(active_op_array) TSRMLS_CC); - - opline->opcode = ZEND_EXT_STMT; - SET_UNUSED(opline->op1); - SET_UNUSED(opline->op2); -} -/* }}} */ + opnum_jmpz = zend_emit_cond_jump(ZEND_JMPZ, &cond_node, 0 TSRMLS_CC); -void zend_do_extended_fcall_begin(TSRMLS_D) /* {{{ */ -{ - zend_op *opline; + zend_compile_expr(&true_node, true_ast TSRMLS_CC); - if (!(CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO)) { - return; - } + opnum_qm_assign1 = get_next_op_number(CG(active_op_array)); + zend_emit_op(result, ZEND_QM_ASSIGN, &true_node, NULL TSRMLS_CC); - opline = get_next_op(CG(active_op_array) TSRMLS_CC); + opnum_jmp = zend_emit_jump(0 TSRMLS_CC); - opline->opcode = ZEND_EXT_FCALL_BEGIN; - SET_UNUSED(opline->op1); - SET_UNUSED(opline->op2); -} -/* }}} */ + zend_update_jump_target_to_next(opnum_jmpz TSRMLS_CC); -void zend_do_extended_fcall_end(TSRMLS_D) /* {{{ */ -{ - zend_op *opline; + zend_compile_expr(&false_node, false_ast TSRMLS_CC); - if (!(CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO)) { - return; + opline_qm_assign1 = &CG(active_op_array)->opcodes[opnum_qm_assign1]; + if (true_node.op_type == IS_VAR || true_node.op_type == IS_CV + || false_node.op_type == IS_VAR || false_node.op_type == IS_CV + ) { + opline_qm_assign1->opcode = ZEND_QM_ASSIGN_VAR; + opline_qm_assign1->result_type = IS_VAR; + GET_NODE(result, opline_qm_assign1->result); } - opline = get_next_op(CG(active_op_array) TSRMLS_CC); + opline_qm_assign2 = zend_emit_op(NULL, opline_qm_assign1->opcode, &false_node, NULL TSRMLS_CC); + SET_NODE(opline_qm_assign2->result, result); - opline->opcode = ZEND_EXT_FCALL_END; - SET_UNUSED(opline->op1); - SET_UNUSED(opline->op2); + zend_update_jump_target_to_next(opnum_jmp TSRMLS_CC); } -/* }}} */ -void zend_do_ticks(TSRMLS_D) /* {{{ */ -{ - zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); +void zend_compile_print(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast *expr_ast = ast->child[0]; - opline->opcode = ZEND_TICKS; - SET_UNUSED(opline->op1); - SET_UNUSED(opline->op2); - opline->extended_value = Z_LVAL(CG(declarables).ticks); + znode expr_node; + zend_compile_expr(&expr_node, expr_ast TSRMLS_CC); + + zend_emit_op_tmp(result, ZEND_PRINT, &expr_node, NULL TSRMLS_CC); } -/* }}} */ -zend_bool zend_is_auto_global(zend_string *name TSRMLS_DC) /* {{{ */ -{ - zend_auto_global *auto_global; +void zend_compile_exit(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast *expr_ast = ast->child[0]; - if ((auto_global = zend_hash_find_ptr(CG(auto_globals), name)) != NULL) { - if (auto_global->armed) { - auto_global->armed = auto_global->auto_global_callback(auto_global->name TSRMLS_CC); - } - return 1; + if (expr_ast) { + znode expr_node; + zend_compile_expr(&expr_node, expr_ast TSRMLS_CC); + zend_emit_op(NULL, ZEND_EXIT, &expr_node, NULL TSRMLS_CC); + } else { + zend_emit_op(NULL, ZEND_EXIT, NULL, NULL TSRMLS_CC); } - return 0; + + result->op_type = IS_CONST; + ZVAL_BOOL(&result->u.constant, 1); } -/* }}} */ -int zend_register_auto_global(zend_string *name, zend_bool jit, zend_auto_global_callback auto_global_callback TSRMLS_DC) /* {{{ */ -{ - zend_auto_global auto_global; - int retval; +void zend_compile_yield(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast *value_ast = ast->child[0]; + zend_ast *key_ast = ast->child[1]; - auto_global.name = zend_new_interned_string(name TSRMLS_CC); - auto_global.auto_global_callback = auto_global_callback; - auto_global.jit = jit; + znode value_node, key_node; + znode *value_node_ptr = NULL, *key_node_ptr = NULL; + zend_op *opline; + zend_bool returns_by_ref = (CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0; - retval = zend_hash_add_mem(CG(auto_globals), name, &auto_global, sizeof(zend_auto_global)) != NULL ? SUCCESS : FAILURE; + if (!CG(active_op_array)->function_name) { + zend_error_noreturn(E_COMPILE_ERROR, + "The \"yield\" expression can only be used inside a function"); + } - STR_RELEASE(auto_global.name); - return retval; -} -/* }}} */ + CG(active_op_array)->fn_flags |= ZEND_ACC_GENERATOR; -ZEND_API void zend_activate_auto_globals(TSRMLS_D) /* {{{ */ -{ - zend_auto_global *auto_global; + if (key_ast) { + zend_compile_expr(&key_node, key_ast TSRMLS_CC); + key_node_ptr = &key_node; + } - ZEND_HASH_FOREACH_PTR(CG(auto_globals), auto_global) { - if (auto_global->jit) { - auto_global->armed = 1; - } else if (auto_global->auto_global_callback) { - auto_global->armed = auto_global->auto_global_callback(auto_global->name TSRMLS_CC); + if (value_ast) { + if (returns_by_ref && zend_is_variable(value_ast) && !zend_is_call(value_ast)) { + zend_compile_var(&value_node, value_ast, BP_VAR_REF TSRMLS_CC); } else { - auto_global->armed = 0; + zend_compile_expr(&value_node, value_ast TSRMLS_CC); } - } ZEND_HASH_FOREACH_END(); + value_node_ptr = &value_node; + } + + opline = zend_emit_op(result, ZEND_YIELD, value_node_ptr, key_node_ptr TSRMLS_CC); + + if (value_ast && returns_by_ref && zend_is_call(value_ast)) { + opline->extended_value = ZEND_RETURNS_FUNCTION; + } } -/* }}} */ -int zendlex(znode *zendlval TSRMLS_DC) /* {{{ */ -{ - int retval; +void zend_compile_instanceof(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast *obj_ast = ast->child[0]; + zend_ast *class_ast = ast->child[1]; - if (CG(increment_lineno)) { - CG(zend_lineno)++; - CG(increment_lineno) = 0; + znode obj_node, class_node; + zend_op *opline; + + zend_compile_expr(&obj_node, obj_ast TSRMLS_CC); + if (obj_node.op_type == IS_CONST) { + zend_error_noreturn(E_COMPILE_ERROR, + "instanceof expects an object instance, constant given"); } -again: - Z_TYPE_INFO(zendlval->u.constant) = IS_LONG; - retval = lex_scan(&zendlval->u.constant TSRMLS_CC); - switch (retval) { - case T_COMMENT: - case T_DOC_COMMENT: - case T_OPEN_TAG: - case T_WHITESPACE: - goto again; + opline = zend_compile_class_ref(&class_node, class_ast TSRMLS_CC); + opline->extended_value |= ZEND_FETCH_CLASS_NO_AUTOLOAD; - case T_CLOSE_TAG: - if (LANG_SCNG(yy_text)[LANG_SCNG(yy_leng)-1] != '>') { - CG(increment_lineno) = 1; - } - if (CG(has_bracketed_namespaces) && !CG(in_namespace)) { - goto again; + zend_emit_op_tmp(result, ZEND_INSTANCEOF, &obj_node, &class_node TSRMLS_CC); +} + +void zend_compile_include_or_eval(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast *expr_ast = ast->child[0]; + znode expr_node; + zend_op *opline; + + zend_do_extended_fcall_begin(TSRMLS_C); + zend_compile_expr(&expr_node, expr_ast TSRMLS_CC); + + opline = zend_emit_op(result, ZEND_INCLUDE_OR_EVAL, &expr_node, NULL TSRMLS_CC); + opline->extended_value = ast->attr; + + zend_do_extended_fcall_end(TSRMLS_C); +} + +void zend_compile_isset_or_empty(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast *var_ast = ast->child[0]; + + znode var_node; + zend_op *opline; + + ZEND_ASSERT(ast->kind == ZEND_AST_ISSET || ast->kind == ZEND_AST_EMPTY); + + if (!zend_is_variable(var_ast) || zend_is_call(var_ast)) { + if (ast->kind == ZEND_AST_EMPTY) { + /* empty(expr) can be transformed to !expr */ + zend_ast *not_ast = zend_ast_create_ex(ZEND_AST_UNARY_OP, ZEND_BOOL_NOT, var_ast); + zend_compile_expr(result, not_ast TSRMLS_CC); + return; + } else { + zend_error_noreturn(E_COMPILE_ERROR, + "Cannot use isset() on the result of an expression " + "(you can use \"null !== expression\" instead)"); + } + } + + switch (var_ast->kind) { + case ZEND_AST_VAR: + if (zend_try_compile_cv(&var_node, var_ast TSRMLS_CC) == SUCCESS) { + opline = zend_emit_op(result, ZEND_ISSET_ISEMPTY_VAR, &var_node, NULL TSRMLS_CC); + opline->extended_value = ZEND_FETCH_LOCAL | ZEND_QUICK_SET; + } else { + opline = zend_compile_simple_var_no_cv(result, var_ast, BP_VAR_IS TSRMLS_CC); + opline->opcode = ZEND_ISSET_ISEMPTY_VAR; } - retval = ';'; /* implicit ; */ break; - case T_OPEN_TAG_WITH_ECHO: - retval = T_ECHO; + case ZEND_AST_DIM: + opline = zend_compile_dim_common(result, var_ast, BP_VAR_IS TSRMLS_CC); + opline->opcode = ZEND_ISSET_ISEMPTY_DIM_OBJ; + break; + case ZEND_AST_PROP: + opline = zend_compile_prop_common(result, var_ast, BP_VAR_IS TSRMLS_CC); + opline->opcode = ZEND_ISSET_ISEMPTY_PROP_OBJ; break; + case ZEND_AST_STATIC_PROP: + opline = zend_compile_static_prop_common(result, var_ast, BP_VAR_IS TSRMLS_CC); + opline->opcode = ZEND_ISSET_ISEMPTY_VAR; + break; + EMPTY_SWITCH_DEFAULT_CASE() } - zendlval->op_type = IS_CONST; - return retval; + opline->result_type = IS_TMP_VAR; + opline->extended_value |= ast->kind == ZEND_AST_ISSET ? ZEND_ISSET : ZEND_ISEMPTY; } -/* }}} */ - -ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify_handlers TSRMLS_DC) /* {{{ */ -{ - zend_bool persistent_hashes = (ce->type == ZEND_INTERNAL_CLASS) ? 1 : 0; - dtor_func_t zval_ptr_dtor_func = ((persistent_hashes) ? ZVAL_INTERNAL_PTR_DTOR : ZVAL_PTR_DTOR); - - ce->refcount = 1; - ce->ce_flags = ZEND_ACC_CONSTANTS_UPDATED; - ce->default_properties_table = NULL; - ce->default_static_members_table = NULL; - zend_hash_init_ex(&ce->properties_info, 8, NULL, (persistent_hashes ? zend_destroy_property_info_internal : zend_destroy_property_info), persistent_hashes, 0); - zend_hash_init_ex(&ce->constants_table, 8, NULL, zval_ptr_dtor_func, persistent_hashes, 0); - zend_hash_init_ex(&ce->function_table, 8, NULL, ZEND_FUNCTION_DTOR, persistent_hashes, 0); +void zend_compile_silence(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast *expr_ast = ast->child[0]; + znode silence_node; - if (ce->type == ZEND_INTERNAL_CLASS) { -#ifdef ZTS - int n = zend_hash_num_elements(CG(class_table)); + zend_emit_op_tmp(&silence_node, ZEND_BEGIN_SILENCE, NULL, NULL TSRMLS_CC); - if (CG(static_members_table) && n >= CG(last_static_member)) { - /* Support for run-time declaration: dl() */ - CG(last_static_member) = n+1; - CG(static_members_table) = realloc(CG(static_members_table), (n+1)*sizeof(zval*)); - CG(static_members_table)[n] = NULL; - } - ce->static_members_table = (zval*)(zend_intptr_t)n; -#else - ce->static_members_table = NULL; -#endif + if (expr_ast->kind == ZEND_AST_VAR) { + /* For @$var we need to force a FETCH instruction, otherwise the CV access will + * happen outside the silenced section. */ + zend_compile_simple_var_no_cv(result, expr_ast, BP_VAR_R TSRMLS_CC); } else { - ce->static_members_table = ce->default_static_members_table; - ce->info.user.doc_comment = NULL; + zend_compile_expr(result, expr_ast TSRMLS_CC); } - ce->default_properties_count = 0; - ce->default_static_members_count = 0; - - if (nullify_handlers) { - ce->constructor = NULL; - ce->destructor = NULL; - ce->clone = NULL; - ce->__get = NULL; - ce->__set = NULL; - ce->__unset = NULL; - ce->__isset = NULL; - ce->__call = NULL; - ce->__callstatic = NULL; - ce->__tostring = NULL; - ce->create_object = NULL; - ce->get_iterator = NULL; - ce->iterator_funcs.funcs = NULL; - ce->interface_gets_implemented = NULL; - ce->get_static_method = NULL; - ce->parent = NULL; - ce->num_interfaces = 0; - ce->interfaces = NULL; - ce->num_traits = 0; - ce->traits = NULL; - ce->trait_aliases = NULL; - ce->trait_precedences = NULL; - ce->serialize = NULL; - ce->unserialize = NULL; - ce->serialize_func = NULL; - ce->unserialize_func = NULL; - ce->__debugInfo = NULL; - if (ce->type == ZEND_INTERNAL_CLASS) { - ce->info.internal.module = NULL; - ce->info.internal.builtin_functions = NULL; - } - } + zend_emit_op(NULL, ZEND_END_SILENCE, &silence_node, NULL TSRMLS_CC); } -/* }}} */ -int zend_get_class_fetch_type(const char *class_name, uint class_name_len) /* {{{ */ -{ - if ((class_name_len == sizeof("self")-1) && - !strncasecmp(class_name, "self", sizeof("self")-1)) { - return ZEND_FETCH_CLASS_SELF; - } else if ((class_name_len == sizeof("parent")-1) && - !strncasecmp(class_name, "parent", sizeof("parent")-1)) { - return ZEND_FETCH_CLASS_PARENT; - } else if ((class_name_len == sizeof("static")-1) && - !strncasecmp(class_name, "static", sizeof("static")-1)) { - return ZEND_FETCH_CLASS_STATIC; - } else { - return ZEND_FETCH_CLASS_DEFAULT; - } -} -/* }}} */ +void zend_compile_shell_exec(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast *expr_ast = ast->child[0]; -ZEND_API zend_string *zend_get_compiled_variable_name(const zend_op_array *op_array, zend_uint var) /* {{{ */ -{ - return op_array->vars[EX_VAR_TO_NUM(var)]; + zval fn_name; + zend_ast *name_ast, *args_ast, *call_ast; + + ZVAL_STRING(&fn_name, "shell_exec"); + name_ast = zend_ast_create_zval(&fn_name); + args_ast = (zend_ast *) zend_ast_create_list(1, ZEND_AST_ARG_LIST, expr_ast); + call_ast = zend_ast_create(ZEND_AST_CALL, name_ast, args_ast); + + zend_compile_expr(result, call_ast TSRMLS_CC); + + zval_ptr_dtor(&fn_name); } -/* }}} */ -void zend_do_build_namespace_name(znode *result, znode *prefix, znode *name TSRMLS_DC) /* {{{ */ -{ - if (prefix) { - *result = *prefix; - if (Z_TYPE(result->u.constant) == IS_STRING && - Z_STRLEN(result->u.constant) == 0) { - /* namespace\ */ - if (Z_TYPE(CG(current_namespace)) != IS_UNDEF) { - znode tmp; - - zval_dtor(&result->u.constant); - tmp.op_type = IS_CONST; - ZVAL_DUP(&tmp.u.constant, &CG(current_namespace)); - zend_do_build_namespace_name(result, NULL, &tmp TSRMLS_CC); - } - } - } else { +void zend_compile_array(znode *result, zend_ast *ast TSRMLS_DC) { + zend_ast_list *list = zend_ast_get_list(ast); + zend_op *opline; + zend_uint i, opnum_init; + zend_bool packed = 1; + + if (zend_try_ct_eval_array(&result->u.constant, ast TSRMLS_CC)) { result->op_type = IS_CONST; - ZVAL_EMPTY_STRING(&result->u.constant); + return; } - /* prefix = result */ - zend_do_build_full_name(NULL, result, name, 0 TSRMLS_CC); -} -/* }}} */ -void zend_do_begin_namespace(znode *name, zend_bool with_bracket TSRMLS_DC) /* {{{ */ -{ - char *lcname; + opnum_init = get_next_op_number(CG(active_op_array)); - /* handle mixed syntax declaration or nested namespaces */ - if (!CG(has_bracketed_namespaces)) { - if (Z_TYPE(CG(current_namespace)) != IS_UNDEF) { - /* previous namespace declarations were unbracketed */ - if (with_bracket) { - zend_error_noreturn(E_COMPILE_ERROR, "Cannot mix bracketed namespace declarations with unbracketed namespace declarations"); - } - } - } else { - /* previous namespace declarations were bracketed */ - if (!with_bracket) { - zend_error_noreturn(E_COMPILE_ERROR, "Cannot mix bracketed namespace declarations with unbracketed namespace declarations"); - } else if (Z_TYPE(CG(current_namespace)) != IS_UNDEF || CG(in_namespace)) { - zend_error_noreturn(E_COMPILE_ERROR, "Namespace declarations cannot be nested"); - } - } + for (i = 0; i < list->children; ++i) { + zend_ast *elem_ast = list->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 (((!with_bracket && Z_TYPE(CG(current_namespace)) == IS_UNDEF) || (with_bracket && !CG(has_bracketed_namespaces))) && CG(active_op_array)->last > 0) { - /* ignore ZEND_EXT_STMT and ZEND_TICKS */ - int num = CG(active_op_array)->last; - while (num > 0 && - (CG(active_op_array)->opcodes[num-1].opcode == ZEND_EXT_STMT || - CG(active_op_array)->opcodes[num-1].opcode == ZEND_TICKS)) { - --num; - } - if (num > 0) { - zend_error_noreturn(E_COMPILE_ERROR, "Namespace declaration statement has to be the very first statement in the script"); - } - } + znode value_node, key_node, *key_node_ptr = NULL; - CG(in_namespace) = 1; - if (with_bracket) { - CG(has_bracketed_namespaces) = 1; - } + if (key_ast) { + zend_compile_expr(&key_node, key_ast TSRMLS_CC); + zend_handle_numeric_op(&key_node TSRMLS_CC); + key_node_ptr = &key_node; + } - if (name) { - lcname = zend_str_tolower_dup(Z_STRVAL(name->u.constant), Z_STRLEN(name->u.constant)); - if (((Z_STRLEN(name->u.constant) == sizeof("self")-1) && - !memcmp(lcname, "self", sizeof("self")-1)) || - ((Z_STRLEN(name->u.constant) == sizeof("parent")-1) && - !memcmp(lcname, "parent", sizeof("parent")-1))) { - zend_error_noreturn(E_COMPILE_ERROR, "Cannot use '%s' as namespace name", Z_STRVAL(name->u.constant)); + if (by_ref) { + zend_ensure_writable_variable(value_ast); + zend_compile_var(&value_node, value_ast, BP_VAR_W TSRMLS_CC); + } else { + zend_compile_expr(&value_node, value_ast TSRMLS_CC); } - efree(lcname); - if (Z_TYPE(CG(current_namespace)) != IS_UNDEF) { - zval_dtor(&CG(current_namespace)); + if (i == 0) { + opline = zend_emit_op_tmp(result, ZEND_INIT_ARRAY, &value_node, key_node_ptr TSRMLS_CC); + opline->extended_value = list->children << ZEND_ARRAY_SIZE_SHIFT; + } else { + opline = zend_emit_op(NULL, ZEND_ADD_ARRAY_ELEMENT, + &value_node, key_node_ptr TSRMLS_CC); + SET_NODE(opline->result, result); } - ZVAL_COPY_VALUE(&CG(current_namespace), &name->u.constant); - } else { - if (Z_TYPE(CG(current_namespace)) != IS_UNDEF) { - zval_dtor(&CG(current_namespace)); - ZVAL_UNDEF(&CG(current_namespace)); + opline->extended_value |= by_ref; + + if (key_ast && key_node.op_type == IS_CONST && Z_TYPE(key_node.u.constant) == IS_STRING) { + packed = 0; } } diff --cc Zend/zend_compile.h index d3d81d0,fa33354..0d343f0 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@@ -450,17 -461,61 +450,16 @@@ typedef int (*unary_op_type)(zval *, zv typedef int (*binary_op_type)(zval *, zval *, zval * TSRMLS_DC); ZEND_API unary_op_type get_unary_op(int opcode); ZEND_API binary_op_type get_binary_op(int opcode); - ZEND_API void zend_make_immutable_array(zval *zv TSRMLS_DC); -void zend_do_while_cond(znode *expr, znode *close_bracket_token TSRMLS_DC); -void zend_do_while_end(const znode *while_token, const znode *close_bracket_token TSRMLS_DC); -void zend_do_do_while_begin(TSRMLS_D); -void zend_do_do_while_end(const znode *do_token, const znode *expr_open_bracket, znode *expr TSRMLS_DC); - - -void zend_do_if_cond(znode *cond, znode *closing_bracket_token TSRMLS_DC); -void zend_do_if_after_statement(const znode *closing_bracket_token, unsigned char initialize TSRMLS_DC); -void zend_do_if_end(TSRMLS_D); - -void zend_do_for_cond(znode *expr, znode *second_semicolon_token TSRMLS_DC); -void zend_do_for_before_statement(const znode *cond_start, const znode *second_semicolon_token TSRMLS_DC); -void zend_do_for_end(const znode *second_semicolon_token TSRMLS_DC); - -void zend_do_pre_incdec(znode *result, znode *op1, zend_uchar op TSRMLS_DC); -void zend_do_post_incdec(znode *result, znode *op1, zend_uchar op TSRMLS_DC); - -void zend_do_begin_variable_parse(TSRMLS_D); -void zend_do_end_variable_parse(znode *variable, int type, int arg_offset TSRMLS_DC); - -void zend_check_writable_variable(const znode *variable); +void zend_stop_lexing(TSRMLS_D); +void zend_emit_final_return(zval *zv TSRMLS_DC); +zend_ast *zend_ast_append_str(zend_ast *left, zend_ast *right); +zend_uint zend_add_member_modifier(zend_uint flags, zend_uint new_flag); +zend_ast_list *zend_ast_append_doc_comment(zend_ast_list *list TSRMLS_DC); +/* parser-driven code generators */ void zend_do_free(znode *op1 TSRMLS_DC); -void zend_do_add_string(znode *result, znode *op1, znode *op2 TSRMLS_DC); -void zend_do_add_variable(znode *result, znode *op1, znode *op2 TSRMLS_DC); - -int zend_do_verify_access_types(const znode *current_access_type, const znode *new_modifier); -void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, znode *fn_flags_znode TSRMLS_DC); -void zend_do_end_function_declaration(const znode *function_token TSRMLS_DC); -void zend_do_receive_param(zend_uchar op, znode *varname, znode *initialization, znode *class_type, zend_bool pass_by_reference, zend_bool is_variadic TSRMLS_DC); -int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace TSRMLS_DC); -void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC); -void zend_do_clone(znode *result, znode *expr TSRMLS_DC); -void zend_do_begin_dynamic_function_call(znode *function_name, int prefix_len TSRMLS_DC); -void zend_do_fetch_class(znode *result, znode *class_name TSRMLS_DC); -void zend_do_build_full_name(znode *result, znode *prefix, znode *name, int is_class_member TSRMLS_DC); -int zend_do_begin_class_member_function_call(znode *class_name, znode *method_name TSRMLS_DC); -void zend_do_end_function_call(znode *function_name, znode *result, int is_method, int is_dynamic_fcall TSRMLS_DC); -void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC); -void zend_do_yield(znode *result, znode *value, znode *key, zend_bool is_variable TSRMLS_DC); -void zend_do_handle_exception(TSRMLS_D); - -void zend_do_begin_lambda_function_declaration(znode *result, znode *function_token, int return_reference, int is_static TSRMLS_DC); -void zend_do_fetch_lexical_variable(znode *varname, zend_bool is_ref TSRMLS_DC); - -void zend_do_try(znode *try_token TSRMLS_DC); -void zend_do_begin_catch(znode *try_token, znode *catch_class, znode *catch_var, znode *first_catch TSRMLS_DC); -void zend_do_bind_catch(znode *try_token, znode *catch_token TSRMLS_DC); -void zend_do_end_catch(znode *catch_token TSRMLS_DC); -void zend_do_finally(znode *finally_token TSRMLS_DC); -void zend_do_end_finally(znode *try_token, znode* catch_token, znode *finally_token TSRMLS_DC); -void zend_do_throw(znode *expr TSRMLS_DC); - ZEND_API int do_bind_function(const zend_op_array *op_array, zend_op *opline, HashTable *function_table, zend_bool compile_time TSRMLS_DC); ZEND_API zend_class_entry *do_bind_class(const zend_op_array *op_array, const zend_op *opline, HashTable *class_table, zend_bool compile_time TSRMLS_DC); ZEND_API zend_class_entry *do_bind_inherited_class(const zend_op_array *op_array, const zend_op *opline, HashTable *class_table, zend_class_entry *parent_ce, zend_bool compile_time TSRMLS_DC);