if (callee_func->type == ZEND_INTERNAL_FUNCTION) {
zval *zv;
- func_info_t *info;
+ zend_string *lcname = Z_STR_P(CRT_CONSTANT_EX(call_info->caller_op_array, call_info->caller_init_opline, call_info->caller_init_opline->op2, ssa->rt_constants));
- zv = zend_hash_find_ex(&func_info, Z_STR_P(CRT_CONSTANT_EX(call_info->caller_op_array, call_info->caller_init_opline, call_info->caller_init_opline->op2, ssa->rt_constants)), 1);
+ zv = zend_hash_find_ex(&func_info, lcname, 1);
if (zv) {
- info = Z_PTR_P(zv);
+ func_info_t *info = Z_PTR_P(zv);
if (UNEXPECTED(zend_optimizer_is_disabled_func(info->name, info->name_len))) {
ret = MAY_BE_NULL;
} else if (info->info_func) {
} else {
ret = info->info;
}
-#if 0
+ return ret;
+ }
+
+ if (callee_func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
+ zend_class_entry *ce; // TODO: Use the CE.
+ ret = zend_fetch_arg_info_type(NULL, callee_func->common.arg_info - 1, &ce);
} else {
+#if 0
fprintf(stderr, "Unknown internal function '%s'\n", func->common.function_name);
#endif
+ ret = MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF
+ | MAY_BE_RC1 | MAY_BE_RCN;
+ }
+ if (callee_func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) {
+ ret |= MAY_BE_REF;
}
} else {
// FIXME: the order of functions matters!!!
if (info) {
ret = info->return_info.type;
}
- }
- if (!ret) {
- ret = MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
- if (callee_func->common.fn_flags & ZEND_ACC_GENERATOR) {
- ret = MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_OBJECT;
- } else if (callee_func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) {
- ret |= MAY_BE_REF;
- } else {
- ret |= MAY_BE_RC1 | MAY_BE_RCN;
+ if (!ret) {
+ ret = MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF
+ | MAY_BE_RC1 | MAY_BE_RCN;
+ /* For generators RETURN_REFERENCE refers to the yielded values. */
+ if ((callee_func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
+ && !(callee_func->common.fn_flags & ZEND_ACC_GENERATOR)) {
+ ret |= MAY_BE_REF;
+ }
}
}
return ret;
}
}
-static uint32_t zend_fetch_arg_info(const zend_script *script, zend_arg_info *arg_info, zend_class_entry **pce)
+uint32_t zend_fetch_arg_info_type(const zend_script *script, zend_arg_info *arg_info, zend_class_entry **pce)
{
uint32_t tmp = 0;
if (ZEND_TYPE_ALLOW_NULL(arg_info->type)) {
tmp |= MAY_BE_NULL;
}
+ if (tmp & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
+ tmp |= MAY_BE_RC1 | MAY_BE_RCN;
+ }
return tmp;
}
ce = NULL;
if (arg_info) {
- tmp = zend_fetch_arg_info(script, arg_info, &ce);
+ tmp = zend_fetch_arg_info_type(script, arg_info, &ce);
if (opline->opcode == ZEND_RECV_INIT &&
Z_TYPE_P(CRT_CONSTANT_EX(op_array, opline, opline->op2, ssa->rt_constants)) == IS_CONSTANT_AST) {
/* The constant may resolve to NULL */
}
if (arg_info->pass_by_reference) {
tmp |= MAY_BE_REF;
- } else if (tmp & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
- tmp |= MAY_BE_RC1|MAY_BE_RCN;
}
} else {
tmp = MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_ANY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
ce = NULL;
} else {
zend_arg_info *ret_info = op_array->arg_info - 1;
-
- tmp = zend_fetch_arg_info(script, ret_info, &ce);
- if (tmp & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
- tmp |= MAY_BE_RC1 | MAY_BE_RCN;
- }
+ tmp = zend_fetch_arg_info_type(script, ret_info, &ce);
}
if (opline->op1_type & (IS_TMP_VAR|IS_VAR|IS_CV)) {
UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def);
zend_arg_info *ret_info = op_array->arg_info - 1;
zend_ssa_range tmp_range = {0, 0, 0, 0};
- ret->type = zend_fetch_arg_info(script, ret_info, &ret->ce);
+ ret->type = zend_fetch_arg_info_type(script, ret_info, &ret->ce);
if (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
ret->type |= MAY_BE_REF;
- } else if (ret->type & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
- ret->type |= MAY_BE_RC1|MAY_BE_RCN;
}
ret->is_instanceof = (ret->ce) ? 1 : 0;
ret->range = tmp_range;
int zend_infer_types_ex(const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa, zend_bitset worklist, zend_long optimization_level);
+uint32_t zend_fetch_arg_info_type(
+ const zend_script *script, zend_arg_info *arg_info, zend_class_entry **pce);
void zend_init_func_return_info(const zend_op_array *op_array,
const zend_script *script,
zend_ssa_var_info *ret);