diff options
Diffstat (limited to 'Zend/zend_compile.c')
-rw-r--r-- | Zend/zend_compile.c | 531 |
1 files changed, 216 insertions, 315 deletions
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index c8017da0ef..daf67de39f 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -138,8 +138,6 @@ void zend_init_compiler_data_structures(TSRMLS_D) CG(in_compilation) = 0; CG(start_lineno) = 0; CG(current_namespace) = NULL; - CG(in_namespace) = 0; - CG(has_bracketed_namespaces) = 0; CG(current_import) = NULL; init_compiler_declarables(TSRMLS_C); zend_hash_apply(CG(auto_globals), (apply_func_t) zend_auto_global_arm TSRMLS_CC); @@ -585,7 +583,6 @@ void zend_do_assign(znode *result, znode *variable, const znode *value TSRMLS_DC CG(active_op_array)->vars[value->u.var].name, CG(active_op_array)->vars[value->u.var].name_len, 1); SET_UNUSED(opline->op2); - opline->op2.u.EA.type = ZEND_FETCH_LOCAL; value = &opline->result; } } @@ -612,13 +609,10 @@ void zend_do_assign(znode *result, znode *variable, const znode *value TSRMLS_DC last_op->result.u.var == variable->u.var) { if (last_op->opcode == ZEND_FETCH_OBJ_W) { if (n > 0) { - int opline_no = (opline-CG(active_op_array)->opcodes)/sizeof(*opline); *opline = *last_op; MAKE_NOP(last_op); - /* last_op = opline; */ + last_op = opline; opline = get_next_op(CG(active_op_array) TSRMLS_CC); - /* get_next_op can realloc, we need to move last_op */ - last_op = &CG(active_op_array)->opcodes[opline_no]; } last_op->opcode = ZEND_ASSIGN_OBJ; zend_do_op_data(opline, value TSRMLS_CC); @@ -627,14 +621,10 @@ void zend_do_assign(znode *result, znode *variable, const znode *value TSRMLS_DC return; } else if (last_op->opcode == ZEND_FETCH_DIM_W) { if (n > 0) { - int opline_no = (opline-CG(active_op_array)->opcodes)/sizeof(*opline); *opline = *last_op; MAKE_NOP(last_op); - /* last_op = opline; */ - /* TBFixed: this can realloc opcodes, leaving last_op pointing wrong */ + last_op = opline; opline = get_next_op(CG(active_op_array) TSRMLS_CC); - /* get_next_op can realloc, we need to move last_op */ - last_op = &CG(active_op_array)->opcodes[opline_no]; } last_op->opcode = ZEND_ASSIGN_DIM; zend_do_op_data(opline, value TSRMLS_CC); @@ -1252,9 +1242,9 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n int short_class_name_length; char *short_class_lcname; - if ((short_class_name = zend_memrchr(CG(active_class_entry)->name, '\\', CG(active_class_entry)->name_length))) { - short_class_name_length = CG(active_class_entry)->name_length - (short_class_name - CG(active_class_entry)->name) - 1; - ++short_class_name; + if ((short_class_name = zend_memrchr(CG(active_class_entry)->name, ':', CG(active_class_entry)->name_length))) { + short_class_name++; + short_class_name_length = CG(active_class_entry)->name_length - (short_class_name - CG(active_class_entry)->name); } else { short_class_name = CG(active_class_entry)->name; short_class_name_length = CG(active_class_entry)->name_length; @@ -1397,7 +1387,7 @@ void zend_do_begin_lambda_function_declaration(znode *result, znode *function_to zend_op *current_op; function_name.op_type = IS_CONST; - ZVAL_STRINGL(&function_name.u.constant, "{closure}", sizeof("{closure}")-1, 1); + ZVAL_STRINGL(&function_name.u.constant, "", sizeof("")-1, 1); zend_do_begin_function_declaration(function_token, &function_name, 0, return_reference, NULL TSRMLS_CC); @@ -1412,7 +1402,7 @@ void zend_do_begin_lambda_function_declaration(znode *result, znode *function_to if (is_static) { CG(active_op_array)->fn_flags |= ZEND_ACC_STATIC; } - CG(active_op_array)->fn_flags |= ZEND_ACC_CLOSURE; + CG(active_op_array)->fn_flags |= ZEND_ACC_CLOSURE; } @@ -1544,28 +1534,32 @@ int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace { zend_function *function; char *lcname; - char *is_compound = memchr(Z_STRVAL(function_name->u.constant), '\\', Z_STRLEN(function_name->u.constant)); + int prefix_len = 0; - zend_resolve_non_class_name(function_name, check_namespace TSRMLS_CC); - - if (check_namespace && CG(current_namespace) && !is_compound) { - /* We assume we call function from the current namespace - if it is not prefixed. */ + if (check_namespace && CG(current_namespace)) { + /* We assume we call function from the current namespace + if it is not prefixed. */ + znode tmp; - /* In run-time PHP will check for function with full name and - internal function with short name */ - zend_do_begin_dynamic_function_call(function_name, 1 TSRMLS_CC); - return 1; - } + tmp.op_type = IS_CONST; + tmp.u.constant = *CG(current_namespace); + zval_copy_ctor(&tmp.u.constant); + zend_do_build_namespace_name(&tmp, &tmp, function_name TSRMLS_CC); + *function_name = tmp; + /* In run-time PHP will check for function with full name and + internal function with short name */ + prefix_len = Z_STRLEN_P(CG(current_namespace)) + 2; + } + lcname = zend_str_tolower_dup(function_name->u.constant.value.str.val, function_name->u.constant.value.str.len); if ((zend_hash_find(CG(function_table), lcname, function_name->u.constant.value.str.len+1, (void **) &function)==FAILURE) || - ((CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS) && - (function->type == ZEND_INTERNAL_FUNCTION))) { - zend_do_begin_dynamic_function_call(function_name, 0 TSRMLS_CC); - efree(lcname); - return 1; /* Dynamic */ - } + ((CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS) && + (function->type == ZEND_INTERNAL_FUNCTION))) { + zend_do_begin_dynamic_function_call(function_name, prefix_len TSRMLS_CC); + efree(lcname); + return 1; /* Dynamic */ + } efree(function_name->u.constant.value.str.val); function_name->u.constant.value.str.val = lcname; @@ -1631,15 +1625,14 @@ void zend_do_clone(znode *result, const znode *expr TSRMLS_DC) } -void zend_do_begin_dynamic_function_call(znode *function_name, int ns_call TSRMLS_DC) +void zend_do_begin_dynamic_function_call(znode *function_name, int prefix_len TSRMLS_DC) { unsigned char *ptr = NULL; - zend_op *opline, *opline2; + zend_op *opline; opline = get_next_op(CG(active_op_array) TSRMLS_CC); - if (ns_call) { - char *slash; - int prefix_len, name_len; + + if (prefix_len) { /* In run-time PHP will check for function with full name and internal function with short name */ opline->opcode = ZEND_INIT_NS_FCALL_BY_NAME; @@ -1650,20 +1643,14 @@ void zend_do_begin_dynamic_function_call(znode *function_name, int ns_call TSRML Z_STRVAL(opline->op1.u.constant) = zend_str_tolower_dup(Z_STRVAL(opline->op2.u.constant), Z_STRLEN(opline->op2.u.constant)); Z_STRLEN(opline->op1.u.constant) = Z_STRLEN(opline->op2.u.constant); opline->extended_value = zend_hash_func(Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant) + 1); - slash = zend_memrchr(Z_STRVAL(opline->op1.u.constant), '\\', Z_STRLEN(opline->op1.u.constant)); - prefix_len = slash-Z_STRVAL(opline->op1.u.constant)+1; - name_len = Z_STRLEN(opline->op1.u.constant)-prefix_len; - opline2 = get_next_op(CG(active_op_array) TSRMLS_CC); - opline2->opcode = ZEND_OP_DATA; - opline2->op1.op_type = IS_CONST; - Z_TYPE(opline2->op1.u.constant) = IS_LONG; - if(!slash) { - zend_error(E_CORE_ERROR, "Namespaced name %s should contain slash", Z_STRVAL(opline->op1.u.constant)); - } - /* this is the length of namespace prefix */ - Z_LVAL(opline2->op1.u.constant) = prefix_len; - /* this is the hash of the non-prefixed part, lowercased */ - opline2->extended_value = zend_hash_func(slash+1, name_len+1); + opline = get_next_op(CG(active_op_array) TSRMLS_CC); + opline->opcode = ZEND_OP_DATA; + opline->op1.op_type = IS_CONST; + Z_TYPE(opline->op1.u.constant) = IS_STRING; + Z_STRLEN(opline->op1.u.constant) = Z_STRLEN(function_name->u.constant) - prefix_len; + Z_STRVAL(opline->op1.u.constant) = zend_str_tolower_dup(Z_STRVAL(function_name->u.constant) + prefix_len, Z_STRLEN(opline->op1.u.constant)); + SET_UNUSED(opline->op2); + opline->extended_value = zend_hash_func(Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant) + 1); } else { opline->opcode = ZEND_INIT_FCALL_BY_NAME; opline->op2 = *function_name; @@ -1679,58 +1666,10 @@ void zend_do_begin_dynamic_function_call(znode *function_name, int ns_call TSRML } } - zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *)); - zend_do_extended_fcall_begin(TSRMLS_C); -} - -void zend_resolve_non_class_name(znode *element_name, zend_bool check_namespace TSRMLS_DC) -{ - znode tmp; - int len; - zval **ns; - char *lcname, *compound = memchr(Z_STRVAL(element_name->u.constant), '\\', Z_STRLEN(element_name->u.constant)); - if (Z_STRVAL(element_name->u.constant)[0] == '\\') { - /* name starts with \ so it is known and unambiguos, nothing to do here but shorten it */ - memmove(Z_STRVAL(element_name->u.constant), Z_STRVAL(element_name->u.constant)+1, Z_STRLEN(element_name->u.constant)); - --Z_STRLEN(element_name->u.constant); - return; - } - - if(!check_namespace) { - return; - } - - if (compound && CG(current_import)) { - len = compound - Z_STRVAL(element_name->u.constant); - lcname = zend_str_tolower_dup(Z_STRVAL(element_name->u.constant), len); - /* Check if first part of compound name is an import name */ - if (zend_hash_find(CG(current_import), lcname, len+1, (void**)&ns) == SUCCESS) { - /* Substitute import name */ - tmp.op_type = IS_CONST; - tmp.u.constant = **ns; - zval_copy_ctor(&tmp.u.constant); - len += 1; - Z_STRLEN(element_name->u.constant) -= len; - memmove(Z_STRVAL(element_name->u.constant), Z_STRVAL(element_name->u.constant)+len, Z_STRLEN(element_name->u.constant)+1); - zend_do_build_namespace_name(&tmp, &tmp, element_name TSRMLS_CC); - *element_name = tmp; - efree(lcname); - return; - } - efree(lcname); - } - if (CG(current_namespace)) { - tmp = *element_name; - Z_STRLEN(tmp.u.constant) = sizeof("\\")-1 + Z_STRLEN(element_name->u.constant) + Z_STRLEN_P(CG(current_namespace)); - Z_STRVAL(tmp.u.constant) = (char *) emalloc(Z_STRLEN(tmp.u.constant)+1); - memcpy(Z_STRVAL(tmp.u.constant), Z_STRVAL_P(CG(current_namespace)), Z_STRLEN_P(CG(current_namespace))); - memcpy(&(Z_STRVAL(tmp.u.constant)[Z_STRLEN_P(CG(current_namespace))]), "\\", sizeof("\\")-1); - memcpy(&(Z_STRVAL(tmp.u.constant)[Z_STRLEN_P(CG(current_namespace)) + sizeof("\\")-1]), Z_STRVAL(element_name->u.constant), Z_STRLEN(element_name->u.constant)+1); - STR_FREE(Z_STRVAL(element_name->u.constant)); - *element_name = tmp; - } + zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *)); + zend_do_extended_fcall_begin(TSRMLS_C); } void zend_resolve_class_name(znode *class_name, ulong *fetch_type, int check_ns_name TSRMLS_DC) @@ -1741,51 +1680,40 @@ void zend_resolve_class_name(znode *class_name, ulong *fetch_type, int check_ns_ znode tmp; int len; - compound = memchr(Z_STRVAL(class_name->u.constant), '\\', Z_STRLEN(class_name->u.constant)); + compound = memchr(Z_STRVAL(class_name->u.constant), ':', Z_STRLEN(class_name->u.constant)); if (compound) { - /* This is a compound class name that contains namespace prefix */ - if (Z_STRVAL(class_name->u.constant)[0] == '\\') { - /* The STRING name has "\" prefix */ - Z_STRLEN(class_name->u.constant) -= 1; - memmove(Z_STRVAL(class_name->u.constant), Z_STRVAL(class_name->u.constant)+1, Z_STRLEN(class_name->u.constant)+1); + /* This is a compound class name that cotains namespace prefix */ + if (Z_TYPE(class_name->u.constant) == IS_STRING && + Z_STRVAL(class_name->u.constant)[0] == ':') { + /* The STRING name has "::" prefix */ + Z_STRLEN(class_name->u.constant) -= 2; + memmove(Z_STRVAL(class_name->u.constant), Z_STRVAL(class_name->u.constant)+2, Z_STRLEN(class_name->u.constant)+1); Z_STRVAL(class_name->u.constant) = erealloc( Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant) + 1); if (ZEND_FETCH_CLASS_DEFAULT != zend_get_class_fetch_type(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant))) { - zend_error(E_COMPILE_ERROR, "'\\%s' is an invalid class name", Z_STRVAL(class_name->u.constant)); + zend_error(E_COMPILE_ERROR, "'::%s' is a wrong class name", Z_STRVAL(class_name->u.constant)); } - } else { - if (CG(current_import)) { - len = compound - Z_STRVAL(class_name->u.constant); - lcname = zend_str_tolower_dup(Z_STRVAL(class_name->u.constant), len); - /* Check if first part of compound name is an import name */ - if (zend_hash_find(CG(current_import), lcname, len+1, (void**)&ns) == SUCCESS) { - /* Substitute import name */ - tmp.op_type = IS_CONST; - tmp.u.constant = **ns; - zval_copy_ctor(&tmp.u.constant); - len += 1; - Z_STRLEN(class_name->u.constant) -= len; - memmove(Z_STRVAL(class_name->u.constant), Z_STRVAL(class_name->u.constant)+len, Z_STRLEN(class_name->u.constant)+1); - zend_do_build_namespace_name(&tmp, &tmp, class_name TSRMLS_CC); - *class_name = tmp; - efree(lcname); - return; - } - efree(lcname); - } - /* Here name is not prefixed with \ and not imported */ - if (CG(current_namespace)) { + } else if (CG(current_import)) { + len = compound - Z_STRVAL(class_name->u.constant); + lcname = zend_str_tolower_dup(Z_STRVAL(class_name->u.constant), len); + /* Check if first part of compound name is an import name */ + if (zend_hash_find(CG(current_import), lcname, len+1, (void**)&ns) == SUCCESS) { + /* Substitute import name */ tmp.op_type = IS_CONST; - tmp.u.constant = *CG(current_namespace); + tmp.u.constant = **ns; zval_copy_ctor(&tmp.u.constant); + len += 2; + Z_STRLEN(class_name->u.constant) -= len; + memmove(Z_STRVAL(class_name->u.constant), Z_STRVAL(class_name->u.constant)+len, Z_STRLEN(class_name->u.constant)+1); zend_do_build_namespace_name(&tmp, &tmp, class_name TSRMLS_CC); *class_name = tmp; } + efree(lcname); } } else if (CG(current_import) || CG(current_namespace)) { - /* this is a plain name (without \) */ + /* this is a plain name (without ::) */ lcname = zend_str_tolower_dup(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant)); if (CG(current_import) && @@ -1795,7 +1723,23 @@ void zend_resolve_class_name(znode *class_name, ulong *fetch_type, int check_ns_ class_name->u.constant = **ns; zval_copy_ctor(&class_name->u.constant); } else if (CG(current_namespace)) { - /* plain name, no import - prepend current namespace to it */ + zend_class_entry **pce; + + if (check_ns_name) { + /* PHP will need to perform additional cheks at run-time to + determine if we assume namespace or class name. */ + *fetch_type |= ZEND_FETCH_CLASS_RT_NS_NAME; + } + + if ((CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_CLASSES) || + (zend_hash_find(CG(class_table), lcname, Z_STRLEN(class_name->u.constant)+1, (void**)&pce) == SUCCESS && + (*pce)->type == ZEND_INTERNAL_CLASS)) { + /* There is an internal class with the same name exists. + PHP will need to perform additional cheks at run-time to + determine if we assume class in current namespace or + internal one. */ + *fetch_type |= ZEND_FETCH_CLASS_RT_NS_CHECK; + } tmp.op_type = IS_CONST; tmp.u.constant = *CG(current_namespace); zval_copy_ctor(&tmp.u.constant); @@ -1958,7 +1902,7 @@ void zend_release_labels(TSRMLS_D) /* {{{ */ } /* }}} */ -void zend_do_build_full_name(znode *result, znode *prefix, znode *name, int is_class_member TSRMLS_DC) +void zend_do_build_full_name(znode *result, znode *prefix, znode *name TSRMLS_DC) { zend_uint length; @@ -1968,21 +1912,12 @@ void zend_do_build_full_name(znode *result, znode *prefix, znode *name, int is_c *result = *prefix; } - if (is_class_member) { - length = sizeof("::")-1 + result->u.constant.value.str.len + name->u.constant.value.str.len; - result->u.constant.value.str.val = erealloc(result->u.constant.value.str.val, length+1); - memcpy(&result->u.constant.value.str.val[result->u.constant.value.str.len], "::", sizeof("::")-1); - memcpy(&result->u.constant.value.str.val[result->u.constant.value.str.len + sizeof("::")-1], name->u.constant.value.str.val, name->u.constant.value.str.len+1); - STR_FREE(name->u.constant.value.str.val); - result->u.constant.value.str.len = length; - } else { - length = sizeof("\\")-1 + result->u.constant.value.str.len + name->u.constant.value.str.len; - result->u.constant.value.str.val = erealloc(result->u.constant.value.str.val, length+1); - memcpy(&result->u.constant.value.str.val[result->u.constant.value.str.len], "\\", sizeof("\\")-1); - memcpy(&result->u.constant.value.str.val[result->u.constant.value.str.len + sizeof("\\")-1], name->u.constant.value.str.val, name->u.constant.value.str.len+1); - STR_FREE(name->u.constant.value.str.val); - result->u.constant.value.str.len = length; - } + length = sizeof("::")-1 + result->u.constant.value.str.len + name->u.constant.value.str.len; + result->u.constant.value.str.val = erealloc(result->u.constant.value.str.val, length+1); + memcpy(&result->u.constant.value.str.val[result->u.constant.value.str.len], "::", sizeof("::")-1); + memcpy(&result->u.constant.value.str.val[result->u.constant.value.str.len + sizeof("::")-1], name->u.constant.value.str.val, name->u.constant.value.str.len+1); + STR_FREE(name->u.constant.value.str.val); + result->u.constant.value.str.len = length; } int zend_do_begin_class_member_function_call(znode *class_name, znode *method_name TSRMLS_DC) @@ -1992,11 +1927,10 @@ int zend_do_begin_class_member_function_call(znode *class_name, znode *method_na zend_op *opline; ulong fetch_type = 0; -#if 0 if (class_name->op_type == IS_CONST && Z_TYPE(class_name->u.constant) == IS_STRING && Z_STRLEN(class_name->u.constant) == 0) { - /* namespace\func() not in namespace */ + /* namespace::func() not in namespace */ zval_dtor(&class_name->u.constant); if (CG(current_namespace)) { znode tmp; @@ -2009,7 +1943,6 @@ int zend_do_begin_class_member_function_call(znode *class_name, znode *method_na } return zend_do_begin_function_call(method_name, 0 TSRMLS_CC); } -#endif if (method_name->op_type == IS_CONST) { char *lcname = zend_str_tolower_dup(Z_STRVAL(method_name->u.constant), Z_STRLEN(method_name->u.constant)); @@ -2032,12 +1965,13 @@ int zend_do_begin_class_member_function_call(znode *class_name, znode *method_na } opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_INIT_STATIC_METHOD_CALL; + opline->extended_value = fetch_type & ~ZEND_FETCH_CLASS_RT_NS_NAME; opline->op1 = class_node; opline->op2 = *method_name; if (class_node.op_type == IS_CONST && method_name->op_type == IS_CONST) { - /* Prebuild ns\func name to speedup run-time check. + /* Prebuild ns::func name to speedup run-time check. The additional names are stored in additional OP_DATA opcode. */ char *nsname, *fname; unsigned int nsname_len, len; @@ -2049,11 +1983,17 @@ int zend_do_begin_class_member_function_call(znode *class_name, znode *method_na nsname = Z_STRVAL(class_node.u.constant); nsname_len = Z_STRLEN(class_node.u.constant); - len = nsname_len + 1 + Z_STRLEN(method_name->u.constant); + if (fetch_type & ZEND_FETCH_CLASS_RT_NS_NAME) { + /* Remove namespace name */ + nsname = (char *)memchr(nsname, ':', nsname_len) + 2; + nsname_len -= (nsname - Z_STRVAL(class_node.u.constant)); + } + len = nsname_len + 2 + Z_STRLEN(method_name->u.constant); fname = emalloc(len + 1); memcpy(fname, nsname, nsname_len); - fname[nsname_len] = '\\'; - memcpy(fname + nsname_len + 1, + fname[nsname_len] = ':'; + fname[nsname_len + 1] = ':'; + memcpy(fname + nsname_len + 2, Z_STRVAL(method_name->u.constant), Z_STRLEN(method_name->u.constant)+1); zend_str_tolower(fname, len); @@ -2583,8 +2523,8 @@ static zend_bool zend_do_perform_implementation_check(const zend_function *fe, c char *colon; if (fe->common.type != ZEND_USER_FUNCTION || - strchr(proto->common.arg_info[i].class_name, '\\') != NULL || - (colon = zend_memrchr(fe->common.arg_info[i].class_name, '\\', fe->common.arg_info[i].class_name_len)) == NULL || + strchr(proto->common.arg_info[i].class_name, ':') != NULL || + (colon = zend_memrchr(fe->common.arg_info[i].class_name, ':', fe->common.arg_info[i].class_name_len)) == NULL || strcasecmp(colon+1, proto->common.arg_info[i].class_name) != 0) { return 0; } @@ -3831,20 +3771,7 @@ static zend_constant* zend_get_ct_const(const zval *const_name, int all_internal { zend_constant *c = NULL; - if (Z_STRVAL_P(const_name)[0] == '\\') { - if (zend_hash_find(EG(zend_constants), Z_STRVAL_P(const_name)+1, Z_STRLEN_P(const_name), (void **) &c) == FAILURE) { - char *lookup_name = zend_str_tolower_dup(Z_STRVAL_P(const_name)+1, Z_STRLEN_P(const_name)-1); - - if (zend_hash_find(EG(zend_constants), lookup_name, Z_STRLEN_P(const_name), (void **) &c)==SUCCESS) { - if ((c->flags & CONST_CT_SUBST) && !(c->flags & CONST_CS)) { - efree(lookup_name); - return c; - } - } - efree(lookup_name); - return NULL; - } - } else if (zend_hash_find(EG(zend_constants), Z_STRVAL_P(const_name), Z_STRLEN_P(const_name)+1, (void **) &c) == FAILURE) { + if (zend_hash_find(EG(zend_constants), Z_STRVAL_P(const_name), Z_STRLEN_P(const_name)+1, (void **) &c) == FAILURE) { char *lookup_name = zend_str_tolower_dup(Z_STRVAL_P(const_name), Z_STRLEN_P(const_name)); if (zend_hash_find(EG(zend_constants), lookup_name, Z_STRLEN_P(const_name)+1, (void **) &c)==SUCCESS) { @@ -3888,88 +3815,112 @@ static int zend_constant_ct_subst(znode *result, zval *const_name, int all_inter void zend_do_fetch_constant(znode *result, znode *constant_container, znode *constant_name, int mode, zend_bool check_namespace TSRMLS_DC) /* {{{ */ { - znode tmp; - zend_op *opline; - int type; - char *compound; ulong fetch_type = 0; + znode tmp; + + if (constant_container && + constant_container->op_type == IS_CONST && + Z_TYPE(constant_container->u.constant) == IS_STRING && + Z_STRLEN(constant_container->u.constant) == 0) { + /* namespace::const */ + zval_dtor(&constant_container->u.constant); + check_namespace = 1; + constant_container = NULL; + fetch_type = ZEND_FETCH_CLASS_RT_NS_CHECK | IS_CONSTANT_RT_NS_CHECK; + } + + switch (mode) { + case ZEND_CT: + if (constant_container) { + int type = zend_get_class_fetch_type(Z_STRVAL(constant_container->u.constant), Z_STRLEN(constant_container->u.constant)); - if (constant_container) { - switch (mode) { - case ZEND_CT: - /* this is a class constant */ - type = zend_get_class_fetch_type(Z_STRVAL(constant_container->u.constant), Z_STRLEN(constant_container->u.constant)); - if (ZEND_FETCH_CLASS_STATIC == type) { zend_error(E_ERROR, "\"static::\" is not allowed in compile-time constants"); } else if (ZEND_FETCH_CLASS_DEFAULT == type) { zend_resolve_class_name(constant_container, &fetch_type, 1 TSRMLS_CC); } - zend_do_build_full_name(NULL, constant_container, constant_name, 1 TSRMLS_CC); + zend_do_build_full_name(NULL, constant_container, constant_name TSRMLS_CC); *result = *constant_container; result->u.constant.type = IS_CONSTANT | fetch_type; - break; - case ZEND_RT: - if (constant_container->op_type == IS_CONST && - ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_STRVAL(constant_container->u.constant), Z_STRLEN(constant_container->u.constant))) { - zend_resolve_class_name(constant_container, &fetch_type, 1 TSRMLS_CC); - } else { - zend_do_fetch_class(&tmp, constant_container TSRMLS_CC); + } else if (fetch_type || !zend_constant_ct_subst(result, &constant_name->u.constant, 0 TSRMLS_CC)) { + if (check_namespace && CG(current_namespace)) { + /* We assume we use constant from the current namespace + if it is not prefixed. */ + tmp.op_type = IS_CONST; + tmp.u.constant = *CG(current_namespace); + zval_copy_ctor(&tmp.u.constant); + zend_do_build_namespace_name(&tmp, &tmp, constant_name TSRMLS_CC); + *constant_name = tmp; + fetch_type |= IS_CONSTANT_RT_NS_CHECK; + } + *result = *constant_name; + result->u.constant.type = IS_CONSTANT | fetch_type; + } + break; + case ZEND_RT: + if (constant_container || + !zend_constant_ct_subst(result, &constant_name->u.constant, (!CG(current_namespace) || !check_namespace) TSRMLS_CC)) { + zend_op *opline; + + if (constant_container) { + if (constant_container->op_type == IS_CONST && + ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_STRVAL(constant_container->u.constant), Z_STRLEN(constant_container->u.constant))) { + zend_resolve_class_name(constant_container, &fetch_type, 1 TSRMLS_CC); + } else { + zend_do_fetch_class(&tmp, constant_container TSRMLS_CC); + constant_container = &tmp; + } + } else if (check_namespace && CG(current_namespace)) { + /* We assume we use constant from the current namespace + if it is not prefixed. */ + tmp.op_type = IS_CONST; + tmp.u.constant = *CG(current_namespace); + zval_copy_ctor(&tmp.u.constant); constant_container = &tmp; + fetch_type |= IS_CONSTANT_RT_NS_CHECK; } opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_FETCH_CONSTANT; + opline->extended_value = fetch_type & ~ZEND_FETCH_CLASS_RT_NS_NAME; opline->result.op_type = IS_TMP_VAR; opline->result.u.var = get_temporary_variable(CG(active_op_array)); - opline->op1 = *constant_container; + if (constant_container) { + opline->op1 = *constant_container; + } else { + SET_UNUSED(opline->op1); + } opline->op2 = *constant_name; *result = opline->result; - break; - } - return; - } - /* namespace constant */ - /* only one that did not contain \ from the start can be converted to string if unknown */ - switch (mode) { - case ZEND_CT: - compound = memchr(Z_STRVAL(constant_name->u.constant), '\\', Z_STRLEN(constant_name->u.constant)); - /* this is a namespace constant, or an unprefixed constant */ - - if (zend_constant_ct_subst(result, &constant_name->u.constant, 0 TSRMLS_CC)) { - break; - } - zend_resolve_non_class_name(constant_name, check_namespace TSRMLS_CC); - - if(!compound) { - fetch_type |= IS_CONSTANT_UNQUALIFIED; - } - - *result = *constant_name; - result->u.constant.type = IS_CONSTANT | fetch_type; - break; - case ZEND_RT: - compound = memchr(Z_STRVAL(constant_name->u.constant), '\\', Z_STRLEN(constant_name->u.constant)); - - zend_resolve_non_class_name(constant_name, check_namespace TSRMLS_CC); - - if(zend_constant_ct_subst(result, &constant_name->u.constant, 1 TSRMLS_CC)) { - break; - } + if (opline->op1.op_type == IS_CONST) { + /* Prebuild ns::func name to speedup run-time check. + The additional names are stored in additional OP_DATA opcode. */ + char *nsname; + unsigned int nsname_len; + + opline = get_next_op(CG(active_op_array) TSRMLS_CC); + opline->opcode = ZEND_OP_DATA; + opline->op1.op_type = IS_CONST; + SET_UNUSED(opline->op2); + + nsname = Z_STRVAL(constant_container->u.constant); + nsname_len = Z_STRLEN(constant_container->u.constant); + if (fetch_type & ZEND_FETCH_CLASS_RT_NS_NAME) { + /* Remove namespace name */ + nsname = (char *)memchr(nsname, ':', nsname_len) + 2; + nsname_len -= (nsname - Z_STRVAL(constant_container->u.constant)); + } - opline = get_next_op(CG(active_op_array) TSRMLS_CC); - opline->opcode = ZEND_FETCH_CONSTANT; - opline->result.op_type = IS_TMP_VAR; - opline->result.u.var = get_temporary_variable(CG(active_op_array)); - *result = opline->result; - SET_UNUSED(opline->op1); - if(compound) { - /* the name is unambiguous */ - opline->extended_value = 0; - } else { - opline->extended_value = IS_CONSTANT_UNQUALIFIED; + Z_TYPE(opline->op1.u.constant) = IS_STRING; + Z_STRVAL(opline->op1.u.constant) = emalloc(nsname_len + 2 + Z_STRLEN(constant_name->u.constant) + 1); + zend_str_tolower_copy(Z_STRVAL(opline->op1.u.constant), nsname, nsname_len); + Z_STRVAL(opline->op1.u.constant)[nsname_len] = ':'; + Z_STRVAL(opline->op1.u.constant)[nsname_len+1] = ':'; + memcpy(Z_STRVAL(opline->op1.u.constant)+nsname_len+2, Z_STRVAL(constant_name->u.constant), Z_STRLEN(constant_name->u.constant) + 1); + Z_STRLEN(opline->op1.u.constant) = nsname_len + 2 + Z_STRLEN(constant_name->u.constant); + opline->extended_value = zend_hash_func(Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant) + 1); + } } - opline->op2 = *constant_name; break; } } @@ -4681,13 +4632,12 @@ void zend_do_declare_stmt(znode *var, znode *val TSRMLS_DC) zend_multibyte_yyinput_again(old_input_filter, old_encoding TSRMLS_CC); } } - efree(val->u.constant.value.str.val); #else /* !ZEND_MULTIBYTE */ } else if (!zend_binary_strcasecmp(var->u.constant.value.str.val, var->u.constant.value.str.len, "encoding", sizeof("encoding")-1)) { /* Do not generate any kind of warning for encoding declares */ /* zend_error(E_COMPILE_WARNING, "Declare encoding [%s] not supported", val->u.constant.value.str.val); */ - zval_dtor(&val->u.constant); #endif /* ZEND_MULTIBYTE */ + efree(val->u.constant.value.str.val); } else { zend_error(E_COMPILE_WARNING, "Unsupported declare '%s'", var->u.constant.value.str.val); zval_dtor(&val->u.constant); @@ -4952,9 +4902,6 @@ again: if (LANG_SCNG(yy_text)[LANG_SCNG(yy_leng)-1] != '>') { CG(increment_lineno) = 1; } - if (CG(has_bracketed_namespaces) && !CG(in_namespace)) { - goto again; - } retval = ';'; /* implicit ; */ break; case T_OPEN_TAG_WITH_ECHO: @@ -5066,7 +5013,7 @@ void zend_do_build_namespace_name(znode *result, znode *prefix, znode *name TSRM *result = *prefix; if (Z_TYPE(result->u.constant) == IS_STRING && Z_STRLEN(result->u.constant) == 0) { - /* namespace\ */ + /* namespace:: */ if (CG(current_namespace)) { znode tmp; @@ -5084,32 +5031,15 @@ void zend_do_build_namespace_name(znode *result, znode *prefix, znode *name TSRM Z_STRLEN(result->u.constant) = 0; } /* prefix = result */ - zend_do_build_full_name(NULL, result, name, 0 TSRMLS_CC); + zend_do_build_full_name(NULL, result, name TSRMLS_CC); } /* }}} */ -void zend_do_begin_namespace(const znode *name, zend_bool with_bracket TSRMLS_DC) /* {{{ */ +void zend_do_namespace(const znode *name TSRMLS_DC) /* {{{ */ { char *lcname; - /* handle mixed syntax declaration or nested namespaces */ - if (!CG(has_bracketed_namespaces)) { - if (CG(current_namespace)) { - /* previous namespace declarations were unbracketed */ - if (with_bracket) { - zend_error(E_COMPILE_ERROR, "Cannot mix bracketed namespace declarations with unbracketed namespace declarations"); - } - } - } else { - /* previous namespace declarations were bracketed */ - if (!with_bracket) { - zend_error(E_COMPILE_ERROR, "Cannot mix bracketed namespace declarations with unbracketed namespace declarations"); - } else if (CG(current_namespace) || CG(in_namespace)) { - zend_error(E_COMPILE_ERROR, "Namespace declarations cannot be nested"); - } - } - - if (((!with_bracket && !CG(current_namespace)) || (with_bracket && !CG(has_bracketed_namespaces))) && CG(active_op_array)->last > 0) { + if (CG(active_op_array)->last > 0) { /* ignore ZEND_EXT_STMT and ZEND_TICKS */ int num = CG(active_op_array)->last; while (num > 0 && @@ -5117,45 +5047,31 @@ void zend_do_begin_namespace(const znode *name, zend_bool with_bracket TSRMLS_DC CG(active_op_array)->opcodes[num-1].opcode == ZEND_TICKS)) { --num; } - if (num > 0) { + if (!CG(current_namespace) && num > 0) { zend_error(E_COMPILE_ERROR, "Namespace declaration statement has to be the very first statement in the script"); } } - - CG(in_namespace) = 1; - if (with_bracket) { - CG(has_bracketed_namespaces) = 1; + 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(E_COMPILE_ERROR, "Cannot use '%s' as namespace name", Z_STRVAL(name->u.constant)); } + efree(lcname); - 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(E_COMPILE_ERROR, "Cannot use '%s' as namespace name", Z_STRVAL(name->u.constant)); - } - efree(lcname); - - if (CG(current_namespace)) { - zval_dtor(CG(current_namespace)); - } else { - ALLOC_ZVAL(CG(current_namespace)); - } - *CG(current_namespace) = name->u.constant; + if (CG(current_namespace)) { + zval_dtor(CG(current_namespace)); } else { - if (CG(current_namespace)) { - zval_dtor(CG(current_namespace)); - FREE_ZVAL(CG(current_namespace)); - CG(current_namespace) = NULL; - } + ALLOC_ZVAL(CG(current_namespace)); } - if (CG(current_import)) { zend_hash_destroy(CG(current_import)); efree(CG(current_import)); CG(current_import) = NULL; } + + *CG(current_namespace) = name->u.constant; } /* }}} */ @@ -5178,10 +5094,10 @@ void zend_do_use(znode *ns_name, znode *new_name, int is_global TSRMLS_DC) /* {{ } else { char *p; - /* The form "use A\B" is eqivalent to "use A\B as B". - So we extract the last part of compound name to use as a new_name */ + /* The form "use A::B" is eqivalent to "use A::B as B". + So we extract the last part of compound name ti use as a new_name */ name = &tmp; - p = zend_memrchr(Z_STRVAL_P(ns), '\\', Z_STRLEN_P(ns)); + p = zend_memrchr(Z_STRVAL_P(ns), ':', Z_STRLEN_P(ns)); if (p) { ZVAL_STRING(name, p+1, 1); } else { @@ -5202,15 +5118,16 @@ void zend_do_use(znode *ns_name, znode *new_name, int is_global TSRMLS_DC) /* {{ if (CG(current_namespace)) { /* Prefix import name with current namespace name to avoid conflicts with classes */ - char *ns_name = emalloc(Z_STRLEN_P(CG(current_namespace)) + 1 + Z_STRLEN_P(name) + 1); + char *ns_name = emalloc(Z_STRLEN_P(CG(current_namespace)) + 2 + Z_STRLEN_P(name) + 1); zend_str_tolower_copy(ns_name, Z_STRVAL_P(CG(current_namespace)), Z_STRLEN_P(CG(current_namespace))); - ns_name[Z_STRLEN_P(CG(current_namespace))] = '\\'; - memcpy(ns_name+Z_STRLEN_P(CG(current_namespace))+1, lcname, Z_STRLEN_P(name)+1); - if (zend_hash_exists(CG(class_table), ns_name, Z_STRLEN_P(CG(current_namespace)) + 1 + Z_STRLEN_P(name)+1)) { + ns_name[Z_STRLEN_P(CG(current_namespace))] = ':'; + ns_name[Z_STRLEN_P(CG(current_namespace))+1] = ':'; + memcpy(ns_name+Z_STRLEN_P(CG(current_namespace))+2, lcname, Z_STRLEN_P(name)+1); + if (zend_hash_exists(CG(class_table), ns_name, Z_STRLEN_P(CG(current_namespace)) + 2 + Z_STRLEN_P(name)+1)) { char *tmp = zend_str_tolower_dup(Z_STRVAL_P(ns), Z_STRLEN_P(ns)); - if (Z_STRLEN_P(ns) != Z_STRLEN_P(CG(current_namespace)) + 1 + Z_STRLEN_P(name) || + if (Z_STRLEN_P(ns) != Z_STRLEN_P(CG(current_namespace)) + 2 + Z_STRLEN_P(name) || memcmp(tmp, ns_name, Z_STRLEN_P(ns))) { zend_error(E_COMPILE_ERROR, "Cannot use %s as %s because the name is already in use", Z_STRVAL_P(ns), Z_STRVAL_P(name)); } @@ -5253,7 +5170,7 @@ void zend_do_declare_constant(znode *name, znode *value TSRMLS_DC) /* {{{ */ } if (CG(current_namespace)) { - /* Prefix constant name with name of current namespace, lowercased */ + /* Prefix constant name with name of current namespace */ znode tmp; tmp.op_type = IS_CONST; @@ -5271,17 +5188,8 @@ void zend_do_declare_constant(znode *name, znode *value TSRMLS_DC) /* {{{ */ } /* }}} */ -void zend_verify_namespace(TSRMLS_D) /* {{{ */ -{ - if (CG(has_bracketed_namespaces) && !CG(in_namespace)) { - zend_error(E_COMPILE_ERROR, "No code may exist outside of namespace {}"); - } -} -/* }}} */ - -void zend_do_end_namespace(TSRMLS_D) /* {{{ */ +void zend_do_end_compilation(TSRMLS_D) /* {{{ */ { - CG(in_namespace) = 0; if (CG(current_namespace)) { zval_dtor(CG(current_namespace)); FREE_ZVAL(CG(current_namespace)); @@ -5295,13 +5203,6 @@ void zend_do_end_namespace(TSRMLS_D) /* {{{ */ } /* }}} */ -void zend_do_end_compilation(TSRMLS_D) /* {{{ */ -{ - CG(has_bracketed_namespaces) = 0; - zend_do_end_namespace(TSRMLS_C); -} -/* }}} */ - /* {{{ zend_dirname Returns directory name component of path */ ZEND_API size_t zend_dirname(char *path, size_t len) |