Skip to content
Browse files

Added caches to eliminate repeatable run-time bindings of functions, …

…classes, constants, methods and properties
  • Loading branch information...
1 parent 1cabc8c commit c5237d82bf01a762bb38f80def59b9c16cb84dc1 Dmitry Stogov committed May 24, 2010
Showing with 2,464 additions and 700 deletions.
  1. +2 −0 NEWS
  2. +0 −1 Zend/bench.php
  3. +6 −3 Zend/zend.h
  4. +69 −47 Zend/zend_API.c
  5. +3 −2 Zend/zend_API.h
  6. +44 −40 Zend/zend_builtin_functions.c
  7. +146 −52 Zend/zend_compile.c
  8. +7 −2 Zend/zend_compile.h
  9. +2 −4 Zend/zend_exceptions.c
  10. +17 −0 Zend/zend_execute.h
  11. +204 −49 Zend/zend_object_handlers.c
  12. +2 −0 Zend/zend_object_handlers.h
  13. +58 −8 Zend/zend_objects.c
  14. +51 −8 Zend/zend_opcode.c
  15. +151 −41 Zend/zend_vm_def.h
  16. +960 −269 Zend/zend_vm_execute.h
  17. +4 −0 Zend/zend_vm_execute.skl
  18. +6 −10 ext/date/php_date.c
  19. +1 −2 ext/dom/php_dom.c
  20. +1 −2 ext/fileinfo/fileinfo.c
  21. +1 −3 ext/mysqli/mysqli.c
  22. +2 −2 ext/pdo/pdo_dbh.c
  23. +5 −4 ext/pdo/pdo_stmt.c
  24. +105 −106 ext/reflection/php_reflection.c
  25. +2 −0 ext/reflection/tests/ReflectionClass_getStaticPropertyValue_001.phpt
  26. +61 −0 ext/reflection/tests/ReflectionClass_getStaticPropertyValue_001_2_4.phpt
  27. +2 −0 ext/reflection/tests/ReflectionClass_setStaticPropertyValue_001.phpt
  28. +61 −0 ext/reflection/tests/ReflectionClass_setStaticPropertyValue_001_2_4.phpt
  29. +17 −1 ext/spl/spl_array.c
  30. +5 −2 ext/spl/spl_directory.c
  31. +4 −2 ext/spl/spl_dllist.c
  32. +5 −5 ext/spl/spl_fixedarray.c
  33. +5 −2 ext/spl/spl_heap.c
  34. +2 −4 ext/spl/spl_iterators.c
  35. +5 −3 ext/spl/spl_observer.c
  36. +2 −3 ext/sqlite/sqlite.c
  37. +3 −6 ext/sqlite3/sqlite3.c
  38. +0 −2 ext/standard/incomplete_class.c
  39. +2 −0 ext/standard/tests/array/array_fill_object.phpt
  40. +434 −0 ext/standard/tests/array/array_fill_object_2_4.phpt
  41. +1 −3 ext/tidy/tidy.c
  42. +1 −2 ext/xmlreader/php_xmlreader.c
  43. +1 −3 ext/xmlwriter/php_xmlwriter.c
  44. +1 −2 ext/xsl/php_xsl.c
  45. +3 −5 ext/zip/php_zip.c
View
2 NEWS
@@ -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
View
1 Zend/bench.php
@@ -3,7 +3,6 @@
date_default_timezone_set("UTC");
}
-date_default_timezone_set('UTC');
function simple() {
$a = 0;
for ($i = 0; $i < 1000000; $i++)
View
9 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;
View
116 Zend/zend_API.c
@@ -1005,72 +1005,86 @@ 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;
ALLOC_ZVAL(r);
*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;
}
}
/* }}} */
+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;
}
View
5 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);
View
84 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);
}
}
/* }}} */
View
198 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;
View
9 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];
};
View
6 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);
View
17 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 */
View
253 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,13 +302,17 @@ 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;
EG(std_property_info).name = Z_STRVAL_P(member);
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,15 +1268,48 @@ 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);
+ }
}
/* }}} */
static int zend_std_has_property(zval *object, zval *member, int has_set_exists, const zend_literal *key TSRMLS_DC) /* {{{ */
{
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;
View
2 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))
View
66 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;
View
59 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;
}
View
192 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();
}
View
1,229 Zend/zend_vm_execute.h
@@ -99,6 +99,10 @@ ZEND_API void execute(zend_op_array *op_array TSRMLS_DC)
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 {