diff options
45 files changed, 2464 insertions, 700 deletions
@@ -4,6 +4,8 @@  - Upgraded bundled sqlite to version 3.6.23.1. (Ilia)  - Upgraded bundled PCRE to version 8.02. (Ilia) +- Added caches to eliminate repeatable run-time bindings of functions, classes, +  constants, methods and properties (Dmitry)  - Added a number of small performance tweaks and optimizations (Dmitry)    . ZEND_RECV now always has IS_CV as its result    . ZEND_CATCH now has to be used only with constant class names diff --git a/Zend/bench.php b/Zend/bench.php index 42b333fceb..5f771803cc 100644 --- a/Zend/bench.php +++ b/Zend/bench.php @@ -3,7 +3,6 @@ if (function_exists("date_default_timezone_set")) {  	date_default_timezone_set("UTC");  } -date_default_timezone_set('UTC');  function simple() {    $a = 0;    for ($i = 0; $i < 1000000; $i++)  diff --git a/Zend/zend.h b/Zend/zend.h index 572b64b043..10ef1bcea7 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -298,6 +298,7 @@ typedef struct _zend_guard {  typedef struct _zend_object {  	zend_class_entry *ce;  	HashTable *properties; +	zval **properties_table;  	HashTable *guards; /* protects from __get/__set ... recursion */  } zend_object; @@ -468,11 +469,13 @@ struct _zend_class_entry {  	zend_uint ce_flags;  	HashTable function_table; -	HashTable default_properties;  	HashTable properties_info; -	HashTable default_static_members; -	HashTable *static_members; +	zval **default_properties_table; +	zval **default_static_members_table; +	zval **static_members_table;  	HashTable constants_table; +	int default_properties_count; +	int default_static_members_count;  	const struct _zend_function_entry *builtin_functions;  	union _zend_function *constructor; diff --git a/Zend/zend_API.c b/Zend/zend_API.c index e44f6f8bc9..567f45c03d 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -1005,45 +1005,41 @@ ZEND_API void zend_merge_properties(zval *obj, HashTable *properties, int destro  ZEND_API void zend_update_class_constants(zend_class_entry *class_type TSRMLS_DC) /* {{{ */  { -	if (!class_type->constants_updated || !CE_STATIC_MEMBERS(class_type)) { +	if (!class_type->constants_updated || (!CE_STATIC_MEMBERS(class_type) && class_type->default_static_members_count)) {  		zend_class_entry **scope = EG(in_execution)?&EG(scope):&CG(active_class_entry);  		zend_class_entry *old_scope = *scope; +		int i;  		*scope = class_type;  		zend_hash_apply_with_argument(&class_type->constants_table, (apply_func_arg_t) zval_update_constant, (void*)1 TSRMLS_CC); -		zend_hash_apply_with_argument(&class_type->default_properties, (apply_func_arg_t) zval_update_constant, (void *) 1 TSRMLS_CC); -		if (!CE_STATIC_MEMBERS(class_type)) { -			HashPosition pos; +		for (i = 0; i < class_type->default_properties_count; i++) { +			if (class_type->default_properties_table[i]) { +				zval_update_constant(&class_type->default_properties_table[i], (void**)1 TSRMLS_CC); +			} +		} + +		if (!CE_STATIC_MEMBERS(class_type) && class_type->default_static_members_count) {  			zval **p;  			if (class_type->parent) {  				zend_update_class_constants(class_type->parent TSRMLS_CC);  			}  #if ZTS -			ALLOC_HASHTABLE(CG(static_members)[(zend_intptr_t)(class_type->static_members)]); +			CG(static_members)[(zend_intptr_t)(class_type->static_members)] = emalloc(sizeof(zval*) * class_type->default_static_members_count);  #else -			ALLOC_HASHTABLE(class_type->static_members); +			class_type->static_members_table = emalloc(sizeof(zval*) * class_type->default_static_members_count);  #endif -			zend_hash_init(CE_STATIC_MEMBERS(class_type), zend_hash_num_elements(&class_type->default_static_members), NULL, ZVAL_PTR_DTOR, 0); - -			zend_hash_internal_pointer_reset_ex(&class_type->default_static_members, &pos); -			while (zend_hash_get_current_data_ex(&class_type->default_static_members, (void**)&p, &pos) == SUCCESS) { -				char *str_index; -				uint str_length; -				ulong num_index; -				zval **q; - -				zend_hash_get_current_key_ex(&class_type->default_static_members, &str_index, &str_length, &num_index, 0, &pos); +			for (i = 0; i < class_type->default_static_members_count; i++) { +				p = &class_type->default_static_members_table[i];  				if (Z_ISREF_PP(p) &&  					class_type->parent && -					zend_hash_find(&class_type->parent->default_static_members, str_index, str_length, (void**)&q) == SUCCESS && -					*p == *q && -					zend_hash_find(CE_STATIC_MEMBERS(class_type->parent), str_index, str_length, (void**)&q) == SUCCESS +					class_type->parent->default_static_members_count < i && +					*p == class_type->parent->default_static_members_table[i]  				) { -					Z_ADDREF_PP(q); -					Z_SET_ISREF_PP(q); -					zend_hash_add(CE_STATIC_MEMBERS(class_type), str_index, str_length, (void**)q, sizeof(zval*), NULL); +					Z_ADDREF_PP(p); +					Z_SET_ISREF_PP(p); +					class_type->static_members_table[i] = *p;  				} else {  					zval *r; @@ -1051,12 +1047,14 @@ ZEND_API void zend_update_class_constants(zend_class_entry *class_type TSRMLS_DC  					*r = **p;  					INIT_PZVAL(r);  					zval_copy_ctor(r); -					zend_hash_add(CE_STATIC_MEMBERS(class_type), str_index, str_length, (void**)&r, sizeof(zval*), NULL); +					class_type->static_members_table[i] = r;  				} -				zend_hash_move_forward_ex(&class_type->default_static_members, &pos);  			}  		} -		zend_hash_apply_with_argument(CE_STATIC_MEMBERS(class_type), (apply_func_arg_t) zval_update_constant, (void *) 1 TSRMLS_CC); + +		for (i = 0; i < class_type->default_static_members_count; i++) { +			zval_update_constant(&CE_STATIC_MEMBERS(class_type)[i], (void**)1 TSRMLS_CC); +		}  		*scope = old_scope;  		class_type->constants_updated = 1; @@ -1064,13 +1062,29 @@ ZEND_API void zend_update_class_constants(zend_class_entry *class_type TSRMLS_DC  }  /* }}} */ +ZEND_API void object_properties_init(zend_object *object, zend_class_entry *class_type) /* {{{ */ +{ +	int i; + +	if (class_type->default_properties_count) { +		object->properties_table = emalloc(sizeof(zval*) * class_type->default_properties_count); +		for (i = 0; i < class_type->default_properties_count; i++) { +			object->properties_table[i] = class_type->default_properties_table[i]; +			if (class_type->default_properties_table[i]) { +				Z_ADDREF_P(object->properties_table[i]); +			} +		} +		object->properties = NULL; +	} +} +/* }}} */ +  /* This function requires 'properties' to contain all props declared in the   * class and all props being public. If only a subset is given or the class   * has protected members then you need to merge the properties seperately by   * calling zend_merge_properties(). */  ZEND_API int _object_and_properties_init(zval *arg, zend_class_entry *class_type, HashTable *properties ZEND_FILE_LINE_DC TSRMLS_DC) /* {{{ */  { -	zval *tmp;  	zend_object *object;  	if (class_type->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) { @@ -1085,10 +1099,9 @@ ZEND_API int _object_and_properties_init(zval *arg, zend_class_entry *class_type  		Z_OBJVAL_P(arg) = zend_objects_new(&object, class_type TSRMLS_CC);  		if (properties) {  			object->properties = properties; +			object->properties_table = NULL;  		} else { -			ALLOC_HASHTABLE_REL(object->properties); -			zend_hash_init(object->properties, zend_hash_num_elements(&class_type->default_properties), NULL, ZVAL_PTR_DTOR, 0); -			zend_hash_copy(object->properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); +			object_properties_init(object, class_type);  		}  	} else {  		Z_OBJVAL_P(arg) = class_type->create_object(class_type TSRMLS_CC); @@ -2315,8 +2328,6 @@ static zend_object_value display_disabled_class(zend_class_entry *class_type TSR  	zend_object_value retval;  	zend_object *intern;  	retval = zend_objects_new(&intern, class_type TSRMLS_CC); -	ALLOC_HASHTABLE(intern->properties); -	zend_hash_init(intern->properties, 0, NULL, ZVAL_PTR_DTOR, 0);  	zend_error(E_WARNING, "%s() has been disabled for security reasons", class_type->name);  	return retval;  } @@ -3076,17 +3087,38 @@ ZEND_API const char *zend_get_module_version(const char *module_name) /* {{{ */  ZEND_API int zend_declare_property_ex(zend_class_entry *ce, const char *name, int name_length, zval *property, int access_type, char *doc_comment, int doc_comment_len TSRMLS_DC) /* {{{ */  { -	zend_property_info property_info; -	HashTable *target_symbol_table; +	zend_property_info property_info, *property_info_ptr;  	char *interned_name; +	ulong h = zend_get_hash_value(name, name_length+1);  	if (!(access_type & ZEND_ACC_PPP_MASK)) {  		access_type |= ZEND_ACC_PUBLIC;  	}  	if (access_type & ZEND_ACC_STATIC) { -		target_symbol_table = &ce->default_static_members; +		if (zend_hash_quick_find(&ce->properties_info, name, name_length + 1, h, (void**)&property_info_ptr) == SUCCESS && +		    (property_info_ptr->flags & ZEND_ACC_STATIC) != 0) { +			property_info.offset = property_info_ptr->offset; +			zval_ptr_dtor(&ce->default_static_members_table[property_info.offset]); +			zend_hash_quick_del(&ce->properties_info, name, name_length + 1, h); +		} else { +			property_info.offset = ce->default_static_members_count++; +			ce->default_static_members_table = perealloc(ce->default_static_members_table, sizeof(zval*) * ce->default_static_members_count, ce->type == ZEND_INTERNAL_CLASS); +		} +		ce->default_static_members_table[property_info.offset] = property; +		if (ce->type == ZEND_USER_CLASS) { +			ce->static_members_table = ce->default_static_members_table; +		}  	} else { -		target_symbol_table = &ce->default_properties; +		if (zend_hash_quick_find(&ce->properties_info, name, name_length + 1, h, (void**)&property_info_ptr) == SUCCESS && +		    (property_info_ptr->flags & ZEND_ACC_STATIC) == 0) { +			property_info.offset = property_info_ptr->offset; +			zval_ptr_dtor(&ce->default_properties_table[property_info.offset]); +			zend_hash_quick_del(&ce->properties_info, name, name_length + 1, h); +		} else { +			property_info.offset = ce->default_properties_count++; +			ce->default_properties_table = perealloc(ce->default_properties_table, sizeof(zval*) * ce->default_properties_count, ce->type == ZEND_INTERNAL_CLASS); +		} +		ce->default_properties_table[property_info.offset] = property;  	}  	if (ce->type & ZEND_INTERNAL_CLASS) {  		switch(Z_TYPE_P(property)) { @@ -3120,14 +3152,6 @@ ZEND_API int zend_declare_property_ex(zend_class_entry *ce, const char *name, in  			}  			break;  		case ZEND_ACC_PUBLIC: -			if (ce->parent) { -				char *prot_name; -				int prot_name_length; - -				zend_mangle_property_name(&prot_name, &prot_name_length, "*", 1, name, name_length, ce->type & ZEND_INTERNAL_CLASS); -				zend_hash_del(target_symbol_table, prot_name, prot_name_length+1); -				pefree(prot_name, ce->type & ZEND_INTERNAL_CLASS); -			}  			if (IS_INTERNED(name)) {  				property_info.name = (char*)name;  			} else { @@ -3147,17 +3171,15 @@ ZEND_API int zend_declare_property_ex(zend_class_entry *ce, const char *name, in  		property_info.name = interned_name;  	} -	zend_hash_update(target_symbol_table, property_info.name, property_info.name_length+1, &property, sizeof(zval *), NULL); -  	property_info.flags = access_type; -	property_info.h = zend_get_hash_value(property_info.name, property_info.name_length+1); +	property_info.h = (access_type & ZEND_ACC_PUBLIC) ? h : zend_get_hash_value(property_info.name, property_info.name_length+1);  	property_info.doc_comment = doc_comment;  	property_info.doc_comment_len = doc_comment_len;  	property_info.ce = ce; -	zend_hash_update(&ce->properties_info, name, name_length + 1, &property_info, sizeof(zend_property_info), NULL); +	zend_hash_quick_update(&ce->properties_info, name, name_length + 1, h, &property_info, sizeof(zend_property_info), NULL);  	return SUCCESS;  } diff --git a/Zend/zend_API.h b/Zend/zend_API.h index df126c806f..e07b52f503 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -208,9 +208,9 @@ typedef struct _zend_fcall_info_cache {  	INIT_OVERLOADED_CLASS_ENTRY(class_container, ZEND_NS_NAME(ns, class_name), functions, handle_fcall, handle_propget, handle_propset)  #ifdef ZTS -#	define CE_STATIC_MEMBERS(ce) (((ce)->type==ZEND_USER_CLASS)?(ce)->static_members:CG(static_members)[(zend_intptr_t)(ce)->static_members]) +#	define CE_STATIC_MEMBERS(ce) (((ce)->type==ZEND_USER_CLASS)?(ce)->static_members:CG(static_members_table)[(zend_intptr_t)(ce)->static_members_table])  #else -#	define CE_STATIC_MEMBERS(ce) ((ce)->static_members) +#	define CE_STATIC_MEMBERS(ce) ((ce)->static_members_table)  #endif  #define ZEND_FCI_INITIALIZED(fci) ((fci).size != 0) @@ -347,6 +347,7 @@ ZEND_API int _array_init(zval *arg, uint size ZEND_FILE_LINE_DC);  ZEND_API int _object_init(zval *arg ZEND_FILE_LINE_DC TSRMLS_DC);  ZEND_API int _object_init_ex(zval *arg, zend_class_entry *ce ZEND_FILE_LINE_DC TSRMLS_DC);  ZEND_API int _object_and_properties_init(zval *arg, zend_class_entry *ce, HashTable *properties ZEND_FILE_LINE_DC TSRMLS_DC); +ZEND_API void object_properties_init(zend_object *object, zend_class_entry *class_type);  ZEND_API void zend_merge_properties(zval *obj, HashTable *properties, int destroy_ht TSRMLS_DC); diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 0a675bba42..1dbaeda049 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -888,49 +888,53 @@ ZEND_FUNCTION(is_a)  /* {{{ add_class_vars */ -static void add_class_vars(zend_class_entry *ce, HashTable *properties, zval *return_value TSRMLS_DC) +static void add_class_vars(zend_class_entry *ce, int statics, zval *return_value TSRMLS_DC)  { -	if (zend_hash_num_elements(properties) > 0) { -		HashPosition pos; -		zval **prop; - -		zend_hash_internal_pointer_reset_ex(properties, &pos); -		while (zend_hash_get_current_data_ex(properties, (void **) &prop, &pos) == SUCCESS) { -			char *key, *class_name, *prop_name; -			uint key_len; -			ulong num_index; -			int prop_name_len = 0;			 -			zval *prop_copy; -			zend_property_info *property_info; -			zval zprop_name; - -			zend_hash_get_current_key_ex(properties, &key, &key_len, &num_index, 0, &pos); -			zend_hash_move_forward_ex(properties, &pos); - -			zend_unmangle_property_name(key, key_len-1, &class_name, &prop_name); -			prop_name_len = strlen(prop_name); - -			ZVAL_STRINGL(&zprop_name, prop_name, prop_name_len, 0); -			property_info = zend_get_property_info(ce, &zprop_name, 1 TSRMLS_CC); - -			if (!property_info || property_info == &EG(std_property_info)) { -				continue; -			} +	HashPosition pos; +	zend_property_info *prop_info; +	zval *prop, *prop_copy; +	char *key; +	uint key_len; +	ulong num_index; -			/* copy: enforce read only access */ -			ALLOC_ZVAL(prop_copy); -			*prop_copy = **prop; -			zval_copy_ctor(prop_copy); -			INIT_PZVAL(prop_copy); +	zend_hash_internal_pointer_reset_ex(&ce->properties_info, &pos); +	while (zend_hash_get_current_data_ex(&ce->properties_info, (void **) &prop_info, &pos) == SUCCESS) { +		zend_hash_get_current_key_ex(&ce->properties_info, &key, &key_len, &num_index, 0, &pos); +		zend_hash_move_forward_ex(&ce->properties_info, &pos); +		if (((prop_info->flags & ZEND_ACC_SHADOW) && +		     prop_info->ce != EG(scope)) || +		    ((prop_info->flags & ZEND_ACC_PROTECTED) && +		     !zend_check_protected(prop_info->ce, EG(scope))) || +		    ((prop_info->flags & ZEND_ACC_PRIVATE) && +		      ce != EG(scope) && +			  prop_info->ce != EG(scope))) { +			continue; +		} +		prop = NULL; +		if (prop_info->offset >= 0) { +			if (statics && (prop_info->flags & ZEND_ACC_STATIC) != 0) { +				prop = ce->default_static_members_table[prop_info->offset]; +			} else if (!statics && (prop_info->flags & ZEND_ACC_STATIC) == 0) { +				prop = ce->default_properties_table[prop_info->offset]; + 			} +		} +		if (!prop) { +			continue; +		} -			/* this is necessary to make it able to work with default array  -			* properties, returned to user */ -			if (Z_TYPE_P(prop_copy) == IS_CONSTANT_ARRAY || (Z_TYPE_P(prop_copy) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT) { -				zval_update_constant(&prop_copy, 0 TSRMLS_CC); -			} +		/* copy: enforce read only access */ +		ALLOC_ZVAL(prop_copy); +		*prop_copy = *prop; +		zval_copy_ctor(prop_copy); +		INIT_PZVAL(prop_copy); -			add_assoc_zval(return_value, prop_name, prop_copy); +		/* this is necessary to make it able to work with default array +		 * properties, returned to user */ +		if (Z_TYPE_P(prop_copy) == IS_CONSTANT_ARRAY || (Z_TYPE_P(prop_copy) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT) { +			zval_update_constant(&prop_copy, 0 TSRMLS_CC);  		} + +		add_assoc_zval(return_value, key, prop_copy);  	}  }  /* }}} */ @@ -953,8 +957,8 @@ ZEND_FUNCTION(get_class_vars)  	} else {  		array_init(return_value);  		zend_update_class_constants(*pce TSRMLS_CC); -		add_class_vars(*pce, &(*pce)->default_properties, return_value TSRMLS_CC); -		add_class_vars(*pce, CE_STATIC_MEMBERS(*pce), return_value TSRMLS_CC); +		add_class_vars(*pce, 0, return_value TSRMLS_CC); +		add_class_vars(*pce, 1, return_value TSRMLS_CC);  	}  }  /* }}} */ diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index a48fca7c40..4af725ecca 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -70,6 +70,25 @@  		} \      } while (0) +#define GET_CACHE_SLOT(literal) do { \ +		CG(active_op_array)->literals[literal].cache_slot = CG(active_op_array)->last_cache_slot++; \ +	} while (0) + +#define POLYMORPHIC_CACHE_SLOT_SIZE 2 + +#define GET_POLYMORPHIC_CACHE_SLOT(literal) do { \ +		CG(active_op_array)->literals[literal].cache_slot = CG(active_op_array)->last_cache_slot; \ +		CG(active_op_array)->last_cache_slot += POLYMORPHIC_CACHE_SLOT_SIZE; \ +	} while (0) + +#define FREE_POLYMORPHIC_CACHE_SLOT(literal) do { \ +		if (CG(active_op_array)->literals[literal].cache_slot == \ +		    CG(active_op_array)->last_cache_slot - POLYMORPHIC_CACHE_SLOT_SIZE) { \ +			CG(active_op_array)->literals[literal].cache_slot = -1; \ +			CG(active_op_array)->last_cache_slot -= POLYMORPHIC_CACHE_SLOT_SIZE; \ +		} \ +	} while (0) +  ZEND_API zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);  ZEND_API zend_op_array *(*zend_compile_string)(zval *source_string, char *filename TSRMLS_DC); @@ -361,6 +380,7 @@ int zend_add_literal(zend_op_array *op_array, const zval *zv) /* {{{ */  	Z_SET_REFCOUNT(CONSTANT_EX(op_array, i), 2);  	Z_SET_ISREF(CONSTANT_EX(op_array, i));  	op_array->literals[i].hash_value = 0; +	op_array->literals[i].cache_slot = -1;  	return i;  }  /* }}} */ @@ -373,7 +393,8 @@ int zend_add_func_name_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC  	int lc_literal;  	if (op_array->last_literal > 0 &&  -	    &op_array->literals[op_array->last_literal - 1].constant == zv) { +	    &op_array->literals[op_array->last_literal - 1].constant == zv && +	    op_array->literals[op_array->last_literal - 1].cache_slot == -1) {  		/* we already have function name as last literal (do nothing) */  		ret = op_array->last_literal - 1;  	} else { @@ -398,7 +419,8 @@ int zend_add_ns_func_name_literal(zend_op_array *op_array, const zval *zv TSRMLS  	int lc_literal;  	if (op_array->last_literal > 0 &&  -	    &op_array->literals[op_array->last_literal - 1].constant == zv) { +	    &op_array->literals[op_array->last_literal - 1].constant == zv && +	    op_array->literals[op_array->last_literal - 1].cache_slot == -1) {  		/* we already have function name as last literal (do nothing) */  		ret = op_array->last_literal - 1;  	} else { @@ -430,7 +452,8 @@ int zend_add_class_name_literal(zend_op_array *op_array, const zval *zv TSRMLS_D  	int lc_literal;  	if (op_array->last_literal > 0 &&  -	    &op_array->literals[op_array->last_literal - 1].constant == zv) { +	    &op_array->literals[op_array->last_literal - 1].constant == zv && +	    op_array->literals[op_array->last_literal - 1].cache_slot == -1) {  		/* we already have function name as last literal (do nothing) */  		ret = op_array->last_literal - 1;  	} else { @@ -448,6 +471,8 @@ int zend_add_class_name_literal(zend_op_array *op_array, const zval *zv TSRMLS_D  	lc_literal = zend_add_literal(CG(active_op_array), &c);  	CALCULATE_LITERAL_HASH(lc_literal); +	GET_CACHE_SLOT(ret); +  	return ret;  }  /* }}} */ @@ -460,7 +485,8 @@ int zend_add_const_name_literal(zend_op_array *op_array, const zval *zv, int unq  	zval c;  	if (op_array->last_literal > 0 &&  -	    &op_array->literals[op_array->last_literal - 1].constant == zv) { +	    &op_array->literals[op_array->last_literal - 1].constant == zv && +	    op_array->literals[op_array->last_literal - 1].cache_slot == -1) {  		/* we already have function name as last literal (do nothing) */  		ret = op_array->last_literal - 1;  	} else { @@ -710,6 +736,7 @@ void zend_do_fetch_static_member(znode *result, znode *class_name TSRMLS_DC) /*  		opline.op1_type = IS_CONST;  		LITERAL_STRINGL(opline.op1, estrdup(CG(active_op_array)->vars[result->u.op.var].name), CG(active_op_array)->vars[result->u.op.var].name_len, 0);  		CALCULATE_LITERAL_HASH(opline.op1.constant); +		GET_POLYMORPHIC_CACHE_SLOT(opline.op1.constant);  		if (class_node.op_type == IS_CONST) {  			opline.op2_type = IS_CONST;  			opline.op2.constant = @@ -734,6 +761,7 @@ void zend_do_fetch_static_member(znode *result, znode *class_name TSRMLS_DC) /*  			opline.op1_type = IS_CONST;  			LITERAL_STRINGL(opline.op1, estrdup(CG(active_op_array)->vars[opline_ptr->op1.var].name), CG(active_op_array)->vars[opline_ptr->op1.var].name_len, 0);  			CALCULATE_LITERAL_HASH(opline.op1.constant); +			GET_POLYMORPHIC_CACHE_SLOT(opline.op1.constant);  			if (class_node.op_type == IS_CONST) {  				opline.op2_type = IS_CONST;  				opline.op2.constant = @@ -746,6 +774,9 @@ void zend_do_fetch_static_member(znode *result, znode *class_name TSRMLS_DC) /*  			zend_llist_prepend_element(fetch_list_ptr, &opline);  		} else { +			if (opline_ptr->op1_type == IS_CONST) { +				GET_POLYMORPHIC_CACHE_SLOT(opline_ptr->op1.constant); +			}  			if (class_node.op_type == IS_CONST) {  				opline_ptr->op2_type = IS_CONST;  				opline_ptr->op2.constant = @@ -1921,8 +1952,16 @@ void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC) /* {{{ */  	if (last_op->opcode == ZEND_FETCH_OBJ_R) {  		if (last_op->op2_type == IS_CONST) { +			zval name; + +			name = CONSTANT(last_op->op2.constant); +			if (!IS_INTERNED(Z_STRVAL(name))) { +				Z_STRVAL(name) = estrndup(Z_STRVAL(name), Z_STRLEN(name)); +			} +			FREE_POLYMORPHIC_CACHE_SLOT(last_op->op2.constant);  			last_op->op2.constant = -				zend_add_func_name_literal(CG(active_op_array), &CONSTANT(last_op->op2.constant) TSRMLS_CC); +				zend_add_func_name_literal(CG(active_op_array), &name TSRMLS_CC); +			GET_POLYMORPHIC_CACHE_SLOT(last_op->op2.constant);  		}  		last_op->opcode = ZEND_INIT_METHOD_CALL;  		SET_UNUSED(last_op->result); @@ -1934,6 +1973,7 @@ void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC) /* {{{ */  		if (left_bracket->op_type == IS_CONST) {  			opline->op2_type = IS_CONST;  			opline->op2.constant = zend_add_func_name_literal(CG(active_op_array), &left_bracket->u.constant TSRMLS_CC); +			GET_CACHE_SLOT(opline->op2.constant);  		} else {  			SET_NODE(opline->op2, left_bracket);  		} @@ -1970,12 +2010,14 @@ void zend_do_begin_dynamic_function_call(znode *function_name, int ns_call TSRML  		SET_UNUSED(opline->op1);  		opline->op2_type = IS_CONST;  		opline->op2.constant = zend_add_ns_func_name_literal(CG(active_op_array), &function_name->u.constant TSRMLS_CC); +		GET_CACHE_SLOT(opline->op2.constant);  	} else {  		opline->opcode = ZEND_INIT_FCALL_BY_NAME;  		SET_UNUSED(opline->op1);  		if (function_name->op_type == IS_CONST) {  			opline->op2_type = IS_CONST;  			opline->op2.constant = zend_add_func_name_literal(CG(active_op_array), &function_name->u.constant TSRMLS_CC); +			GET_CACHE_SLOT(opline->op2.constant);  		} else {  			SET_NODE(opline->op2, function_name);  		} @@ -2341,6 +2383,11 @@ int zend_do_begin_class_member_function_call(znode *class_name, znode *method_na  		opline->op2_type = IS_CONST;  		opline->op2.constant =  			zend_add_func_name_literal(CG(active_op_array), &method_name->u.constant TSRMLS_CC); +		if (opline->op1_type == IS_CONST) { +			GET_CACHE_SLOT(opline->op2.constant); +		} else { +			GET_POLYMORPHIC_CACHE_SLOT(opline->op2.constant); +		}  	} else {  		SET_NODE(opline->op2, method_name);  	} @@ -2367,6 +2414,7 @@ void zend_do_end_function_call(znode *function_name, znode *result, const znode  			opline->opcode = ZEND_DO_FCALL;  			SET_NODE(opline->op1, function_name);  			CALCULATE_LITERAL_HASH(opline->op1.constant); +			GET_CACHE_SLOT(opline->op1.constant);  		} else {  			opline->opcode = ZEND_DO_FCALL_BY_NAME;  			SET_UNUSED(opline->op1); @@ -2727,6 +2775,7 @@ ZEND_API void function_add_ref(zend_function *function) /* {{{ */  			zend_hash_init(op_array->static_variables, zend_hash_num_elements(static_variables), NULL, ZVAL_PTR_DTOR, 0);  			zend_hash_copy(op_array->static_variables, static_variables, (copy_ctor_func_t) zval_add_ref, (void *) &tmp_zval, sizeof(zval *));  		} +		op_array->run_time_cache = NULL;  	}  }  /* }}} */ @@ -3032,42 +3081,11 @@ static zend_bool do_inherit_property_access_check(HashTable *target_ht, zend_pro  		if ((child_info->flags & ZEND_ACC_PPP_MASK) > (parent_info->flags & ZEND_ACC_PPP_MASK)) {  			zend_error(E_COMPILE_ERROR, "Access level to %s::$%s must be %s (as in class %s)%s", ce->name, hash_key->arKey, zend_visibility_string(parent_info->flags), parent_ce->name, (parent_info->flags&ZEND_ACC_PUBLIC) ? "" : " or weaker"); -		} else if (child_info->flags & ZEND_ACC_IMPLICIT_PUBLIC) { -			if (!(parent_info->flags & ZEND_ACC_IMPLICIT_PUBLIC)) { -				/* Explicitly copy the default value from the parent (if it has one) */ -				zval **pvalue; -	 -				if (zend_hash_quick_find(&parent_ce->default_properties, parent_info->name, parent_info->name_length+1, parent_info->h, (void **) &pvalue) == SUCCESS) { -					Z_ADDREF_PP(pvalue); -					zend_hash_quick_del(&ce->default_properties, child_info->name, child_info->name_length+1, parent_info->h); -					zend_hash_quick_update(&ce->default_properties, parent_info->name, parent_info->name_length+1, parent_info->h, pvalue, sizeof(zval *), NULL); -				} -			} -			return 1; /* Inherit from the parent */ -		} else if ((child_info->flags & ZEND_ACC_PUBLIC) && (parent_info->flags & ZEND_ACC_PROTECTED)) { -			char *prot_name; -			int prot_name_length; - -			zend_mangle_property_name(&prot_name, &prot_name_length, "*", 1, child_info->name, child_info->name_length, ce->type & ZEND_INTERNAL_CLASS); -			if (child_info->flags & ZEND_ACC_STATIC) { -				zval **prop; -				HashTable *ht; - -				if (parent_ce->type != ce->type) { -					/* User class extends internal class */ -					TSRMLS_FETCH(); - -					ht = CE_STATIC_MEMBERS(parent_ce); -				} else { -					ht = &parent_ce->default_static_members; -				} -				if (zend_hash_find(ht, prot_name, prot_name_length+1, (void**)&prop) == SUCCESS) { -					zend_hash_del(&ce->default_static_members, prot_name, prot_name_length+1); -				} -			} else { -				zend_hash_del(&ce->default_properties, prot_name, prot_name_length+1); -			} -			pefree(prot_name, ce->type & ZEND_INTERNAL_CLASS); +		} else if ((child_info->flags & ZEND_ACC_STATIC) == 0) { +			Z_DELREF_P(ce->default_properties_table[parent_info->offset]); +			ce->default_properties_table[parent_info->offset] = ce->default_properties_table[child_info->offset]; +			ce->default_properties_table[child_info->offset] = NULL; +			child_info->offset = parent_info->offset;  		}  		return 0;	/* Don't copy from parent */  	} else { @@ -3140,6 +3158,8 @@ static int inherit_static_prop(zval **p TSRMLS_DC, int num_args, va_list args, c  ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce TSRMLS_DC) /* {{{ */  { +	zend_property_info *property_info; +  	if ((ce->ce_flags & ZEND_ACC_INTERFACE)  		&& !(parent_ce->ce_flags & ZEND_ACC_INTERFACE)) {  		zend_error(E_COMPILE_ERROR, "Interface %s may not inherit from class (%s)", ce->name, parent_ce->name); @@ -3161,14 +3181,78 @@ ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent  	zend_do_inherit_interfaces(ce, parent_ce TSRMLS_CC);  	/* Inherit properties */ -	zend_hash_merge(&ce->default_properties, &parent_ce->default_properties, (void (*)(void *)) zval_add_ref, NULL, sizeof(zval *), 0); +	if (parent_ce->default_properties_count) { +		int i = ce->default_properties_count + parent_ce->default_properties_count; + +		ce->default_properties_table = perealloc(ce->default_properties_table, sizeof(void*) * i, ce->type == ZEND_INTERNAL_CLASS); +		if (ce->default_properties_count) { +			while (i-- > parent_ce->default_properties_count) { +				ce->default_properties_table[i] = ce->default_properties_table[i - parent_ce->default_properties_count]; +			} +		} +		for (i = 0; i < parent_ce->default_properties_count; i++) { +			ce->default_properties_table[i] = parent_ce->default_properties_table[i]; +			if (ce->default_properties_table[i]) { +				Z_ADDREF_P(ce->default_properties_table[i]); +			} +		} +		ce->default_properties_count += parent_ce->default_properties_count; +	} +  	if (parent_ce->type != ce->type) {  		/* User class extends internal class */  		zend_update_class_constants(parent_ce  TSRMLS_CC); -		zend_hash_apply_with_arguments(CE_STATIC_MEMBERS(parent_ce) TSRMLS_CC, (apply_func_args_t)inherit_static_prop, 1, &ce->default_static_members); +		if (parent_ce->default_static_members_count) { +			int i = ce->default_static_members_count + parent_ce->default_static_members_count; + +			ce->default_static_members_table = erealloc(ce->default_static_members_table, sizeof(void*) * i); +			if (ce->default_static_members_count) { +				while (i-- > parent_ce->default_static_members_count) { +					ce->default_static_members_table[i] = ce->default_static_members_table[i - parent_ce->default_static_members_count]; +				} +			} +			for (i = 0; i < parent_ce->default_static_members_count; i++) { +				SEPARATE_ZVAL_TO_MAKE_IS_REF(&CE_STATIC_MEMBERS(parent_ce)[i]); +				ce->default_static_members_table[i] = CE_STATIC_MEMBERS(parent_ce)[i]; +				Z_ADDREF_P(ce->default_static_members_table[i]); +			} +			ce->default_static_members_count += parent_ce->default_static_members_count; +			ce->static_members_table = ce->default_static_members_table; +		}  	} else { -		zend_hash_apply_with_arguments(&parent_ce->default_static_members TSRMLS_CC, (apply_func_args_t)inherit_static_prop, 1, &ce->default_static_members); +		if (parent_ce->default_static_members_count) { +			int i = ce->default_static_members_count + parent_ce->default_static_members_count; + +			ce->default_static_members_table = perealloc(ce->default_static_members_table, sizeof(void*) * i, ce->type == ZEND_INTERNAL_CLASS); +			if (ce->default_static_members_count) { +				while (i-- > parent_ce->default_static_members_count) { +					ce->default_static_members_table[i] = ce->default_static_members_table[i - parent_ce->default_static_members_count]; +				} +			} +			for (i = 0; i < parent_ce->default_static_members_count; i++) { +				SEPARATE_ZVAL_TO_MAKE_IS_REF(&parent_ce->default_static_members_table[i]); +				ce->default_static_members_table[i] = parent_ce->default_static_members_table[i]; +				Z_ADDREF_P(ce->default_static_members_table[i]); +			} +			ce->default_static_members_count += parent_ce->default_static_members_count; +			if (ce->type == ZEND_USER_CLASS) { +				ce->static_members_table = ce->default_static_members_table; +			} +		}  	} +	                                                               	 +	for (zend_hash_internal_pointer_reset(&ce->properties_info); +	     zend_hash_get_current_data(&ce->properties_info, (void *) &property_info) == SUCCESS; +	     zend_hash_move_forward(&ce->properties_info)) { +		if (property_info->ce == ce) { +			if (property_info->flags & ZEND_ACC_STATIC) { +				property_info->offset += parent_ce->default_static_members_count; +			} else { +				property_info->offset += parent_ce->default_properties_count; +			} +		} +	} +  	zend_hash_merge_ex(&ce->properties_info, &parent_ce->properties_info, (copy_ctor_func_t) (ce->type & ZEND_INTERNAL_CLASS ? zend_duplicate_property_info_internal : zend_duplicate_property_info), sizeof(zend_property_info), (merge_checker_func_t) do_inherit_property_access_check, ce);  	zend_hash_merge(&ce->constants_table, &parent_ce->constants_table, (void (*)(void *)) zval_add_ref, NULL, sizeof(zval *), 0); @@ -4651,9 +4735,7 @@ void zend_do_declare_property(const znode *var_name, const znode *value, zend_ui  	}  	if (zend_hash_find(&CG(active_class_entry)->properties_info, var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, (void **) &existing_property_info)==SUCCESS) { -		if (!(existing_property_info->flags & ZEND_ACC_IMPLICIT_PUBLIC)) { -			zend_error(E_COMPILE_ERROR, "Cannot redeclare %s::$%s", CG(active_class_entry)->name, var_name->u.constant.value.str.val); -		} +		zend_error(E_COMPILE_ERROR, "Cannot redeclare %s::$%s", CG(active_class_entry)->name, var_name->u.constant.value.str.val);  	}  	ALLOC_ZVAL(property); @@ -4748,6 +4830,7 @@ void zend_do_fetch_property(znode *result, znode *object, const znode *property  			}  			if (opline_ptr->op2_type == IS_CONST && Z_TYPE(CONSTANT(opline_ptr->op2.constant)) == IS_STRING) {  				CALCULATE_LITERAL_HASH(opline_ptr->op2.constant); +				GET_POLYMORPHIC_CACHE_SLOT(opline_ptr->op2.constant);  			}  			GET_NODE(result, opline_ptr->result);  			return; @@ -4762,6 +4845,7 @@ void zend_do_fetch_property(znode *result, znode *object, const znode *property  	SET_NODE(opline.op2, property);  	if (opline.op2_type == IS_CONST && Z_TYPE(CONSTANT(opline.op2.constant)) == IS_STRING) {  		CALCULATE_LITERAL_HASH(opline.op2.constant); +		GET_POLYMORPHIC_CACHE_SLOT(opline.op2.constant);  	}  	GET_NODE(result, opline.result); @@ -4931,6 +5015,11 @@ void zend_do_fetch_constant(znode *result, znode *constant_container, znode *con  				}  				SET_NODE(opline->op2, constant_name);  				CALCULATE_LITERAL_HASH(opline->op2.constant); +				if (opline->op1_type == IS_CONST) { +					GET_CACHE_SLOT(opline->op2.constant); +				} else { +					GET_POLYMORPHIC_CACHE_SLOT(opline->op2.constant); +				}  				GET_NODE(result, opline->result);  				break;  		} @@ -4985,6 +5074,7 @@ void zend_do_fetch_constant(znode *result, znode *constant_container, znode *con  					opline->op2.constant = zend_add_const_name_literal(CG(active_op_array), &constant_name->u.constant, 0 TSRMLS_CC);  				}  			} +			GET_CACHE_SLOT(opline->op2.constant);  			break;  	}  } @@ -5016,6 +5106,7 @@ void zend_do_shell_exec(znode *result, const znode *cmd TSRMLS_DC) /* {{{ */  	LITERAL_STRINGL(opline->op1, estrndup("shell_exec", sizeof("shell_exec")-1), sizeof("shell_exec")-1, 0);  	CALCULATE_LITERAL_HASH(opline->op1.constant);  	opline->op1_type = IS_CONST; +	GET_CACHE_SLOT(opline->op1.constant);  	opline->extended_value = 1;  	SET_UNUSED(opline->op2);  	GET_NODE(result, opline->result); @@ -6039,9 +6130,9 @@ ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify  	ce->doc_comment = NULL;  	ce->doc_comment_len = 0; -	zend_hash_init_ex(&ce->default_properties, 0, NULL, zval_ptr_dtor_func, persistent_hashes, 0); +	ce->default_properties_table = NULL; +	ce->default_static_members_table = NULL;  	zend_hash_init_ex(&ce->properties_info, 0, NULL, (dtor_func_t) (persistent_hashes ? zend_destroy_property_info_internal : zend_destroy_property_info), persistent_hashes, 0); -	zend_hash_init_ex(&ce->default_static_members, 0, NULL, zval_ptr_dtor_func, persistent_hashes, 0);  	zend_hash_init_ex(&ce->constants_table, 0, NULL, zval_ptr_dtor_func, persistent_hashes, 0);  	zend_hash_init_ex(&ce->function_table, 0, NULL, ZEND_FUNCTION_DTOR, persistent_hashes, 0); @@ -6055,14 +6146,17 @@ ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify  			CG(static_members) = realloc(CG(static_members), (n+1)*sizeof(HashTable*));  			CG(static_members)[n] = NULL;  		} -		ce->static_members = (HashTable*)(zend_intptr_t)n; +		ce->static_members_table = (zval**)(zend_intptr_t)n;  #else -		ce->static_members = NULL; +		ce->static_members_table = NULL;  #endif  	} else { -		ce->static_members = &ce->default_static_members; +		ce->static_members_table = &ce->default_static_members_table;  	} +	ce->default_properties_count = 0; +	ce->default_static_members_count = 0; +  	if (nullify_handlers) {  		ce->constructor = NULL;  		ce->destructor = NULL; diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 480008ea4c..c22c7f979d 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -53,8 +53,9 @@ typedef struct _zend_op_array zend_op_array;  typedef struct _zend_op zend_op;  typedef struct _zend_literal { -	zval constant; -	ulong hash_value; +	zval       constant; +	zend_ulong hash_value; +	zend_uint  cache_slot;  } zend_literal;  #define Z_HASH_P(zv) \ @@ -183,6 +184,7 @@ typedef struct _zend_property_info {  	char *name;  	int name_length;  	ulong h; +	int offset;  	char *doc_comment;  	int doc_comment_len;  	zend_class_entry *ce; @@ -258,6 +260,9 @@ struct _zend_op_array {  	zend_literal *literals;  	int last_literal, size_literal; +	void **run_time_cache; +	int  last_cache_slot; +  	void *reserved[ZEND_MAX_RESERVED_RESOURCES];  }; diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index 301037ade5..abed6c7f84 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -138,16 +138,14 @@ ZEND_API void zend_clear_exception(TSRMLS_D) /* {{{ */  static zend_object_value zend_default_exception_new_ex(zend_class_entry *class_type, int skip_top_traces TSRMLS_DC) /* {{{ */  { -	zval tmp, obj; +	zval obj;  	zend_object *object;  	zval *trace;  	Z_OBJVAL(obj) = zend_objects_new(&object, class_type TSRMLS_CC);  	Z_OBJ_HT(obj) = &default_exception_handlers; -	ALLOC_HASHTABLE(object->properties); -	zend_hash_init(object->properties, 0, NULL, ZVAL_PTR_DTOR, 0); -	zend_hash_copy(object->properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); +	object_properties_init(object, class_type);  	ALLOC_ZVAL(trace);  	Z_UNSET_ISREF_P(trace); diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 28e26d3932..78b79431a9 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -429,6 +429,23 @@ ZEND_API zval **zend_get_zval_ptr_ptr(int op_type, const znode_op *node, const t  ZEND_API int zend_do_fcall(ZEND_OPCODE_HANDLER_ARGS); +#define CACHED_PTR(num) \ +	EG(active_op_array)->run_time_cache[(num)] + +#define CACHE_PTR(num, ptr) do { \ +		EG(active_op_array)->run_time_cache[(num)] = (ptr); \ +	} while (0) + +#define CACHED_POLYMORPHIC_PTR(num, ce) \ +	((EG(active_op_array)->run_time_cache[(num)] == (ce)) ? \ +		EG(active_op_array)->run_time_cache[(num) + 1] : \ +		NULL) + +#define CACHE_POLYMORPHIC_PTR(num, ce, ptr) do { \ +		EG(active_op_array)->run_time_cache[(num)] = (ce); \ +		EG(active_op_array)->run_time_cache[(num) + 1] = (ptr); \ +	} while (0) +  END_EXTERN_C()  #endif /* ZEND_EXECUTE_H */ diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 335d29ad7f..ef1ee3dad9 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -32,7 +32,8 @@  #define DEBUG_OBJECT_HANDLERS 0 -#define Z_OBJ_P(zval_p) zend_objects_get_address(zval_p TSRMLS_CC) +#define Z_OBJ_P(zval_p) \ +	((zend_object*)(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(zval_p)].bucket.obj.object))  /*    __X accessors explanation: @@ -51,10 +52,52 @@    called, we cal __call handler.  */ +ZEND_API void rebuild_object_properties(zend_object *zobj) /* {{{ */ +{ +	if (!zobj->properties) { +		HashPosition pos; +		zend_property_info *prop_info; +		zend_class_entry *ce = zobj->ce; + +		ALLOC_HASHTABLE(zobj->properties); +		zend_hash_init(zobj->properties, 0, NULL, ZVAL_PTR_DTOR, 0); +		if (ce->default_properties_count) { +			for (zend_hash_internal_pointer_reset_ex(&ce->properties_info, &pos); +			     zend_hash_get_current_data_ex(&ce->properties_info, (void**)&prop_info, &pos) == SUCCESS; +			     zend_hash_move_forward_ex(&ce->properties_info, &pos)) { +				if (/*prop_info->ce == ce &&*/ +				    (prop_info->flags & ZEND_ACC_STATIC) == 0 &&  +				    prop_info->offset >= 0 && +				    zobj->properties_table[prop_info->offset]) { +					zend_hash_quick_add(zobj->properties, prop_info->name, prop_info->name_length+1, prop_info->h, (void**)&zobj->properties_table[prop_info->offset], sizeof(zval*), (void**)&zobj->properties_table[prop_info->offset]); +				}				 +			} +			while (ce->parent && ce->parent->default_properties_count) { +				ce = ce->parent; +				for (zend_hash_internal_pointer_reset_ex(&ce->properties_info, &pos); +				     zend_hash_get_current_data_ex(&ce->properties_info, (void**)&prop_info, &pos) == SUCCESS; +				     zend_hash_move_forward_ex(&ce->properties_info, &pos)) { +					if (prop_info->ce == ce && +					    (prop_info->flags & ZEND_ACC_STATIC) == 0 &&  +					    (prop_info->flags & ZEND_ACC_PRIVATE) != 0 &&  +					    prop_info->offset >= 0 && +					    zobj->properties_table[prop_info->offset]) { +						zend_hash_quick_add(zobj->properties, prop_info->name, prop_info->name_length+1, prop_info->h, (void**)&zobj->properties_table[prop_info->offset], sizeof(zval*), (void**)&zobj->properties_table[prop_info->offset]); +					}				 +				} +			} +		} +	} +} + +  ZEND_API HashTable *zend_std_get_properties(zval *object TSRMLS_DC) /* {{{ */  {  	zend_object *zobj;  	zobj = Z_OBJ_P(object); +	if (!zobj->properties) { +		rebuild_object_properties(zobj); +	}  	return zobj->properties;  }  /* }}} */ @@ -158,7 +201,7 @@ static zval *zend_std_call_issetter(zval *object, zval *member TSRMLS_DC) /* {{{  }  /* }}} */ -static int zend_verify_property_access(zend_property_info *property_info, zend_class_entry *ce TSRMLS_DC) /* {{{ */ +static zend_always_inline int zend_verify_property_access(zend_property_info *property_info, zend_class_entry *ce TSRMLS_DC) /* {{{ */  {  	switch (property_info->flags & ZEND_ACC_PPP_MASK) {  		case ZEND_ACC_PUBLIC: @@ -177,7 +220,7 @@ static int zend_verify_property_access(zend_property_info *property_info, zend_c  }  /* }}} */ -static inline zend_bool is_derived_class(zend_class_entry *child_class, zend_class_entry *parent_class) /* {{{ */ +static zend_always_inline zend_bool is_derived_class(zend_class_entry *child_class, zend_class_entry *parent_class) /* {{{ */  {  	child_class = child_class->parent;  	while (child_class) { @@ -191,13 +234,17 @@ static inline zend_bool is_derived_class(zend_class_entry *child_class, zend_cla  }  /* }}} */ -static struct _zend_property_info *zend_get_property_info_quick(zend_class_entry *ce, zval *member, int silent, const zend_literal *key TSRMLS_DC) /* {{{ */ +static zend_always_inline struct _zend_property_info *zend_get_property_info_quick(zend_class_entry *ce, zval *member, int silent, const zend_literal *key TSRMLS_DC) /* {{{ */  {  	zend_property_info *property_info;  	zend_property_info *scope_property_info;  	zend_bool denied_access = 0;  	ulong h; +	if (key && (property_info = CACHED_POLYMORPHIC_PTR(key->cache_slot, ce)) != NULL) { +		return property_info; +	} +  	if (UNEXPECTED(Z_STRVAL_P(member)[0] == '\0')) {  		if (!silent) {  			if (Z_STRLEN_P(member) == 0) { @@ -223,9 +270,12 @@ static struct _zend_property_info *zend_get_property_info_quick(zend_class_entry  					 * continue checking below...  					 */  				} else { -					if (!silent && (property_info->flags & ZEND_ACC_STATIC)) { +					if (UNEXPECTED((property_info->flags & ZEND_ACC_STATIC) != 0) && !silent) {  						zend_error(E_STRICT, "Accessing static property %s::$%s as non static", ce->name, Z_STRVAL_P(member));  					} +					if (key) { +						CACHE_POLYMORPHIC_PTR(key->cache_slot, ce, property_info); +					}  					return property_info;  				}  			} else { @@ -235,10 +285,13 @@ static struct _zend_property_info *zend_get_property_info_quick(zend_class_entry  		}  	}  	if (EG(scope) != ce -		&& is_derived_class(ce, EG(scope))  		&& EG(scope) +		&& is_derived_class(ce, EG(scope))  		&& zend_hash_quick_find(&EG(scope)->properties_info, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, h, (void **) &scope_property_info)==SUCCESS  		&& scope_property_info->flags & ZEND_ACC_PRIVATE) { +		if (key) { +			CACHE_POLYMORPHIC_PTR(key->cache_slot, ce, scope_property_info); +		}  		return scope_property_info;  	} else if (property_info) {  		if (UNEXPECTED(denied_access != 0)) { @@ -249,6 +302,9 @@ static struct _zend_property_info *zend_get_property_info_quick(zend_class_entry  			return NULL;  		} else {  			/* fall through, return property_info... */ +			if (key) { +				CACHE_POLYMORPHIC_PTR(key->cache_slot, ce, property_info); +			}  		}  	} else {  		EG(std_property_info).flags = ZEND_ACC_PUBLIC; @@ -256,6 +312,7 @@ static struct _zend_property_info *zend_get_property_info_quick(zend_class_entry  		EG(std_property_info).name_length = Z_STRLEN_P(member);  		EG(std_property_info).h = h;  		EG(std_property_info).ce = ce; +		EG(std_property_info).offset = -1;  		property_info = &EG(std_property_info);  	}  	return property_info; @@ -348,7 +405,13 @@ zval *zend_std_read_property(zval *object, zval *member, int type, const zend_li  	property_info = zend_get_property_info_quick(zobj->ce, member, (zobj->ce->__get != NULL), key TSRMLS_CC);  	if (UNEXPECTED(!property_info) || -	    UNEXPECTED(zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &retval) == FAILURE)) { +	    ((EXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0) && +	     property_info->offset >= 0) ? +	        (zobj->properties ? +	            ((retval = (zval**)zobj->properties_table[property_info->offset]) == NULL) : +	            (*(retval = &zobj->properties_table[property_info->offset]) == NULL)) : +	        (UNEXPECTED(!zobj->properties) || +	          UNEXPECTED(zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &retval) == FAILURE)))) {  		zend_guard *guard;  		if (zobj->ce->__get && @@ -397,7 +460,7 @@ zval *zend_std_read_property(zval *object, zval *member, int type, const zend_li  }  /* }}} */ -static void zend_std_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC) /* {{{ */ +ZEND_API void zend_std_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC) /* {{{ */  {  	zend_object *zobj;  	zval *tmp_member = NULL; @@ -419,7 +482,13 @@ static void zend_std_write_property(zval *object, zval *member, zval *value, con  	property_info = zend_get_property_info_quick(zobj->ce, member, (zobj->ce->__set != NULL), key TSRMLS_CC);  	if (EXPECTED(property_info != NULL) && -	    EXPECTED(zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &variable_ptr) == SUCCESS)) { +	    ((EXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0) && +	     property_info->offset >= 0) ? +	        (zobj->properties ? +	            ((variable_ptr = (zval**)zobj->properties_table[property_info->offset]) != NULL) : +	            (*(variable_ptr = &zobj->properties_table[property_info->offset]) != NULL)) : +	        (EXPECTED(zobj->properties != NULL) && +	          EXPECTED(zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &variable_ptr) == SUCCESS)))) {  		/* if we already have this value there, we don't actually need to do anything */  		if (EXPECTED(*variable_ptr != value)) {  			/* if we are assigning reference, we shouldn't move it, but instead assign variable @@ -462,15 +531,27 @@ static void zend_std_write_property(zval *object, zval *member, zval *value, con  			guard->in_set = 0;  			zval_ptr_dtor(&object);  		} -		if (!setter_done && property_info) { -			zval **foo; - +		if (!setter_done && EXPECTED(property_info != NULL)) {  			/* if we assign referenced variable, we should separate it */  			Z_ADDREF_P(value);  			if (PZVAL_IS_REF(value)) {  				SEPARATE_ZVAL(&value);  			} -			zend_hash_quick_update(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, &value, sizeof(zval *), (void **) &foo); +			if (EXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0) && +			    property_info->offset >= 0) { +				if (!zobj->properties) { +					zobj->properties_table[property_info->offset] = value; +				} else if (zobj->properties_table[property_info->offset]) { +					*(zval**)zobj->properties_table[property_info->offset] = value; +				} else { +					zend_hash_quick_update(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, &value, sizeof(zval *), (void**)&zobj->properties_table[property_info->offset]); +				} +			} else { +				if (!zobj->properties) { +					rebuild_object_properties(zobj); +				} +				zend_hash_quick_update(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, &value, sizeof(zval *), NULL); +			}  		}  	} @@ -587,7 +668,13 @@ static zval **zend_std_get_property_ptr_ptr(zval *object, zval *member, const ze  	property_info = zend_get_property_info_quick(zobj->ce, member, (zobj->ce->__get != NULL), key TSRMLS_CC);  	if (UNEXPECTED(!property_info) || -	    UNEXPECTED(zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &retval) == FAILURE)) { +	    ((EXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0) && +	     property_info->offset >= 0) ? +	        (zobj->properties ? +	            ((retval = (zval**)zobj->properties_table[property_info->offset]) == NULL) : +	            (*(retval = &zobj->properties_table[property_info->offset]) == NULL)) : +	        (UNEXPECTED(!zobj->properties) || +	          UNEXPECTED(zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &retval) == FAILURE)))) {  		zval *new_zval;  		zend_guard *guard; @@ -599,7 +686,24 @@ static zval **zend_std_get_property_ptr_ptr(zval *object, zval *member, const ze  /* 			zend_error(E_NOTICE, "Undefined property: %s", Z_STRVAL_P(member)); */  			Z_ADDREF_P(new_zval); -			zend_hash_quick_update(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, &new_zval, sizeof(zval *), (void **) &retval); +			if (EXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0) && +			    property_info->offset >= 0) { +				if (!zobj->properties) { +					zobj->properties_table[property_info->offset] = new_zval; +					retval = &zobj->properties_table[property_info->offset]; +				} else if (zobj->properties_table[property_info->offset]) { +					*(zval**)zobj->properties_table[property_info->offset] = new_zval; +					retval = (zval**)zobj->properties_table[property_info->offset]; +				} else { +					zend_hash_quick_update(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, &new_zval, sizeof(zval *), (void**)&zobj->properties_table[property_info->offset]); +					retval = (zval**)zobj->properties_table[property_info->offset]; +				} +			} else { +				if (!zobj->properties) { +					rebuild_object_properties(zobj); +				} +				zend_hash_quick_update(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, &new_zval, sizeof(zval *), (void **) &retval); +			}  		} else {  			/* we do have getter - fail and let it try again with usual get/set */  			retval = NULL; @@ -632,8 +736,16 @@ static void zend_std_unset_property(zval *object, zval *member, const zend_liter  	property_info = zend_get_property_info_quick(zobj->ce, member, (zobj->ce->__unset != NULL), key TSRMLS_CC); -	if (UNEXPECTED(!property_info) || -	    UNEXPECTED(zend_hash_quick_del(zobj->properties, property_info->name, property_info->name_length+1, property_info->h) == FAILURE)) { +	if (EXPECTED(property_info != NULL) && +	    EXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0) &&  +	    !zobj->properties && +	    property_info->offset >= 0 && +	    EXPECTED(zobj->properties_table[property_info->offset] != NULL)) { +		zval_ptr_dtor(&zobj->properties_table[property_info->offset]); +		zobj->properties_table[property_info->offset] = NULL; +	} else if (UNEXPECTED(!property_info) || +	           !zobj->properties || +	           UNEXPECTED(zend_hash_quick_del(zobj->properties, property_info->name, property_info->name_length+1, property_info->h) == FAILURE)) {  		zend_guard *guard;  		if (zobj->ce->__unset && @@ -646,6 +758,10 @@ static void zend_std_unset_property(zval *object, zval *member, const zend_liter  			guard->in_unset = 0;  			zval_ptr_dtor(&object);  		} +	} else if (EXPECTED(property_info != NULL) &&  +	           EXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0) &&  +	           property_info->offset >= 0) { +		zobj->properties_table[property_info->offset] = NULL;  	}  	if (UNEXPECTED(tmp_member != NULL)) { @@ -1049,50 +1165,50 @@ ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, char *f  ZEND_API zval **zend_std_get_static_property(zend_class_entry *ce, char *property_name, int property_name_len, zend_bool silent, const zend_literal *key TSRMLS_DC) /* {{{ */  { -	zval **retval = NULL; -	zend_class_entry *tmp_ce = ce;  	zend_property_info *property_info; -	zend_property_info std_property_info;  	ulong hash_value; -	if (EXPECTED(key != NULL)) { -		hash_value = key->hash_value; -	} else { -		hash_value = zend_hash_func(property_name, property_name_len+1); -	} +	if (UNEXPECTED(!key) || +	    (property_info = CACHED_POLYMORPHIC_PTR(key->cache_slot, ce)) == NULL) { +		if (EXPECTED(key != NULL)) { +			hash_value = key->hash_value; +		} else { +			hash_value = zend_hash_func(property_name, property_name_len+1); +		} -	if (UNEXPECTED(zend_hash_quick_find(&ce->properties_info, property_name, property_name_len+1, hash_value, (void **) &property_info)==FAILURE)) { -		std_property_info.flags = ZEND_ACC_PUBLIC; -		std_property_info.name = property_name; -		std_property_info.name_length = property_name_len; -		std_property_info.h = hash_value; -		std_property_info.ce = ce; -		property_info = &std_property_info; -	} +		if (UNEXPECTED(zend_hash_quick_find(&ce->properties_info, property_name, property_name_len+1, hash_value, (void **) &property_info)==FAILURE)) { +			if (!silent) { +				zend_error_noreturn(E_ERROR, "Access to undeclared static property: %s::$%s", ce->name, property_name); +			} +			return NULL; +		}  #if DEBUG_OBJECT_HANDLERS -	zend_printf("Access type for %s::%s is %s\n", ce->name, property_name, zend_visibility_string(property_info->flags)); +		zend_printf("Access type for %s::%s is %s\n", ce->name, property_name, zend_visibility_string(property_info->flags));  #endif -	if (UNEXPECTED(!zend_verify_property_access(property_info, ce TSRMLS_CC))) { -		if (!silent) { -			zend_error_noreturn(E_ERROR, "Cannot access %s property %s::$%s", zend_visibility_string(property_info->flags), ce->name, property_name); +		if (UNEXPECTED(!zend_verify_property_access(property_info, ce TSRMLS_CC))) { +			if (!silent) { +				zend_error_noreturn(E_ERROR, "Cannot access %s property %s::$%s", zend_visibility_string(property_info->flags), ce->name, property_name); +			} +			return NULL;  		} -		return NULL; -	} -	zend_update_class_constants(tmp_ce TSRMLS_CC); +		if (UNEXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0)) { +			if (!silent) { +				zend_error_noreturn(E_ERROR, "Access to undeclared static property: %s::$%s", ce->name, property_name); +			} +			return NULL; +		} -	zend_hash_quick_find(CE_STATIC_MEMBERS(tmp_ce), property_info->name, property_info->name_length+1, property_info->h, (void **) &retval); +		zend_update_class_constants(ce TSRMLS_CC); -	if (UNEXPECTED(!retval)) { -		if (!silent) { -			zend_error_noreturn(E_ERROR, "Access to undeclared static property: %s::$%s", ce->name, property_name); +		if (EXPECTED(key != NULL)) { +			CACHE_POLYMORPHIC_PTR(key->cache_slot, ce, property_info);  		} -		return NULL;  	} -	return retval; +	return &CE_STATIC_MEMBERS(ce)[property_info->offset];  }  /* }}} */ @@ -1152,7 +1268,40 @@ static int zend_std_compare_objects(zval *o1, zval *o2 TSRMLS_DC) /* {{{ */  	if (zobj1->ce != zobj2->ce) {  		return 1; /* different classes */  	} -	return zend_compare_symbol_tables_i(zobj1->properties, zobj2->properties TSRMLS_CC); +	if (!zobj1->properties && !zobj2->properties) { +		int i; +		for (i = 0; i < zobj1->ce->default_properties_count; i++) { +			if (zobj1->properties_table[i]) { +				if (zobj2->properties_table[i]) { +					zval result; + +					if (compare_function(&result, zobj1->properties_table[i], zobj2->properties_table[i] TSRMLS_CC)==FAILURE) { +						return 1; +					} +					if (Z_LVAL(result) != 0) { +						return Z_LVAL(result); +					} +				} else { +					return 1; +				} +			} else { +				if (zobj2->properties_table[i]) { +					return 1; +				} else { +					return 0; +				} +			} +		} +		return 0; +	} else { +		if (!zobj1->properties) { +			rebuild_object_properties(zobj1); +		} +		if (!zobj2->properties) { +			rebuild_object_properties(zobj2); +		} +		return zend_compare_symbol_tables_i(zobj1->properties, zobj2->properties TSRMLS_CC); +	}  }  /* }}} */ @@ -1160,7 +1309,7 @@ static int zend_std_has_property(zval *object, zval *member, int has_set_exists,  {  	zend_object *zobj;  	int result; -	zval **value; +	zval **value = NULL;  	zval *tmp_member = NULL;  	zend_property_info *property_info; @@ -1183,7 +1332,13 @@ static int zend_std_has_property(zval *object, zval *member, int has_set_exists,  	property_info = zend_get_property_info_quick(zobj->ce, member, 1, key TSRMLS_CC);  	if (UNEXPECTED(!property_info) || -	    zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &value) == FAILURE) { +	    ((EXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0) && +	     property_info->offset >= 0) ? +	        (zobj->properties ? +	            ((value = (zval**)zobj->properties_table[property_info->offset]) == NULL) : +	            (*(value = &zobj->properties_table[property_info->offset]) == NULL)) : +	        (UNEXPECTED(!zobj->properties) || +	          UNEXPECTED(zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &value) == FAILURE)))) {  		zend_guard *guard;  		result = 0; diff --git a/Zend/zend_object_handlers.h b/Zend/zend_object_handlers.h index 611ba87f7d..542d163e23 100644 --- a/Zend/zend_object_handlers.h +++ b/Zend/zend_object_handlers.h @@ -152,6 +152,8 @@ ZEND_API struct _zend_property_info *zend_get_property_info(zend_class_entry *ce  ZEND_API HashTable *zend_std_get_properties(zval *object TSRMLS_DC);  ZEND_API HashTable *zend_std_get_debug_info(zval *object, int *is_temp TSRMLS_DC);  ZEND_API int zend_std_cast_object_tostring(zval *readobj, zval *writeobj, int type TSRMLS_DC); +ZEND_API void zend_std_write_property(zval *object, zval *member, zval *value, const struct _zend_literal *key TSRMLS_DC); +ZEND_API void rebuild_object_properties(zend_object *zobj);  #define IS_ZEND_STD_OBJECT(z)  (Z_TYPE(z) == IS_OBJECT && (Z_OBJ_HT((z))->get_class_entry != NULL)) diff --git a/Zend/zend_objects.c b/Zend/zend_objects.c index a2f1d3287e..6a87284ced 100644 --- a/Zend/zend_objects.c +++ b/Zend/zend_objects.c @@ -28,10 +28,9 @@  ZEND_API void zend_object_std_init(zend_object *object, zend_class_entry *ce TSRMLS_DC)  { -	ALLOC_HASHTABLE(object->properties); -	zend_hash_init(object->properties, 0, NULL, ZVAL_PTR_DTOR, 0); -  	object->ce = ce;	 +	object->properties = NULL; +	object->properties_table = NULL;  	object->guards = NULL;  } @@ -44,6 +43,18 @@ ZEND_API void zend_object_std_dtor(zend_object *object TSRMLS_DC)  	if (object->properties) {  		zend_hash_destroy(object->properties);  		FREE_HASHTABLE(object->properties); +		if (object->properties_table) { +			efree(object->properties_table); +		} +	} else if (object->properties_table) { +		int i; + +		for (i = 0; i < object->ce->default_properties_count; i++) { +			if (object->properties_table[i]) { +				zval_ptr_dtor(&object->properties_table[i]); +			} +		} +		efree(object->properties_table);  	}  } @@ -135,9 +146,11 @@ ZEND_API zend_object_value zend_objects_new(zend_object **object, zend_class_ent  	*object = emalloc(sizeof(zend_object));  	(*object)->ce = class_type; +	(*object)->properties = NULL; +	(*object)->properties_table = NULL; +	(*object)->guards = NULL;  	retval.handle = zend_objects_store_put(*object, (zend_objects_store_dtor_t) zend_objects_destroy_object, (zend_objects_free_object_storage_t) zend_objects_free_object_storage, NULL TSRMLS_CC);  	retval.handlers = &std_object_handlers; -	(*object)->guards = NULL;  	return retval;  } @@ -148,7 +161,47 @@ ZEND_API zend_object *zend_objects_get_address(const zval *zobject TSRMLS_DC)  ZEND_API void zend_objects_clone_members(zend_object *new_object, zend_object_value new_obj_val, zend_object *old_object, zend_object_handle handle TSRMLS_DC)  { -	zend_hash_copy(new_object->properties, old_object->properties, (copy_ctor_func_t) zval_add_ref, (void *) NULL /* Not used anymore */, sizeof(zval *)); +	int i; + +	if (old_object->properties_table) { +		if (!new_object->properties_table) { +			new_object->properties_table = emalloc(sizeof(zval*) * old_object->ce->default_properties_count); +			memset(new_object->properties_table, 0, sizeof(zval*) * old_object->ce->default_properties_count); +		} +		for (i = 0; i < old_object->ce->default_properties_count; i++) { +			if (!new_object->properties) { +				if (new_object->properties_table[i]) { +					zval_ptr_dtor(&new_object->properties_table[i]); +				} +			} +			if (!old_object->properties) { +				new_object->properties_table[i] = old_object->properties_table[i]; +				if (new_object->properties_table[i]) { +					Z_ADDREF_P(new_object->properties_table[i]); +				} +			} +		} +	} +	if (old_object->properties) { +		if (!new_object->properties) { +			ALLOC_HASHTABLE(new_object->properties); +			zend_hash_init(new_object->properties, 0, NULL, ZVAL_PTR_DTOR, 0); +		} +		zend_hash_copy(new_object->properties, old_object->properties, (copy_ctor_func_t) zval_add_ref, (void *) NULL /* Not used anymore */, sizeof(zval *)); +		if (old_object->properties_table) { +			HashPosition pos; +			zend_property_info *prop_info; +			for (zend_hash_internal_pointer_reset_ex(&old_object->ce->properties_info, &pos); +			     zend_hash_get_current_data_ex(&old_object->ce->properties_info, (void**)&prop_info, &pos) == SUCCESS; +			     zend_hash_move_forward_ex(&old_object->ce->properties_info, &pos)) { +				if ((prop_info->flags & ZEND_ACC_STATIC) == 0) { +					if (zend_hash_quick_find(new_object->properties, prop_info->name, prop_info->name_length+1, prop_info->h, (void**)&new_object->properties_table[prop_info->offset]) == FAILURE) { +						new_object->properties_table[prop_info->offset] = NULL; +					} +				} +			} +		} +	}  	if (old_object->ce->clone) {  		zval *new_obj; @@ -176,9 +229,6 @@ ZEND_API zend_object_value zend_objects_clone_obj(zval *zobject TSRMLS_DC)  	old_object = zend_objects_get_address(zobject TSRMLS_CC);  	new_obj_val = zend_objects_new(&new_object, old_object->ce TSRMLS_CC); -	ALLOC_HASHTABLE(new_object->properties); -	zend_hash_init(new_object->properties, 0, NULL, ZVAL_PTR_DTOR, 0); -  	zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC);  	return new_obj_val; diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 11a846b5ff..880be865a5 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -107,6 +107,9 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz  	op_array->last_literal = 0;  	op_array->literals = NULL; +	op_array->run_time_cache = NULL; +	op_array->last_cache_slot = 0; +  	memset(op_array->reserved, 0, ZEND_MAX_RESERVED_RESOURCES * sizeof(void*));  	zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_ctor_handler, op_array TSRMLS_CC); @@ -163,14 +166,18 @@ ZEND_API int zend_cleanup_class_data(zend_class_entry **pce TSRMLS_DC)  		/* Note that only run-time accessed data need to be cleaned up, pre-defined data can  		   not contain objects and thus are not probelmatic */  		zend_hash_apply(&(*pce)->function_table, (apply_func_t) zend_cleanup_function_data_full TSRMLS_CC); -		(*pce)->static_members = NULL; +		(*pce)->static_members_table = NULL;  	} else if (CE_STATIC_MEMBERS(*pce)) { -		zend_hash_destroy(CE_STATIC_MEMBERS(*pce)); -		FREE_HASHTABLE(CE_STATIC_MEMBERS(*pce)); +		int i; +		 +		for (i = 0; i < (*pce)->default_static_members_count; i++) { +			zval_ptr_dtor(&CE_STATIC_MEMBERS(*pce)[i]); +		} +		efree(CE_STATIC_MEMBERS(*pce));  #ifdef ZTS  		CG(static_members)[(zend_intptr_t)((*pce)->static_members)] = NULL;  #else -		(*pce)->static_members = NULL; +		(*pce)->static_members_table = NULL;  #endif  	}  	return 0; @@ -234,9 +241,25 @@ ZEND_API void destroy_zend_class(zend_class_entry **pce)  	}  	switch (ce->type) {  		case ZEND_USER_CLASS: -			zend_hash_destroy(&ce->default_properties); +			if (ce->default_properties_table) { +				int i; + +				for (i = 0; i < ce->default_properties_count; i++) { +					if (ce->default_properties_table[i]) { +						zval_ptr_dtor(&ce->default_properties_table[i]); +				    } +				} +				efree(ce->default_properties_table); +			} +			if (ce->default_static_members_table) { +				int i; + +				for (i = 0; i < ce->default_static_members_count; i++) { +					zval_ptr_dtor(&ce->default_static_members_table[i]); +				} +				efree(ce->default_static_members_table); +			}  			zend_hash_destroy(&ce->properties_info); -			zend_hash_destroy(&ce->default_static_members);  			efree(ce->name);  			zend_hash_destroy(&ce->function_table);  			zend_hash_destroy(&ce->constants_table); @@ -252,9 +275,25 @@ ZEND_API void destroy_zend_class(zend_class_entry **pce)  			efree(ce);  			break;  		case ZEND_INTERNAL_CLASS: -			zend_hash_destroy(&ce->default_properties); +			if (ce->default_properties_table) { +				int i; + +				for (i = 0; i < ce->default_properties_count; i++) { +					if (ce->default_properties_table[i]) { +						zval_internal_ptr_dtor(&ce->default_properties_table[i]); +					} +				} +				free(ce->default_properties_table); +			} +			if (ce->default_static_members_table) { +				int i; + +				for (i = 0; i < ce->default_static_members_count; i++) { +					zval_internal_ptr_dtor(&ce->default_static_members_table[i]); +				} +				free(ce->default_static_members_table); +			}  			zend_hash_destroy(&ce->properties_info); -			zend_hash_destroy(&ce->default_static_members);  			free(ce->name);  			zend_hash_destroy(&ce->function_table);  			zend_hash_destroy(&ce->constants_table); @@ -285,6 +324,10 @@ ZEND_API void destroy_op_array(zend_op_array *op_array TSRMLS_DC)  		FREE_HASHTABLE(op_array->static_variables);  	} +	if (op_array->run_time_cache) { +		efree(op_array->run_time_cache); +	} +  	if (--(*op_array->refcount)>0) {  		return;  	} diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index d13b3b281a..5dfcaa0555 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1035,7 +1035,12 @@ ZEND_VM_HELPER_EX(zend_fetch_var_address_helper, CONST|TMP|VAR|CV, UNUSED|CONST|  		zend_class_entry *ce;  		if (OP2_TYPE == IS_CONST) { -			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				ce = CACHED_PTR(opline->op2.literal->cache_slot); +			} else { +				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				CACHE_PTR(opline->op2.literal->cache_slot, ce); +			}  		} else {  			ce = EX_T(opline->op2.var).class_entry;  		} @@ -2145,7 +2150,12 @@ ZEND_VM_HANDLER(109, ZEND_FETCH_CLASS, ANY, CONST|TMP|VAR|UNUSED|CV)  		zval *class_name = GET_OP2_ZVAL_PTR(BP_VAR_R);  		if (OP2_TYPE == IS_CONST) { -			EX_T(opline->result.var).class_entry = zend_fetch_class_by_name(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), opline->op2.literal + 1, opline->extended_value TSRMLS_CC); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				EX_T(opline->result.var).class_entry = CACHED_PTR(opline->op2.literal->cache_slot); +			} else { +				EX_T(opline->result.var).class_entry = zend_fetch_class_by_name(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), opline->op2.literal + 1, opline->extended_value TSRMLS_CC); +				CACHE_PTR(opline->op2.literal->cache_slot, EX_T(opline->result.var).class_entry); +			}  		} else if (Z_TYPE_P(class_name) == IS_OBJECT) {  			EX_T(opline->result.var).class_entry = Z_OBJCE_P(class_name);  		} else if (Z_TYPE_P(class_name) == IS_STRING) { @@ -2185,17 +2195,27 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV)  	if (EXPECTED(EX(object) != NULL) &&  	    EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) { -		if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { -			zend_error_noreturn(E_ERROR, "Object does not support method calls"); -		} +		EX(called_scope) = Z_OBJCE_P(EX(object)); +	 +		if (OP2_TYPE != IS_CONST || +		    (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) { +		    zval *object = EX(object); -		/* First, locate the function. */ -		EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((OP2_TYPE == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); -		if (UNEXPECTED(EX(fbc) == NULL)) { -			zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); +			if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { +				zend_error_noreturn(E_ERROR, "Object does not support method calls"); +			} + +			/* First, locate the function. */ +			EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((OP2_TYPE == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); +			if (UNEXPECTED(EX(fbc) == NULL)) { +				zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); +			} +			if (OP2_TYPE == IS_CONST && +			    EXPECTED((EX(fbc)->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0) && +			    EXPECTED(EX(object) == object)) { +				CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc)); +			}  		} -		 -		EX(called_scope) = Z_OBJCE_P(EX(object));  	} else {  		zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);  	} @@ -2232,21 +2252,35 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS  	if (OP1_TYPE == IS_CONST) {  		/* no function found. try a static method in class */ -		ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, opline->extended_value TSRMLS_CC); -		if (UNEXPECTED(ce == NULL)) { -			zend_error_noreturn(E_ERROR, "Class '%s' not found", Z_STRVAL_P(opline->op1.zv)); +		if (CACHED_PTR(opline->op1.literal->cache_slot)) { +			ce = CACHED_PTR(opline->op1.literal->cache_slot); +		} else { +			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, opline->extended_value TSRMLS_CC); +			if (UNEXPECTED(ce == NULL)) { +				zend_error_noreturn(E_ERROR, "Class '%s' not found", Z_STRVAL_P(opline->op1.zv)); +			} +			CACHE_PTR(opline->op1.literal->cache_slot, ce);  		}  		EX(called_scope) = ce;  	} else {  		ce = EX_T(opline->op1.var).class_entry; -		 +  		if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) {  			EX(called_scope) = EG(called_scope);  		} else {  			EX(called_scope) = ce;  		}  	} -	if(OP2_TYPE != IS_UNUSED) { + +	if (OP1_TYPE == IS_CONST && +	    OP2_TYPE == IS_CONST && +	    CACHED_PTR(opline->op2.literal->cache_slot)) { +		EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); +	} else if (OP1_TYPE != IS_CONST && +	           OP2_TYPE == IS_CONST && +	           (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) { +		/* do nothing */ +	} else if (OP2_TYPE != IS_UNUSED) {  		char *function_name_strval = NULL;  		int function_name_strlen = 0;  		zend_free_op free_op2; @@ -2274,8 +2308,14 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS  			if (UNEXPECTED(EX(fbc) == NULL)) {  				zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, function_name_strval);  			} +			if (OP2_TYPE == IS_CONST && EXPECTED((EX(fbc)->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0)) { +				if (OP1_TYPE == IS_CONST) { +					CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc)); +				} else { +					CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, EX(fbc)); +				} +			}  		} -  		if (OP2_TYPE != IS_CONST) {  			FREE_OP2();  		} @@ -2322,9 +2362,13 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV)  	if (OP2_TYPE == IS_CONST) {  		function_name = (zval*)(opline->op2.literal+1); -		if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(function_name), Z_STRLEN_P(function_name)+1, Z_HASH_P(function_name), (void **) &EX(fbc)) == FAILURE)) { +		if (CACHED_PTR(opline->op2.literal->cache_slot)) { +			EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); +		} else if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(function_name), Z_STRLEN_P(function_name)+1, Z_HASH_P(function_name), (void **) &EX(fbc)) == FAILURE)) {  			SAVE_OPLINE();  			zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); +		} else { +			CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc));  		}  		EX(object) = NULL;  		/*CHECK_EXCEPTION();*/ @@ -2379,12 +2423,18 @@ ZEND_VM_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST)  	zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));  	func_name = opline->op2.literal + 1; -	if (zend_hash_quick_find(EG(function_table), Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant)+1, func_name->hash_value, (void **) &EX(fbc))==FAILURE) { +	if (CACHED_PTR(opline->op2.literal->cache_slot)) { +		EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); +	} else if (zend_hash_quick_find(EG(function_table), Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant)+1, func_name->hash_value, (void **) &EX(fbc))==FAILURE) {  		func_name++;  		if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant)+1, func_name->hash_value, (void **) &EX(fbc))==FAILURE)) {  			SAVE_OPLINE();  			zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); +		} else { +			CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc));  		} +	} else { +		CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc));  	}  	EX(object) = NULL; @@ -2694,9 +2744,13 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, CONST, ANY)  	zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); -	if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(fname), Z_STRLEN_P(fname)+1, Z_HASH_P(fname), (void **) &EX(function_state).function)==FAILURE)) { +	if (CACHED_PTR(opline->op1.literal->cache_slot)) { +		EX(function_state).function = CACHED_PTR(opline->op1.literal->cache_slot); +	} else if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(fname), Z_STRLEN_P(fname)+1, Z_HASH_P(fname), (void **) &EX(function_state).function)==FAILURE)) {  	    SAVE_OPLINE();  		zend_error_noreturn(E_ERROR, "Call to undefined function %s()", fname->value.str.val); +	} else { +		CACHE_PTR(opline->op1.literal->cache_slot, EX(function_state).function);  	}  	EX(object) = NULL; @@ -2849,7 +2903,12 @@ ZEND_VM_HANDLER(107, ZEND_CATCH, CONST, CV)  		ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->extended_value]);  		ZEND_VM_CONTINUE(); /* CHECK_ME */  	} -	catch_ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC); +	if (CACHED_PTR(opline->op1.literal->cache_slot)) { +		catch_ce = CACHED_PTR(opline->op1.literal->cache_slot); +	} else { +		catch_ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC); +		CACHE_PTR(opline->op1.literal->cache_slot, catch_ce); +	}  	ce = Z_OBJCE_P(EG(exception));  #ifdef HAVE_DTRACE @@ -3339,7 +3398,9 @@ ZEND_VM_HANDLER(99, ZEND_FETCH_CONSTANT, VAR|CONST|UNUSED, CONST)  		zend_constant *c;  		zval *retval; -		if ((c = zend_quick_get_constant(opline->op2.literal + 1, opline->extended_value TSRMLS_CC)) == NULL) { +		if (CACHED_PTR(opline->op2.literal->cache_slot)) { +			c = CACHED_PTR(opline->op2.literal->cache_slot); +		} else if ((c = zend_quick_get_constant(opline->op2.literal + 1, opline->extended_value TSRMLS_CC)) == NULL) {  			if ((opline->extended_value & IS_CONSTANT_UNQUALIFIED) != 0) {  				char *actual = (char *)zend_memrchr(Z_STRVAL_P(opline->op2.zv), '\\', Z_STRLEN_P(opline->op2.zv));  				if(!actual) { @@ -3355,6 +3416,8 @@ ZEND_VM_HANDLER(99, ZEND_FETCH_CONSTANT, VAR|CONST|UNUSED, CONST)  			} else {  				zend_error_noreturn(E_ERROR, "Undefined constant '%s'", Z_STRVAL_P(opline->op2.zv));  			} +		} else { +			CACHE_PTR(opline->op2.literal->cache_slot, c);  		}  		retval = &EX_T(opline->result.var).tmp_var;  		INIT_PZVAL_COPY(retval, &c->value); @@ -3367,13 +3430,29 @@ ZEND_VM_HANDLER(99, ZEND_FETCH_CONSTANT, VAR|CONST|UNUSED, CONST)  		zval **value;  		if (OP1_TYPE == IS_CONST) { - -			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, opline->extended_value TSRMLS_CC); -			if (UNEXPECTED(ce == NULL)) { -				zend_error_noreturn(E_ERROR, "Undefined class constant '%s'", Z_STRVAL_P(opline->op2.zv)); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				value = CACHED_PTR(opline->op2.literal->cache_slot); +				ZVAL_COPY_VALUE(&EX_T(opline->result.var).tmp_var, *value); +				zval_copy_ctor(&EX_T(opline->result.var).tmp_var); +				CHECK_EXCEPTION(); +				ZEND_VM_NEXT_OPCODE(); +			} else if (CACHED_PTR(opline->op1.literal->cache_slot)) { +				ce = CACHED_PTR(opline->op1.literal->cache_slot); +			} else { +				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, opline->extended_value TSRMLS_CC); +				if (UNEXPECTED(ce == NULL)) { +					zend_error_noreturn(E_ERROR, "Undefined class constant '%s'", Z_STRVAL_P(opline->op2.zv)); +				} +				CACHE_PTR(opline->op1.literal->cache_slot, ce);  			}  		} else {  			ce = EX_T(opline->op1.var).class_entry; +			if ((value = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce)) != NULL) { +				ZVAL_COPY_VALUE(&EX_T(opline->result.var).tmp_var, *value); +				zval_copy_ctor(&EX_T(opline->result.var).tmp_var); +				CHECK_EXCEPTION(); +				ZEND_VM_NEXT_OPCODE(); +			}  		}  		if (EXPECTED(zend_hash_quick_find(&ce->constants_table, Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv)+1, Z_HASH_P(opline->op2.zv), (void **) &value) == SUCCESS)) { @@ -3385,6 +3464,11 @@ ZEND_VM_HANDLER(99, ZEND_FETCH_CONSTANT, VAR|CONST|UNUSED, CONST)  				zval_update_constant(value, (void *) 1 TSRMLS_CC);  				EG(scope) = old_scope;  			} +			if (OP1_TYPE == IS_CONST) { +				CACHE_PTR(opline->op2.literal->cache_slot, value); +			} else { +				CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, value); +			}  			ZVAL_COPY_VALUE(&EX_T(opline->result.var).tmp_var, *value);  			zval_copy_ctor(&EX_T(opline->result.var).tmp_var);  		} else { @@ -3727,7 +3811,12 @@ ZEND_VM_HANDLER(74, ZEND_UNSET_VAR, CONST|TMP|VAR|CV, UNUSED|CONST|VAR)  		zend_class_entry *ce;  		if (OP2_TYPE == IS_CONST) { -			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				ce = CACHED_PTR(opline->op2.literal->cache_slot); +			} else { +				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				CACHE_PTR(opline->op2.literal->cache_slot, ce); +			}  		} else {  			ce = EX_T(opline->op2.var).class_entry;  		} @@ -4227,7 +4316,12 @@ ZEND_VM_HANDLER(114, ZEND_ISSET_ISEMPTY_VAR, CONST|TMP|VAR|CV, UNUSED|CONST|VAR)  			zend_class_entry *ce;  			if (OP2_TYPE == IS_CONST) { -				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				if (CACHED_PTR(opline->op2.literal->cache_slot)) { +					ce = CACHED_PTR(opline->op2.literal->cache_slot); +				} else { +					ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +					CACHE_PTR(opline->op2.literal->cache_slot, ce); +				}  			} else {  				ce = EX_T(opline->op2.var).class_entry;  			} @@ -4654,14 +4748,21 @@ ZEND_VM_HANDLER(144, ZEND_ADD_INTERFACE, ANY, CONST)  	zend_class_entry *iface;  	SAVE_OPLINE(); -	iface = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, opline->extended_value TSRMLS_CC); - -	if (iface) { -		if (UNEXPECTED((iface->ce_flags & ZEND_ACC_INTERFACE) == 0)) { -			zend_error_noreturn(E_ERROR, "%s cannot implement %s - it is not an interface", ce->name, iface->name); +	if (CACHED_PTR(opline->op2.literal->cache_slot)) { +		iface = CACHED_PTR(opline->op2.literal->cache_slot); +	} else { +		iface = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, opline->extended_value TSRMLS_CC); +		if (UNEXPECTED(iface == NULL)) { +			CHECK_EXCEPTION(); +			ZEND_VM_NEXT_OPCODE();  		} -		zend_do_implement_interface(ce, iface TSRMLS_CC); +		CACHE_PTR(opline->op2.literal->cache_slot, ce); +	} + +	if (UNEXPECTED((iface->ce_flags & ZEND_ACC_INTERFACE) == 0)) { +		zend_error_noreturn(E_ERROR, "%s cannot implement %s - it is not an interface", ce->name, iface->name);  	} +	zend_do_implement_interface(ce, iface TSRMLS_CC);  	CHECK_EXCEPTION();  	ZEND_VM_NEXT_OPCODE(); @@ -4671,18 +4772,27 @@ ZEND_VM_HANDLER(154, ZEND_ADD_TRAIT, ANY, ANY)  {  	zend_op *opline = EX(opline);  	zend_class_entry *ce = EX_T(opline->op1.var).class_entry; -	zend_class_entry *trait = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), -                                             Z_STRLEN_P(opline->op2.zv), -                                             opline->op2.literal + 1, -                                             opline->extended_value TSRMLS_CC); -	 -	if (trait) { +	zend_class_entry *trait; + +	if (CACHED_PTR(opline->op2.literal->cache_slot)) { +		trait = CACHED_PTR(opline->op2.literal->cache_slot); +	} else { +		trait = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), +		                                 Z_STRLEN_P(opline->op2.zv), +		                                 opline->op2.literal + 1, +		                                 opline->extended_value TSRMLS_CC); +		if (UNEXPECTED(trait == NULL)) { +			CHECK_EXCEPTION(); +			ZEND_VM_NEXT_OPCODE(); +		}  		if (!((trait->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT)) {  			zend_error_noreturn(E_ERROR, "%s cannot use %s - it is not a trait", ce->name, trait->name);  		} -		zend_do_implement_trait(ce, trait TSRMLS_CC); +		CACHE_PTR(opline->op2.literal->cache_slot, trait);  	} +	zend_do_implement_trait(ce, trait TSRMLS_CC); +   	CHECK_EXCEPTION();  	ZEND_VM_NEXT_OPCODE();  } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index f9370750f7..7254fc3933 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -99,6 +99,10 @@ zend_vm_enter:  	LOAD_REGS(); +	if (!op_array->run_time_cache && op_array->last_cache_slot) { +		op_array->run_time_cache = ecalloc(op_array->last_cache_slot, sizeof(void*)); +	} +  	if (op_array->this_var != -1 && EG(This)) {   		Z_ADDREF_P(EG(This)); /* For $this pointer */  		if (!EG(active_symbol_table)) { @@ -684,18 +688,27 @@ static int ZEND_FASTCALL  ZEND_ADD_TRAIT_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)  {  	zend_op *opline = EX(opline);  	zend_class_entry *ce = EX_T(opline->op1.var).class_entry; -	zend_class_entry *trait = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), -                                             Z_STRLEN_P(opline->op2.zv), -                                             opline->op2.literal + 1, -                                             opline->extended_value TSRMLS_CC); +	zend_class_entry *trait; -	if (trait) { +	if (CACHED_PTR(opline->op2.literal->cache_slot)) { +		trait = CACHED_PTR(opline->op2.literal->cache_slot); +	} else { +		trait = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), +		                                 Z_STRLEN_P(opline->op2.zv), +		                                 opline->op2.literal + 1, +		                                 opline->extended_value TSRMLS_CC); +		if (UNEXPECTED(trait == NULL)) { +			CHECK_EXCEPTION(); +			ZEND_VM_NEXT_OPCODE(); +		}  		if (!((trait->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT)) {  			zend_error_noreturn(E_ERROR, "%s cannot use %s - it is not a trait", ce->name, trait->name);  		} -		zend_do_implement_trait(ce, trait TSRMLS_CC); +		CACHE_PTR(opline->op2.literal->cache_slot, trait);  	} +	zend_do_implement_trait(ce, trait TSRMLS_CC); +   	CHECK_EXCEPTION();  	ZEND_VM_NEXT_OPCODE();  } @@ -850,7 +863,12 @@ static int ZEND_FASTCALL  ZEND_FETCH_CLASS_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLE  		zval *class_name = opline->op2.zv;  		if (IS_CONST == IS_CONST) { -			EX_T(opline->result.var).class_entry = zend_fetch_class_by_name(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), opline->op2.literal + 1, opline->extended_value TSRMLS_CC); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				EX_T(opline->result.var).class_entry = CACHED_PTR(opline->op2.literal->cache_slot); +			} else { +				EX_T(opline->result.var).class_entry = zend_fetch_class_by_name(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), opline->op2.literal + 1, opline->extended_value TSRMLS_CC); +				CACHE_PTR(opline->op2.literal->cache_slot, EX_T(opline->result.var).class_entry); +			}  		} else if (Z_TYPE_P(class_name) == IS_OBJECT) {  			EX_T(opline->result.var).class_entry = Z_OBJCE_P(class_name);  		} else if (Z_TYPE_P(class_name) == IS_STRING) { @@ -872,9 +890,13 @@ static int ZEND_FASTCALL  ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE  	if (IS_CONST == IS_CONST) {  		function_name = (zval*)(opline->op2.literal+1); -		if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(function_name), Z_STRLEN_P(function_name)+1, Z_HASH_P(function_name), (void **) &EX(fbc)) == FAILURE)) { +		if (CACHED_PTR(opline->op2.literal->cache_slot)) { +			EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); +		} else if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(function_name), Z_STRLEN_P(function_name)+1, Z_HASH_P(function_name), (void **) &EX(fbc)) == FAILURE)) {  			SAVE_OPLINE();  			zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); +		} else { +			CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc));  		}  		EX(object) = NULL;  		/*CHECK_EXCEPTION();*/ @@ -929,12 +951,18 @@ static int ZEND_FASTCALL  ZEND_INIT_NS_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPC  	zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));  	func_name = opline->op2.literal + 1; -	if (zend_hash_quick_find(EG(function_table), Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant)+1, func_name->hash_value, (void **) &EX(fbc))==FAILURE) { +	if (CACHED_PTR(opline->op2.literal->cache_slot)) { +		EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); +	} else if (zend_hash_quick_find(EG(function_table), Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant)+1, func_name->hash_value, (void **) &EX(fbc))==FAILURE) {  		func_name++;  		if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant)+1, func_name->hash_value, (void **) &EX(fbc))==FAILURE)) {  			SAVE_OPLINE();  			zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); +		} else { +			CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc));  		} +	} else { +		CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc));  	}  	EX(object) = NULL; @@ -1035,14 +1063,21 @@ static int ZEND_FASTCALL  ZEND_ADD_INTERFACE_SPEC_CONST_HANDLER(ZEND_OPCODE_HAND  	zend_class_entry *iface;  	SAVE_OPLINE(); -	iface = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, opline->extended_value TSRMLS_CC); - -	if (iface) { -		if (UNEXPECTED((iface->ce_flags & ZEND_ACC_INTERFACE) == 0)) { -			zend_error_noreturn(E_ERROR, "%s cannot implement %s - it is not an interface", ce->name, iface->name); +	if (CACHED_PTR(opline->op2.literal->cache_slot)) { +		iface = CACHED_PTR(opline->op2.literal->cache_slot); +	} else { +		iface = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, opline->extended_value TSRMLS_CC); +		if (UNEXPECTED(iface == NULL)) { +			CHECK_EXCEPTION(); +			ZEND_VM_NEXT_OPCODE();  		} -		zend_do_implement_interface(ce, iface TSRMLS_CC); +		CACHE_PTR(opline->op2.literal->cache_slot, ce); +	} + +	if (UNEXPECTED((iface->ce_flags & ZEND_ACC_INTERFACE) == 0)) { +		zend_error_noreturn(E_ERROR, "%s cannot implement %s - it is not an interface", ce->name, iface->name);  	} +	zend_do_implement_interface(ce, iface TSRMLS_CC);  	CHECK_EXCEPTION();  	ZEND_VM_NEXT_OPCODE(); @@ -1063,7 +1098,12 @@ static int ZEND_FASTCALL  ZEND_FETCH_CLASS_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_  		zval *class_name = _get_zval_ptr_tmp(opline->op2.var, EX_Ts(), &free_op2 TSRMLS_CC);  		if (IS_TMP_VAR == IS_CONST) { -			EX_T(opline->result.var).class_entry = zend_fetch_class_by_name(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), opline->op2.literal + 1, opline->extended_value TSRMLS_CC); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				EX_T(opline->result.var).class_entry = CACHED_PTR(opline->op2.literal->cache_slot); +			} else { +				EX_T(opline->result.var).class_entry = zend_fetch_class_by_name(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), opline->op2.literal + 1, opline->extended_value TSRMLS_CC); +				CACHE_PTR(opline->op2.literal->cache_slot, EX_T(opline->result.var).class_entry); +			}  		} else if (Z_TYPE_P(class_name) == IS_OBJECT) {  			EX_T(opline->result.var).class_entry = Z_OBJCE_P(class_name);  		} else if (Z_TYPE_P(class_name) == IS_STRING) { @@ -1086,9 +1126,13 @@ static int ZEND_FASTCALL  ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H  	if (IS_TMP_VAR == IS_CONST) {  		function_name = (zval*)(opline->op2.literal+1); -		if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(function_name), Z_STRLEN_P(function_name)+1, Z_HASH_P(function_name), (void **) &EX(fbc)) == FAILURE)) { +		if (CACHED_PTR(opline->op2.literal->cache_slot)) { +			EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); +		} else if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(function_name), Z_STRLEN_P(function_name)+1, Z_HASH_P(function_name), (void **) &EX(fbc)) == FAILURE)) {  			SAVE_OPLINE();  			zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); +		} else { +			CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc));  		}  		EX(object) = NULL;  		/*CHECK_EXCEPTION();*/ @@ -1176,7 +1220,12 @@ static int ZEND_FASTCALL  ZEND_FETCH_CLASS_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_  		zval *class_name = _get_zval_ptr_var(opline->op2.var, EX_Ts(), &free_op2 TSRMLS_CC);  		if (IS_VAR == IS_CONST) { -			EX_T(opline->result.var).class_entry = zend_fetch_class_by_name(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), opline->op2.literal + 1, opline->extended_value TSRMLS_CC); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				EX_T(opline->result.var).class_entry = CACHED_PTR(opline->op2.literal->cache_slot); +			} else { +				EX_T(opline->result.var).class_entry = zend_fetch_class_by_name(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), opline->op2.literal + 1, opline->extended_value TSRMLS_CC); +				CACHE_PTR(opline->op2.literal->cache_slot, EX_T(opline->result.var).class_entry); +			}  		} else if (Z_TYPE_P(class_name) == IS_OBJECT) {  			EX_T(opline->result.var).class_entry = Z_OBJCE_P(class_name);  		} else if (Z_TYPE_P(class_name) == IS_STRING) { @@ -1199,9 +1248,13 @@ static int ZEND_FASTCALL  ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H  	if (IS_VAR == IS_CONST) {  		function_name = (zval*)(opline->op2.literal+1); -		if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(function_name), Z_STRLEN_P(function_name)+1, Z_HASH_P(function_name), (void **) &EX(fbc)) == FAILURE)) { +		if (CACHED_PTR(opline->op2.literal->cache_slot)) { +			EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); +		} else if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(function_name), Z_STRLEN_P(function_name)+1, Z_HASH_P(function_name), (void **) &EX(fbc)) == FAILURE)) {  			SAVE_OPLINE();  			zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); +		} else { +			CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc));  		}  		EX(object) = NULL;  		/*CHECK_EXCEPTION();*/ @@ -1289,7 +1342,12 @@ static int ZEND_FASTCALL  ZEND_FETCH_CLASS_SPEC_UNUSED_HANDLER(ZEND_OPCODE_HANDL  		zval *class_name = NULL;  		if (IS_UNUSED == IS_CONST) { -			EX_T(opline->result.var).class_entry = zend_fetch_class_by_name(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), opline->op2.literal + 1, opline->extended_value TSRMLS_CC); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				EX_T(opline->result.var).class_entry = CACHED_PTR(opline->op2.literal->cache_slot); +			} else { +				EX_T(opline->result.var).class_entry = zend_fetch_class_by_name(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), opline->op2.literal + 1, opline->extended_value TSRMLS_CC); +				CACHE_PTR(opline->op2.literal->cache_slot, EX_T(opline->result.var).class_entry); +			}  		} else if (Z_TYPE_P(class_name) == IS_OBJECT) {  			EX_T(opline->result.var).class_entry = Z_OBJCE_P(class_name);  		} else if (Z_TYPE_P(class_name) == IS_STRING) { @@ -1318,7 +1376,12 @@ static int ZEND_FASTCALL  ZEND_FETCH_CLASS_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_A  		zval *class_name = _get_zval_ptr_cv_BP_VAR_R(EX_CVs(), opline->op2.var TSRMLS_CC);  		if (IS_CV == IS_CONST) { -			EX_T(opline->result.var).class_entry = zend_fetch_class_by_name(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), opline->op2.literal + 1, opline->extended_value TSRMLS_CC); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				EX_T(opline->result.var).class_entry = CACHED_PTR(opline->op2.literal->cache_slot); +			} else { +				EX_T(opline->result.var).class_entry = zend_fetch_class_by_name(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), opline->op2.literal + 1, opline->extended_value TSRMLS_CC); +				CACHE_PTR(opline->op2.literal->cache_slot, EX_T(opline->result.var).class_entry); +			}  		} else if (Z_TYPE_P(class_name) == IS_OBJECT) {  			EX_T(opline->result.var).class_entry = Z_OBJCE_P(class_name);  		} else if (Z_TYPE_P(class_name) == IS_STRING) { @@ -1340,9 +1403,13 @@ static int ZEND_FASTCALL  ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA  	if (IS_CV == IS_CONST) {  		function_name = (zval*)(opline->op2.literal+1); -		if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(function_name), Z_STRLEN_P(function_name)+1, Z_HASH_P(function_name), (void **) &EX(fbc)) == FAILURE)) { +		if (CACHED_PTR(opline->op2.literal->cache_slot)) { +			EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); +		} else if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(function_name), Z_STRLEN_P(function_name)+1, Z_HASH_P(function_name), (void **) &EX(fbc)) == FAILURE)) {  			SAVE_OPLINE();  			zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); +		} else { +			CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc));  		}  		EX(object) = NULL;  		/*CHECK_EXCEPTION();*/ @@ -1637,9 +1704,13 @@ static int ZEND_FASTCALL  ZEND_DO_FCALL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_A  	zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); -	if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(fname), Z_STRLEN_P(fname)+1, Z_HASH_P(fname), (void **) &EX(function_state).function)==FAILURE)) { +	if (CACHED_PTR(opline->op1.literal->cache_slot)) { +		EX(function_state).function = CACHED_PTR(opline->op1.literal->cache_slot); +	} else if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(fname), Z_STRLEN_P(fname)+1, Z_HASH_P(fname), (void **) &EX(function_state).function)==FAILURE)) {  	    SAVE_OPLINE();  		zend_error_noreturn(E_ERROR, "Call to undefined function %s()", fname->value.str.val); +	} else { +		CACHE_PTR(opline->op1.literal->cache_slot, EX(function_state).function);  	}  	EX(object) = NULL; @@ -2607,7 +2678,12 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_CONST_CONST(int type  		zend_class_entry *ce;  		if (IS_CONST == IS_CONST) { -			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				ce = CACHED_PTR(opline->op2.literal->cache_slot); +			} else { +				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				CACHE_PTR(opline->op2.literal->cache_slot, ce); +			}  		} else {  			ce = EX_T(opline->op2.var).class_entry;  		} @@ -2771,9 +2847,14 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER(  	if (IS_CONST == IS_CONST) {  		/* no function found. try a static method in class */ -		ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, opline->extended_value TSRMLS_CC); -		if (UNEXPECTED(ce == NULL)) { -			zend_error_noreturn(E_ERROR, "Class '%s' not found", Z_STRVAL_P(opline->op1.zv)); +		if (CACHED_PTR(opline->op1.literal->cache_slot)) { +			ce = CACHED_PTR(opline->op1.literal->cache_slot); +		} else { +			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, opline->extended_value TSRMLS_CC); +			if (UNEXPECTED(ce == NULL)) { +				zend_error_noreturn(E_ERROR, "Class '%s' not found", Z_STRVAL_P(opline->op1.zv)); +			} +			CACHE_PTR(opline->op1.literal->cache_slot, ce);  		}  		EX(called_scope) = ce;  	} else { @@ -2785,7 +2866,16 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER(  			EX(called_scope) = ce;  		}  	} -	if(IS_CONST != IS_UNUSED) { + +	if (IS_CONST == IS_CONST && +	    IS_CONST == IS_CONST && +	    CACHED_PTR(opline->op2.literal->cache_slot)) { +		EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); +	} else if (IS_CONST != IS_CONST && +	           IS_CONST == IS_CONST && +	           (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) { +		/* do nothing */ +	} else if (IS_CONST != IS_UNUSED) {  		char *function_name_strval = NULL;  		int function_name_strlen = 0; @@ -2813,8 +2903,14 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER(  			if (UNEXPECTED(EX(fbc) == NULL)) {  				zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, function_name_strval);  			} +			if (IS_CONST == IS_CONST && EXPECTED((EX(fbc)->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0)) { +				if (IS_CONST == IS_CONST) { +					CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc)); +				} else { +					CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, EX(fbc)); +				} +			}  		} -  		if (IS_CONST != IS_CONST) {  		} @@ -2895,7 +2991,9 @@ static int ZEND_FASTCALL  ZEND_FETCH_CONSTANT_SPEC_CONST_CONST_HANDLER(ZEND_OPCO  		zend_constant *c;  		zval *retval; -		if ((c = zend_quick_get_constant(opline->op2.literal + 1, opline->extended_value TSRMLS_CC)) == NULL) { +		if (CACHED_PTR(opline->op2.literal->cache_slot)) { +			c = CACHED_PTR(opline->op2.literal->cache_slot); +		} else if ((c = zend_quick_get_constant(opline->op2.literal + 1, opline->extended_value TSRMLS_CC)) == NULL) {  			if ((opline->extended_value & IS_CONSTANT_UNQUALIFIED) != 0) {  				char *actual = (char *)zend_memrchr(Z_STRVAL_P(opline->op2.zv), '\\', Z_STRLEN_P(opline->op2.zv));  				if(!actual) { @@ -2911,6 +3009,8 @@ static int ZEND_FASTCALL  ZEND_FETCH_CONSTANT_SPEC_CONST_CONST_HANDLER(ZEND_OPCO  			} else {  				zend_error_noreturn(E_ERROR, "Undefined constant '%s'", Z_STRVAL_P(opline->op2.zv));  			} +		} else { +			CACHE_PTR(opline->op2.literal->cache_slot, c);  		}  		retval = &EX_T(opline->result.var).tmp_var;  		INIT_PZVAL_COPY(retval, &c->value); @@ -2923,13 +3023,29 @@ static int ZEND_FASTCALL  ZEND_FETCH_CONSTANT_SPEC_CONST_CONST_HANDLER(ZEND_OPCO  		zval **value;  		if (IS_CONST == IS_CONST) { - -			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, opline->extended_value TSRMLS_CC); -			if (UNEXPECTED(ce == NULL)) { -				zend_error_noreturn(E_ERROR, "Undefined class constant '%s'", Z_STRVAL_P(opline->op2.zv)); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				value = CACHED_PTR(opline->op2.literal->cache_slot); +				ZVAL_COPY_VALUE(&EX_T(opline->result.var).tmp_var, *value); +				zval_copy_ctor(&EX_T(opline->result.var).tmp_var); +				CHECK_EXCEPTION(); +				ZEND_VM_NEXT_OPCODE(); +			} else if (CACHED_PTR(opline->op1.literal->cache_slot)) { +				ce = CACHED_PTR(opline->op1.literal->cache_slot); +			} else { +				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, opline->extended_value TSRMLS_CC); +				if (UNEXPECTED(ce == NULL)) { +					zend_error_noreturn(E_ERROR, "Undefined class constant '%s'", Z_STRVAL_P(opline->op2.zv)); +				} +				CACHE_PTR(opline->op1.literal->cache_slot, ce);  			}  		} else {  			ce = EX_T(opline->op1.var).class_entry; +			if ((value = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce)) != NULL) { +				ZVAL_COPY_VALUE(&EX_T(opline->result.var).tmp_var, *value); +				zval_copy_ctor(&EX_T(opline->result.var).tmp_var); +				CHECK_EXCEPTION(); +				ZEND_VM_NEXT_OPCODE(); +			}  		}  		if (EXPECTED(zend_hash_quick_find(&ce->constants_table, Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv)+1, Z_HASH_P(opline->op2.zv), (void **) &value) == SUCCESS)) { @@ -2941,6 +3057,11 @@ static int ZEND_FASTCALL  ZEND_FETCH_CONSTANT_SPEC_CONST_CONST_HANDLER(ZEND_OPCO  				zval_update_constant(value, (void *) 1 TSRMLS_CC);  				EG(scope) = old_scope;  			} +			if (IS_CONST == IS_CONST) { +				CACHE_PTR(opline->op2.literal->cache_slot, value); +			} else { +				CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, value); +			}  			ZVAL_COPY_VALUE(&EX_T(opline->result.var).tmp_var, *value);  			zval_copy_ctor(&EX_T(opline->result.var).tmp_var);  		} else { @@ -3087,7 +3208,12 @@ static int ZEND_FASTCALL  ZEND_UNSET_VAR_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HA  		zend_class_entry *ce;  		if (IS_CONST == IS_CONST) { -			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				ce = CACHED_PTR(opline->op2.literal->cache_slot); +			} else { +				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				CACHE_PTR(opline->op2.literal->cache_slot, ce); +			}  		} else {  			ce = EX_T(opline->op2.var).class_entry;  		} @@ -3144,7 +3270,12 @@ static int ZEND_FASTCALL  ZEND_ISSET_ISEMPTY_VAR_SPEC_CONST_CONST_HANDLER(ZEND_O  			zend_class_entry *ce;  			if (IS_CONST == IS_CONST) { -				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				if (CACHED_PTR(opline->op2.literal->cache_slot)) { +					ce = CACHED_PTR(opline->op2.literal->cache_slot); +				} else { +					ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +					CACHE_PTR(opline->op2.literal->cache_slot, ce); +				}  			} else {  				ce = EX_T(opline->op2.var).class_entry;  			} @@ -3514,9 +3645,14 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZE  	if (IS_CONST == IS_CONST) {  		/* no function found. try a static method in class */ -		ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, opline->extended_value TSRMLS_CC); -		if (UNEXPECTED(ce == NULL)) { -			zend_error_noreturn(E_ERROR, "Class '%s' not found", Z_STRVAL_P(opline->op1.zv)); +		if (CACHED_PTR(opline->op1.literal->cache_slot)) { +			ce = CACHED_PTR(opline->op1.literal->cache_slot); +		} else { +			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, opline->extended_value TSRMLS_CC); +			if (UNEXPECTED(ce == NULL)) { +				zend_error_noreturn(E_ERROR, "Class '%s' not found", Z_STRVAL_P(opline->op1.zv)); +			} +			CACHE_PTR(opline->op1.literal->cache_slot, ce);  		}  		EX(called_scope) = ce;  	} else { @@ -3528,7 +3664,16 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZE  			EX(called_scope) = ce;  		}  	} -	if(IS_TMP_VAR != IS_UNUSED) { + +	if (IS_CONST == IS_CONST && +	    IS_TMP_VAR == IS_CONST && +	    CACHED_PTR(opline->op2.literal->cache_slot)) { +		EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); +	} else if (IS_CONST != IS_CONST && +	           IS_TMP_VAR == IS_CONST && +	           (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) { +		/* do nothing */ +	} else if (IS_TMP_VAR != IS_UNUSED) {  		char *function_name_strval = NULL;  		int function_name_strlen = 0;  		zend_free_op free_op2; @@ -3556,8 +3701,14 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZE  			if (UNEXPECTED(EX(fbc) == NULL)) {  				zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, function_name_strval);  			} +			if (IS_TMP_VAR == IS_CONST && EXPECTED((EX(fbc)->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0)) { +				if (IS_CONST == IS_CONST) { +					CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc)); +				} else { +					CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, EX(fbc)); +				} +			}  		} -  		if (IS_TMP_VAR != IS_CONST) {  			zval_dtor(free_op2.var);  		} @@ -4032,7 +4183,12 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_CONST_VAR(int type,  		zend_class_entry *ce;  		if (IS_VAR == IS_CONST) { -			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				ce = CACHED_PTR(opline->op2.literal->cache_slot); +			} else { +				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				CACHE_PTR(opline->op2.literal->cache_slot, ce); +			}  		} else {  			ce = EX_T(opline->op2.var).class_entry;  		} @@ -4170,9 +4326,14 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZE  	if (IS_CONST == IS_CONST) {  		/* no function found. try a static method in class */ -		ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, opline->extended_value TSRMLS_CC); -		if (UNEXPECTED(ce == NULL)) { -			zend_error_noreturn(E_ERROR, "Class '%s' not found", Z_STRVAL_P(opline->op1.zv)); +		if (CACHED_PTR(opline->op1.literal->cache_slot)) { +			ce = CACHED_PTR(opline->op1.literal->cache_slot); +		} else { +			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, opline->extended_value TSRMLS_CC); +			if (UNEXPECTED(ce == NULL)) { +				zend_error_noreturn(E_ERROR, "Class '%s' not found", Z_STRVAL_P(opline->op1.zv)); +			} +			CACHE_PTR(opline->op1.literal->cache_slot, ce);  		}  		EX(called_scope) = ce;  	} else { @@ -4184,7 +4345,16 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZE  			EX(called_scope) = ce;  		}  	} -	if(IS_VAR != IS_UNUSED) { + +	if (IS_CONST == IS_CONST && +	    IS_VAR == IS_CONST && +	    CACHED_PTR(opline->op2.literal->cache_slot)) { +		EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); +	} else if (IS_CONST != IS_CONST && +	           IS_VAR == IS_CONST && +	           (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) { +		/* do nothing */ +	} else if (IS_VAR != IS_UNUSED) {  		char *function_name_strval = NULL;  		int function_name_strlen = 0;  		zend_free_op free_op2; @@ -4212,8 +4382,14 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZE  			if (UNEXPECTED(EX(fbc) == NULL)) {  				zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, function_name_strval);  			} +			if (IS_VAR == IS_CONST && EXPECTED((EX(fbc)->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0)) { +				if (IS_CONST == IS_CONST) { +					CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc)); +				} else { +					CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, EX(fbc)); +				} +			}  		} -  		if (IS_VAR != IS_CONST) {  			if (free_op2.var) {zval_ptr_dtor(&free_op2.var);};  		} @@ -4421,7 +4597,12 @@ static int ZEND_FASTCALL  ZEND_UNSET_VAR_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HAND  		zend_class_entry *ce;  		if (IS_VAR == IS_CONST) { -			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				ce = CACHED_PTR(opline->op2.literal->cache_slot); +			} else { +				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				CACHE_PTR(opline->op2.literal->cache_slot, ce); +			}  		} else {  			ce = EX_T(opline->op2.var).class_entry;  		} @@ -4478,7 +4659,12 @@ static int ZEND_FASTCALL  ZEND_ISSET_ISEMPTY_VAR_SPEC_CONST_VAR_HANDLER(ZEND_OPC  			zend_class_entry *ce;  			if (IS_VAR == IS_CONST) { -				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				if (CACHED_PTR(opline->op2.literal->cache_slot)) { +					ce = CACHED_PTR(opline->op2.literal->cache_slot); +				} else { +					ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +					CACHE_PTR(opline->op2.literal->cache_slot, ce); +				}  			} else {  				ce = EX_T(opline->op2.var).class_entry;  			} @@ -4541,7 +4727,12 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_CONST_UNUSED(int typ  		zend_class_entry *ce;  		if (IS_UNUSED == IS_CONST) { -			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				ce = CACHED_PTR(opline->op2.literal->cache_slot); +			} else { +				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				CACHE_PTR(opline->op2.literal->cache_slot, ce); +			}  		} else {  			ce = EX_T(opline->op2.var).class_entry;  		} @@ -4679,9 +4870,14 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER  	if (IS_CONST == IS_CONST) {  		/* no function found. try a static method in class */ -		ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, opline->extended_value TSRMLS_CC); -		if (UNEXPECTED(ce == NULL)) { -			zend_error_noreturn(E_ERROR, "Class '%s' not found", Z_STRVAL_P(opline->op1.zv)); +		if (CACHED_PTR(opline->op1.literal->cache_slot)) { +			ce = CACHED_PTR(opline->op1.literal->cache_slot); +		} else { +			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, opline->extended_value TSRMLS_CC); +			if (UNEXPECTED(ce == NULL)) { +				zend_error_noreturn(E_ERROR, "Class '%s' not found", Z_STRVAL_P(opline->op1.zv)); +			} +			CACHE_PTR(opline->op1.literal->cache_slot, ce);  		}  		EX(called_scope) = ce;  	} else { @@ -4693,7 +4889,16 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER  			EX(called_scope) = ce;  		}  	} -	if(IS_UNUSED != IS_UNUSED) { + +	if (IS_CONST == IS_CONST && +	    IS_UNUSED == IS_CONST && +	    CACHED_PTR(opline->op2.literal->cache_slot)) { +		EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); +	} else if (IS_CONST != IS_CONST && +	           IS_UNUSED == IS_CONST && +	           (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) { +		/* do nothing */ +	} else if (IS_UNUSED != IS_UNUSED) {  		char *function_name_strval = NULL;  		int function_name_strlen = 0; @@ -4721,8 +4926,14 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER  			if (UNEXPECTED(EX(fbc) == NULL)) {  				zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, function_name_strval);  			} +			if (IS_UNUSED == IS_CONST && EXPECTED((EX(fbc)->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0)) { +				if (IS_CONST == IS_CONST) { +					CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc)); +				} else { +					CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, EX(fbc)); +				} +			}  		} -  		if (IS_UNUSED != IS_CONST) {  		} @@ -4896,7 +5107,12 @@ static int ZEND_FASTCALL  ZEND_UNSET_VAR_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_H  		zend_class_entry *ce;  		if (IS_UNUSED == IS_CONST) { -			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				ce = CACHED_PTR(opline->op2.literal->cache_slot); +			} else { +				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				CACHE_PTR(opline->op2.literal->cache_slot, ce); +			}  		} else {  			ce = EX_T(opline->op2.var).class_entry;  		} @@ -4953,7 +5169,12 @@ static int ZEND_FASTCALL  ZEND_ISSET_ISEMPTY_VAR_SPEC_CONST_UNUSED_HANDLER(ZEND_  			zend_class_entry *ce;  			if (IS_UNUSED == IS_CONST) { -				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				if (CACHED_PTR(opline->op2.literal->cache_slot)) { +					ce = CACHED_PTR(opline->op2.literal->cache_slot); +				} else { +					ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +					CACHE_PTR(opline->op2.literal->cache_slot, ce); +				}  			} else {  				ce = EX_T(opline->op2.var).class_entry;  			} @@ -5301,9 +5522,14 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEN  	if (IS_CONST == IS_CONST) {  		/* no function found. try a static method in class */ -		ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, opline->extended_value TSRMLS_CC); -		if (UNEXPECTED(ce == NULL)) { -			zend_error_noreturn(E_ERROR, "Class '%s' not found", Z_STRVAL_P(opline->op1.zv)); +		if (CACHED_PTR(opline->op1.literal->cache_slot)) { +			ce = CACHED_PTR(opline->op1.literal->cache_slot); +		} else { +			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, opline->extended_value TSRMLS_CC); +			if (UNEXPECTED(ce == NULL)) { +				zend_error_noreturn(E_ERROR, "Class '%s' not found", Z_STRVAL_P(opline->op1.zv)); +			} +			CACHE_PTR(opline->op1.literal->cache_slot, ce);  		}  		EX(called_scope) = ce;  	} else { @@ -5315,7 +5541,16 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEN  			EX(called_scope) = ce;  		}  	} -	if(IS_CV != IS_UNUSED) { + +	if (IS_CONST == IS_CONST && +	    IS_CV == IS_CONST && +	    CACHED_PTR(opline->op2.literal->cache_slot)) { +		EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); +	} else if (IS_CONST != IS_CONST && +	           IS_CV == IS_CONST && +	           (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) { +		/* do nothing */ +	} else if (IS_CV != IS_UNUSED) {  		char *function_name_strval = NULL;  		int function_name_strlen = 0; @@ -5343,8 +5578,14 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEN  			if (UNEXPECTED(EX(fbc) == NULL)) {  				zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, function_name_strval);  			} +			if (IS_CV == IS_CONST && EXPECTED((EX(fbc)->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0)) { +				if (IS_CONST == IS_CONST) { +					CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc)); +				} else { +					CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, EX(fbc)); +				} +			}  		} -  		if (IS_CV != IS_CONST) {  		} @@ -5395,7 +5636,12 @@ static int ZEND_FASTCALL  ZEND_CATCH_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_A  		ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->extended_value]);  		ZEND_VM_CONTINUE(); /* CHECK_ME */  	} -	catch_ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC); +	if (CACHED_PTR(opline->op1.literal->cache_slot)) { +		catch_ce = CACHED_PTR(opline->op1.literal->cache_slot); +	} else { +		catch_ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC); +		CACHE_PTR(opline->op1.literal->cache_slot, catch_ce); +	}  	ce = Z_OBJCE_P(EG(exception));  #ifdef HAVE_DTRACE @@ -6790,7 +7036,12 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_TMP_CONST(int type,  		zend_class_entry *ce;  		if (IS_CONST == IS_CONST) { -			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				ce = CACHED_PTR(opline->op2.literal->cache_slot); +			} else { +				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				CACHE_PTR(opline->op2.literal->cache_slot, ce); +			}  		} else {  			ce = EX_T(opline->op2.var).class_entry;  		} @@ -7014,17 +7265,27 @@ static int ZEND_FASTCALL  ZEND_INIT_METHOD_CALL_SPEC_TMP_CONST_HANDLER(ZEND_OPCO  	if (EXPECTED(EX(object) != NULL) &&  	    EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) { -		if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { -			zend_error_noreturn(E_ERROR, "Object does not support method calls"); -		} +		EX(called_scope) = Z_OBJCE_P(EX(object)); -		/* First, locate the function. */ -		EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_CONST == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); -		if (UNEXPECTED(EX(fbc) == NULL)) { -			zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); -		} +		if (IS_CONST != IS_CONST || +		    (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) { +		    zval *object = EX(object); -		EX(called_scope) = Z_OBJCE_P(EX(object)); +			if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { +				zend_error_noreturn(E_ERROR, "Object does not support method calls"); +			} + +			/* First, locate the function. */ +			EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_CONST == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); +			if (UNEXPECTED(EX(fbc) == NULL)) { +				zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); +			} +			if (IS_CONST == IS_CONST && +			    EXPECTED((EX(fbc)->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0) && +			    EXPECTED(EX(object) == object)) { +				CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc)); +			} +		}  	} else {  		zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);  	} @@ -7216,7 +7477,12 @@ static int ZEND_FASTCALL  ZEND_UNSET_VAR_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HAND  		zend_class_entry *ce;  		if (IS_CONST == IS_CONST) { -			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				ce = CACHED_PTR(opline->op2.literal->cache_slot); +			} else { +				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				CACHE_PTR(opline->op2.literal->cache_slot, ce); +			}  		} else {  			ce = EX_T(opline->op2.var).class_entry;  		} @@ -7273,7 +7539,12 @@ static int ZEND_FASTCALL  ZEND_ISSET_ISEMPTY_VAR_SPEC_TMP_CONST_HANDLER(ZEND_OPC  			zend_class_entry *ce;  			if (IS_CONST == IS_CONST) { -				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				if (CACHED_PTR(opline->op2.literal->cache_slot)) { +					ce = CACHED_PTR(opline->op2.literal->cache_slot); +				} else { +					ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +					CACHE_PTR(opline->op2.literal->cache_slot, ce); +				}  			} else {  				ce = EX_T(opline->op2.var).class_entry;  			} @@ -7662,17 +7933,27 @@ static int ZEND_FASTCALL  ZEND_INIT_METHOD_CALL_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE  	if (EXPECTED(EX(object) != NULL) &&  	    EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) { -		if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { -			zend_error_noreturn(E_ERROR, "Object does not support method calls"); -		} +		EX(called_scope) = Z_OBJCE_P(EX(object)); -		/* First, locate the function. */ -		EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_TMP_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); -		if (UNEXPECTED(EX(fbc) == NULL)) { -			zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); -		} +		if (IS_TMP_VAR != IS_CONST || +		    (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) { +		    zval *object = EX(object); -		EX(called_scope) = Z_OBJCE_P(EX(object)); +			if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { +				zend_error_noreturn(E_ERROR, "Object does not support method calls"); +			} + +			/* First, locate the function. */ +			EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_TMP_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); +			if (UNEXPECTED(EX(fbc) == NULL)) { +				zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); +			} +			if (IS_TMP_VAR == IS_CONST && +			    EXPECTED((EX(fbc)->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0) && +			    EXPECTED(EX(object) == object)) { +				CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc)); +			} +		}  	} else {  		zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);  	} @@ -8133,7 +8414,12 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_TMP_VAR(int type, ZE  		zend_class_entry *ce;  		if (IS_VAR == IS_CONST) { -			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				ce = CACHED_PTR(opline->op2.literal->cache_slot); +			} else { +				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				CACHE_PTR(opline->op2.literal->cache_slot, ce); +			}  		} else {  			ce = EX_T(opline->op2.var).class_entry;  		} @@ -8330,17 +8616,27 @@ static int ZEND_FASTCALL  ZEND_INIT_METHOD_CALL_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE  	if (EXPECTED(EX(object) != NULL) &&  	    EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) { -		if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { -			zend_error_noreturn(E_ERROR, "Object does not support method calls"); -		} +		EX(called_scope) = Z_OBJCE_P(EX(object)); -		/* First, locate the function. */ -		EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); -		if (UNEXPECTED(EX(fbc) == NULL)) { -			zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); -		} +		if (IS_VAR != IS_CONST || +		    (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) { +		    zval *object = EX(object); -		EX(called_scope) = Z_OBJCE_P(EX(object)); +			if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { +				zend_error_noreturn(E_ERROR, "Object does not support method calls"); +			} + +			/* First, locate the function. */ +			EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); +			if (UNEXPECTED(EX(fbc) == NULL)) { +				zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); +			} +			if (IS_VAR == IS_CONST && +			    EXPECTED((EX(fbc)->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0) && +			    EXPECTED(EX(object) == object)) { +				CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc)); +			} +		}  	} else {  		zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);  	} @@ -8534,7 +8830,12 @@ static int ZEND_FASTCALL  ZEND_UNSET_VAR_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLE  		zend_class_entry *ce;  		if (IS_VAR == IS_CONST) { -			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				ce = CACHED_PTR(opline->op2.literal->cache_slot); +			} else { +				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				CACHE_PTR(opline->op2.literal->cache_slot, ce); +			}  		} else {  			ce = EX_T(opline->op2.var).class_entry;  		} @@ -8591,7 +8892,12 @@ static int ZEND_FASTCALL  ZEND_ISSET_ISEMPTY_VAR_SPEC_TMP_VAR_HANDLER(ZEND_OPCOD  			zend_class_entry *ce;  			if (IS_VAR == IS_CONST) { -				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				if (CACHED_PTR(opline->op2.literal->cache_slot)) { +					ce = CACHED_PTR(opline->op2.literal->cache_slot); +				} else { +					ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +					CACHE_PTR(opline->op2.literal->cache_slot, ce); +				}  			} else {  				ce = EX_T(opline->op2.var).class_entry;  			} @@ -8654,7 +8960,12 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_TMP_UNUSED(int type,  		zend_class_entry *ce;  		if (IS_UNUSED == IS_CONST) { -			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				ce = CACHED_PTR(opline->op2.literal->cache_slot); +			} else { +				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				CACHE_PTR(opline->op2.literal->cache_slot, ce); +			}  		} else {  			ce = EX_T(opline->op2.var).class_entry;  		} @@ -8916,7 +9227,12 @@ static int ZEND_FASTCALL  ZEND_UNSET_VAR_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCODE_HAN  		zend_class_entry *ce;  		if (IS_UNUSED == IS_CONST) { -			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				ce = CACHED_PTR(opline->op2.literal->cache_slot); +			} else { +				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				CACHE_PTR(opline->op2.literal->cache_slot, ce); +			}  		} else {  			ce = EX_T(opline->op2.var).class_entry;  		} @@ -8973,7 +9289,12 @@ static int ZEND_FASTCALL  ZEND_ISSET_ISEMPTY_VAR_SPEC_TMP_UNUSED_HANDLER(ZEND_OP  			zend_class_entry *ce;  			if (IS_UNUSED == IS_CONST) { -				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				if (CACHED_PTR(opline->op2.literal->cache_slot)) { +					ce = CACHED_PTR(opline->op2.literal->cache_slot); +				} else { +					ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +					CACHE_PTR(opline->op2.literal->cache_slot, ce); +				}  			} else {  				ce = EX_T(opline->op2.var).class_entry;  			} @@ -9361,17 +9682,27 @@ static int ZEND_FASTCALL  ZEND_INIT_METHOD_CALL_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_  	if (EXPECTED(EX(object) != NULL) &&  	    EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) { -		if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { -			zend_error_noreturn(E_ERROR, "Object does not support method calls"); -		} +		EX(called_scope) = Z_OBJCE_P(EX(object)); -		/* First, locate the function. */ -		EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_CV == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); -		if (UNEXPECTED(EX(fbc) == NULL)) { -			zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); -		} +		if (IS_CV != IS_CONST || +		    (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) { +		    zval *object = EX(object); -		EX(called_scope) = Z_OBJCE_P(EX(object)); +			if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { +				zend_error_noreturn(E_ERROR, "Object does not support method calls"); +			} + +			/* First, locate the function. */ +			EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_CV == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); +			if (UNEXPECTED(EX(fbc) == NULL)) { +				zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); +			} +			if (IS_CV == IS_CONST && +			    EXPECTED((EX(fbc)->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0) && +			    EXPECTED(EX(object) == object)) { +				CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc)); +			} +		}  	} else {  		zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);  	} @@ -11648,7 +11979,12 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_VAR_CONST(int type,  		zend_class_entry *ce;  		if (IS_CONST == IS_CONST) { -			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				ce = CACHED_PTR(opline->op2.literal->cache_slot); +			} else { +				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				CACHE_PTR(opline->op2.literal->cache_slot, ce); +			}  		} else {  			ce = EX_T(opline->op2.var).class_entry;  		} @@ -12401,17 +12737,27 @@ static int ZEND_FASTCALL  ZEND_INIT_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZEND_OPCO  	if (EXPECTED(EX(object) != NULL) &&  	    EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) { -		if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { -			zend_error_noreturn(E_ERROR, "Object does not support method calls"); -		} +		EX(called_scope) = Z_OBJCE_P(EX(object)); -		/* First, locate the function. */ -		EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_CONST == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); -		if (UNEXPECTED(EX(fbc) == NULL)) { -			zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); -		} +		if (IS_CONST != IS_CONST || +		    (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) { +		    zval *object = EX(object); -		EX(called_scope) = Z_OBJCE_P(EX(object)); +			if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { +				zend_error_noreturn(E_ERROR, "Object does not support method calls"); +			} + +			/* First, locate the function. */ +			EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_CONST == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); +			if (UNEXPECTED(EX(fbc) == NULL)) { +				zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); +			} +			if (IS_CONST == IS_CONST && +			    EXPECTED((EX(fbc)->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0) && +			    EXPECTED(EX(object) == object)) { +				CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc)); +			} +		}  	} else {  		zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);  	} @@ -12447,9 +12793,14 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZE  	if (IS_VAR == IS_CONST) {  		/* no function found. try a static method in class */ -		ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, opline->extended_value TSRMLS_CC); -		if (UNEXPECTED(ce == NULL)) { -			zend_error_noreturn(E_ERROR, "Class '%s' not found", Z_STRVAL_P(opline->op1.zv)); +		if (CACHED_PTR(opline->op1.literal->cache_slot)) { +			ce = CACHED_PTR(opline->op1.literal->cache_slot); +		} else { +			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, opline->extended_value TSRMLS_CC); +			if (UNEXPECTED(ce == NULL)) { +				zend_error_noreturn(E_ERROR, "Class '%s' not found", Z_STRVAL_P(opline->op1.zv)); +			} +			CACHE_PTR(opline->op1.literal->cache_slot, ce);  		}  		EX(called_scope) = ce;  	} else { @@ -12461,7 +12812,16 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZE  			EX(called_scope) = ce;  		}  	} -	if(IS_CONST != IS_UNUSED) { + +	if (IS_VAR == IS_CONST && +	    IS_CONST == IS_CONST && +	    CACHED_PTR(opline->op2.literal->cache_slot)) { +		EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); +	} else if (IS_VAR != IS_CONST && +	           IS_CONST == IS_CONST && +	           (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) { +		/* do nothing */ +	} else if (IS_CONST != IS_UNUSED) {  		char *function_name_strval = NULL;  		int function_name_strlen = 0; @@ -12489,8 +12849,14 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZE  			if (UNEXPECTED(EX(fbc) == NULL)) {  				zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, function_name_strval);  			} +			if (IS_CONST == IS_CONST && EXPECTED((EX(fbc)->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0)) { +				if (IS_VAR == IS_CONST) { +					CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc)); +				} else { +					CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, EX(fbc)); +				} +			}  		} -  		if (IS_CONST != IS_CONST) {  		} @@ -12571,7 +12937,9 @@ static int ZEND_FASTCALL  ZEND_FETCH_CONSTANT_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE  		zend_constant *c;  		zval *retval; -		if ((c = zend_quick_get_constant(opline->op2.literal + 1, opline->extended_value TSRMLS_CC)) == NULL) { +		if (CACHED_PTR(opline->op2.literal->cache_slot)) { +			c = CACHED_PTR(opline->op2.literal->cache_slot); +		} else if ((c = zend_quick_get_constant(opline->op2.literal + 1, opline->extended_value TSRMLS_CC)) == NULL) {  			if ((opline->extended_value & IS_CONSTANT_UNQUALIFIED) != 0) {  				char *actual = (char *)zend_memrchr(Z_STRVAL_P(opline->op2.zv), '\\', Z_STRLEN_P(opline->op2.zv));  				if(!actual) { @@ -12587,6 +12955,8 @@ static int ZEND_FASTCALL  ZEND_FETCH_CONSTANT_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE  			} else {  				zend_error_noreturn(E_ERROR, "Undefined constant '%s'", Z_STRVAL_P(opline->op2.zv));  			} +		} else { +			CACHE_PTR(opline->op2.literal->cache_slot, c);  		}  		retval = &EX_T(opline->result.var).tmp_var;  		INIT_PZVAL_COPY(retval, &c->value); @@ -12599,13 +12969,29 @@ static int ZEND_FASTCALL  ZEND_FETCH_CONSTANT_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE  		zval **value;  		if (IS_VAR == IS_CONST) { - -			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, opline->extended_value TSRMLS_CC); -			if (UNEXPECTED(ce == NULL)) { -				zend_error_noreturn(E_ERROR, "Undefined class constant '%s'", Z_STRVAL_P(opline->op2.zv)); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				value = CACHED_PTR(opline->op2.literal->cache_slot); +				ZVAL_COPY_VALUE(&EX_T(opline->result.var).tmp_var, *value); +				zval_copy_ctor(&EX_T(opline->result.var).tmp_var); +				CHECK_EXCEPTION(); +				ZEND_VM_NEXT_OPCODE(); +			} else if (CACHED_PTR(opline->op1.literal->cache_slot)) { +				ce = CACHED_PTR(opline->op1.literal->cache_slot); +			} else { +				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, opline->extended_value TSRMLS_CC); +				if (UNEXPECTED(ce == NULL)) { +					zend_error_noreturn(E_ERROR, "Undefined class constant '%s'", Z_STRVAL_P(opline->op2.zv)); +				} +				CACHE_PTR(opline->op1.literal->cache_slot, ce);  			}  		} else {  			ce = EX_T(opline->op1.var).class_entry; +			if ((value = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce)) != NULL) { +				ZVAL_COPY_VALUE(&EX_T(opline->result.var).tmp_var, *value); +				zval_copy_ctor(&EX_T(opline->result.var).tmp_var); +				CHECK_EXCEPTION(); +				ZEND_VM_NEXT_OPCODE(); +			}  		}  		if (EXPECTED(zend_hash_quick_find(&ce->constants_table, Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv)+1, Z_HASH_P(opline->op2.zv), (void **) &value) == SUCCESS)) { @@ -12617,6 +13003,11 @@ static int ZEND_FASTCALL  ZEND_FETCH_CONSTANT_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE  				zval_update_constant(value, (void *) 1 TSRMLS_CC);  				EG(scope) = old_scope;  			} +			if (IS_VAR == IS_CONST) { +				CACHE_PTR(opline->op2.literal->cache_slot, value); +			} else { +				CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, value); +			}  			ZVAL_COPY_VALUE(&EX_T(opline->result.var).tmp_var, *value);  			zval_copy_ctor(&EX_T(opline->result.var).tmp_var);  		} else { @@ -12763,7 +13154,12 @@ static int ZEND_FASTCALL  ZEND_UNSET_VAR_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HAND  		zend_class_entry *ce;  		if (IS_CONST == IS_CONST) { -			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				ce = CACHED_PTR(opline->op2.literal->cache_slot); +			} else { +				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				CACHE_PTR(opline->op2.literal->cache_slot, ce); +			}  		} else {  			ce = EX_T(opline->op2.var).class_entry;  		} @@ -12956,7 +13352,12 @@ static int ZEND_FASTCALL  ZEND_ISSET_ISEMPTY_VAR_SPEC_VAR_CONST_HANDLER(ZEND_OPC  			zend_class_entry *ce;  			if (IS_CONST == IS_CONST) { -				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				if (CACHED_PTR(opline->op2.literal->cache_slot)) { +					ce = CACHED_PTR(opline->op2.literal->cache_slot); +				} else { +					ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +					CACHE_PTR(opline->op2.literal->cache_slot, ce); +				}  			} else {  				ce = EX_T(opline->op2.var).class_entry;  			} @@ -14516,17 +14917,27 @@ static int ZEND_FASTCALL  ZEND_INIT_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE  	if (EXPECTED(EX(object) != NULL) &&  	    EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) { -		if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { -			zend_error_noreturn(E_ERROR, "Object does not support method calls"); -		} +		EX(called_scope) = Z_OBJCE_P(EX(object)); -		/* First, locate the function. */ -		EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_TMP_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); -		if (UNEXPECTED(EX(fbc) == NULL)) { -			zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); -		} +		if (IS_TMP_VAR != IS_CONST || +		    (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) { +		    zval *object = EX(object); -		EX(called_scope) = Z_OBJCE_P(EX(object)); +			if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { +				zend_error_noreturn(E_ERROR, "Object does not support method calls"); +			} + +			/* First, locate the function. */ +			EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_TMP_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); +			if (UNEXPECTED(EX(fbc) == NULL)) { +				zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); +			} +			if (IS_TMP_VAR == IS_CONST && +			    EXPECTED((EX(fbc)->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0) && +			    EXPECTED(EX(object) == object)) { +				CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc)); +			} +		}  	} else {  		zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);  	} @@ -14563,9 +14974,14 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND  	if (IS_VAR == IS_CONST) {  		/* no function found. try a static method in class */ -		ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, opline->extended_value TSRMLS_CC); -		if (UNEXPECTED(ce == NULL)) { -			zend_error_noreturn(E_ERROR, "Class '%s' not found", Z_STRVAL_P(opline->op1.zv)); +		if (CACHED_PTR(opline->op1.literal->cache_slot)) { +			ce = CACHED_PTR(opline->op1.literal->cache_slot); +		} else { +			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, opline->extended_value TSRMLS_CC); +			if (UNEXPECTED(ce == NULL)) { +				zend_error_noreturn(E_ERROR, "Class '%s' not found", Z_STRVAL_P(opline->op1.zv)); +			} +			CACHE_PTR(opline->op1.literal->cache_slot, ce);  		}  		EX(called_scope) = ce;  	} else { @@ -14577,7 +14993,16 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND  			EX(called_scope) = ce;  		}  	} -	if(IS_TMP_VAR != IS_UNUSED) { + +	if (IS_VAR == IS_CONST && +	    IS_TMP_VAR == IS_CONST && +	    CACHED_PTR(opline->op2.literal->cache_slot)) { +		EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); +	} else if (IS_VAR != IS_CONST && +	           IS_TMP_VAR == IS_CONST && +	           (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) { +		/* do nothing */ +	} else if (IS_TMP_VAR != IS_UNUSED) {  		char *function_name_strval = NULL;  		int function_name_strlen = 0;  		zend_free_op free_op2; @@ -14605,8 +15030,14 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND  			if (UNEXPECTED(EX(fbc) == NULL)) {  				zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, function_name_strval);  			} +			if (IS_TMP_VAR == IS_CONST && EXPECTED((EX(fbc)->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0)) { +				if (IS_VAR == IS_CONST) { +					CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc)); +				} else { +					CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, EX(fbc)); +				} +			}  		} -  		if (IS_TMP_VAR != IS_CONST) {  			zval_dtor(free_op2.var);  		} @@ -15831,7 +16262,12 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_VAR_VAR(int type, ZE  		zend_class_entry *ce;  		if (IS_VAR == IS_CONST) { -			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				ce = CACHED_PTR(opline->op2.literal->cache_slot); +			} else { +				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				CACHE_PTR(opline->op2.literal->cache_slot, ce); +			}  		} else {  			ce = EX_T(opline->op2.var).class_entry;  		} @@ -16640,17 +17076,27 @@ static int ZEND_FASTCALL  ZEND_INIT_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE  	if (EXPECTED(EX(object) != NULL) &&  	    EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) { -		if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { -			zend_error_noreturn(E_ERROR, "Object does not support method calls"); -		} +		EX(called_scope) = Z_OBJCE_P(EX(object)); -		/* First, locate the function. */ -		EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); -		if (UNEXPECTED(EX(fbc) == NULL)) { -			zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); -		} +		if (IS_VAR != IS_CONST || +		    (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) { +		    zval *object = EX(object); -		EX(called_scope) = Z_OBJCE_P(EX(object)); +			if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { +				zend_error_noreturn(E_ERROR, "Object does not support method calls"); +			} + +			/* First, locate the function. */ +			EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); +			if (UNEXPECTED(EX(fbc) == NULL)) { +				zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); +			} +			if (IS_VAR == IS_CONST && +			    EXPECTED((EX(fbc)->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0) && +			    EXPECTED(EX(object) == object)) { +				CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc)); +			} +		}  	} else {  		zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);  	} @@ -16687,9 +17133,14 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND  	if (IS_VAR == IS_CONST) {  		/* no function found. try a static method in class */ -		ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, opline->extended_value TSRMLS_CC); -		if (UNEXPECTED(ce == NULL)) { -			zend_error_noreturn(E_ERROR, "Class '%s' not found", Z_STRVAL_P(opline->op1.zv)); +		if (CACHED_PTR(opline->op1.literal->cache_slot)) { +			ce = CACHED_PTR(opline->op1.literal->cache_slot); +		} else { +			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, opline->extended_value TSRMLS_CC); +			if (UNEXPECTED(ce == NULL)) { +				zend_error_noreturn(E_ERROR, "Class '%s' not found", Z_STRVAL_P(opline->op1.zv)); +			} +			CACHE_PTR(opline->op1.literal->cache_slot, ce);  		}  		EX(called_scope) = ce;  	} else { @@ -16701,7 +17152,16 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND  			EX(called_scope) = ce;  		}  	} -	if(IS_VAR != IS_UNUSED) { + +	if (IS_VAR == IS_CONST && +	    IS_VAR == IS_CONST && +	    CACHED_PTR(opline->op2.literal->cache_slot)) { +		EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); +	} else if (IS_VAR != IS_CONST && +	           IS_VAR == IS_CONST && +	           (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) { +		/* do nothing */ +	} else if (IS_VAR != IS_UNUSED) {  		char *function_name_strval = NULL;  		int function_name_strlen = 0;  		zend_free_op free_op2; @@ -16729,8 +17189,14 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND  			if (UNEXPECTED(EX(fbc) == NULL)) {  				zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, function_name_strval);  			} +			if (IS_VAR == IS_CONST && EXPECTED((EX(fbc)->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0)) { +				if (IS_VAR == IS_CONST) { +					CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc)); +				} else { +					CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, EX(fbc)); +				} +			}  		} -  		if (IS_VAR != IS_CONST) {  			if (free_op2.var) {zval_ptr_dtor(&free_op2.var);};  		} @@ -16938,7 +17404,12 @@ static int ZEND_FASTCALL  ZEND_UNSET_VAR_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLE  		zend_class_entry *ce;  		if (IS_VAR == IS_CONST) { -			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				ce = CACHED_PTR(opline->op2.literal->cache_slot); +			} else { +				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				CACHE_PTR(opline->op2.literal->cache_slot, ce); +			}  		} else {  			ce = EX_T(opline->op2.var).class_entry;  		} @@ -17131,7 +17602,12 @@ static int ZEND_FASTCALL  ZEND_ISSET_ISEMPTY_VAR_SPEC_VAR_VAR_HANDLER(ZEND_OPCOD  			zend_class_entry *ce;  			if (IS_VAR == IS_CONST) { -				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				if (CACHED_PTR(opline->op2.literal->cache_slot)) { +					ce = CACHED_PTR(opline->op2.literal->cache_slot); +				} else { +					ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +					CACHE_PTR(opline->op2.literal->cache_slot, ce); +				}  			} else {  				ce = EX_T(opline->op2.var).class_entry;  			} @@ -17601,7 +18077,12 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_VAR_UNUSED(int type,  		zend_class_entry *ce;  		if (IS_UNUSED == IS_CONST) { -			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				ce = CACHED_PTR(opline->op2.literal->cache_slot); +			} else { +				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				CACHE_PTR(opline->op2.literal->cache_slot, ce); +			}  		} else {  			ce = EX_T(opline->op2.var).class_entry;  		} @@ -17906,9 +18387,14 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_UNUSED_HANDLER(Z  	if (IS_VAR == IS_CONST) {  		/* no function found. try a static method in class */ -		ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, opline->extended_value TSRMLS_CC); -		if (UNEXPECTED(ce == NULL)) { -			zend_error_noreturn(E_ERROR, "Class '%s' not found", Z_STRVAL_P(opline->op1.zv)); +		if (CACHED_PTR(opline->op1.literal->cache_slot)) { +			ce = CACHED_PTR(opline->op1.literal->cache_slot); +		} else { +			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, opline->extended_value TSRMLS_CC); +			if (UNEXPECTED(ce == NULL)) { +				zend_error_noreturn(E_ERROR, "Class '%s' not found", Z_STRVAL_P(opline->op1.zv)); +			} +			CACHE_PTR(opline->op1.literal->cache_slot, ce);  		}  		EX(called_scope) = ce;  	} else { @@ -17920,7 +18406,16 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_UNUSED_HANDLER(Z  			EX(called_scope) = ce;  		}  	} -	if(IS_UNUSED != IS_UNUSED) { + +	if (IS_VAR == IS_CONST && +	    IS_UNUSED == IS_CONST && +	    CACHED_PTR(opline->op2.literal->cache_slot)) { +		EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); +	} else if (IS_VAR != IS_CONST && +	           IS_UNUSED == IS_CONST && +	           (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) { +		/* do nothing */ +	} else if (IS_UNUSED != IS_UNUSED) {  		char *function_name_strval = NULL;  		int function_name_strlen = 0; @@ -17948,8 +18443,14 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_UNUSED_HANDLER(Z  			if (UNEXPECTED(EX(fbc) == NULL)) {  				zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, function_name_strval);  			} +			if (IS_UNUSED == IS_CONST && EXPECTED((EX(fbc)->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0)) { +				if (IS_VAR == IS_CONST) { +					CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc)); +				} else { +					CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, EX(fbc)); +				} +			}  		} -  		if (IS_UNUSED != IS_CONST) {  		} @@ -18123,7 +18624,12 @@ static int ZEND_FASTCALL  ZEND_UNSET_VAR_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HAN  		zend_class_entry *ce;  		if (IS_UNUSED == IS_CONST) { -			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				ce = CACHED_PTR(opline->op2.literal->cache_slot); +			} else { +				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				CACHE_PTR(opline->op2.literal->cache_slot, ce); +			}  		} else {  			ce = EX_T(opline->op2.var).class_entry;  		} @@ -18180,7 +18686,12 @@ static int ZEND_FASTCALL  ZEND_ISSET_ISEMPTY_VAR_SPEC_VAR_UNUSED_HANDLER(ZEND_OP  			zend_class_entry *ce;  			if (IS_UNUSED == IS_CONST) { -				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				if (CACHED_PTR(opline->op2.literal->cache_slot)) { +					ce = CACHED_PTR(opline->op2.literal->cache_slot); +				} else { +					ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +					CACHE_PTR(opline->op2.literal->cache_slot, ce); +				}  			} else {  				ce = EX_T(opline->op2.var).class_entry;  			} @@ -19640,17 +20151,27 @@ static int ZEND_FASTCALL  ZEND_INIT_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_  	if (EXPECTED(EX(object) != NULL) &&  	    EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) { -		if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { -			zend_error_noreturn(E_ERROR, "Object does not support method calls"); -		} +		EX(called_scope) = Z_OBJCE_P(EX(object)); -		/* First, locate the function. */ -		EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_CV == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); -		if (UNEXPECTED(EX(fbc) == NULL)) { -			zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); -		} +		if (IS_CV != IS_CONST || +		    (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) { +		    zval *object = EX(object); -		EX(called_scope) = Z_OBJCE_P(EX(object)); +			if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { +				zend_error_noreturn(E_ERROR, "Object does not support method calls"); +			} + +			/* First, locate the function. */ +			EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_CV == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); +			if (UNEXPECTED(EX(fbc) == NULL)) { +				zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); +			} +			if (IS_CV == IS_CONST && +			    EXPECTED((EX(fbc)->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0) && +			    EXPECTED(EX(object) == object)) { +				CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc)); +			} +		}  	} else {  		zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);  	} @@ -19686,9 +20207,14 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_  	if (IS_VAR == IS_CONST) {  		/* no function found. try a static method in class */ -		ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, opline->extended_value TSRMLS_CC); -		if (UNEXPECTED(ce == NULL)) { -			zend_error_noreturn(E_ERROR, "Class '%s' not found", Z_STRVAL_P(opline->op1.zv)); +		if (CACHED_PTR(opline->op1.literal->cache_slot)) { +			ce = CACHED_PTR(opline->op1.literal->cache_slot); +		} else { +			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, opline->extended_value TSRMLS_CC); +			if (UNEXPECTED(ce == NULL)) { +				zend_error_noreturn(E_ERROR, "Class '%s' not found", Z_STRVAL_P(opline->op1.zv)); +			} +			CACHE_PTR(opline->op1.literal->cache_slot, ce);  		}  		EX(called_scope) = ce;  	} else { @@ -19700,7 +20226,16 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_  			EX(called_scope) = ce;  		}  	} -	if(IS_CV != IS_UNUSED) { + +	if (IS_VAR == IS_CONST && +	    IS_CV == IS_CONST && +	    CACHED_PTR(opline->op2.literal->cache_slot)) { +		EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); +	} else if (IS_VAR != IS_CONST && +	           IS_CV == IS_CONST && +	           (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) { +		/* do nothing */ +	} else if (IS_CV != IS_UNUSED) {  		char *function_name_strval = NULL;  		int function_name_strlen = 0; @@ -19728,8 +20263,14 @@ static int ZEND_FASTCALL  ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_  			if (UNEXPECTED(EX(fbc) == NULL)) {  				zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, function_name_strval);  			} +			if (IS_CV == IS_CONST && EXPECTED((EX(fbc)->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0)) { +				if (IS_VAR == IS_CONST) { +					CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc)); +				} else { +					CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, EX(fbc)); +				} +			}  		} -  		if (IS_CV != IS_CONST) {  		} @@ -21098,17 +21639,27 @@ static int ZEND_FASTCALL  ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CONST_HANDLER(ZEND_O  	if (EXPECTED(EX(object) != NULL) &&  	    EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) { -		if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { -			zend_error_noreturn(E_ERROR, "Object does not support method calls"); -		} +		EX(called_scope) = Z_OBJCE_P(EX(object)); -		/* First, locate the function. */ -		EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_CONST == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); -		if (UNEXPECTED(EX(fbc) == NULL)) { -			zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); -		} +		if (IS_CONST != IS_CONST || +		    (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) { +		    zval *object = EX(object); -		EX(called_scope) = Z_OBJCE_P(EX(object)); +			if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { +				zend_error_noreturn(E_ERROR, "Object does not support method calls"); +			} + +			/* First, locate the function. */ +			EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_CONST == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); +			if (UNEXPECTED(EX(fbc) == NULL)) { +				zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); +			} +			if (IS_CONST == IS_CONST && +			    EXPECTED((EX(fbc)->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0) && +			    EXPECTED(EX(object) == object)) { +				CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc)); +			} +		}  	} else {  		zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);  	} @@ -21141,7 +21692,9 @@ static int ZEND_FASTCALL  ZEND_FETCH_CONSTANT_SPEC_UNUSED_CONST_HANDLER(ZEND_OPC  		zend_constant *c;  		zval *retval; -		if ((c = zend_quick_get_constant(opline->op2.literal + 1, opline->extended_value TSRMLS_CC)) == NULL) { +		if (CACHED_PTR(opline->op2.literal->cache_slot)) { +			c = CACHED_PTR(opline->op2.literal->cache_slot); +		} else if ((c = zend_quick_get_constant(opline->op2.literal + 1, opline->extended_value TSRMLS_CC)) == NULL) {  			if ((opline->extended_value & IS_CONSTANT_UNQUALIFIED) != 0) {  				char *actual = (char *)zend_memrchr(Z_STRVAL_P(opline->op2.zv), '\\', Z_STRLEN_P(opline->op2.zv));  				if(!actual) { @@ -21157,6 +21710,8 @@ static int ZEND_FASTCALL  ZEND_FETCH_CONSTANT_SPEC_UNUSED_CONST_HANDLER(ZEND_OPC  			} else {  				zend_error_noreturn(E_ERROR, "Undefined constant '%s'", Z_STRVAL_P(opline->op2.zv));  			} +		} else { +			CACHE_PTR(opline->op2.literal->cache_slot, c);  		}  		retval = &EX_T(opline->result.var).tmp_var;  		INIT_PZVAL_COPY(retval, &c->value); @@ -21169,13 +21724,29 @@ static int ZEND_FASTCALL  ZEND_FETCH_CONSTANT_SPEC_UNUSED_CONST_HANDLER(ZEND_OPC  		zval **value;  		if (IS_UNUSED == IS_CONST) { - -			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, opline->extended_value TSRMLS_CC); -			if (UNEXPECTED(ce == NULL)) { -				zend_error_noreturn(E_ERROR, "Undefined class constant '%s'", Z_STRVAL_P(opline->op2.zv)); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				value = CACHED_PTR(opline->op2.literal->cache_slot); +				ZVAL_COPY_VALUE(&EX_T(opline->result.var).tmp_var, *value); +				zval_copy_ctor(&EX_T(opline->result.var).tmp_var); +				CHECK_EXCEPTION(); +				ZEND_VM_NEXT_OPCODE(); +			} else if (CACHED_PTR(opline->op1.literal->cache_slot)) { +				ce = CACHED_PTR(opline->op1.literal->cache_slot); +			} else { +				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, opline->extended_value TSRMLS_CC); +				if (UNEXPECTED(ce == NULL)) { +					zend_error_noreturn(E_ERROR, "Undefined class constant '%s'", Z_STRVAL_P(opline->op2.zv)); +				} +				CACHE_PTR(opline->op1.literal->cache_slot, ce);  			}  		} else {  			ce = EX_T(opline->op1.var).class_entry; +			if ((value = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce)) != NULL) { +				ZVAL_COPY_VALUE(&EX_T(opline->result.var).tmp_var, *value); +				zval_copy_ctor(&EX_T(opline->result.var).tmp_var); +				CHECK_EXCEPTION(); +				ZEND_VM_NEXT_OPCODE(); +			}  		}  		if (EXPECTED(zend_hash_quick_find(&ce->constants_table, Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv)+1, Z_HASH_P(opline->op2.zv), (void **) &value) == SUCCESS)) { @@ -21187,6 +21758,11 @@ static int ZEND_FASTCALL  ZEND_FETCH_CONSTANT_SPEC_UNUSED_CONST_HANDLER(ZEND_OPC  				zval_update_constant(value, (void *) 1 TSRMLS_CC);  				EG(scope) = old_scope;  			} +			if (IS_UNUSED == IS_CONST) { +				CACHE_PTR(opline->op2.literal->cache_slot, value); +			} else { +				CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, value); +			}  			ZVAL_COPY_VALUE(&EX_T(opline->result.var).tmp_var, *value);  			zval_copy_ctor(&EX_T(opline->result.var).tmp_var);  		} else { @@ -22321,17 +22897,27 @@ static int ZEND_FASTCALL  ZEND_INIT_METHOD_CALL_SPEC_UNUSED_TMP_HANDLER(ZEND_OPC  	if (EXPECTED(EX(object) != NULL) &&  	    EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) { -		if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { -			zend_error_noreturn(E_ERROR, "Object does not support method calls"); -		} +		EX(called_scope) = Z_OBJCE_P(EX(object)); -		/* First, locate the function. */ -		EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_TMP_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); -		if (UNEXPECTED(EX(fbc) == NULL)) { -			zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); -		} +		if (IS_TMP_VAR != IS_CONST || +		    (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) { +		    zval *object = EX(object); -		EX(called_scope) = Z_OBJCE_P(EX(object)); +			if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { +				zend_error_noreturn(E_ERROR, "Object does not support method calls"); +			} + +			/* First, locate the function. */ +			EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_TMP_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); +			if (UNEXPECTED(EX(fbc) == NULL)) { +				zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); +			} +			if (IS_TMP_VAR == IS_CONST && +			    EXPECTED((EX(fbc)->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0) && +			    EXPECTED(EX(object) == object)) { +				CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc)); +			} +		}  	} else {  		zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);  	} @@ -23479,17 +24065,27 @@ static int ZEND_FASTCALL  ZEND_INIT_METHOD_CALL_SPEC_UNUSED_VAR_HANDLER(ZEND_OPC  	if (EXPECTED(EX(object) != NULL) &&  	    EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) { -		if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { -			zend_error_noreturn(E_ERROR, "Object does not support method calls"); -		} +		EX(called_scope) = Z_OBJCE_P(EX(object)); -		/* First, locate the function. */ -		EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); -		if (UNEXPECTED(EX(fbc) == NULL)) { -			zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); -		} +		if (IS_VAR != IS_CONST || +		    (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) { +		    zval *object = EX(object); -		EX(called_scope) = Z_OBJCE_P(EX(object)); +			if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { +				zend_error_noreturn(E_ERROR, "Object does not support method calls"); +			} + +			/* First, locate the function. */ +			EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); +			if (UNEXPECTED(EX(fbc) == NULL)) { +				zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); +			} +			if (IS_VAR == IS_CONST && +			    EXPECTED((EX(fbc)->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0) && +			    EXPECTED(EX(object) == object)) { +				CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc)); +			} +		}  	} else {  		zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);  	} @@ -24904,17 +25500,27 @@ static int ZEND_FASTCALL  ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CV_HANDLER(ZEND_OPCO  	if (EXPECTED(EX(object) != NULL) &&  	    EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) { -		if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { -			zend_error_noreturn(E_ERROR, "Object does not support method calls"); -		} +		EX(called_scope) = Z_OBJCE_P(EX(object)); -		/* First, locate the function. */ -		EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_CV == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); -		if (UNEXPECTED(EX(fbc) == NULL)) { -			zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); -		} +		if (IS_CV != IS_CONST || +		    (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) { +		    zval *object = EX(object); -		EX(called_scope) = Z_OBJCE_P(EX(object)); +			if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { +				zend_error_noreturn(E_ERROR, "Object does not support method calls"); +			} + +			/* First, locate the function. */ +			EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_CV == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); +			if (UNEXPECTED(EX(fbc) == NULL)) { +				zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); +			} +			if (IS_CV == IS_CONST && +			    EXPECTED((EX(fbc)->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0) && +			    EXPECTED(EX(object) == object)) { +				CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc)); +			} +		}  	} else {  		zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);  	} @@ -27191,7 +27797,12 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_CV_CONST(int type, Z  		zend_class_entry *ce;  		if (IS_CONST == IS_CONST) { -			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				ce = CACHED_PTR(opline->op2.literal->cache_slot); +			} else { +				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				CACHE_PTR(opline->op2.literal->cache_slot, ce); +			}  		} else {  			ce = EX_T(opline->op2.var).class_entry;  		} @@ -27937,17 +28548,27 @@ static int ZEND_FASTCALL  ZEND_INIT_METHOD_CALL_SPEC_CV_CONST_HANDLER(ZEND_OPCOD  	if (EXPECTED(EX(object) != NULL) &&  	    EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) { -		if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { -			zend_error_noreturn(E_ERROR, "Object does not support method calls"); -		} +		EX(called_scope) = Z_OBJCE_P(EX(object)); -		/* First, locate the function. */ -		EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_CONST == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); -		if (UNEXPECTED(EX(fbc) == NULL)) { -			zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); -		} +		if (IS_CONST != IS_CONST || +		    (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) { +		    zval *object = EX(object); -		EX(called_scope) = Z_OBJCE_P(EX(object)); +			if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { +				zend_error_noreturn(E_ERROR, "Object does not support method calls"); +			} + +			/* First, locate the function. */ +			EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_CONST == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); +			if (UNEXPECTED(EX(fbc) == NULL)) { +				zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); +			} +			if (IS_CONST == IS_CONST && +			    EXPECTED((EX(fbc)->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0) && +			    EXPECTED(EX(object) == object)) { +				CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc)); +			} +		}  	} else {  		zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);  	} @@ -28139,7 +28760,12 @@ static int ZEND_FASTCALL  ZEND_UNSET_VAR_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDL  		zend_class_entry *ce;  		if (IS_CONST == IS_CONST) { -			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				ce = CACHED_PTR(opline->op2.literal->cache_slot); +			} else { +				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				CACHE_PTR(opline->op2.literal->cache_slot, ce); +			}  		} else {  			ce = EX_T(opline->op2.var).class_entry;  		} @@ -28330,7 +28956,12 @@ static int ZEND_FASTCALL  ZEND_ISSET_ISEMPTY_VAR_SPEC_CV_CONST_HANDLER(ZEND_OPCO  			zend_class_entry *ce;  			if (IS_CONST == IS_CONST) { -				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				if (CACHED_PTR(opline->op2.literal->cache_slot)) { +					ce = CACHED_PTR(opline->op2.literal->cache_slot); +				} else { +					ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +					CACHE_PTR(opline->op2.literal->cache_slot, ce); +				}  			} else {  				ce = EX_T(opline->op2.var).class_entry;  			} @@ -29880,17 +30511,27 @@ static int ZEND_FASTCALL  ZEND_INIT_METHOD_CALL_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_  	if (EXPECTED(EX(object) != NULL) &&  	    EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) { -		if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { -			zend_error_noreturn(E_ERROR, "Object does not support method calls"); -		} +		EX(called_scope) = Z_OBJCE_P(EX(object)); -		/* First, locate the function. */ -		EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_TMP_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); -		if (UNEXPECTED(EX(fbc) == NULL)) { -			zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); -		} +		if (IS_TMP_VAR != IS_CONST || +		    (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) { +		    zval *object = EX(object); -		EX(called_scope) = Z_OBJCE_P(EX(object)); +			if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { +				zend_error_noreturn(E_ERROR, "Object does not support method calls"); +			} + +			/* First, locate the function. */ +			EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_TMP_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); +			if (UNEXPECTED(EX(fbc) == NULL)) { +				zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); +			} +			if (IS_TMP_VAR == IS_CONST && +			    EXPECTED((EX(fbc)->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0) && +			    EXPECTED(EX(object) == object)) { +				CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc)); +			} +		}  	} else {  		zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);  	} @@ -31096,7 +31737,12 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_CV_VAR(int type, ZEN  		zend_class_entry *ce;  		if (IS_VAR == IS_CONST) { -			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				ce = CACHED_PTR(opline->op2.literal->cache_slot); +			} else { +				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				CACHE_PTR(opline->op2.literal->cache_slot, ce); +			}  		} else {  			ce = EX_T(opline->op2.var).class_entry;  		} @@ -31897,17 +32543,27 @@ static int ZEND_FASTCALL  ZEND_INIT_METHOD_CALL_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_  	if (EXPECTED(EX(object) != NULL) &&  	    EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) { -		if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { -			zend_error_noreturn(E_ERROR, "Object does not support method calls"); -		} +		EX(called_scope) = Z_OBJCE_P(EX(object)); -		/* First, locate the function. */ -		EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); -		if (UNEXPECTED(EX(fbc) == NULL)) { -			zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); -		} +		if (IS_VAR != IS_CONST || +		    (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) { +		    zval *object = EX(object); -		EX(called_scope) = Z_OBJCE_P(EX(object)); +			if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { +				zend_error_noreturn(E_ERROR, "Object does not support method calls"); +			} + +			/* First, locate the function. */ +			EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); +			if (UNEXPECTED(EX(fbc) == NULL)) { +				zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); +			} +			if (IS_VAR == IS_CONST && +			    EXPECTED((EX(fbc)->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0) && +			    EXPECTED(EX(object) == object)) { +				CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc)); +			} +		}  	} else {  		zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);  	} @@ -32101,7 +32757,12 @@ static int ZEND_FASTCALL  ZEND_UNSET_VAR_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER  		zend_class_entry *ce;  		if (IS_VAR == IS_CONST) { -			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				ce = CACHED_PTR(opline->op2.literal->cache_slot); +			} else { +				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				CACHE_PTR(opline->op2.literal->cache_slot, ce); +			}  		} else {  			ce = EX_T(opline->op2.var).class_entry;  		} @@ -32292,7 +32953,12 @@ static int ZEND_FASTCALL  ZEND_ISSET_ISEMPTY_VAR_SPEC_CV_VAR_HANDLER(ZEND_OPCODE  			zend_class_entry *ce;  			if (IS_VAR == IS_CONST) { -				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				if (CACHED_PTR(opline->op2.literal->cache_slot)) { +					ce = CACHED_PTR(opline->op2.literal->cache_slot); +				} else { +					ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +					CACHE_PTR(opline->op2.literal->cache_slot, ce); +				}  			} else {  				ce = EX_T(opline->op2.var).class_entry;  			} @@ -32759,7 +33425,12 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_CV_UNUSED(int type,  		zend_class_entry *ce;  		if (IS_UNUSED == IS_CONST) { -			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				ce = CACHED_PTR(opline->op2.literal->cache_slot); +			} else { +				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				CACHE_PTR(opline->op2.literal->cache_slot, ce); +			}  		} else {  			ce = EX_T(opline->op2.var).class_entry;  		} @@ -33187,7 +33858,12 @@ static int ZEND_FASTCALL  ZEND_UNSET_VAR_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HAND  		zend_class_entry *ce;  		if (IS_UNUSED == IS_CONST) { -			ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +			if (CACHED_PTR(opline->op2.literal->cache_slot)) { +				ce = CACHED_PTR(opline->op2.literal->cache_slot); +			} else { +				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				CACHE_PTR(opline->op2.literal->cache_slot, ce); +			}  		} else {  			ce = EX_T(opline->op2.var).class_entry;  		} @@ -33244,7 +33920,12 @@ static int ZEND_FASTCALL  ZEND_ISSET_ISEMPTY_VAR_SPEC_CV_UNUSED_HANDLER(ZEND_OPC  			zend_class_entry *ce;  			if (IS_UNUSED == IS_CONST) { -				ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +				if (CACHED_PTR(opline->op2.literal->cache_slot)) { +					ce = CACHED_PTR(opline->op2.literal->cache_slot); +				} else { +					ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC); +					CACHE_PTR(opline->op2.literal->cache_slot, ce); +				}  			} else {  				ce = EX_T(opline->op2.var).class_entry;  			} @@ -34695,17 +35376,27 @@ static int ZEND_FASTCALL  ZEND_INIT_METHOD_CALL_SPEC_CV_CV_HANDLER(ZEND_OPCODE_H  	if (EXPECTED(EX(object) != NULL) &&  	    EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) { -		if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { -			zend_error_noreturn(E_ERROR, "Object does not support method calls"); -		} +		EX(called_scope) = Z_OBJCE_P(EX(object)); -		/* First, locate the function. */ -		EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_CV == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); -		if (UNEXPECTED(EX(fbc) == NULL)) { -			zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); -		} +		if (IS_CV != IS_CONST || +		    (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) { +		    zval *object = EX(object); -		EX(called_scope) = Z_OBJCE_P(EX(object)); +			if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { +				zend_error_noreturn(E_ERROR, "Object does not support method calls"); +			} + +			/* First, locate the function. */ +			EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_CV == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); +			if (UNEXPECTED(EX(fbc) == NULL)) { +				zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); +			} +			if (IS_CV == IS_CONST && +			    EXPECTED((EX(fbc)->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0) && +			    EXPECTED(EX(object) == object)) { +				CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc)); +			} +		}  	} else {  		zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);  	} diff --git a/Zend/zend_vm_execute.skl b/Zend/zend_vm_execute.skl index 6f6fed9834..05584d6fb3 100644 --- a/Zend/zend_vm_execute.skl +++ b/Zend/zend_vm_execute.skl @@ -39,6 +39,10 @@ zend_vm_enter:  	LOAD_REGS(); +	if (!op_array->run_time_cache && op_array->last_cache_slot) { +		op_array->run_time_cache = ecalloc(op_array->last_cache_slot, sizeof(void*)); +	} +  	if (op_array->this_var != -1 && EG(This)) {   		Z_ADDREF_P(EG(This)); /* For $this pointer */  		if (!EG(active_symbol_table)) { diff --git a/ext/date/php_date.c b/ext/date/php_date.c index a9df4e476c..c974846a73 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -2011,7 +2011,6 @@ static inline zend_object_value date_object_new_date_ex(zend_class_entry *class_  {  	php_date_obj *intern;  	zend_object_value retval; -	zval *tmp;  	intern = emalloc(sizeof(php_date_obj));  	memset(intern, 0, sizeof(php_date_obj)); @@ -2020,7 +2019,7 @@ static inline zend_object_value date_object_new_date_ex(zend_class_entry *class_  	}  	zend_object_std_init(&intern->std, class_type TSRMLS_CC); -	zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); +	object_properties_init(&intern->std, class_type);  	retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) date_object_free_storage_date, NULL TSRMLS_CC);  	retval.handlers = &date_object_handlers_date; @@ -2084,7 +2083,7 @@ static HashTable *date_object_get_properties(zval *object TSRMLS_DC)  	dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC); -	props = dateobj->std.properties; +	props = zend_std_get_properties(object TSRMLS_CC);  	if (!dateobj->time || GC_G(gc_active)) {  		return props; @@ -2132,7 +2131,6 @@ static inline zend_object_value date_object_new_timezone_ex(zend_class_entry *cl  {  	php_timezone_obj *intern;  	zend_object_value retval; -	zval *tmp;  	intern = emalloc(sizeof(php_timezone_obj));  	memset(intern, 0, sizeof(php_timezone_obj)); @@ -2141,7 +2139,7 @@ static inline zend_object_value date_object_new_timezone_ex(zend_class_entry *cl  	}  	zend_object_std_init(&intern->std, class_type TSRMLS_CC); -	zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); +	object_properties_init(&intern->std, class_type);  	retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) date_object_free_storage_timezone, NULL TSRMLS_CC);  	retval.handlers = &date_object_handlers_timezone; @@ -2184,7 +2182,6 @@ static inline zend_object_value date_object_new_interval_ex(zend_class_entry *cl  {  	php_interval_obj *intern;  	zend_object_value retval; -	zval *tmp;  	intern = emalloc(sizeof(php_interval_obj));  	memset(intern, 0, sizeof(php_interval_obj)); @@ -2193,7 +2190,7 @@ static inline zend_object_value date_object_new_interval_ex(zend_class_entry *cl  	}  	zend_object_std_init(&intern->std, class_type TSRMLS_CC); -	zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); +	object_properties_init(&intern->std, class_type);  	retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) date_object_free_storage_interval, NULL TSRMLS_CC);  	retval.handlers = &date_object_handlers_interval; @@ -2227,7 +2224,7 @@ static HashTable *date_object_get_properties_interval(zval *object TSRMLS_DC)  	intervalobj = (php_interval_obj *) zend_object_store_get_object(object TSRMLS_CC); -	props = intervalobj->std.properties; +	props = zend_std_get_properties(object TSRMLS_CC);  	if (!intervalobj->initialized || GC_G(gc_active)) {  		return props; @@ -2260,7 +2257,6 @@ static inline zend_object_value date_object_new_period_ex(zend_class_entry *clas  {  	php_period_obj *intern;  	zend_object_value retval; -	zval *tmp;  	intern = emalloc(sizeof(php_period_obj));  	memset(intern, 0, sizeof(php_period_obj)); @@ -2269,7 +2265,7 @@ static inline zend_object_value date_object_new_period_ex(zend_class_entry *clas  	}  	zend_object_std_init(&intern->std, class_type TSRMLS_CC); -	zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); +	object_properties_init(&intern->std, class_type);  	retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) date_object_free_storage_period, NULL TSRMLS_CC);  	retval.handlers = &date_object_handlers_period; diff --git a/ext/dom/php_dom.c b/ext/dom/php_dom.c index eb364a73b2..9a6367c23d 100644 --- a/ext/dom/php_dom.c +++ b/ext/dom/php_dom.c @@ -1053,7 +1053,6 @@ void dom_namednode_iter(dom_object *basenode, int ntype, dom_object *intern, xml  static dom_object* dom_objects_set_class(zend_class_entry *class_type, zend_bool hash_copy TSRMLS_DC) /* {{{ */  {  	zend_class_entry *base_class; -	zval *tmp;  	dom_object *intern;  	if (instanceof_function(class_type, dom_xpath_class_entry TSRMLS_CC)) { @@ -1075,7 +1074,7 @@ static dom_object* dom_objects_set_class(zend_class_entry *class_type, zend_bool  	zend_object_std_init(&intern->std, class_type TSRMLS_CC);  	if (hash_copy) { -		zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); +		object_properties_init(&intern->std, class_type);  	}  	return intern; diff --git a/ext/fileinfo/fileinfo.c b/ext/fileinfo/fileinfo.c index 81ee428e94..f9b4c30051 100644 --- a/ext/fileinfo/fileinfo.c +++ b/ext/fileinfo/fileinfo.c @@ -98,13 +98,12 @@ PHP_FILEINFO_API zend_object_value finfo_objects_new(zend_class_entry *class_typ  {  	zend_object_value retval;  	struct finfo_object *intern; -	zval *tmp;  	intern = emalloc(sizeof(struct finfo_object));  	memset(intern, 0, sizeof(struct finfo_object));  	zend_object_std_init(&intern->zo, class_type TSRMLS_CC); -	zend_hash_copy(intern->zo.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref,(void *) &tmp, sizeof(zval *)); +	object_properties_init(&intern->zo, class_type);  	intern->ptr = NULL; diff --git a/ext/mysqli/mysqli.c b/ext/mysqli/mysqli.c index a82a3f1716..66b1f6f7d9 100644 --- a/ext/mysqli/mysqli.c +++ b/ext/mysqli/mysqli.c @@ -484,7 +484,6 @@ PHP_MYSQLI_EXPORT(zend_object_value) mysqli_objects_new(zend_class_entry *class_  {  	zend_object_value retval;  	mysqli_object *intern; -	zval *tmp;  	zend_class_entry *mysqli_base_class;  	zend_objects_free_object_storage_t free_storage; @@ -502,8 +501,7 @@ PHP_MYSQLI_EXPORT(zend_object_value) mysqli_objects_new(zend_class_entry *class_  					(void **) &intern->prop_handler);  	zend_object_std_init(&intern->zo, class_type TSRMLS_CC); -	zend_hash_copy(intern->zo.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, -					(void *) &tmp, sizeof(zval *)); +	object_properties_init(&intern->zo, class_type);  	/* link object */  	if (instanceof_function(class_type, mysqli_link_class_entry TSRMLS_CC)) { diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index 404619e9c1..1573290420 100755 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -1552,12 +1552,12 @@ zend_object_value pdo_dbh_new(zend_class_entry *ce TSRMLS_DC)  {  	zend_object_value retval;  	pdo_dbh_t *dbh; -	zval *tmp;  	dbh = emalloc(sizeof(*dbh));  	memset(dbh, 0, sizeof(*dbh));  	zend_object_std_init(&dbh->std, ce TSRMLS_CC); -	zend_hash_copy(dbh->std.properties, &ce->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); +	object_properties_init(&dbh->std, ce); +	rebuild_object_properties(&dbh->std);  	dbh->refcount = 1;  	dbh->def_stmt_ce = pdo_dbstmt_ce; diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index 40d10c54b3..5e761053f1 100755 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -2313,14 +2313,13 @@ static int dbstmt_compare(zval *object1, zval *object2 TSRMLS_DC)  static zend_object_value dbstmt_clone_obj(zval *zobject TSRMLS_DC)  {  	zend_object_value retval; -	zval *tmp;  	pdo_stmt_t *stmt;  	pdo_stmt_t *old_stmt;  	zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);  	stmt = ecalloc(1, sizeof(*stmt));  	zend_object_std_init(&stmt->std, Z_OBJCE_P(zobject) TSRMLS_CC); -	zend_hash_copy(stmt->std.properties, &stmt->std.ce->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); +	object_properties_init(&stmt->std, Z_OBJCE_P(zobject));  	stmt->refcount = 1;  	old_stmt = (pdo_stmt_t *)zend_object_store_get_object(zobject TSRMLS_CC); @@ -2436,13 +2435,12 @@ void pdo_dbstmt_free_storage(pdo_stmt_t *stmt TSRMLS_DC)  zend_object_value pdo_dbstmt_new(zend_class_entry *ce TSRMLS_DC)  {  	zend_object_value retval; -	zval *tmp;  	pdo_stmt_t *stmt;  	stmt = emalloc(sizeof(*stmt));  	memset(stmt, 0, sizeof(*stmt));  	zend_object_std_init(&stmt->std, ce TSRMLS_CC); -	zend_hash_copy(stmt->std.properties, &ce->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); +	object_properties_init(&stmt->std, ce);  	stmt->refcount = 1;  	retval.handle = zend_objects_store_put(stmt, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t)pdo_dbstmt_free_storage, (zend_objects_store_clone_t)dbstmt_clone_obj TSRMLS_CC); @@ -2680,6 +2678,9 @@ static HashTable *row_get_properties(zval *object TSRMLS_DC)  		return NULL;  	} +	if (!stmt->std.properties) { +		rebuild_object_properties(&stmt->std); +	}  	for (i = 0; i < stmt->column_count; i++) {  		zval *val;  		MAKE_STD_ZVAL(val); diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 315580615d..c1919afb5f 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -41,6 +41,15 @@  #include "zend_closures.h"  #include "zend_extensions.h" +#define reflection_update_property(object, name, value) do { \ +		zval *member; \ +		MAKE_STD_ZVAL(member); \ +		ZVAL_STRINGL(member, name, sizeof(name)-1, 1); \ +		zend_std_write_property(object, member, value, NULL TSRMLS_CC); \ +		Z_DELREF_P(value); \ +		zval_ptr_dtor(&member); \ +	} while (0) +  /* Class entry pointers */  PHPAPI zend_class_entry *reflector_ptr;  PHPAPI zend_class_entry *reflection_exception_ptr; @@ -296,7 +305,6 @@ static void reflection_free_objects_storage(void *object TSRMLS_DC)  static zend_object_value reflection_objects_new(zend_class_entry *class_type TSRMLS_DC)  { -	zval tmp;  	zend_object_value retval;  	reflection_object *intern; @@ -304,7 +312,7 @@ static zend_object_value reflection_objects_new(zend_class_entry *class_type TSR  	intern->zo.ce = class_type;  	zend_object_std_init(&intern->zo, class_type TSRMLS_CC); -	zend_hash_copy(intern->zo.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); +	object_properties_init(&intern->zo, class_type);  	retval.handle = zend_objects_store_put(intern, NULL, reflection_free_objects_storage, NULL TSRMLS_CC);  	retval.handlers = &reflection_object_handlers;  	return retval; @@ -1157,7 +1165,7 @@ PHPAPI void zend_reflection_class_factory(zend_class_entry *ce, zval *object TSR  	intern->ptr = ce;  	intern->ref_type = REF_TYPE_OTHER;  	intern->ce = ce; -	zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); +	reflection_update_property(object, "name", name);  }  /* }}} */ @@ -1186,7 +1194,7 @@ static void reflection_extension_factory(zval *object, const char *name_str TSRM  	intern->ptr = module;  	intern->ref_type = REF_TYPE_OTHER;  	intern->ce = NULL; -	zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); +	reflection_update_property(object, "name", name);  }  /* }}} */ @@ -1217,7 +1225,7 @@ static void reflection_parameter_factory(zend_function *fptr, zval *closure_obje  	intern->ref_type = REF_TYPE_PARAMETER;  	intern->ce = fptr->common.scope;  	intern->obj = closure_object; -	zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); +	reflection_update_property(object, "name", name);  }  /* }}} */ @@ -1239,7 +1247,7 @@ static void reflection_function_factory(zend_function *function, zval *closure_o  	intern->ref_type = REF_TYPE_FUNCTION;  	intern->ce = NULL;  	intern->obj = closure_object; -	zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); +	reflection_update_property(object, "name", name);  }  /* }}} */ @@ -1263,8 +1271,8 @@ static void reflection_method_factory(zend_class_entry *ce, zend_function *metho  	intern->ref_type = REF_TYPE_FUNCTION;  	intern->ce = ce;  	intern->obj = closure_object; -	zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); -	zend_hash_update(Z_OBJPROP_P(object), "class", sizeof("class"), (void **) &classname, sizeof(zval *), NULL); +	reflection_update_property(object, "name", name); +	reflection_update_property(object, "class", classname);  }  /* }}} */ @@ -1310,8 +1318,8 @@ static void reflection_property_factory(zend_class_entry *ce, zend_property_info  	intern->ref_type = REF_TYPE_PROPERTY;  	intern->ce = ce;  	intern->ignore_visibility = 0; -	zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); -	zend_hash_update(Z_OBJPROP_P(object), "class", sizeof("class"), (void **) &classname, sizeof(zval *), NULL); +	reflection_update_property(object, "name", name); +	reflection_update_property(object, "class", classname);  }  /* }}} */ @@ -1556,7 +1564,7 @@ ZEND_METHOD(reflection_function, __construct)  	MAKE_STD_ZVAL(name);  	ZVAL_STRING(name, fptr->common.function_name, 1); -	zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); +	reflection_update_property(object, "name", name TSRMLS_CC);  	intern->ptr = fptr;  	intern->ref_type = REF_TYPE_FUNCTION;  	intern->obj = closure; @@ -2185,7 +2193,7 @@ ZEND_METHOD(reflection_parameter, __construct)  	} else {  		ZVAL_NULL(name);  	} -	zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); +	reflection_update_property(object, "name", name);  	ref = (parameter_reference*) emalloc(sizeof(parameter_reference));  	ref->arg_info = &arg_info[position]; @@ -2663,11 +2671,11 @@ ZEND_METHOD(reflection_method, __construct)  	MAKE_STD_ZVAL(classname);  	ZVAL_STRINGL(classname, mptr->common.scope->name, mptr->common.scope->name_length, 1); -	zend_hash_update(Z_OBJPROP_P(object), "class", sizeof("class"), (void **) &classname, sizeof(zval *), NULL); +	reflection_update_property(object, "class", classname);  	MAKE_STD_ZVAL(name);  	ZVAL_STRING(name, mptr->common.function_name, 1); -	zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); +	reflection_update_property(object, "name", name);  	intern->ptr = mptr;  	intern->ref_type = REF_TYPE_FUNCTION;  	intern->ce = ce; @@ -3202,7 +3210,7 @@ static void reflection_class_object_ctor(INTERNAL_FUNCTION_PARAMETERS, int is_ob  	if (Z_TYPE_P(argument) == IS_OBJECT) {  		MAKE_STD_ZVAL(classname);  		ZVAL_STRINGL(classname, Z_OBJCE_P(argument)->name, Z_OBJCE_P(argument)->name_length, 1); -		zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &classname, sizeof(zval *), NULL); +		reflection_update_property(object, "name", classname);  		intern->ptr = Z_OBJCE_P(argument);  		if (is_object) {  			intern->obj = argument; @@ -3219,7 +3227,7 @@ static void reflection_class_object_ctor(INTERNAL_FUNCTION_PARAMETERS, int is_ob  		MAKE_STD_ZVAL(classname);  		ZVAL_STRINGL(classname, (*ce)->name, (*ce)->name_length, 1); -		zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &classname, sizeof(zval *), NULL); +		reflection_update_property(object, "name", classname);  		intern->ptr = *ce;  	} @@ -3235,14 +3243,63 @@ ZEND_METHOD(reflection_class, __construct)  }  /* }}} */ +/* {{{ add_class_vars */ +static void add_class_vars(zend_class_entry *ce, int statics, zval *return_value TSRMLS_DC) +{ +	HashPosition pos; +	zend_property_info *prop_info; +	zval *prop, *prop_copy; +	char *key; +	uint key_len; +	ulong num_index; + +	zend_hash_internal_pointer_reset_ex(&ce->properties_info, &pos); +	while (zend_hash_get_current_data_ex(&ce->properties_info, (void **) &prop_info, &pos) == SUCCESS) { +		zend_hash_get_current_key_ex(&ce->properties_info, &key, &key_len, &num_index, 0, &pos); +		zend_hash_move_forward_ex(&ce->properties_info, &pos); +		if (((prop_info->flags & ZEND_ACC_SHADOW) && +		     prop_info->ce != ce) || +		    ((prop_info->flags & ZEND_ACC_PROTECTED) && +		     !zend_check_protected(prop_info->ce, ce)) || +		    ((prop_info->flags & ZEND_ACC_PRIVATE) && +		     prop_info->ce != ce)) { +			continue; +		} +		prop = NULL; +		if (prop_info->offset >= 0) { +			if (statics && (prop_info->flags & ZEND_ACC_STATIC) != 0) { +				prop = ce->default_static_members_table[prop_info->offset]; +			} else if (!statics && (prop_info->flags & ZEND_ACC_STATIC) == 0) { +				prop = ce->default_properties_table[prop_info->offset]; +			} +		} +		if (!prop) { +			continue; +		} + +		/* copy: enforce read only access */ +		ALLOC_ZVAL(prop_copy); +		*prop_copy = *prop; +		zval_copy_ctor(prop_copy); +		INIT_PZVAL(prop_copy); + +		/* this is necessary to make it able to work with default array  +		* properties, returned to user */ +		if (Z_TYPE_P(prop_copy) == IS_CONSTANT_ARRAY || (Z_TYPE_P(prop_copy) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT) { +			zval_update_constant(&prop_copy, 1 TSRMLS_CC); +		} + +		add_assoc_zval(return_value, key, prop_copy); +	} +} +/* }}} */ +  /* {{{ proto public array ReflectionClass::getStaticProperties()     Returns an associative array containing all static property values of the class */  ZEND_METHOD(reflection_class, getStaticProperties)  {  	reflection_object *intern;  	zend_class_entry *ce; -	HashPosition pos; -	zval **value;  	if (zend_parse_parameters_none() == FAILURE) {  		return; @@ -3253,31 +3310,7 @@ ZEND_METHOD(reflection_class, getStaticProperties)  	zend_update_class_constants(ce TSRMLS_CC);  	array_init(return_value); - -	zend_hash_internal_pointer_reset_ex(CE_STATIC_MEMBERS(ce), &pos); - -	while (zend_hash_get_current_data_ex(CE_STATIC_MEMBERS(ce), (void **) &value, &pos) == SUCCESS) { -		uint key_len; -		char *key; -		ulong num_index; - -		if (zend_hash_get_current_key_ex(CE_STATIC_MEMBERS(ce), &key, &key_len, &num_index, 0, &pos) != FAILURE && key) { -			char *prop_name, *class_name; -			zval *prop_copy; - -			zend_unmangle_property_name(key, key_len-1, &class_name, &prop_name); - -			/* filter privates from base classes */ -			if (!(class_name && class_name[0] != '*' && strcmp(class_name, ce->name))) { -				/* copy: enforce read only access */ -				ALLOC_ZVAL(prop_copy); -				MAKE_COPY_ZVAL(value, prop_copy); - -				add_assoc_zval(return_value, prop_name, prop_copy); -			} -		} -		zend_hash_move_forward_ex(CE_STATIC_MEMBERS(ce), &pos); -	} +	add_class_vars(ce, 1, return_value TSRMLS_CC);  }  /* }}} */ @@ -3355,51 +3388,15 @@ ZEND_METHOD(reflection_class, getDefaultProperties)  {  	reflection_object *intern;  	zend_class_entry *ce; -	int count, i; -	HashTable *ht_list[3];  	if (zend_parse_parameters_none() == FAILURE) {  		return;  	}  	GET_REFLECTION_OBJECT_PTR(ce);  	array_init(return_value); -  	zend_update_class_constants(ce TSRMLS_CC); - -	ht_list[0] = CE_STATIC_MEMBERS(ce); -	ht_list[1] = &ce->default_properties; -	ht_list[2] = NULL; - -	for (i = 0; ht_list[i] != NULL; i++) { - -		count = zend_hash_num_elements(ht_list[i]); -		if (count > 0) { -			HashPosition pos; -			zval **prop; - -			zend_hash_internal_pointer_reset_ex(ht_list[i], &pos); -			while (zend_hash_get_current_data_ex(ht_list[i], (void **) &prop, &pos) == SUCCESS) { -				char *key, *class_name, *prop_name; -				uint key_len; -				ulong num_index; -				zval *prop_copy; - -				zend_hash_get_current_key_ex(ht_list[i], &key, &key_len, &num_index, 0, &pos); -				zend_hash_move_forward_ex(ht_list[i], &pos); -				zend_unmangle_property_name(key, key_len-1, &class_name, &prop_name); -				if (class_name && class_name[0] != '*' && strcmp(class_name, ce->name)) { -					/* filter privates from base classes */ -					continue; -				} - -				/* copy: enforce read only access */ -				ALLOC_ZVAL(prop_copy); -				MAKE_COPY_ZVAL(prop, prop_copy); - -				add_assoc_zval(return_value, prop_name, prop_copy); -			} -		} -	} +	add_class_vars(ce, 1, return_value TSRMLS_CC); +	add_class_vars(ce, 0, return_value TSRMLS_CC);  }  /* }}} */ @@ -4564,8 +4561,8 @@ ZEND_METHOD(reflection_property, __construct)  		ZVAL_STRINGL(classname, ce->name, ce->name_length, 1);	  		ZVAL_STRINGL(propname, name_str, name_len, 1);  	} -	zend_hash_update(Z_OBJPROP_P(object), "class", sizeof("class"), (void **) &classname, sizeof(zval *), NULL); -	zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &propname, sizeof(zval *), NULL); +	reflection_update_property(object, "class", classname); +	reflection_update_property(object, "name", propname);  	reference = (property_reference*) emalloc(sizeof(property_reference));  	if (dynam_prop) { @@ -4690,7 +4687,7 @@ ZEND_METHOD(reflection_property, getValue)  	reflection_object *intern;  	property_reference *ref;  	zval *object, name; -	zval **member = NULL, *member_p = NULL; +	zval *member_p = NULL;  	METHOD_NOTSTATIC(reflection_property_ptr);  	GET_REFLECTION_OBJECT_PTR(ref); @@ -4705,11 +4702,13 @@ ZEND_METHOD(reflection_property, getValue)  	if ((ref->prop.flags & ZEND_ACC_STATIC)) {  		zend_update_class_constants(intern->ce TSRMLS_CC); -		if (zend_hash_quick_find(CE_STATIC_MEMBERS(intern->ce), ref->prop.name, ref->prop.name_length + 1, ref->prop.h, (void **) &member) == FAILURE) { +		if (!CE_STATIC_MEMBERS(intern->ce)[ref->prop.offset]) {  			php_error_docref(NULL TSRMLS_CC, E_ERROR, "Internal error: Could not find the property %s::%s", intern->ce->name, ref->prop.name);  			/* Bails out */  		} -		MAKE_COPY_ZVAL(member, return_value); +		*return_value= *CE_STATIC_MEMBERS(intern->ce)[ref->prop.offset]; +		zval_copy_ctor(return_value); + 		INIT_PZVAL(return_value);  	} else {  		char *class_name, *prop_name; @@ -4738,7 +4737,6 @@ ZEND_METHOD(reflection_property, setValue)  	zval *value;  	int setter_done = 0;  	zval *tmp; -	HashTable *prop_table;  	METHOD_NOTSTATIC(reflection_property_ptr);  	GET_REFLECTION_OBJECT_PTR(ref); @@ -4758,33 +4756,34 @@ ZEND_METHOD(reflection_property, setValue)  			}  		}  		zend_update_class_constants(intern->ce TSRMLS_CC); -		prop_table = CE_STATIC_MEMBERS(intern->ce); -		if (zend_hash_quick_find(prop_table, ref->prop.name, ref->prop.name_length + 1, ref->prop.h, (void **) &variable_ptr) == FAILURE) { +		if (!CE_STATIC_MEMBERS(intern->ce)[ref->prop.offset]) {  			php_error_docref(NULL TSRMLS_CC, E_ERROR, "Internal error: Could not find the property %s::%s", intern->ce->name, ref->prop.name);  			/* Bails out */  		} -		if (*variable_ptr == value) { -			setter_done = 1; -		} else { +		variable_ptr = &CE_STATIC_MEMBERS(intern->ce)[ref->prop.offset]; +		if (*variable_ptr != value) {  			if (PZVAL_IS_REF(*variable_ptr)) { -				zval_dtor(*variable_ptr); -				(*variable_ptr)->type = value->type; +				zval garbage = **variable_ptr; /* old value should be destroyed */ + +				/* To check: can't *variable_ptr be some system variable like error_zval here? */ +				Z_TYPE_PP(variable_ptr) = Z_TYPE_P(value);  				(*variable_ptr)->value = value->value;  				if (Z_REFCOUNT_P(value) > 0) {  					zval_copy_ctor(*variable_ptr);  				} -				setter_done = 1; -			} -		} -		if (!setter_done) { -			zval **foo; +				zval_dtor(&garbage); +			} else { +				zval *garbage = *variable_ptr; -			Z_ADDREF_P(value); -			if (PZVAL_IS_REF(value)) { -				SEPARATE_ZVAL(&value); +				/* if we assign referenced variable, we should separate it */ +				Z_ADDREF_P(value); +				if (PZVAL_IS_REF(value)) { +					SEPARATE_ZVAL(&value); +				} +				*variable_ptr = value; +				zval_ptr_dtor(&garbage);  			} -			zend_hash_quick_update(prop_table, ref->prop.name, ref->prop.name_length+1, ref->prop.h, &value, sizeof(zval *), (void **) &foo);  		}  	} else {  		char *class_name, *prop_name; @@ -4917,7 +4916,7 @@ ZEND_METHOD(reflection_extension, __construct)  	free_alloca(lcname, use_heap);  	MAKE_STD_ZVAL(name);  	ZVAL_STRING(name, module->name, 1); -	zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); +	reflection_update_property( object, "name", name);  	intern->ptr = module;  	intern->ref_type = REF_TYPE_OTHER;  	intern->ce = NULL; @@ -5269,7 +5268,7 @@ ZEND_METHOD(reflection_zend_extension, __construct)  	}  	MAKE_STD_ZVAL(name);  	ZVAL_STRING(name, extension->name, 1); -	zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); +	reflection_update_property(object, "name", name);  	intern->ptr = extension;  	intern->ref_type = REF_TYPE_OTHER;  	intern->ce = NULL; @@ -5783,7 +5782,7 @@ static zend_object_handlers *zend_std_obj_handlers;  static void _reflection_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC)  {  	if ((Z_TYPE_P(member) == IS_STRING) -		&& zend_hash_exists(&Z_OBJCE_P(object)->default_properties, Z_STRVAL_P(member), Z_STRLEN_P(member)+1) +		&& zend_hash_exists(&Z_OBJCE_P(object)->properties_info, Z_STRVAL_P(member), Z_STRLEN_P(member)+1)  		&& ((Z_STRLEN_P(member) == sizeof("name") - 1  && !memcmp(Z_STRVAL_P(member), "name",  sizeof("name")))  			|| (Z_STRLEN_P(member) == sizeof("class") - 1 && !memcmp(Z_STRVAL_P(member), "class", sizeof("class")))))  	{ diff --git a/ext/reflection/tests/ReflectionClass_getStaticPropertyValue_001.phpt b/ext/reflection/tests/ReflectionClass_getStaticPropertyValue_001.phpt index 733c4c7e4d..ffd81ffb87 100644 --- a/ext/reflection/tests/ReflectionClass_getStaticPropertyValue_001.phpt +++ b/ext/reflection/tests/ReflectionClass_getStaticPropertyValue_001.phpt @@ -3,6 +3,8 @@ ReflectionClass::getStaticPropertyValue()  --CREDITS--  Robin Fernandes <robinf@php.net>  Steve Seear <stevseea@php.net> +--SKIPIF-- +<?php if (version_compare(zend_version(), '2.4.0', '>=')) die('skip ZendEngine 2.3 or below needed'); ?>  --FILE--  <?php  class A { diff --git a/ext/reflection/tests/ReflectionClass_getStaticPropertyValue_001_2_4.phpt b/ext/reflection/tests/ReflectionClass_getStaticPropertyValue_001_2_4.phpt new file mode 100644 index 0000000000..c299412e13 --- /dev/null +++ b/ext/reflection/tests/ReflectionClass_getStaticPropertyValue_001_2_4.phpt @@ -0,0 +1,61 @@ +--TEST-- +ReflectionClass::getStaticPropertyValue()  +--CREDITS-- +Robin Fernandes <robinf@php.net> +Steve Seear <stevseea@php.net> +--SKIPIF-- +<?php if (version_compare(zend_version(), '2.4.0', '<')) die('skip ZendEngine 2.4 needed'); ?> +--FILE-- +<?php +class A { +	static private $privateOverridden = "original private"; +	static protected $protectedOverridden = "original protected"; +	static public $publicOverridden = "original public"; +} + +class B extends A { +	static private $privateOverridden = "changed private"; +	static protected $protectedOverridden = "changed protected"; +	static public $publicOverridden = "changed public"; +} + +echo "Retrieving static values from A:\n"; +$rcA = new ReflectionClass('A'); +var_dump($rcA->getStaticPropertyValue("privateOverridden", "default value")); +var_dump($rcA->getStaticPropertyValue("\0A\0privateOverridden")); +var_dump($rcA->getStaticPropertyValue("protectedOverridden", "default value")); +var_dump($rcA->getStaticPropertyValue("\0*\0protectedOverridden")); +var_dump($rcA->getStaticPropertyValue("publicOverridden")); + +echo "\nRetrieving static values from B:\n"; +$rcB = new ReflectionClass('B'); +var_dump($rcB->getStaticPropertyValue("\0A\0privateOverridden")); +var_dump($rcB->getStaticPropertyValue("\0B\0privateOverridden")); +var_dump($rcB->getStaticPropertyValue("\0*\0protectedOverridden")); +var_dump($rcB->getStaticPropertyValue("publicOverridden")); + +echo "\nRetrieving non-existent values from A with no default value:\n"; +try { +	var_dump($rcA->getStaticPropertyValue("protectedOverridden")); +	echo "you should not see this"; +} catch (Exception $e) { +	echo $e->getMessage() . "\n"; +} + +try { +	var_dump($rcA->getStaticPropertyValue("privateOverridden")); +	echo "you should not see this";	 +} catch (Exception $e) { +	echo $e->getMessage() . "\n"; +} + +?> +--EXPECTF-- +Retrieving static values from A: +string(13) "default value" + +Fatal error: Uncaught exception 'ReflectionException' with message 'Class A does not have a property named ' in %sReflectionClass_getStaticPropertyValue_001_2_4.php:%d +Stack trace: +#0 %sReflectionClass_getStaticPropertyValue_001_2_4.php(%d): ReflectionClass->getStaticPropertyValue('?A?privateOverr...') +#1 {main} +  thrown in %sReflectionClass_getStaticPropertyValue_001_2_4.php on line %d diff --git a/ext/reflection/tests/ReflectionClass_setStaticPropertyValue_001.phpt b/ext/reflection/tests/ReflectionClass_setStaticPropertyValue_001.phpt index 082ef676cd..9e8f01e679 100644 --- a/ext/reflection/tests/ReflectionClass_setStaticPropertyValue_001.phpt +++ b/ext/reflection/tests/ReflectionClass_setStaticPropertyValue_001.phpt @@ -3,6 +3,8 @@ ReflectionClass::setStaticPropertyValue()  --CREDITS--  Robin Fernandes <robinf@php.net>  Steve Seear <stevseea@php.net> +--SKIPIF-- +<?php if (version_compare(zend_version(), '2.4.0', '>=')) die('skip ZendEngine 2.3 or below needed'); ?>  --FILE--  <?php  class A { diff --git a/ext/reflection/tests/ReflectionClass_setStaticPropertyValue_001_2_4.phpt b/ext/reflection/tests/ReflectionClass_setStaticPropertyValue_001_2_4.phpt new file mode 100644 index 0000000000..1092f6553d --- /dev/null +++ b/ext/reflection/tests/ReflectionClass_setStaticPropertyValue_001_2_4.phpt @@ -0,0 +1,61 @@ +--TEST-- +ReflectionClass::setStaticPropertyValue()  +--CREDITS-- +Robin Fernandes <robinf@php.net> +Steve Seear <stevseea@php.net> +--SKIPIF-- +<?php if (version_compare(zend_version(), '2.4.0', '<')) die('skip ZendEngine 2.4 needed'); ?> +--FILE-- +<?php +class A { +	static private $privateOverridden = "original private"; +	static protected $protectedOverridden = "original protected"; +	static public $publicOverridden = "original public"; +} + +class B extends A { +	static private $privateOverridden = "changed private"; +	static protected $protectedOverridden = "changed protected"; +	static public $publicOverridden = "changed public"; +} + +echo "Set static values in A:\n"; +$rcA = new ReflectionClass('A'); +$rcA->setStaticPropertyValue("\0A\0privateOverridden", "new value 1"); +$rcA->setStaticPropertyValue("\0*\0protectedOverridden", "new value 2"); +$rcA->setStaticPropertyValue("publicOverridden", "new value 3"); +print_r($rcA->getStaticProperties()); + +echo "\nSet static values in B:\n"; +$rcB = new ReflectionClass('B'); +$rcB->setStaticPropertyValue("\0A\0privateOverridden", "new value 4"); +$rcB->setStaticPropertyValue("\0B\0privateOverridden", "new value 5"); +$rcB->setStaticPropertyValue("\0*\0protectedOverridden", "new value 6"); +$rcB->setStaticPropertyValue("publicOverridden", "new value 7"); +print_r($rcA->getStaticProperties()); +print_r($rcB->getStaticProperties()); + +echo "\nSet non-existent values from A with no default value:\n"; +try { +	var_dump($rcA->setStaticPropertyValue("protectedOverridden", "new value 8")); +	echo "you should not see this"; +} catch (Exception $e) { +	echo $e->getMessage() . "\n"; +} + +try { +	var_dump($rcA->setStaticPropertyValue("privateOverridden", "new value 9")); +	echo "you should not see this";	 +} catch (Exception $e) { +	echo $e->getMessage() . "\n"; +} + +?> +--EXPECTF-- +Set static values in A: + +Fatal error: Uncaught exception 'ReflectionException' with message 'Class A does not have a property named ' in %sReflectionClass_setStaticPropertyValue_001_2_4.php:%d +Stack trace: +#0 %sReflectionClass_setStaticPropertyValue_001_2_4.php(%d): ReflectionClass->setStaticPropertyValue('?A?privateOverr...', 'new value 1') +#1 {main} +  thrown in %sReflectionClass_setStaticPropertyValue_001_2_4.php on line %d diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c index b061125f97..f98e8fa16e 100755 --- a/ext/spl/spl_array.c +++ b/ext/spl/spl_array.c @@ -81,11 +81,17 @@ typedef struct _spl_array_object {  static inline HashTable *spl_array_get_hash_table(spl_array_object* intern, int check_std_props TSRMLS_DC) { /* {{{ */  	if ((intern->ar_flags & SPL_ARRAY_IS_SELF) != 0) { +		if (!intern->std.properties) { +			rebuild_object_properties(&intern->std); +		}  		return intern->std.properties;  	} else if ((intern->ar_flags & SPL_ARRAY_USE_OTHER) && (check_std_props == 0 || (intern->ar_flags & SPL_ARRAY_STD_PROP_LIST) == 0) && Z_TYPE_P(intern->array) == IS_OBJECT) {  		spl_array_object *other  = (spl_array_object*)zend_object_store_get_object(intern->array TSRMLS_CC);  		return spl_array_get_hash_table(other, check_std_props TSRMLS_CC);  	} else if ((intern->ar_flags & ((check_std_props ? SPL_ARRAY_STD_PROP_LIST : 0) | SPL_ARRAY_IS_SELF)) != 0) { +		if (!intern->std.properties) { +			rebuild_object_properties(&intern->std); +		}  		return intern->std.properties;  	} else {  		return HASH_OF(intern->array); @@ -173,7 +179,7 @@ static zend_object_value spl_array_object_new_ex(zend_class_entry *class_type, s  	ALLOC_INIT_ZVAL(intern->retval);  	zend_object_std_init(&intern->std, class_type TSRMLS_CC); -	zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); +	object_properties_init(&intern->std, class_type);  	intern->ar_flags = 0;  	intern->serialize_data   = NULL; @@ -728,6 +734,10 @@ static HashTable* spl_array_get_debug_info(zval *obj, int *is_temp TSRMLS_DC) /*  	*is_temp = 0; +	if (!intern->std.properties) { +		rebuild_object_properties(&intern->std); +	} +  	if (HASH_OF(intern->array) == intern->std.properties) {  		return intern->std.properties;  	} else { @@ -1584,6 +1594,9 @@ smart_str spl_array_serialize_helper(spl_array_object *intern, php_serialize_dat  	/* members */  	smart_str_appendl(&buf, "m:", 2);  	INIT_PZVAL(&members); +	if (!intern->std.properties) { +		rebuild_object_properties(&intern->std); +	}  	Z_ARRVAL(members) = intern->std.properties;  	Z_TYPE(members) = IS_ARRAY;  	pmembers = &members; @@ -1719,6 +1732,9 @@ void spl_array_unserialize_helper(spl_array_object *intern, const unsigned char  	}  	/* copy members */ +	if (!intern->std.properties) { +		rebuild_object_properties(&intern->std); +	}  	zend_hash_copy(intern->std.properties, Z_ARRVAL_P(pmembers), (copy_ctor_func_t) zval_add_ref, (void *) NULL, sizeof(zval *));  	zval_ptr_dtor(&pmembers); diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index 23044122a9..cc049a1e27 100755 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -136,7 +136,6 @@ static zend_object_value spl_filesystem_object_new_ex(zend_class_entry *class_ty  {  	zend_object_value retval;  	spl_filesystem_object *intern; -	zval *tmp;  	intern = emalloc(sizeof(spl_filesystem_object));  	memset(intern, 0, sizeof(spl_filesystem_object)); @@ -146,7 +145,7 @@ static zend_object_value spl_filesystem_object_new_ex(zend_class_entry *class_ty  	if (obj) *obj = intern;  	zend_object_std_init(&intern->std, class_type TSRMLS_CC); -	zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); +	object_properties_init(&intern->std, class_type);  	retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t) zend_objects_destroy_object, (zend_objects_free_object_storage_t) spl_filesystem_object_free_storage, NULL TSRMLS_CC);  	retval.handlers = &spl_filesystem_object_handlers; @@ -549,6 +548,10 @@ static HashTable* spl_filesystem_object_get_debug_info(zval *obj, int *is_temp T  	*is_temp = 1; +	if (!intern->std.properties) { +		rebuild_object_properties(&intern->std); +	} +  	ALLOC_HASHTABLE(rv);  	ZEND_INIT_SYMTABLE_EX(rv, zend_hash_num_elements(intern->std.properties) + 3, 0); diff --git a/ext/spl/spl_dllist.c b/ext/spl/spl_dllist.c index af7389cf65..d3b0b38b91 100644 --- a/ext/spl/spl_dllist.c +++ b/ext/spl/spl_dllist.c @@ -367,7 +367,6 @@ static zend_object_value spl_dllist_object_new_ex(zend_class_entry *class_type,  {  	zend_object_value  retval;  	spl_dllist_object *intern; -	zval              *tmp;  	zend_class_entry  *parent = class_type;  	int                inherited = 0; @@ -376,7 +375,7 @@ static zend_object_value spl_dllist_object_new_ex(zend_class_entry *class_type,  	ALLOC_INIT_ZVAL(intern->retval);  	zend_object_std_init(&intern->std, class_type TSRMLS_CC); -	zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); +	object_properties_init(&intern->std, class_type);  	intern->flags = 0;  	intern->traverse_position = 0; @@ -523,6 +522,9 @@ static HashTable* spl_dllist_object_get_debug_info(zval *obj, int *is_temp TSRML  		INIT_PZVAL(&zrv);  		Z_ARRVAL(zrv) = intern->debug_info; +		if (!intern->std.properties) { +			rebuild_object_properties(&intern->std); +		}  		zend_hash_copy(intern->debug_info, intern->std.properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));  		pnstr = spl_gen_private_prop_name(spl_ce_SplDoublyLinkedList, "flags", sizeof("flags")-1, &pnlen TSRMLS_CC); diff --git a/ext/spl/spl_fixedarray.c b/ext/spl/spl_fixedarray.c index 783c854e5e..73f5fcbd01 100644 --- a/ext/spl/spl_fixedarray.c +++ b/ext/spl/spl_fixedarray.c @@ -150,21 +150,22 @@ static void spl_fixedarray_copy(spl_fixedarray *to, spl_fixedarray *from TSRMLS_  static HashTable* spl_fixedarray_object_get_properties(zval *obj TSRMLS_DC) /* {{{{ */  {  	spl_fixedarray_object *intern  = (spl_fixedarray_object*)zend_object_store_get_object(obj TSRMLS_CC); +	HashTable *ht = zend_std_get_properties(obj TSRMLS_CC);  	int  i = 0;  	if (intern->array) {  		for (i = 0; i < intern->array->size; i++) {  			if (intern->array->elements[i]) { -				zend_hash_index_update(intern->std.properties, i, (void *)&intern->array->elements[i], sizeof(zval *), NULL); +				zend_hash_index_update(ht, i, (void *)&intern->array->elements[i], sizeof(zval *), NULL);  				Z_ADDREF_P(intern->array->elements[i]);  			} else { -				zend_hash_index_update(intern->std.properties, i, (void *)&EG(uninitialized_zval_ptr), sizeof(zval *), NULL); +				zend_hash_index_update(ht, i, (void *)&EG(uninitialized_zval_ptr), sizeof(zval *), NULL);  				Z_ADDREF_P(EG(uninitialized_zval_ptr));  			}  		}  	} -	return intern->std.properties; +	return ht;  }  /* }}}} */ @@ -199,7 +200,6 @@ static zend_object_value spl_fixedarray_object_new_ex(zend_class_entry *class_ty  {  	zend_object_value     retval;  	spl_fixedarray_object *intern; -	zval                 *tmp;  	zend_class_entry     *parent = class_type;  	int                   inherited = 0; @@ -208,7 +208,7 @@ static zend_object_value spl_fixedarray_object_new_ex(zend_class_entry *class_ty  	ALLOC_INIT_ZVAL(intern->retval);  	zend_object_std_init(&intern->std, class_type TSRMLS_CC); -	zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); +	object_properties_init(&intern->std, class_type);  	intern->current = 0;  	intern->flags = 0; diff --git a/ext/spl/spl_heap.c b/ext/spl/spl_heap.c index 6f11ef92cf..45ec68096a 100644 --- a/ext/spl/spl_heap.c +++ b/ext/spl/spl_heap.c @@ -385,7 +385,6 @@ static zend_object_value spl_heap_object_new_ex(zend_class_entry *class_type, sp  {  	zend_object_value  retval;  	spl_heap_object   *intern; -	zval              *tmp;  	zend_class_entry  *parent = class_type;  	int                inherited = 0; @@ -394,7 +393,7 @@ static zend_object_value spl_heap_object_new_ex(zend_class_entry *class_type, sp  	ALLOC_INIT_ZVAL(intern->retval);  	zend_object_std_init(&intern->std, class_type TSRMLS_CC); -	zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); +	object_properties_init(&intern->std, class_type);  	intern->flags      = 0;  	intern->fptr_cmp   = NULL; @@ -529,6 +528,10 @@ static HashTable* spl_heap_object_get_debug_info_helper(zend_class_entry *ce, zv  	*is_temp = 0; +	if (!intern->std.properties) { +		rebuild_object_properties(&intern->std); +	} +  	if (intern->debug_info == NULL) {  		ALLOC_HASHTABLE(intern->debug_info);  		ZEND_INIT_SYMTABLE_EX(intern->debug_info, zend_hash_num_elements(intern->std.properties) + 1, 0); diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c index d71f4e80da..c8d0e64461 100755 --- a/ext/spl/spl_iterators.c +++ b/ext/spl/spl_iterators.c @@ -810,7 +810,6 @@ static zend_object_value spl_RecursiveIteratorIterator_new_ex(zend_class_entry *  {  	zend_object_value retval;  	spl_recursive_it_object *intern; -	zval *tmp;  	intern = emalloc(sizeof(spl_recursive_it_object));  	memset(intern, 0, sizeof(spl_recursive_it_object)); @@ -825,7 +824,7 @@ static zend_object_value spl_RecursiveIteratorIterator_new_ex(zend_class_entry *  	}  	zend_object_std_init(&intern->std, class_type TSRMLS_CC); -	zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); +	object_properties_init(&intern->std, class_type);  	retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) spl_RecursiveIteratorIterator_free_storage, NULL TSRMLS_CC);  	retval.handlers = &spl_handlers_rec_it_it; @@ -1960,14 +1959,13 @@ static zend_object_value spl_dual_it_new(zend_class_entry *class_type TSRMLS_DC)  {  	zend_object_value retval;  	spl_dual_it_object *intern; -	zval *tmp;  	intern = emalloc(sizeof(spl_dual_it_object));  	memset(intern, 0, sizeof(spl_dual_it_object));  	intern->dit_type = DIT_Unknown;  	zend_object_std_init(&intern->std, class_type TSRMLS_CC); -	zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); +	object_properties_init(&intern->std, class_type);  	retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) spl_dual_it_free_storage, NULL TSRMLS_CC);  	retval.handlers = &spl_handlers_dual_it; diff --git a/ext/spl/spl_observer.c b/ext/spl/spl_observer.c index c8f80a1fda..1e09ca98b9 100755 --- a/ext/spl/spl_observer.c +++ b/ext/spl/spl_observer.c @@ -253,14 +253,13 @@ static zend_object_value spl_object_storage_new_ex(zend_class_entry *class_type,  	zend_object_value     retval;  	spl_SplObjectStorage *intern;  	zend_class_entry     *parent = class_type; -	zval                 *tmp;  	intern = emalloc(sizeof(spl_SplObjectStorage));  	memset(intern, 0, sizeof(spl_SplObjectStorage));  	*obj = intern;  	zend_object_std_init(&intern->std, class_type TSRMLS_CC); -	zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); +	object_properties_init(&intern->std, class_type);  	zend_hash_init(&intern->storage, 0, NULL, (void (*)(void *))spl_object_storage_dtor, 0); @@ -669,7 +668,7 @@ SPL_METHOD(SplObjectStorage, serialize)  	/* members */  	smart_str_appendl(&buf, "m:", 2);  	INIT_PZVAL(&members); -	Z_ARRVAL(members) = intern->std.properties; +	Z_ARRVAL(members) = zend_std_get_properties(getThis() TSRMLS_CC);  	Z_TYPE(members) = IS_ARRAY;  	pmembers = &members;  	php_var_serialize(&buf, &pmembers, &var_hash TSRMLS_CC); /* finishes the string */ @@ -767,6 +766,9 @@ SPL_METHOD(SplObjectStorage, unserialize)  	}  	/* copy members */ +	if (!intern->std.properties) { +		rebuild_object_properties(&intern->std); +	}  	zend_hash_copy(intern->std.properties, Z_ARRVAL_P(pmembers), (copy_ctor_func_t) zval_add_ref, (void *) NULL, sizeof(zval *));  	zval_ptr_dtor(&pmembers); diff --git a/ext/sqlite/sqlite.c b/ext/sqlite/sqlite.c index db0dab40ba..1f33caf43b 100644 --- a/ext/sqlite/sqlite.c +++ b/ext/sqlite/sqlite.c @@ -1154,14 +1154,13 @@ static void sqlite_object_free_storage(void *object TSRMLS_DC)  static void sqlite_object_new(zend_class_entry *class_type, zend_object_handlers *handlers, zend_object_value *retval TSRMLS_DC)  {  	sqlite_object *intern; -	zval *tmp;  	intern = emalloc(sizeof(sqlite_object));  	memset(intern, 0, sizeof(sqlite_object));  	zend_object_std_init(&intern->std, class_type TSRMLS_CC); -	zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); - +	object_properties_init(&intern->std, class_type); +	  	retval->handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) sqlite_object_free_storage, NULL TSRMLS_CC);  	retval->handlers = handlers;  } diff --git a/ext/sqlite3/sqlite3.c b/ext/sqlite3/sqlite3.c index 00364b0dd4..643e1a07bc 100644 --- a/ext/sqlite3/sqlite3.c +++ b/ext/sqlite3/sqlite3.c @@ -1933,7 +1933,6 @@ static void php_sqlite3_result_object_free_storage(void *object TSRMLS_DC) /* {{  static zend_object_value php_sqlite3_object_new(zend_class_entry *class_type TSRMLS_DC) /* {{{ */  { -	zval *tmp;  	zend_object_value retval;  	php_sqlite3_db_object *intern; @@ -1946,7 +1945,7 @@ static zend_object_value php_sqlite3_object_new(zend_class_entry *class_type TSR  	zend_llist_init(&(intern->free_list),   sizeof(php_sqlite3_free_list *), (llist_dtor_func_t)php_sqlite3_free_list_dtor, 0);  	zend_object_std_init(&intern->zo, class_type TSRMLS_CC); -	zend_hash_copy(intern->zo.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref,(void *) &tmp, sizeof(zval *)); +	object_properties_init(&intern->zo, class_type);  	retval.handle = zend_objects_store_put(intern, NULL, (zend_objects_free_object_storage_t) php_sqlite3_object_free_storage, NULL TSRMLS_CC);  	retval.handlers = (zend_object_handlers *) &sqlite3_object_handlers; @@ -1957,7 +1956,6 @@ static zend_object_value php_sqlite3_object_new(zend_class_entry *class_type TSR  static zend_object_value php_sqlite3_stmt_object_new(zend_class_entry *class_type TSRMLS_DC) /* {{{ */  { -	zval *tmp;  	zend_object_value retval;  	php_sqlite3_stmt *intern; @@ -1968,7 +1966,7 @@ static zend_object_value php_sqlite3_stmt_object_new(zend_class_entry *class_typ  	intern->db_obj_zval = NULL;  	zend_object_std_init(&intern->zo, class_type TSRMLS_CC); -	zend_hash_copy(intern->zo.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref,(void *) &tmp, sizeof(zval *)); +	object_properties_init(&intern->zo, class_type);  	retval.handle = zend_objects_store_put(intern, NULL, (zend_objects_free_object_storage_t) php_sqlite3_stmt_object_free_storage, NULL TSRMLS_CC);  	retval.handlers = (zend_object_handlers *) &sqlite3_stmt_object_handlers; @@ -1979,7 +1977,6 @@ static zend_object_value php_sqlite3_stmt_object_new(zend_class_entry *class_typ  static zend_object_value php_sqlite3_result_object_new(zend_class_entry *class_type TSRMLS_DC) /* {{{ */  { -	zval *tmp;  	zend_object_value retval;  	php_sqlite3_result *intern; @@ -1992,7 +1989,7 @@ static zend_object_value php_sqlite3_result_object_new(zend_class_entry *class_t  	intern->stmt_obj_zval = NULL;  	zend_object_std_init(&intern->zo, class_type TSRMLS_CC); -	zend_hash_copy(intern->zo.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref,(void *) &tmp, sizeof(zval *)); +	object_properties_init(&intern->zo, class_type);  	retval.handle = zend_objects_store_put(intern, NULL, (zend_objects_free_object_storage_t) php_sqlite3_result_object_free_storage, NULL TSRMLS_CC);  	retval.handlers = (zend_object_handlers *) &sqlite3_result_object_handlers; diff --git a/ext/standard/incomplete_class.c b/ext/standard/incomplete_class.c index ce9a95375a..f42c64d8b9 100644 --- a/ext/standard/incomplete_class.c +++ b/ext/standard/incomplete_class.c @@ -109,8 +109,6 @@ static zend_object_value php_create_incomplete_object(zend_class_entry *class_ty  	value = zend_objects_new(&object, class_type TSRMLS_CC);  	value.handlers = &php_incomplete_object_handlers; -	ALLOC_HASHTABLE(object->properties); -	zend_hash_init(object->properties, 0, NULL, ZVAL_PTR_DTOR, 0);  	return value;  } diff --git a/ext/standard/tests/array/array_fill_object.phpt b/ext/standard/tests/array/array_fill_object.phpt index 48aac60b55..86773b17f8 100644 --- a/ext/standard/tests/array/array_fill_object.phpt +++ b/ext/standard/tests/array/array_fill_object.phpt @@ -1,5 +1,7 @@  --TEST--  Test array_fill() function : usage variations - various object values for 'val' argument +--SKIPIF-- +<?php if (version_compare(zend_version(), '2.4.0', '>=')) die('skip ZendEngine 2.3 or below needed'); ?>  --FILE--  <?php  /* Prototype  : array array_fill(int $start_key, int $num, mixed $val) diff --git a/ext/standard/tests/array/array_fill_object_2_4.phpt b/ext/standard/tests/array/array_fill_object_2_4.phpt new file mode 100644 index 0000000000..fb8179766c --- /dev/null +++ b/ext/standard/tests/array/array_fill_object_2_4.phpt @@ -0,0 +1,434 @@ +--TEST-- +Test array_fill() function : usage variations - various object values for 'val' argument +--SKIPIF-- +<?php if (version_compare(zend_version(), '2.4.0', '<')) die('skip ZendEngine 2.4 needed'); ?> +--FILE-- +<?php +/* Prototype  : array array_fill(int $start_key, int $num, mixed $val) + * Description: Create an array containing num elements starting with index start_key each initialized to val  + * Source code: ext/standard/array.c + */ + +/* + * testing array_fill() by passing various  object values for 'val' argument + */ + +echo "*** Testing array_fill() : usage variations ***\n"; + +// Initialise function arguments not being substituted  +$start_key = 0; +$num = 2; + +// class without a member +class Test +{ +} + +//class with public member, static member , constant and consturctor to initialize the public member  +class Test1 +{ +  const test1_constant = "test1"; +  public static $test1_static = 0; +  public $member1; +  var $var1 = 30; +  var $var2; + +  function __construct($value1 , $value2) +  { +    $this->member1 = $value1; +    $this->var2 = $value2; +  } +} + +// child class which inherits parent class test1 +class Child_test1 extends Test1 +{ +  public $member2; + +  function __construct($value1 , $value2 , $value3) +  { +    parent::__construct($value1 , $value2); +    $this->member2 = $value3; +  } +} + +//class with private member, static member, constant and constructor to initialize the private member +class Test2 +{ +  const test2_constant = "test2"; +  public static $test2_static = 0; +  private $member1; +  var $var1 = 30; +  var $var2; + +  function __construct($value1 , $value2) +  { +    $this->member1 = $value1; +    $this->var2 = $value2; +  } +} + +// child class which inherits parent class test2 +class Child_test2 extends Test2 +{ +  private $member1; + +  function __construct($value1 , $value2 , $value3) +  { +    parent::__construct($value1 , $value2); +    $this->member1 = $value3; +  } +} + +// class with protected member, static member, constant and consturctor to initialize the protected member  +class Test3 +{ +  const test3_constant = "test3"; +  public static $test3_static = 0; +  protected $member1; +  var $var1 = 30; +  var $var2;  + +  function __construct($value1 , $value2) +  { +     $this->member1 = $value1; +     $this->var2 = $value2; +  } +} + +// child class which inherits parent class test3 +class Child_test3 extends Test3 +{ +  protected $member1; + +  function __construct($value1 , $value2 , $value3) +  { +    parent::__construct($value1 , $value2); +    $this->member1 = $value3; +  } +} + +// class with public, private, protected members, static, constant members and constructor to initialize all the members +class Test4 +{ +  const test4_constant = "test4"; +  public static $test4_static = 0; +  public $member1; +  private $member2; +  protected $member3; + +  function __construct($value1 , $value2 , $value3) +  { +    $this->member1 = $value1; +    $this->member2 = $value2; +    $this->member3 = $value3; +  } +} + +// child class which inherits parent class test4 +class Child_test4 extends Test4 +{ +  var $var1; +   +  function __construct($value1 , $value2 , $value3 , $value4) +  { +    parent::__construct($value1 , $value2 , $value3); +    $this->var1 = $value4; +  } +} + +// abstract class with public, private, protected members  +abstract class AbstractClass +{ +  public $member1; +  private $member2; +  protected $member3; +  var $var1 = 30; +   +  abstract protected function display(); +} + +// implement abstract 'AbstractClass' class +class ConcreteClass1 extends AbstractClass +{ +  protected function display() +  { +    echo "class name is ConcreteClass1 \n"; +  } +} + + +// declarationn of the interface 'iTemplate' +interface iTemplate +{ +  public function display(); +} + +// implement the interface 'iTemplate' +class Template1 implements iTemplate +{ +  public function display() +  { +    echo "class name is Template1\n"; +  } +} + +//array of object values for 'val' argument +$objects = array( +   +  /* 1  */  new Test(), +            new Test1(100 , 101), +            new Child_test1(100 , 101 , 102), +            new Test2(100 , 101), +  /* 5  */  new Child_test2(100 , 101 , 102), +            new Test3(100 , 101), +            new Child_test3(100 , 101 , 102), +            new Test4( 100 , 101 , 102), +            new Child_test4(100 , 101 , 102 , 103), +            new ConcreteClass1(), +  /* 11 */  new Template1() +); + +// loop through each element of the array for 'val' argument  +// check the working of array_fill() +echo "--- Testing array_fill() with different object values for 'val' argument ---\n"; +$counter = 1; +for($index = 0; $index < count($objects); $index ++) +{ +  echo "-- Iteration $counter --\n"; +  $val = $objects[$index]; + +  var_dump( array_fill($start_key,$num,$val) ); + +  $counter++; +} + +echo "Done"; +?> +--EXPECTF-- +*** Testing array_fill() : usage variations *** +--- Testing array_fill() with different object values for 'val' argument --- +-- Iteration 1 -- +array(2) { +  [0]=> +  object(Test)#%d (0) { +  } +  [1]=> +  object(Test)#%d (0) { +  } +} +-- Iteration 2 -- +array(2) { +  [0]=> +  object(Test1)#%d (3) { +    ["member1"]=> +    int(100) +    ["var1"]=> +    int(30) +    ["var2"]=> +    int(101) +  } +  [1]=> +  object(Test1)#%d (3) { +    ["member1"]=> +    int(100) +    ["var1"]=> +    int(30) +    ["var2"]=> +    int(101) +  } +} +-- Iteration 3 -- +array(2) { +  [0]=> +  object(Child_test1)#%d (4) { +    ["member2"]=> +    int(102) +    ["member1"]=> +    int(100) +    ["var1"]=> +    int(30) +    ["var2"]=> +    int(101) +  } +  [1]=> +  object(Child_test1)#%d (4) { +    ["member2"]=> +    int(102) +    ["member1"]=> +    int(100) +    ["var1"]=> +    int(30) +    ["var2"]=> +    int(101) +  } +} +-- Iteration 4 -- +array(2) { +  [0]=> +  object(Test2)#%d (3) { +    ["member1":"Test2":private]=> +    int(100) +    ["var1"]=> +    int(30) +    ["var2"]=> +    int(101) +  } +  [1]=> +  object(Test2)#%d (3) { +    ["member1":"Test2":private]=> +    int(100) +    ["var1"]=> +    int(30) +    ["var2"]=> +    int(101) +  } +} +-- Iteration 5 -- +array(2) { +  [0]=> +  object(Child_test2)#%d (4) { +    ["member1":"Child_test2":private]=> +    int(102) +    ["var1"]=> +    int(30) +    ["var2"]=> +    int(101) +    ["member1":"Test2":private]=> +    int(100) +  } +  [1]=> +  object(Child_test2)#%d (4) { +    ["member1":"Child_test2":private]=> +    int(102) +    ["var1"]=> +    int(30) +    ["var2"]=> +    int(101) +    ["member1":"Test2":private]=> +    int(100) +  } +} +-- Iteration 6 -- +array(2) { +  [0]=> +  object(Test3)#%d (3) { +    ["member1":protected]=> +    int(100) +    ["var1"]=> +    int(30) +    ["var2"]=> +    int(101) +  } +  [1]=> +  object(Test3)#%d (3) { +    ["member1":protected]=> +    int(100) +    ["var1"]=> +    int(30) +    ["var2"]=> +    int(101) +  } +} +-- Iteration 7 -- +array(2) { +  [0]=> +  object(Child_test3)#%d (3) { +    ["member1":protected]=> +    int(102) +    ["var1"]=> +    int(30) +    ["var2"]=> +    int(101) +  } +  [1]=> +  object(Child_test3)#%d (3) { +    ["member1":protected]=> +    int(102) +    ["var1"]=> +    int(30) +    ["var2"]=> +    int(101) +  } +} +-- Iteration 8 -- +array(2) { +  [0]=> +  object(Test4)#%d (3) { +    ["member1"]=> +    int(100) +    ["member2":"Test4":private]=> +    int(101) +    ["member3":protected]=> +    int(102) +  } +  [1]=> +  object(Test4)#%d (3) { +    ["member1"]=> +    int(100) +    ["member2":"Test4":private]=> +    int(101) +    ["member3":protected]=> +    int(102) +  } +} +-- Iteration 9 -- +array(2) { +  [0]=> +  object(Child_test4)#%d (4) { +    ["var1"]=> +    int(103) +    ["member1"]=> +    int(100) +    ["member2":"Test4":private]=> +    int(101) +    ["member3":protected]=> +    int(102) +  } +  [1]=> +  object(Child_test4)#%d (4) { +    ["var1"]=> +    int(103) +    ["member1"]=> +    int(100) +    ["member2":"Test4":private]=> +    int(101) +    ["member3":protected]=> +    int(102) +  } +} +-- Iteration 10 -- +array(2) { +  [0]=> +  object(ConcreteClass1)#%d (4) { +    ["member1"]=> +    NULL +    ["member2":"AbstractClass":private]=> +    NULL +    ["member3":protected]=> +    NULL +    ["var1"]=> +    int(30) +  } +  [1]=> +  object(ConcreteClass1)#%d (4) { +    ["member1"]=> +    NULL +    ["member2":"AbstractClass":private]=> +    NULL +    ["member3":protected]=> +    NULL +    ["var1"]=> +    int(30) +  } +} +-- Iteration 11 -- +array(2) { +  [0]=> +  object(Template1)#%d (0) { +  } +  [1]=> +  object(Template1)#%d (0) { +  } +} +Done diff --git a/ext/tidy/tidy.c b/ext/tidy/tidy.c index 85d9740821..f48b4f5bf1 100644 --- a/ext/tidy/tidy.c +++ b/ext/tidy/tidy.c @@ -676,13 +676,11 @@ static void tidy_object_new(zend_class_entry *class_type, zend_object_handlers *  							zend_object_value *retval, tidy_obj_type objtype TSRMLS_DC)  {  	PHPTidyObj *intern; -	zval *tmp;  	intern = emalloc(sizeof(PHPTidyObj));  	memset(intern, 0, sizeof(PHPTidyObj));  	zend_object_std_init(&intern->std, class_type TSRMLS_CC); -	 -	zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); +	object_properties_init(&intern->std, class_type);  	switch(objtype) {  		case is_node: diff --git a/ext/xmlreader/php_xmlreader.c b/ext/xmlreader/php_xmlreader.c index a151062184..30de80f41d 100644 --- a/ext/xmlreader/php_xmlreader.c +++ b/ext/xmlreader/php_xmlreader.c @@ -391,7 +391,6 @@ zend_object_value xmlreader_objects_new(zend_class_entry *class_type TSRMLS_DC)  {  	zend_object_value retval;  	xmlreader_object *intern; -	zval *tmp;  	intern = emalloc(sizeof(xmlreader_object));  	memset(&intern->std, 0, sizeof(zend_object)); @@ -401,7 +400,7 @@ zend_object_value xmlreader_objects_new(zend_class_entry *class_type TSRMLS_DC)  	intern->prop_handler = &xmlreader_prop_handlers;  	zend_object_std_init(&intern->std, class_type TSRMLS_CC); -	zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); +	object_properties_init(&intern->std, class_type);  	retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) xmlreader_objects_free_storage, xmlreader_objects_clone TSRMLS_CC);  	intern->handle = retval.handle;  	retval.handlers = &xmlreader_object_handlers; diff --git a/ext/xmlwriter/php_xmlwriter.c b/ext/xmlwriter/php_xmlwriter.c index e26c6dc7e1..365fc82429 100644 --- a/ext/xmlwriter/php_xmlwriter.c +++ b/ext/xmlwriter/php_xmlwriter.c @@ -143,7 +143,6 @@ static void xmlwriter_object_free_storage(void *object TSRMLS_DC)  static zend_object_value xmlwriter_object_new(zend_class_entry *class_type TSRMLS_DC)  {  	ze_xmlwriter_object *intern; -	zval *tmp;  	zend_object_value retval;  	intern = emalloc(sizeof(ze_xmlwriter_object)); @@ -151,8 +150,7 @@ static zend_object_value xmlwriter_object_new(zend_class_entry *class_type TSRML  	intern->xmlwriter_ptr = NULL;  	zend_object_std_init(&intern->zo, class_type TSRMLS_CC); -	zend_hash_copy(intern->zo.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, -					(void *) &tmp, sizeof(zval *)); +	object_properties_init(&intern->zo, class_type);  	retval.handle = zend_objects_store_put(intern,  						NULL, diff --git a/ext/xsl/php_xsl.c b/ext/xsl/php_xsl.c index f177f42e66..53e5e06b8d 100644 --- a/ext/xsl/php_xsl.c +++ b/ext/xsl/php_xsl.c @@ -115,7 +115,6 @@ zend_object_value xsl_objects_new(zend_class_entry *class_type TSRMLS_DC)  {  	zend_object_value retval;  	xsl_object *intern; -	zval *tmp;  	intern = emalloc(sizeof(xsl_object));  	intern->ptr = NULL; @@ -129,7 +128,7 @@ zend_object_value xsl_objects_new(zend_class_entry *class_type TSRMLS_DC)  	intern->profiling = NULL;  	zend_object_std_init(&intern->std, class_type TSRMLS_CC); -	zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); +	object_properties_init(&intern->std, class_type);  	ALLOC_HASHTABLE(intern->parameter);  	zend_hash_init(intern->parameter, 0, NULL, ZVAL_PTR_DTOR, 0);  	ALLOC_HASHTABLE(intern->registered_phpfunctions); diff --git a/ext/zip/php_zip.c b/ext/zip/php_zip.c index ba89cce5f3..7645c56ada 100644 --- a/ext/zip/php_zip.c +++ b/ext/zip/php_zip.c @@ -971,7 +971,7 @@ static HashTable *php_zip_get_properties(zval *object TSRMLS_DC)/* {{{ */  	ulong num_key;  	obj = (ze_zip_object *)zend_objects_get_address(object TSRMLS_CC); -	props = obj->zo.properties; +	props = zend_std_get_properties(object TSRMLS_CC);  	if (obj->prop_handler == NULL) {  		return NULL; @@ -988,7 +988,7 @@ static HashTable *php_zip_get_properties(zval *object TSRMLS_DC)/* {{{ */  		zend_hash_update(props, key, key_len, (void *)&val, sizeof(zval *), NULL);  		zend_hash_move_forward_ex(obj->prop_handler, &pos);  	} -	return obj->zo.properties; +	return props;  }  /* }}} */ @@ -1040,7 +1040,6 @@ static void php_zip_object_free_storage(void *object TSRMLS_DC) /* {{{ */  static zend_object_value php_zip_object_new(zend_class_entry *class_type TSRMLS_DC) /* {{{ */  {  	ze_zip_object *intern; -	zval *tmp;  	zend_object_value retval;  	intern = emalloc(sizeof(ze_zip_object)); @@ -1060,8 +1059,7 @@ static zend_object_value php_zip_object_new(zend_class_entry *class_type TSRMLS_  	intern->zo.ce = class_type;  #endif -	zend_hash_copy(intern->zo.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, -					(void *) &tmp, sizeof(zval *)); +	object_properties_init(&intern->zo, class_type);  	retval.handle = zend_objects_store_put(intern,  						NULL,  | 
