From: Andi Gutmans Date: Tue, 24 Sep 2002 19:05:53 +0000 (+0000) Subject: - Megapatch to try and support inheritance from sub-classes. Things might X-Git-Tag: MODERN_SYMMETRIC_SESSION_BEHAVIOUR_20021003~206 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f78fa5042318563d0ec4d8a3d60a8a7645022348;p=php - Megapatch to try and support inheritance from sub-classes. Things might - be *very* buggy now so don't get too upset if that happens. - I still need to improve some stuff but it's a good step (hopefully). --- diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 31a06aac7b..d4e7f4be7e 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -34,7 +34,7 @@ ZEND_API zend_compiler_globals compiler_globals; ZEND_API zend_executor_globals executor_globals; #endif -static void build_runtime_defined_function_key(zval *result, zval *name, zend_op *opline TSRMLS_DC) +static void build_runtime_defined_function_key(zval *result, char *name, int name_length, zend_op *opline TSRMLS_DC) { char lineno_buf[32]; uint lineno_len; @@ -48,9 +48,9 @@ static void build_runtime_defined_function_key(zval *result, zval *name, zend_op } /* NULL, name length, filename length, line number length */ - result->value.str.len = 1+name->value.str.len+strlen(filename)+lineno_len; + result->value.str.len = 1+name_length+strlen(filename)+lineno_len; result->value.str.val = (char *) emalloc(result->value.str.len+1); - sprintf(result->value.str.val, "%c%s%s%s", '\0', name->value.str.val, filename, lineno_buf); + sprintf(result->value.str.val, "%c%s%s%s", '\0', name, filename, lineno_buf); result->type = IS_STRING; result->refcount = 1; } @@ -944,9 +944,9 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n } else { zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); - opline->opcode = ZEND_DECLARE_FUNCTION_OR_CLASS; + opline->opcode = ZEND_DECLARE_FUNCTION; opline->op1.op_type = IS_CONST; - build_runtime_defined_function_key(&opline->op1.u.constant, &function_name->u.constant, opline TSRMLS_CC); + build_runtime_defined_function_key(&opline->op1.u.constant, function_name->u.constant.value.str.val, function_name->u.constant.value.str.len, opline TSRMLS_CC); opline->op2.op_type = IS_CONST; opline->op2.u.constant.type = IS_STRING; opline->op2.u.constant.value.str.val = estrndup(name, name_len); @@ -1613,150 +1613,104 @@ static int create_nested_class(HashTable *class_table, char *path, zend_class_en return SUCCESS; } -ZEND_API int do_bind_function_or_class(zend_op *opline, HashTable *function_table, HashTable *class_table, int compile_time) -{ - switch (opline->extended_value) { - case ZEND_DECLARE_FUNCTION: { - zend_function *function; - - zend_hash_find(function_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, (void *) &function); - if (zend_hash_add(function_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, function, sizeof(zend_function), NULL)==FAILURE) { - int error_level = compile_time ? E_COMPILE_ERROR : E_ERROR; - zend_function *function; - - if (zend_hash_find(function_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, (void *) &function)==SUCCESS - && function->type==ZEND_USER_FUNCTION - && ((zend_op_array *) function)->last>0) { - zend_error(error_level, "Cannot redeclare %s() (previously declared in %s:%d)", - opline->op2.u.constant.value.str.val, - ((zend_op_array *) function)->filename, - ((zend_op_array *) function)->opcodes[0].lineno); - } else { - zend_error(error_level, "Cannot redeclare %s()", opline->op2.u.constant.value.str.val); - } - return FAILURE; - } else { - (*function->op_array.refcount)++; - function->op_array.static_variables = NULL; /* NULL out the unbound function */ - return SUCCESS; - } - } - break; - case ZEND_DECLARE_CLASS: { - zend_class_entry *ce, **pce; +ZEND_API int do_bind_function(zend_op *opline, HashTable *function_table, HashTable *class_table, int compile_time) +{ + zend_function *function; - if (zend_hash_find(class_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, (void **) &pce)==FAILURE) { - zend_error(E_ERROR, "Internal Zend error - Missing class information for %s", opline->op1.u.constant.value.str.val); - return FAILURE; - } else { - ce = *pce; - } - if (strchr(opline->op2.u.constant.value.str.val, ':')) { - return create_nested_class(class_table, opline->op2.u.constant.value.str.val, ce); - } - ce->refcount++; - if (zend_hash_add(class_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, &ce, sizeof(zend_class_entry *), NULL)==FAILURE) { - ce->refcount--; - if (!compile_time) { - zend_error(E_ERROR, "Cannot redeclare class %s", opline->op2.u.constant.value.str.val); - } - return FAILURE; - } else { - return SUCCESS; - } - } - break; - case ZEND_DECLARE_INHERITED_CLASS: { - zend_class_entry **parent_pce, *ce, **pce; - int parent_name_length; - char *class_name, *parent_name; - int found_ce; - int retval; - - found_ce = zend_hash_find(class_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, (void **) &pce); - - /* Restore base class / derived class names */ - class_name = strchr(opline->op2.u.constant.value.str.val, ':'); - if (!class_name) { - zend_error(E_CORE_ERROR, "Invalid runtime class entry"); - } - class_name++; + zend_hash_find(function_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, (void *) &function); + if (zend_hash_add(function_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, function, sizeof(zend_function), NULL)==FAILURE) { + int error_level = compile_time ? E_COMPILE_ERROR : E_ERROR; + zend_function *function; + + if (zend_hash_find(function_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, (void *) &function)==SUCCESS + && function->type==ZEND_USER_FUNCTION + && ((zend_op_array *) function)->last>0) { + zend_error(error_level, "Cannot redeclare %s() (previously declared in %s:%d)", + opline->op2.u.constant.value.str.val, + ((zend_op_array *) function)->filename, + ((zend_op_array *) function)->opcodes[0].lineno); + } else { + zend_error(error_level, "Cannot redeclare %s()", opline->op2.u.constant.value.str.val); + } + return FAILURE; + } else { + (*function->op_array.refcount)++; + function->op_array.static_variables = NULL; /* NULL out the unbound function */ + return SUCCESS; + } +} + - if (found_ce==FAILURE) { - zend_error(E_ERROR, "Cannot redeclare class %s", class_name); - return FAILURE; - } else { - ce = *pce; - } - ce->refcount++; +ZEND_API int do_bind_class(zend_op *opline, HashTable *function_table, HashTable *class_table) +{ + zend_class_entry *ce, **pce; - /* Obtain parent class */ - parent_name_length = class_name - opline->op2.u.constant.value.str.val - 1; - parent_name = estrndup(opline->op2.u.constant.value.str.val, parent_name_length); - if (!compile_time) { - TSRMLS_FETCH(); + if (zend_hash_find(class_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, (void **) &pce)==FAILURE) { + zend_error(E_ERROR, "Internal Zend error - Missing class information for %s", opline->op1.u.constant.value.str.val); + return FAILURE; + } else { + ce = *pce; + } + if (strchr(opline->op2.u.constant.value.str.val, ':')) { + return create_nested_class(class_table, opline->op2.u.constant.value.str.val, ce); + } + ce->refcount++; + if (zend_hash_add(class_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, &ce, sizeof(zend_class_entry *), NULL)==FAILURE) { + ce->refcount--; + zend_error(E_ERROR, "Cannot redeclare class %s", opline->op2.u.constant.value.str.val); + return FAILURE; + } else { + return SUCCESS; + } +} - retval = zend_lookup_class(parent_name, parent_name_length, &parent_pce TSRMLS_CC); - } else { - retval = zend_hash_find(class_table, parent_name, parent_name_length+1, (void **) &parent_pce); - } - if (retval == FAILURE) { - if (!compile_time) { - zend_error(E_ERROR, "Class %s: Cannot inherit from undefined class %s", class_name, parent_name); - } - ce->refcount--; - efree(parent_name); - return FAILURE; - } - efree(parent_name); - - zend_do_inheritance(ce, *parent_pce); - - /* Register the derived class */ - if (zend_hash_add(class_table, class_name, strlen(class_name)+1, pce, sizeof(zend_class_entry *), NULL)==FAILURE) { - if (!compile_time) { - zend_error(E_ERROR, "Cannot redeclare class %s", opline->op2.u.constant.value.str.val); - } - ce->refcount--; - zend_hash_destroy(&ce->function_table); - zend_hash_destroy(&ce->default_properties); - zend_hash_destroy(&ce->private_properties); - zend_hash_destroy(&ce->protected_properties); - zend_hash_destroy(ce->static_members); - zend_hash_destroy(&ce->constants_table); - return FAILURE; - } - return SUCCESS; - } - break; +ZEND_API int do_bind_inherited_class(zend_op *opline, HashTable *function_table, HashTable *class_table, zend_class_entry *parent_ce) +{ + zend_class_entry *ce, **pce; + int found_ce; + + found_ce = zend_hash_find(class_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, (void **) &pce); + + if (found_ce == FAILURE) { + zend_error(E_ERROR, "Cannot redeclare class %s", (*pce)->name); + return FAILURE; + } else { + ce = *pce; + } + + ce->refcount++; + + zend_do_inheritance(ce, parent_ce); + + if (strchr(opline->op2.u.constant.value.str.val, ':')) { + return create_nested_class(class_table, opline->op2.u.constant.value.str.val, ce); + } + + /* Register the derived class */ + if (zend_hash_add(class_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, pce, sizeof(zend_class_entry *), NULL)==FAILURE) { + zend_error(E_ERROR, "Cannot redeclare class %s", opline->op2.u.constant.value.str.val); + ce->refcount--; + zend_hash_destroy(&ce->function_table); + zend_hash_destroy(&ce->default_properties); + zend_hash_destroy(&ce->private_properties); + zend_hash_destroy(&ce->protected_properties); + zend_hash_destroy(ce->static_members); + zend_hash_destroy(&ce->constants_table); + return FAILURE; } - return FAILURE; + return SUCCESS; } void zend_do_early_binding(TSRMLS_D) { zend_op *opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1]; - HashTable *table; - if (opline->op2.op_type != IS_UNUSED && strchr(opline->op2.u.constant.value.str.val, ':')) { + if (do_bind_function(opline, CG(function_table), CG(class_table), 1) == FAILURE) { return; } - if (do_bind_function_or_class(opline, CG(function_table), CG(class_table), 1)==FAILURE) { - return; - } - switch (opline->extended_value) { - case ZEND_DECLARE_FUNCTION: - table = CG(function_table); - break; - case ZEND_DECLARE_CLASS: - table = CG(class_table); - break; - default: - zend_error(E_COMPILE_ERROR, "Invalid binding type"); - return; - } - zend_hash_del(table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len); + + zend_hash_del(CG(function_table), opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len); zval_dtor(&opline->op1.u.constant); zval_dtor(&opline->op2.u.constant); opline->opcode = ZEND_NOP; @@ -2042,13 +1996,22 @@ void zend_do_default_before_statement(znode *case_list, znode *default_token TSR void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znode *parent_class_name TSRMLS_DC) { zend_op *opline; - int runtime_inheritance = 0; + int doing_inheritance = 0; zend_class_entry *new_class_entry = emalloc(sizeof(zend_class_entry)); class_token->u.previously_active_class_entry = CG(active_class_entry); new_class_entry->type = ZEND_USER_CLASS; - new_class_entry->name = class_name->u.constant.value.str.val; - new_class_entry->name_length = class_name->u.constant.value.str.len; + if (CG(active_class_entry)) { + new_class_entry->name_length = sizeof("::")-1 + class_name->u.constant.value.str.len + CG(active_class_entry)->name_length; + new_class_entry->name = emalloc(new_class_entry->name_length+1); + strcpy(new_class_entry->name, CG(active_class_entry)->name); + strcat(new_class_entry->name, "::"); + strcat(new_class_entry->name, class_name->u.constant.value.str.val); + STR_FREE(class_name->u.constant.value.str.val); + } else { + new_class_entry->name = class_name->u.constant.value.str.val; + new_class_entry->name_length = class_name->u.constant.value.str.len; + } new_class_entry->refcount = 1; new_class_entry->constants_updated = 0; @@ -2075,89 +2038,31 @@ void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znod new_class_entry->handle_property_set = NULL; new_class_entry->handle_property_get = NULL; - /* code for inheritance from parent class */ - if (parent_class_name->op_type == IS_CONST) { - zend_class_entry *parent_class, **parent_class_p; - zend_function tmp_zend_function; - zval *tmp; - - zend_str_tolower(parent_class_name->u.constant.value.str.val, parent_class_name->u.constant.value.str.len); - CG(active_ce_parent_class_name).value.str.val = estrndup(parent_class_name->u.constant.value.str.val, parent_class_name->u.constant.value.str.len); - CG(active_ce_parent_class_name).value.str.len = parent_class_name->u.constant.value.str.len; - - if ((CG(active_class_entry) && (zend_hash_find(&CG(active_class_entry)->class_table, parent_class_name->u.constant.value.str.val, parent_class_name->u.constant.value.str.len+1, (void **) &parent_class_p) == SUCCESS)) || - zend_hash_find(CG(class_table), parent_class_name->u.constant.value.str.val, parent_class_name->u.constant.value.str.len+1, (void **) &parent_class_p) == SUCCESS) { - parent_class = *parent_class_p; - /* copy functions */ - zend_hash_copy(&new_class_entry->function_table, &parent_class->function_table, (copy_ctor_func_t) function_add_ref, &tmp_zend_function, sizeof(zend_function)); - - /* copy default properties */ - zend_hash_copy(&new_class_entry->default_properties, &parent_class->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); - - /* copy static members */ - zend_hash_copy(new_class_entry->static_members, parent_class->static_members, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); - - /* copy constants */ - zend_hash_copy(&new_class_entry->constants_table, &parent_class->constants_table, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); - - new_class_entry->constructor = parent_class->constructor; - new_class_entry->destructor = parent_class->destructor; - - /* FIXME: What do we do with clone? */ - - /* copy overloaded handlers */ - new_class_entry->handle_function_call = parent_class->handle_function_call; - new_class_entry->handle_property_get = parent_class->handle_property_get; - new_class_entry->handle_property_set = parent_class->handle_property_set; - - new_class_entry->parent = parent_class; - - zval_dtor(&parent_class_name->u.constant); - } else { - runtime_inheritance = 1; - new_class_entry->parent = NULL; - } - } else { - new_class_entry->parent = NULL; - } + new_class_entry->parent = NULL; - if (CG(active_class_entry)) { - if (runtime_inheritance) { - zend_error(E_COMPILE_ERROR, "Only first level classes can inherit from undefined classes"); - } - zend_hash_update(&CG(active_class_entry)->class_table, new_class_entry->name, new_class_entry->name_length+1, &new_class_entry, sizeof(zend_class_entry *), NULL); - CG(active_class_entry) = new_class_entry; - return; + if (parent_class_name->op_type != IS_UNUSED) { + doing_inheritance = 1; } opline = get_next_op(CG(active_op_array) TSRMLS_CC); - opline->opcode = ZEND_DECLARE_FUNCTION_OR_CLASS; + opline->op1.op_type = IS_CONST; - build_runtime_defined_function_key(&opline->op1.u.constant, &class_name->u.constant, opline TSRMLS_CC); + build_runtime_defined_function_key(&opline->op1.u.constant, new_class_entry->name, new_class_entry->name_length, opline TSRMLS_CC); + opline->op2.op_type = IS_CONST; opline->op2.u.constant.type = IS_STRING; opline->op2.u.constant.refcount = 1; - if (runtime_inheritance) { - char *full_class_name; - - opline->op2.u.constant.value.str.len = parent_class_name->u.constant.value.str.len+1+new_class_entry->name_length; - full_class_name = opline->op2.u.constant.value.str.val = (char *) emalloc(opline->op2.u.constant.value.str.len+1); - - memcpy(full_class_name, parent_class_name->u.constant.value.str.val, parent_class_name->u.constant.value.str.len); - full_class_name += parent_class_name->u.constant.value.str.len; - full_class_name[0] = ':'; - full_class_name++; - memcpy(full_class_name, new_class_entry->name, new_class_entry->name_length); - zval_dtor(&parent_class_name->u.constant); - full_class_name += new_class_entry->name_length; - full_class_name[0] = 0; - opline->extended_value = ZEND_DECLARE_INHERITED_CLASS; + + if (doing_inheritance) { + opline->extended_value = parent_class_name->u.var; + opline->opcode = ZEND_DECLARE_INHERITED_CLASS; } else { - opline->op2.u.constant.value.str.val = estrndup(new_class_entry->name, new_class_entry->name_length); - opline->op2.u.constant.value.str.len = new_class_entry->name_length; - opline->extended_value = ZEND_DECLARE_CLASS; + opline->opcode = ZEND_DECLARE_CLASS; } - + + opline->op2.u.constant.value.str.val = estrndup(new_class_entry->name, new_class_entry->name_length); + opline->op2.u.constant.value.str.len = new_class_entry->name_length; + zend_hash_update(CG(class_table), opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, &new_class_entry, sizeof(zend_class_entry *), NULL); CG(active_class_entry) = new_class_entry; } diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 94422bf766..8fac9268d5 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -305,7 +305,10 @@ void zend_do_begin_catch(znode *try_token, znode *catch_class, znode *catch_var, void zend_do_end_catch(znode *try_token TSRMLS_DC); void zend_do_throw(znode *expr TSRMLS_DC); -ZEND_API int do_bind_function_or_class(zend_op *opline, HashTable *function_table, HashTable *class_table, int compile_time); +ZEND_API int do_bind_function(zend_op *opline, HashTable *function_table, HashTable *class_table, int compile_time); +ZEND_API int do_bind_class(zend_op *opline, HashTable *function_table, HashTable *class_table); +ZEND_API int do_bind_inherited_class(zend_op *opline, HashTable *function_table, HashTable *class_table, zend_class_entry *parent_ce); + void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce); void zend_do_early_binding(TSRMLS_D); @@ -549,7 +552,7 @@ int zendlex(znode *zendlval TSRMLS_DC); #define ZEND_FETCH_DIM_TMP_VAR 98 #define ZEND_FETCH_CONSTANT 99 -#define ZEND_DECLARE_FUNCTION_OR_CLASS 100 +/* Hole - 100 */ #define ZEND_EXT_STMT 101 #define ZEND_EXT_FCALL_BEGIN 102 @@ -600,6 +603,10 @@ int zendlex(znode *zendlval TSRMLS_DC); #define ZEND_IS_CLASS 138 +#define ZEND_DECLARE_CLASS 139 +#define ZEND_DECLARE_INHERITED_CLASS 140 +#define ZEND_DECLARE_FUNCTION 141 + /* end of block */ @@ -667,10 +674,6 @@ int zendlex(znode *zendlval TSRMLS_DC); #define ZEND_HANDLE_STDIOSTREAM 3 #define ZEND_HANDLE_FSTREAM 4 -#define ZEND_DECLARE_CLASS 1 -#define ZEND_DECLARE_FUNCTION 2 -#define ZEND_DECLARE_INHERITED_CLASS 3 - #define ZEND_FETCH_STANDARD 0 #define ZEND_FETCH_ADD_LOCK 1 diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index d7e3079cf2..001eb0b1c2 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -3140,8 +3140,16 @@ send_by_ref: zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_fcall_end_handler, op_array TSRMLS_CC); } NEXT_OPCODE(); - case ZEND_DECLARE_FUNCTION_OR_CLASS: - do_bind_function_or_class(EX(opline), EG(function_table), EG(class_table), 0); + case ZEND_DECLARE_CLASS: + do_bind_class(EX(opline), EG(function_table), EG(class_table)); + NEXT_OPCODE() + break; + case ZEND_DECLARE_INHERITED_CLASS: + do_bind_inherited_class(EX(opline), EG(function_table), EG(class_table), EX(Ts)[EX(opline)->extended_value].EA.class_entry); + NEXT_OPCODE(); + break; + case ZEND_DECLARE_FUNCTION: + do_bind_function(EX(opline), EG(function_table), EG(class_table), 0); NEXT_OPCODE(); case ZEND_TICKS: if (++EG(ticks_count)>=EX(opline)->op1.u.constant.value.lval) { diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index fb7f2f09cc..618a94fd55 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -286,7 +286,7 @@ unticked_class_declaration_statement: extends_from: /* empty */ { $$.op_type = IS_UNUSED; } - | T_EXTENDS T_STRING { $$ = $2; } + | T_EXTENDS catch_or_import_class_entry { $$ = $2; } ; declaration_class_name: