Skip to content

Commit

Permalink
Use zend_string* for op_array->arg_info[]->name and op_array->arg_inf…
Browse files Browse the repository at this point in the history
…o[]->class_name. For internal functions we still use char*.
  • Loading branch information
dstogov committed Dec 3, 2014
1 parent e938064 commit 5dd427e
Show file tree
Hide file tree
Showing 15 changed files with 205 additions and 76 deletions.
2 changes: 1 addition & 1 deletion Zend/zend_API.c
Expand Up @@ -2192,7 +2192,7 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio
if (ptr->arg_info) {
zend_internal_function_info *info = (zend_internal_function_info*)ptr->arg_info;

internal_function->arg_info = (zend_arg_info*)ptr->arg_info+1;
internal_function->arg_info = (zend_internal_arg_info*)ptr->arg_info+1;
internal_function->num_args = ptr->num_args;
/* Currently you cannot denote that the function can accept less arguments than num_args */
if (info->required_num_args == -1) {
Expand Down
18 changes: 9 additions & 9 deletions Zend/zend_API.h
Expand Up @@ -35,7 +35,7 @@ BEGIN_EXTERN_C()
typedef struct _zend_function_entry {
const char *fname;
void (*handler)(INTERNAL_FUNCTION_PARAMETERS);
const struct _zend_arg_info *arg_info;
const struct _zend_internal_arg_info *arg_info;
uint32_t num_args;
uint32_t flags;
} zend_function_entry;
Expand Down Expand Up @@ -98,16 +98,16 @@ typedef struct _zend_fcall_info_cache {

#define ZEND_FE_END { NULL, NULL, NULL, 0, 0 }

#define ZEND_ARG_INFO(pass_by_ref, name) { #name, sizeof(#name)-1, NULL, 0, 0, pass_by_ref, 0, 0 },
#define ZEND_ARG_PASS_INFO(pass_by_ref) { NULL, 0, NULL, 0, 0, pass_by_ref, 0, 0 },
#define ZEND_ARG_OBJ_INFO(pass_by_ref, name, classname, allow_null) { #name, sizeof(#name)-1, #classname, sizeof(#classname)-1, IS_OBJECT, pass_by_ref, allow_null, 0 },
#define ZEND_ARG_ARRAY_INFO(pass_by_ref, name, allow_null) { #name, sizeof(#name)-1, NULL, 0, IS_ARRAY, pass_by_ref, allow_null, 0 },
#define ZEND_ARG_TYPE_INFO(pass_by_ref, name, type_hint, allow_null) { #name, sizeof(#name)-1, NULL, 0, type_hint, pass_by_ref, allow_null, 0 },
#define ZEND_ARG_VARIADIC_INFO(pass_by_ref, name) { #name, sizeof(#name)-1, NULL, 0, 0, pass_by_ref, 0, 1 },
#define ZEND_ARG_INFO(pass_by_ref, name) { #name, NULL, 0, pass_by_ref, 0, 0 },
#define ZEND_ARG_PASS_INFO(pass_by_ref) { NULL, NULL, 0, pass_by_ref, 0, 0 },
#define ZEND_ARG_OBJ_INFO(pass_by_ref, name, classname, allow_null) { #name, #classname, IS_OBJECT, pass_by_ref, allow_null, 0 },
#define ZEND_ARG_ARRAY_INFO(pass_by_ref, name, allow_null) { #name, NULL, IS_ARRAY, pass_by_ref, allow_null, 0 },
#define ZEND_ARG_TYPE_INFO(pass_by_ref, name, type_hint, allow_null) { #name, NULL, type_hint, pass_by_ref, allow_null, 0 },
#define ZEND_ARG_VARIADIC_INFO(pass_by_ref, name) { #name, NULL, 0, pass_by_ref, 0, 1 },

#define ZEND_BEGIN_ARG_INFO_EX(name, _unused, return_reference, required_num_args) \
static const zend_arg_info name[] = { \
{ NULL, 0, NULL, required_num_args, 0, return_reference, 0, 0 },
static const zend_internal_arg_info name[] = { \
{ (const char*)(zend_uintptr_t)(required_num_args), NULL, 0, return_reference, 0, 0 },
#define ZEND_BEGIN_ARG_INFO(name, _unused) \
ZEND_BEGIN_ARG_INFO_EX(name, 0, ZEND_RETURN_VALUE, -1)
#define ZEND_END_ARG_INFO() };
Expand Down
3 changes: 2 additions & 1 deletion Zend/zend_closures.c
Expand Up @@ -182,6 +182,7 @@ ZEND_API zend_function *zend_get_closure_invoke_method(zend_object *object TSRML
zend_function *invoke = (zend_function*)emalloc(sizeof(zend_function));

invoke->common = closure->func.common;
/* TODO: return ZEND_INTERNAL_FUNCTION, but arg_info representation is suitable for ZEND_USER_FUNCTION ??? */
invoke->type = ZEND_INTERNAL_FUNCTION;
invoke->internal_function.fn_flags = ZEND_ACC_PUBLIC | ZEND_ACC_CALL_VIA_HANDLER | (closure->func.common.fn_flags & ZEND_ACC_RETURN_REFERENCE);
invoke->internal_function.handler = ZEND_MN(Closure___invoke);
Expand Down Expand Up @@ -370,7 +371,7 @@ static HashTable *zend_closure_get_debug_info(zval *object, int *is_temp TSRMLS_
if (arg_info->name) {
name = zend_strpprintf(0, "%s$%s",
arg_info->pass_by_reference ? "&" : "",
arg_info->name);
arg_info->name->val);
} else {
name = zend_strpprintf(0, "%s$param%d",
arg_info->pass_by_reference ? "&" : "",
Expand Down
9 changes: 2 additions & 7 deletions Zend/zend_compile.c
Expand Up @@ -3833,14 +3833,12 @@ void zend_compile_params(zend_ast *ast TSRMLS_DC) /* {{{ */
opline->op1.num = i + 1;

arg_info = &arg_infos[i];
arg_info->name = estrndup(name->val, name->len);
arg_info->name_len = (uint32_t)name->len;
arg_info->name = zend_string_copy(name);
arg_info->pass_by_reference = is_ref;
arg_info->is_variadic = is_variadic;
arg_info->type_hint = 0;
arg_info->allow_null = 1;
arg_info->class_name = NULL;
arg_info->class_name_len = 0;

if (type_ast) {
zend_bool has_null_default = default_ast
Expand Down Expand Up @@ -3877,10 +3875,7 @@ void zend_compile_params(zend_ast *ast TSRMLS_DC) /* {{{ */
}

arg_info->type_hint = IS_OBJECT;
arg_info->class_name = estrndup(class_name->val, class_name->len);
arg_info->class_name_len = (uint32_t)class_name->len;

zend_string_release(class_name);
arg_info->class_name = class_name;

if (default_ast && !has_null_default && !Z_CONSTANT(default_node.u.constant)) {
zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters "
Expand Down
25 changes: 16 additions & 9 deletions Zend/zend_compile.h
Expand Up @@ -245,26 +245,33 @@ typedef struct _zend_property_info {
#define OBJ_PROP_TO_NUM(offset) \
((offset - OBJ_PROP_TO_OFFSET(0)) / sizeof(zval))

/* arg_info for internal functions */
typedef struct _zend_internal_arg_info {
const char *name;
const char *class_name;
zend_uchar type_hint;
zend_uchar pass_by_reference;
zend_bool allow_null;
zend_bool is_variadic;
} zend_internal_arg_info;

/* arg_info for user functions */
typedef struct _zend_arg_info {
const char *name; // TODO: convert into zend_string ???
uint32_t name_len;
const char *class_name; // TODO: convert into zend_string ???
uint32_t class_name_len;
zend_string *name;
zend_string *class_name;
zend_uchar type_hint;
zend_uchar pass_by_reference;
zend_bool allow_null;
zend_bool is_variadic;
} zend_arg_info;

/* the following structure repeats the layout of zend_arg_info,
/* the following structure repeats the layout of zend_internal_arg_info,
* but its fields have different meaning. It's used as the first element of
* arg_info array to define properties of internal functions.
*/
typedef struct _zend_internal_function_info {
const char *_name;
uint32_t _name_len;
zend_uintptr_t required_num_args;
const char *_class_name;
uint32_t required_num_args;
zend_uchar _type_hint;
zend_bool return_reference;
zend_bool _allow_null;
Expand Down Expand Up @@ -330,7 +337,7 @@ typedef struct _zend_internal_function {
zend_function *prototype;
uint32_t num_args;
uint32_t required_num_args;
zend_arg_info *arg_info;
zend_internal_arg_info *arg_info;
/* END of common elements */

void (*handler)(INTERNAL_FUNCTION_PARAMETERS);
Expand Down
65 changes: 63 additions & 2 deletions Zend/zend_execute.c
Expand Up @@ -525,12 +525,12 @@ static inline zval* make_real_object(zval *object_ptr TSRMLS_DC)
return object;
}

ZEND_API char * zend_verify_arg_class_kind(const zend_arg_info *cur_arg_info, char **class_name, zend_class_entry **pce TSRMLS_DC)
ZEND_API char * zend_verify_internal_arg_class_kind(const zend_internal_arg_info *cur_arg_info, char **class_name, zend_class_entry **pce TSRMLS_DC)
{
zend_string *key;
ALLOCA_FLAG(use_heap);

STR_ALLOCA_INIT(key, cur_arg_info->class_name, cur_arg_info->class_name_len, use_heap);
STR_ALLOCA_INIT(key, cur_arg_info->class_name, strlen(cur_arg_info->class_name), use_heap);
*pce = zend_fetch_class(key, (ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD) TSRMLS_CC);
STR_ALLOCA_FREE(key, use_heap);

Expand All @@ -542,6 +542,18 @@ ZEND_API char * zend_verify_arg_class_kind(const zend_arg_info *cur_arg_info, ch
}
}

ZEND_API char * zend_verify_arg_class_kind(const zend_arg_info *cur_arg_info, char **class_name, zend_class_entry **pce TSRMLS_DC)
{
*pce = zend_fetch_class(cur_arg_info->class_name, (ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD) TSRMLS_CC);

*class_name = (*pce) ? (*pce)->name->val : cur_arg_info->class_name->val;
if (*pce && (*pce)->ce_flags & ZEND_ACC_INTERFACE) {
return "implement interface ";
} else {
return "be an instance of ";
}
}

ZEND_API void zend_verify_arg_error(int error_type, const zend_function *zf, uint32_t arg_num, const char *need_msg, const char *need_kind, const char *given_msg, const char *given_kind, zval *arg TSRMLS_DC)
{
zend_execute_data *ptr = EG(current_execute_data)->prev_execute_data;
Expand Down Expand Up @@ -593,6 +605,55 @@ static int is_null_constant(zval *default_value TSRMLS_DC)
return 0;
}

static void zend_verify_internal_arg_type(zend_function *zf, uint32_t arg_num, zval *arg TSRMLS_DC)
{
zend_internal_arg_info *cur_arg_info;
char *need_msg;
zend_class_entry *ce;

if (UNEXPECTED(!zf->internal_function.arg_info)) {
return;
}

if (EXPECTED(arg_num <= zf->internal_function.num_args)) {
cur_arg_info = &zf->internal_function.arg_info[arg_num-1];
} else if (zf->internal_function.fn_flags & ZEND_ACC_VARIADIC) {
cur_arg_info = &zf->internal_function.arg_info[zf->internal_function.num_args-1];
} else {
return;
}

if (cur_arg_info->class_name) {
char *class_name;

ZVAL_DEREF(arg);
if (Z_TYPE_P(arg) == IS_OBJECT) {
need_msg = zend_verify_internal_arg_class_kind((zend_internal_arg_info*)cur_arg_info, &class_name, &ce TSRMLS_CC);
if (!ce || !instanceof_function(Z_OBJCE_P(arg), ce TSRMLS_CC)) {
zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name->val, arg TSRMLS_CC);
}
} else if (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null) {
need_msg = zend_verify_internal_arg_class_kind((zend_internal_arg_info*)cur_arg_info, &class_name, &ce TSRMLS_CC);
zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "", arg TSRMLS_CC);
}
} else if (cur_arg_info->type_hint) {
if (cur_arg_info->type_hint == IS_ARRAY) {
ZVAL_DEREF(arg);
if (Z_TYPE_P(arg) != IS_ARRAY && (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null)) {
zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", zend_zval_type_name(arg), "", arg TSRMLS_CC);
}
} else if (cur_arg_info->type_hint == IS_CALLABLE) {
if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL TSRMLS_CC) && (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null)) {
zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", zend_zval_type_name(arg), "", arg TSRMLS_CC);
}
#if ZEND_DEBUG
} else {
zend_error(E_ERROR, "Unknown typehint");
#endif
}
}
}

static void zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, zval *default_value TSRMLS_DC)
{
zend_arg_info *cur_arg_info;
Expand Down
1 change: 1 addition & 0 deletions Zend/zend_execute.h
Expand Up @@ -48,6 +48,7 @@ ZEND_API int zend_eval_stringl(char *str, size_t str_len, zval *retval_ptr, char
ZEND_API int zend_eval_string_ex(char *str, zval *retval_ptr, char *string_name, int handle_exceptions TSRMLS_DC);
ZEND_API int zend_eval_stringl_ex(char *str, size_t str_len, zval *retval_ptr, char *string_name, int handle_exceptions TSRMLS_DC);

ZEND_API char * zend_verify_internal_arg_class_kind(const zend_internal_arg_info *cur_arg_info, char **class_name, zend_class_entry **pce TSRMLS_DC);
ZEND_API char * zend_verify_arg_class_kind(const zend_arg_info *cur_arg_info, char **class_name, zend_class_entry **pce TSRMLS_DC);
ZEND_API void zend_verify_arg_error(int error_type, const zend_function *zf, uint32_t arg_num, const char *need_msg, const char *need_kind, const char *given_msg, const char *given_kind, zval *arg TSRMLS_DC);

Expand Down
57 changes: 41 additions & 16 deletions Zend/zend_inheritance.c
Expand Up @@ -283,25 +283,40 @@ static zend_bool zend_do_perform_implementation_check(const zend_function *fe, c

if (fe_arg_info->class_name) {
zend_string *fe_class_name, *proto_class_name;
const char *class_name;

if (!strcasecmp(fe_arg_info->class_name, "parent") && proto->common.scope) {
if (fe->type == ZEND_INTERNAL_FUNCTION) {
fe_class_name = NULL;
class_name = ((zend_internal_arg_info*)fe_arg_info)->class_name;
} else {
fe_class_name = fe_arg_info->class_name;
class_name = fe_arg_info->class_name->val;
}
if (!strcasecmp(class_name, "parent") && proto->common.scope) {
fe_class_name = zend_string_copy(proto->common.scope->name);
} else if (!strcasecmp(fe_arg_info->class_name, "self") && fe->common.scope) {
} else if (!strcasecmp(class_name, "self") && fe->common.scope) {
fe_class_name = zend_string_copy(fe->common.scope->name);
} else if (fe_class_name) {
zend_string_addref(fe_class_name);
} else {
fe_class_name = zend_string_init(
fe_arg_info->class_name,
fe_arg_info->class_name_len, 0);
fe_class_name = zend_string_init(class_name, strlen(class_name), 0);
}

if (!strcasecmp(proto_arg_info->class_name, "parent") && proto->common.scope && proto->common.scope->parent) {
if (proto->type == ZEND_INTERNAL_FUNCTION) {
proto_class_name = NULL;
class_name = ((zend_internal_arg_info*)proto_arg_info)->class_name;
} else {
proto_class_name = proto_arg_info->class_name;
class_name = proto_arg_info->class_name->val;
}
if (!strcasecmp(class_name, "parent") && proto->common.scope && proto->common.scope->parent) {
proto_class_name = zend_string_copy(proto->common.scope->parent->name);
} else if (!strcasecmp(proto_arg_info->class_name, "self") && proto->common.scope) {
} else if (!strcasecmp(class_name, "self") && proto->common.scope) {
proto_class_name = zend_string_copy(proto->common.scope->name);
} else if (proto_class_name) {
zend_string_addref(proto_class_name);
} else {
proto_class_name = zend_string_init(
proto_arg_info->class_name,
proto_arg_info->class_name_len, 0);
proto_class_name = zend_string_init(class_name, strlen(class_name), 0);
}

if (strcasecmp(fe_class_name->val, proto_class_name->val)!=0) {
Expand Down Expand Up @@ -373,15 +388,21 @@ static zend_string *zend_get_function_declaration(zend_function *fptr TSRMLS_DC)
if (arg_info->class_name) {
const char *class_name;
size_t class_name_len;
if (!strcasecmp(arg_info->class_name, "self") && fptr->common.scope) {

if (fptr->type == ZEND_INTERNAL_FUNCTION) {
class_name = ((zend_internal_arg_info*)arg_info)->class_name;
class_name_len = strlen(class_name);
} else {
class_name = arg_info->class_name->val;
class_name_len = arg_info->class_name->len;
}

if (!strcasecmp(class_name, "self") && fptr->common.scope) {
class_name = fptr->common.scope->name->val;
class_name_len = fptr->common.scope->name->len;
} else if (!strcasecmp(arg_info->class_name, "parent") && fptr->common.scope->parent) {
} else if (!strcasecmp(class_name, "parent") && fptr->common.scope->parent) {
class_name = fptr->common.scope->parent->name->val;
class_name_len = fptr->common.scope->parent->name->len;
} else {
class_name = arg_info->class_name;
class_name_len = arg_info->class_name_len;
}

smart_str_appendl(&str, class_name, class_name_len);
Expand All @@ -403,7 +424,11 @@ static zend_string *zend_get_function_declaration(zend_function *fptr TSRMLS_DC)
smart_str_appendc(&str, '$');

if (arg_info->name) {
smart_str_appendl(&str, arg_info->name, arg_info->name_len);
if (fptr->type == ZEND_INTERNAL_FUNCTION) {
smart_str_appends(&str, ((zend_internal_arg_info*)arg_info)->name);
} else {
smart_str_appendl(&str, arg_info->name->val, arg_info->name->len);
}
} else {
smart_str_appends(&str, "param");
smart_str_append_unsigned(&str, i);
Expand Down
4 changes: 2 additions & 2 deletions Zend/zend_opcode.c
Expand Up @@ -370,9 +370,9 @@ ZEND_API void destroy_op_array(zend_op_array *op_array TSRMLS_DC)
}
if (op_array->arg_info) {
for (i=0; i<op_array->num_args; i++) {
efree((char*)op_array->arg_info[i].name);
zend_string_release(op_array->arg_info[i].name);
if (op_array->arg_info[i].class_name) {
efree((char*)op_array->arg_info[i].class_name);
zend_string_release(op_array->arg_info[i].class_name);
}
}
efree(op_array->arg_info);
Expand Down
2 changes: 1 addition & 1 deletion Zend/zend_vm_def.h
Expand Up @@ -2666,7 +2666,7 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY)
zval *p = ZEND_CALL_ARG(call, 1);

for (i = 0; i < ZEND_CALL_NUM_ARGS(call); ++i) {
zend_verify_arg_type(fbc, i + 1, p, NULL TSRMLS_CC);
zend_verify_internal_arg_type(fbc, i + 1, p TSRMLS_CC);
p++;
}
if (UNEXPECTED(EG(exception) != NULL)) {
Expand Down
2 changes: 1 addition & 1 deletion Zend/zend_vm_execute.h
Expand Up @@ -538,7 +538,7 @@ static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
zval *p = ZEND_CALL_ARG(call, 1);

for (i = 0; i < ZEND_CALL_NUM_ARGS(call); ++i) {
zend_verify_arg_type(fbc, i + 1, p, NULL TSRMLS_CC);
zend_verify_internal_arg_type(fbc, i + 1, p TSRMLS_CC);
p++;
}
if (UNEXPECTED(EG(exception) != NULL)) {
Expand Down
6 changes: 2 additions & 4 deletions ext/opcache/zend_persist.c
Expand Up @@ -419,12 +419,10 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc
zend_accel_store(op_array->arg_info, sizeof(zend_arg_info) * op_array->num_args);
for (i = 0; i < op_array->num_args; i++) {
if (op_array->arg_info[i].name) {
//??? zend_accel_store_interned_string(op_array->arg_info[i].name, op_array->arg_info[i].name_len + 1);
zend_accel_store(op_array->arg_info[i].name, op_array->arg_info[i].name_len + 1);
zend_accel_store_interned_string(op_array->arg_info[i].name);
}
if (op_array->arg_info[i].class_name) {
//??? zend_accel_store_interned_string(op_array->arg_info[i].class_name, op_array->arg_info[i].class_name_len + 1);
zend_accel_store(op_array->arg_info[i].class_name, op_array->arg_info[i].class_name_len + 1);
zend_accel_store_interned_string(op_array->arg_info[i].class_name);
}
}
}
Expand Down
6 changes: 2 additions & 4 deletions ext/opcache/zend_persist_calc.c
Expand Up @@ -199,12 +199,10 @@ static void zend_persist_op_array_calc_ex(zend_op_array *op_array TSRMLS_DC)
ADD_DUP_SIZE(op_array->arg_info, sizeof(zend_arg_info) * op_array->num_args);
for (i = 0; i < op_array->num_args; i++) {
if (op_array->arg_info[i].name) {
//??? ADD_INTERNED_STRING(op_array->arg_info[i].name, op_array->arg_info[i].name_len + 1);
ADD_SIZE(op_array->arg_info[i].name_len + 1);
ADD_INTERNED_STRING(op_array->arg_info[i].name, 1);
}
if (op_array->arg_info[i].class_name) {
//??? ADD_INTERNED_STRING(op_array->arg_info[i].class_name, op_array->arg_info[i].class_name_len + 1);
ADD_SIZE(op_array->arg_info[i].class_name_len + 1);
ADD_INTERNED_STRING(op_array->arg_info[i].class_name, 1);
}

}
Expand Down
2 changes: 1 addition & 1 deletion ext/pdo/pdo_dbh.c
Expand Up @@ -1300,7 +1300,7 @@ int pdo_hash_methods(pdo_dbh_object_t *dbh_obj, int kind TSRMLS_DC)
if (funcs->arg_info) {
zend_internal_function_info *info = (zend_internal_function_info*)funcs->arg_info;

ifunc->arg_info = (zend_arg_info*)funcs->arg_info + 1;
ifunc->arg_info = (zend_internal_arg_info*)funcs->arg_info + 1;
ifunc->num_args = funcs->num_args;
if (info->required_num_args == -1) {
ifunc->required_num_args = funcs->num_args;
Expand Down

0 comments on commit 5dd427e

Please sign in to comment.