Skip to content

Commit 15a5f61

Browse files
committed
Use fast method to check if first arguments should be passed by reference (not tested onbig endian).
1 parent af33279 commit 15a5f61

11 files changed

+103
-6
lines changed

Zend/zend_API.c

+1
Original file line numberDiff line numberDiff line change
@@ -2232,6 +2232,7 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio
22322232
internal_function->num_args = 0;
22332233
internal_function->required_num_args = 0;
22342234
}
2235+
zend_set_function_arg_flags((zend_function*)internal_function);
22352236
if (ptr->flags & ZEND_ACC_ABSTRACT) {
22362237
if (scope) {
22372238
/* This is a class that must be abstract itself. Here we set the check info. */

Zend/zend_compile.c

+26
Original file line numberDiff line numberDiff line change
@@ -4108,6 +4108,31 @@ void zend_compile_stmt_list(zend_ast *ast) /* {{{ */
41084108
}
41094109
/* }}} */
41104110

4111+
ZEND_API int zend_set_function_arg_flags(zend_function *func) /* {{{ */
4112+
{
4113+
uint32_t i, n;
4114+
4115+
func->common.arg_flags[0] = 0;
4116+
func->common.arg_flags[1] = 0;
4117+
func->common.arg_flags[2] = 0;
4118+
if (func->common.arg_info) {
4119+
n = MIN(func->common.num_args, MAX_ARG_FLAG_NUM);
4120+
i = 0;
4121+
while (i < n) {
4122+
ZEND_SET_ARG_FLAG(func, i + 1, func->common.arg_info[i].pass_by_reference);
4123+
i++;
4124+
}
4125+
if (func->common.fn_flags & ZEND_ACC_VARIADIC) {
4126+
uint32_t pass_by_reference = func->common.arg_info[i].pass_by_reference;
4127+
while (i < MAX_ARG_FLAG_NUM) {
4128+
ZEND_SET_ARG_FLAG(func, i + 1, pass_by_reference);
4129+
i++;
4130+
}
4131+
}
4132+
}
4133+
}
4134+
/* }}} */
4135+
41114136
void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, zend_bool is_method) /* {{{ */
41124137
{
41134138
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_
42944319
if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
42954320
op_array->num_args--;
42964321
}
4322+
zend_set_function_arg_flags((zend_function*)op_array);
42974323
}
42984324
/* }}} */
42994325

Zend/zend_compile.h

