summaryrefslogtreecommitdiff
path: root/ext/opcache/ZendAccelerator.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/opcache/ZendAccelerator.c')
-rw-r--r--ext/opcache/ZendAccelerator.c46
1 files changed, 46 insertions, 0 deletions
diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c
index 6704481cbc..99fae3f9f0 100644
--- a/ext/opcache/ZendAccelerator.c
+++ b/ext/opcache/ZendAccelerator.c
@@ -3452,6 +3452,44 @@ static zend_bool preload_try_resolve_property_types(zend_class_entry *ce)
return ok;
}
+static zend_bool preload_is_type_known(zend_class_entry *ce, zend_type type) {
+ zend_string *name, *lcname;
+ zend_bool known;
+ if (!ZEND_TYPE_IS_NAME(type)) {
+ return 1;
+ }
+
+ name = ZEND_TYPE_NAME(type);
+ if (zend_string_equals_literal_ci(name, "self") ||
+ zend_string_equals_literal_ci(name, "parent") ||
+ zend_string_equals_ci(name, ce->name)) {
+ return 1;
+ }
+
+ lcname = zend_string_tolower(name);
+ known = zend_hash_exists(EG(class_table), lcname);
+ zend_string_release(lcname);
+ return known;
+}
+
+static zend_bool preload_all_types_known(zend_class_entry *ce) {
+ zend_function *fptr;
+ ZEND_HASH_FOREACH_PTR(&ce->function_table, fptr) {
+ uint32_t i;
+ if (fptr->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
+ if (!preload_is_type_known(ce, fptr->common.arg_info[-1].type)) {
+ return 0;
+ }
+ }
+ for (i = 0; i < fptr->common.num_args; i++) {
+ if (!preload_is_type_known(ce, fptr->common.arg_info[i].type)) {
+ return 0;
+ }
+ }
+ } ZEND_HASH_FOREACH_END();
+ return 1;
+}
+
static void preload_link(void)
{
zval *zv;
@@ -3545,6 +3583,14 @@ static void preload_link(void)
if (!found) continue;
}
+ /* TODO: This is much more restrictive than necessary. We only need to actually
+ * know the types for covariant checks, but don't need them if we can ensure
+ * compatibility through a simple string comparison. We could improve this using
+ * a more general version of zend_can_early_bind(). */
+ if (!preload_all_types_known(ce)) {
+ continue;
+ }
+
zend_string *key = zend_string_tolower(ce->name);
zv = zend_hash_set_bucket_key(EG(class_table), (Bucket*)zv, key);
zend_string_release(key);