- 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).
This commit is contained in:
Andi Gutmans 2002-09-24 19:05:53 +00:00
parent f91b3d5c6d
commit f78fa50423
4 changed files with 136 additions and 220 deletions

View File

@ -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,10 +1613,8 @@ 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)
ZEND_API int do_bind_function(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);
@ -1641,8 +1639,10 @@ ZEND_API int do_bind_function_or_class(zend_op *opline, HashTable *function_tabl
return SUCCESS;
}
}
break;
case ZEND_DECLARE_CLASS: {
ZEND_API int do_bind_class(zend_op *opline, HashTable *function_table, HashTable *class_table)
{
zend_class_entry *ce, **pce;
if (zend_hash_find(class_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, (void **) &pce)==FAILURE) {
@ -1657,66 +1657,38 @@ ZEND_API int do_bind_function_or_class(zend_op *opline, HashTable *function_tabl
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;
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;
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++;
if (found_ce == FAILURE) {
zend_error(E_ERROR, "Cannot redeclare class %s", class_name);
zend_error(E_ERROR, "Cannot redeclare class %s", (*pce)->name);
return FAILURE;
} else {
ce = *pce;
}
ce->refcount++;
/* 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();
zend_do_inheritance(ce, parent_ce);
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 (strchr(opline->op2.u.constant.value.str.val, ':')) {
return create_nested_class(class_table, opline->op2.u.constant.value.str.val, ce);
}
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) {
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);
@ -1728,35 +1700,17 @@ ZEND_API int do_bind_function_or_class(zend_op *opline, HashTable *function_tabl
}
return SUCCESS;
}
break;
}
return FAILURE;
}
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;
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,88 +2038,30 @@ 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;
}
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->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;
opline->extended_value = ZEND_DECLARE_CLASS;
}
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;

View File

@ -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

View File

@ -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) {

View File

@ -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: