summaryrefslogtreecommitdiff
path: root/Zend/zend_compile.c
diff options
context:
space:
mode:
Diffstat (limited to 'Zend/zend_compile.c')
-rw-r--r--Zend/zend_compile.c531
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)