]> granicus.if.org Git - php/commitdiff
Use fast method to check if first arguments should be passed by reference (not tested...
authorDmitry Stogov <dmitry@zend.com>
Wed, 22 Apr 2015 18:46:13 +0000 (21:46 +0300)
committerDmitry Stogov <dmitry@zend.com>
Wed, 22 Apr 2015 18:46:13 +0000 (21:46 +0300)
Zend/zend_API.c
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_execute.c
Zend/zend_object_handlers.c
Zend/zend_opcode.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
ext/com_dotnet/com_handlers.c
ext/pdo/pdo_dbh.c
ext/soap/soap.c

index e6c8e56d86d19a170b663100d2b6054b760b6d07..dc517138073dd54225268761c56fb03288b3c38c 100644 (file)
@@ -2232,6 +2232,7 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio
                        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. */
index aeba6a94029f3065e5a05f82cb1519b04230531f..ff22e0ceb3feb5ea8ea31dcdf8ca62b23974eb30 100644 (file)
@@ -4108,6 +4108,31 @@ void zend_compile_stmt_list(zend_ast *ast) /* {{{ */
 }
 /* }}} */
 
+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);
@@ -4294,6 +4319,7 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, zend_bool is_
        if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
                op_array->num_args--;
        }
+       zend_set_function_arg_flags((zend_function*)op_array);
 }
 /* }}} */
 
index 4b3d0a25b2b2c8ef097bb75a00577ffebfadbc56..6ae1cd5f456a95eacb8936de6100ebeaa1918b33 100644 (file)
@@ -334,6 +334,7 @@ typedef struct _zend_internal_function_info {
 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;
@@ -384,6 +385,7 @@ struct _zend_op_array {
 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;
@@ -404,6 +406,7 @@ union _zend_function {
 
        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;
@@ -776,6 +779,7 @@ ZEND_API void zend_activate_auto_globals(void);
 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);
 
@@ -910,6 +914,32 @@ static zend_always_inline int zend_check_arg_send_type(const zend_function *zf,
 #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
 
index eb37d48522b3d191c813d6ac9f7b5c379b1af0c8..ffeba914e6665b1a04b15a85689303e864607f23 100644 (file)
@@ -72,6 +72,7 @@ static ZEND_FUNCTION(pass)
 
 static const zend_internal_function zend_pass_function = {
        ZEND_INTERNAL_FUNCTION, /* type              */
+       {0, 0, 0},              /* arg_flags         */
        0,                      /* fn_flags          */
        NULL,                   /* name              */
        NULL,                   /* scope             */
index 679a104a59019adc81a3d063420b9139ddd210b7..a14f60080b2751b5442296c5ae4554731fe77bb9 100644 (file)
@@ -1007,6 +1007,9 @@ ZEND_API zend_function *zend_get_call_trampoline_func(zend_class_entry *ce, zend
        }
 
        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;
index 35c42fe4d70dbdc499e1acd93db7590ea134102e..8bdaded38f94aaf11f82a179a13df16c711c9f0b 100644 (file)
@@ -51,6 +51,9 @@ static void op_array_alloc_ops(zend_op_array *op_array, uint32_t size)
 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;
index 79b2f70133269756f25b2c98143d87d01366d7b9..16d3a23a16878ae341da394ebbbf7188008164e2 100644 (file)
@@ -4085,7 +4085,12 @@ ZEND_VM_HANDLER(116, ZEND_SEND_VAL_EX, CONST|TMP, ANY)
        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();
@@ -4225,7 +4230,12 @@ ZEND_VM_HANDLER(66, ZEND_SEND_VAR_EX, VAR|CV, ANY)
        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);
        }
 
index 27be74d6e1e3a463d87f65a7caf68e37bbcf8ea7..0472feb379035a86d394b4af50e1072a40512057 100644 (file)
@@ -3215,7 +3215,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAL_EX_SPEC_CONST_HANDLER
        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);
 
@@ -11466,7 +11471,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAL_EX_SPEC_TMP_HANDLER(Z
        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));
@@ -14703,7 +14713,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_EX_SPEC_VAR_HANDLER(Z
        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);
        }
 
@@ -28441,7 +28456,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_EX_SPEC_CV_HANDLER(ZE
        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);
        }
 
index 66983d1b34f11102cd964cc0a3d829c5a76dc873..ec5c70defaa6414ade047a31b611a0314b08354d 100644 (file)
@@ -279,6 +279,7 @@ static union _zend_function *com_method_get(zend_object **object_ptr, zend_strin
                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;
 
index 9029e4a8ea5209b86fed9776b7c2e95555a2aee3..8189473524c6400a99d2ad9b3adb6bcf1de495f8 100644 (file)
@@ -1319,6 +1319,7 @@ int pdo_hash_methods(pdo_dbh_object_t *dbh_obj, int kind)
                        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);
index 883e0ac541fe3c3f7a8d1a3db5a91822df86ab5e..120274b272244c3973adfc1b13f3de3841243a83 100644 (file)
@@ -668,6 +668,7 @@ PHP_MINIT_FUNCTION(soap)
                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);