+30
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,7 @@ typedef struct _zend_internal_function_info {
334334
struct _zend_op_array {
335335
/* Common elements */
336336
zend_uchar type;
337+
zend_uchar arg_flags[3]; /* bitset of arg_info.pass_by_reference */
337338
uint32_t fn_flags;
338339
zend_string *function_name;
339340
zend_class_entry *scope;
@@ -384,6 +385,7 @@ struct _zend_op_array {
384385
typedef struct _zend_internal_function {
385386
/* Common elements */
386387
zend_uchar type;
388+
zend_uchar arg_flags[3]; /* bitset of arg_info.pass_by_reference */
387389
uint32_t fn_flags;
388390
zend_string* function_name;
389391
zend_class_entry *scope;
@@ -404,6 +406,7 @@ union _zend_function {
404406

405407
struct {
406408
zend_uchar type; /* never used */
409+
zend_uchar arg_flags[3]; /* bitset of arg_info.pass_by_reference */
407410
uint32_t fn_flags;
408411
zend_string *function_name;
409412
zend_class_entry *scope;
@@ -776,6 +779,7 @@ ZEND_API void zend_activate_auto_globals(void);
776779
ZEND_API zend_bool zend_is_auto_global(zend_string *name);
777780
ZEND_API zend_bool zend_is_auto_global_str(char *name, size_t len);
778781
ZEND_API size_t zend_dirname(char *path, size_t len);
782+
ZEND_API int zend_set_function_arg_flags(zend_function *func);
779783

780784
int zendlex(zend_parser_stack_elem *elem);
781785

@@ -910,6 +914,32 @@ static zend_always_inline int zend_check_arg_send_type(const zend_function *zf,
910914
#define ARG_MAY_BE_SENT_BY_REF(zf, arg_num) \
911915
zend_check_arg_send_type(zf, arg_num, ZEND_SEND_PREFER_REF)
912916

917+
/* Quick API to check firat 12 arguments */
918+
#define MAX_ARG_FLAG_NUM 12
919+
920+
#ifdef WORDS_BIGENDIAN
921+
# define ZEND_SET_ARG_FLAG(zf, arg_num, mask) do { \
922+
*(uint32_t*)&(zf)->type |= ((mask) << ((arg_num) - 1) * 2); \
923+
} while (0)
924+
# define ZEND_CHECK_ARG_FLAG(zf, arg_num, mask) \
925+
(((*((uint32_t*)&((zf)->type))) >> (((arg_num) - 1) * 2)) & (mask))
926+
#else
927+
# define ZEND_SET_ARG_FLAG(zf, arg_num, mask) do { \
928+
*(uint32_t*)&(zf)->type |= (((mask) << 6) << (arg_num) * 2); \
929+
} while (0)
930+
# define ZEND_CHECK_ARG_FLAG(zf, arg_num, mask) \
931+
(((*(uint32_t*)&(zf)->type) >> (((arg_num) + 3) * 2)) & (mask))
932+
#endif
933+
934+
#define QUICK_ARG_MUST_BE_SENT_BY_REF(zf, arg_num) \
935+
ZEND_CHECK_ARG_FLAG(zf, arg_num, ZEND_SEND_BY_REF)
936+
937+
#define QUICK_ARG_SHOULD_BE_SENT_BY_REF(zf, arg_num) \
938+
ZEND_CHECK_ARG_FLAG(zf, arg_num, ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF)
939+
940+
#define QUICK_ARG_MAY_BE_SENT_BY_REF(zf, arg_num) \
941+
ZEND_CHECK_ARG_FLAG(zf, arg_num, ZEND_SEND_PREFER_REF)
942+
913943
#define ZEND_RETURN_VAL 0
914944
#define ZEND_RETURN_REF 1
915945

Zend/zend_execute.c

+1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ static ZEND_FUNCTION(pass)
7272

7373
static const zend_internal_function zend_pass_function = {
7474
ZEND_INTERNAL_FUNCTION, /* type */
75+
{0, 0, 0}, /* arg_flags */
7576
0, /* fn_flags */
7677
NULL, /* name */
7778
NULL, /* scope */

Zend/zend_object_handlers.c

+3
Original file line numberDiff line numberDiff line change
@@ -1007,6 +1007,9 @@ ZEND_API zend_function *zend_get_call_trampoline_func(zend_class_entry *ce, zend
10071007
}
10081008

10091009
func->type = ZEND_USER_FUNCTION;
1010+
func->arg_flags[0] = 0;
1011+
func->arg_flags[1] = 0;
1012+
func->arg_flags[2] = 0;
10101013
func->fn_flags = ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_PUBLIC;
10111014
if (is_static) {
10121015
func->fn_flags |= ZEND_ACC_STATIC;

Zend/zend_opcode.c

+3
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ static void op_array_alloc_ops(zend_op_array *op_array, uint32_t size)
5151
void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_size)
5252
{
5353
op_array->type = type;
54+
op_array->arg_flags[0] = 0;
55+
op_array->arg_flags[1] = 0;
56+
op_array->arg_flags[2] = 0;
5457

5558
op_array->refcount = (uint32_t *) emalloc(sizeof(uint32_t));
5659
*op_array->refcount = 1;

Zend/zend_vm_def.h

+12-2
Original file line numberDiff line numberDiff line change
@@ -4085,7 +4085,12 @@ ZEND_VM_HANDLER(116, ZEND_SEND_VAL_EX, CONST|TMP, ANY)
40854085
zval *value, *arg;
40864086
zend_free_op free_op1;
40874087

4088-
if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
4088+
if (EXPECTED(opline->op2.num <= MAX_ARG_FLAG_NUM)) {
4089+
if (QUICK_ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
4090+
ZEND_VM_C_GOTO(send_val_by_ref);
4091+
}
4092+
} else if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
4093+
ZEND_VM_C_LABEL(send_val_by_ref):
40894094
SAVE_OPLINE();
40904095
zend_error(E_EXCEPTION | E_ERROR, "Cannot pass parameter %d by reference", opline->op2.num);
40914096
FREE_UNFETCHED_OP1();
@@ -4225,7 +4230,12 @@ ZEND_VM_HANDLER(66, ZEND_SEND_VAR_EX, VAR|CV, ANY)
42254230
zval *varptr, *arg;
42264231
zend_free_op free_op1;
42274232

4228-
if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
4233+
if (EXPECTED(opline->op2.num <= MAX_ARG_FLAG_NUM)) {
4234+
if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
4235+
ZEND_VM_C_GOTO(send_var_by_ref);
4236+
}
4237+
} else if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
4238+
ZEND_VM_C_LABEL(send_var_by_ref):
42294239
ZEND_VM_DISPATCH_TO_HANDLER(ZEND_SEND_REF);
42304240
}
42314241

Zend/zend_vm_execute.h

+24-4
Original file line numberDiff line numberDiff line change
@@ -3215,7 +3215,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAL_EX_SPEC_CONST_HANDLER
32153215
zval *value, *arg;
32163216

32173217

3218-
if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
3218+
if (EXPECTED(opline->op2.num <= MAX_ARG_FLAG_NUM)) {
3219+
if (QUICK_ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
3220+
goto send_val_by_ref;
3221+
}
3222+
} else if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
3223+
send_val_by_ref:
32193224
SAVE_OPLINE();
32203225
zend_error(E_EXCEPTION | E_ERROR, "Cannot pass parameter %d by reference", opline->op2.num);
32213226

@@ -11466,7 +11471,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAL_EX_SPEC_TMP_HANDLER(Z
1146611471
zval *value, *arg;
1146711472
zend_free_op free_op1;
1146811473

11469-
if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
11474+
if (EXPECTED(opline->op2.num <= MAX_ARG_FLAG_NUM)) {
11475+
if (QUICK_ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
11476+
goto send_val_by_ref;
11477+
}
11478+
} else if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
11479+
send_val_by_ref:
1147011480
SAVE_OPLINE();
1147111481
zend_error(E_EXCEPTION | E_ERROR, "Cannot pass parameter %d by reference", opline->op2.num);
1147211482
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
1470314713
zval *varptr, *arg;
1470414714
zend_free_op free_op1;
1470514715

14706-
if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
14716+
if (EXPECTED(opline->op2.num <= MAX_ARG_FLAG_NUM)) {
14717+
if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
14718+
goto send_var_by_ref;
14719+
}
14720+
} else if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
14721+
send_var_by_ref:
1470714722
return ZEND_SEND_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
1470814723
}
1470914724

@@ -28441,7 +28456,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_EX_SPEC_CV_HANDLER(ZE
2844128456
zval *varptr, *arg;
2844228457

2844328458

28444-
if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
28459+
if (EXPECTED(opline->op2.num <= MAX_ARG_FLAG_NUM)) {
28460+
if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
28461+
goto send_var_by_ref;
28462+
}
28463+
} else if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
28464+
send_var_by_ref:
2844528465
return ZEND_SEND_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
2844628466
}
2844728467

ext/com_dotnet/com_handlers.c

+1
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@ static union _zend_function *com_method_get(zend_object **object_ptr, zend_strin
279279
f.fn_flags = ZEND_ACC_CALL_VIA_HANDLER;
280280
f.function_name = zend_string_copy(name);
281281
f.handler = PHP_FN(com_method_handler);
282+
zend_set_function_arg_flags((zend_function*)&f);
282283

283284
fptr = &f;
284285

ext/pdo/pdo_dbh.c

+1
Original file line numberDiff line numberDiff line change
@@ -1319,6 +1319,7 @@ int pdo_hash_methods(pdo_dbh_object_t *dbh_obj, int kind)
13191319
ifunc->num_args = 0;
13201320
ifunc->required_num_args = 0;
13211321
}
1322+
zend_set_function_arg_flags((zend_function*)ifunc);
13221323
namelen = strlen(funcs->fname);
13231324
lc_name = emalloc(namelen+1);
13241325
zend_str_tolower_copy(lc_name, funcs->fname, namelen);

ext/soap/soap.c

+1
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,7 @@ PHP_MINIT_FUNCTION(soap)
668668
fe.prototype = NULL;
669669
fe.num_args = 2;
670670
fe.arg_info = NULL;
671+
zend_set_function_arg_flags((zend_function*)&fe);
671672

672673
INIT_OVERLOADED_CLASS_ENTRY(ce, PHP_SOAP_CLIENT_CLASSNAME, soap_client_functions,
673674
(zend_function *)&fe, NULL, NULL);

0 commit comments

Comments
 (0)