internal_function->num_args = 0;
internal_function->required_num_args = 0;
}
+ zend_set_function_arg_flags((zend_function*)internal_function);
if (ptr->flags & ZEND_ACC_ABSTRACT) {
if (scope) {
/* This is a class that must be abstract itself. Here we set the check info. */
}
/* }}} */
+ZEND_API int zend_set_function_arg_flags(zend_function *func) /* {{{ */
+{
+ uint32_t i, n;
+
+ func->common.arg_flags[0] = 0;
+ func->common.arg_flags[1] = 0;
+ func->common.arg_flags[2] = 0;
+ if (func->common.arg_info) {
+ n = MIN(func->common.num_args, MAX_ARG_FLAG_NUM);
+ i = 0;
+ while (i < n) {
+ ZEND_SET_ARG_FLAG(func, i + 1, func->common.arg_info[i].pass_by_reference);
+ i++;
+ }
+ if (func->common.fn_flags & ZEND_ACC_VARIADIC) {
+ uint32_t pass_by_reference = func->common.arg_info[i].pass_by_reference;
+ while (i < MAX_ARG_FLAG_NUM) {
+ ZEND_SET_ARG_FLAG(func, i + 1, pass_by_reference);
+ i++;
+ }
+ }
+ }
+}
+/* }}} */
+
void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, zend_bool is_method) /* {{{ */
{
zend_ast_list *list = zend_ast_get_list(ast);
if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
op_array->num_args--;
}
+ zend_set_function_arg_flags((zend_function*)op_array);
}
/* }}} */
struct _zend_op_array {
/* Common elements */
zend_uchar type;
+ zend_uchar arg_flags[3]; /* bitset of arg_info.pass_by_reference */
uint32_t fn_flags;
zend_string *function_name;
zend_class_entry *scope;
typedef struct _zend_internal_function {
/* Common elements */
zend_uchar type;
+ zend_uchar arg_flags[3]; /* bitset of arg_info.pass_by_reference */
uint32_t fn_flags;
zend_string* function_name;
zend_class_entry *scope;
struct {
zend_uchar type; /* never used */
+ zend_uchar arg_flags[3]; /* bitset of arg_info.pass_by_reference */
uint32_t fn_flags;
zend_string *function_name;
zend_class_entry *scope;
ZEND_API zend_bool zend_is_auto_global(zend_string *name);
ZEND_API zend_bool zend_is_auto_global_str(char *name, size_t len);
ZEND_API size_t zend_dirname(char *path, size_t len);
+ZEND_API int zend_set_function_arg_flags(zend_function *func);
int zendlex(zend_parser_stack_elem *elem);
#define ARG_MAY_BE_SENT_BY_REF(zf, arg_num) \
zend_check_arg_send_type(zf, arg_num, ZEND_SEND_PREFER_REF)
+/* Quick API to check firat 12 arguments */
+#define MAX_ARG_FLAG_NUM 12
+
+#ifdef WORDS_BIGENDIAN
+# define ZEND_SET_ARG_FLAG(zf, arg_num, mask) do { \
+ *(uint32_t*)&(zf)->type |= ((mask) << ((arg_num) - 1) * 2); \
+ } while (0)
+# define ZEND_CHECK_ARG_FLAG(zf, arg_num, mask) \
+ (((*((uint32_t*)&((zf)->type))) >> (((arg_num) - 1) * 2)) & (mask))
+#else
+# define ZEND_SET_ARG_FLAG(zf, arg_num, mask) do { \
+ *(uint32_t*)&(zf)->type |= (((mask) << 6) << (arg_num) * 2); \
+ } while (0)
+# define ZEND_CHECK_ARG_FLAG(zf, arg_num, mask) \
+ (((*(uint32_t*)&(zf)->type) >> (((arg_num) + 3) * 2)) & (mask))
+#endif
+
+#define QUICK_ARG_MUST_BE_SENT_BY_REF(zf, arg_num) \
+ ZEND_CHECK_ARG_FLAG(zf, arg_num, ZEND_SEND_BY_REF)
+
+#define QUICK_ARG_SHOULD_BE_SENT_BY_REF(zf, arg_num) \
+ ZEND_CHECK_ARG_FLAG(zf, arg_num, ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF)
+
+#define QUICK_ARG_MAY_BE_SENT_BY_REF(zf, arg_num) \
+ ZEND_CHECK_ARG_FLAG(zf, arg_num, ZEND_SEND_PREFER_REF)
+
#define ZEND_RETURN_VAL 0
#define ZEND_RETURN_REF 1
static const zend_internal_function zend_pass_function = {
ZEND_INTERNAL_FUNCTION, /* type */
+ {0, 0, 0}, /* arg_flags */
0, /* fn_flags */
NULL, /* name */
NULL, /* scope */
}
func->type = ZEND_USER_FUNCTION;
+ func->arg_flags[0] = 0;
+ func->arg_flags[1] = 0;
+ func->arg_flags[2] = 0;
func->fn_flags = ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_PUBLIC;
if (is_static) {
func->fn_flags |= ZEND_ACC_STATIC;
void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_size)
{
op_array->type = type;
+ op_array->arg_flags[0] = 0;
+ op_array->arg_flags[1] = 0;
+ op_array->arg_flags[2] = 0;
op_array->refcount = (uint32_t *) emalloc(sizeof(uint32_t));
*op_array->refcount = 1;
zval *value, *arg;
zend_free_op free_op1;
- if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
+ if (EXPECTED(opline->op2.num <= MAX_ARG_FLAG_NUM)) {
+ if (QUICK_ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
+ ZEND_VM_C_GOTO(send_val_by_ref);
+ }
+ } else if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
+ZEND_VM_C_LABEL(send_val_by_ref):
SAVE_OPLINE();
zend_error(E_EXCEPTION | E_ERROR, "Cannot pass parameter %d by reference", opline->op2.num);
FREE_UNFETCHED_OP1();
zval *varptr, *arg;
zend_free_op free_op1;
- if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
+ if (EXPECTED(opline->op2.num <= MAX_ARG_FLAG_NUM)) {
+ if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
+ ZEND_VM_C_GOTO(send_var_by_ref);
+ }
+ } else if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
+ZEND_VM_C_LABEL(send_var_by_ref):
ZEND_VM_DISPATCH_TO_HANDLER(ZEND_SEND_REF);
}
zval *value, *arg;
- if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
+ if (EXPECTED(opline->op2.num <= MAX_ARG_FLAG_NUM)) {
+ if (QUICK_ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
+ goto send_val_by_ref;
+ }
+ } else if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
+send_val_by_ref:
SAVE_OPLINE();
zend_error(E_EXCEPTION | E_ERROR, "Cannot pass parameter %d by reference", opline->op2.num);
zval *value, *arg;
zend_free_op free_op1;
- if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
+ if (EXPECTED(opline->op2.num <= MAX_ARG_FLAG_NUM)) {
+ if (QUICK_ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
+ goto send_val_by_ref;
+ }
+ } else if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
+send_val_by_ref:
SAVE_OPLINE();
zend_error(E_EXCEPTION | E_ERROR, "Cannot pass parameter %d by reference", opline->op2.num);
zval_ptr_dtor_nogc(EX_VAR(opline->op1.var));
zval *varptr, *arg;
zend_free_op free_op1;
- if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
+ if (EXPECTED(opline->op2.num <= MAX_ARG_FLAG_NUM)) {
+ if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
+ goto send_var_by_ref;
+ }
+ } else if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
+send_var_by_ref:
return ZEND_SEND_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
}
zval *varptr, *arg;
- if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
+ if (EXPECTED(opline->op2.num <= MAX_ARG_FLAG_NUM)) {
+ if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
+ goto send_var_by_ref;
+ }
+ } else if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
+send_var_by_ref:
return ZEND_SEND_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
}
f.fn_flags = ZEND_ACC_CALL_VIA_HANDLER;
f.function_name = zend_string_copy(name);
f.handler = PHP_FN(com_method_handler);
+ zend_set_function_arg_flags((zend_function*)&f);
fptr = &f;
ifunc->num_args = 0;
ifunc->required_num_args = 0;
}
+ zend_set_function_arg_flags((zend_function*)ifunc);
namelen = strlen(funcs->fname);
lc_name = emalloc(namelen+1);
zend_str_tolower_copy(lc_name, funcs->fname, namelen);
fe.prototype = NULL;
fe.num_args = 2;
fe.arg_info = NULL;
+ zend_set_function_arg_flags((zend_function*)&fe);
INIT_OVERLOADED_CLASS_ENTRY(ce, PHP_SOAP_CLIENT_CLASSNAME, soap_client_functions,
(zend_function *)&fe, NULL, NULL);