@@ -66,6 +66,14 @@ static zend_always_inline bool zp_is_non_static_closure(const zend_function *fun
6666 return ((function -> common .fn_flags & (ZEND_ACC_STATIC |ZEND_ACC_CLOSURE )) == ZEND_ACC_CLOSURE );
6767}
6868
69+ /* Whether argument at offset 'offset' is const. Such arguments can be burned into the generated op_array */
70+ static inline bool zp_is_const_arg (uint32_t const_args , uint32_t offset ) {
71+ if (offset < sizeof (const_args ) * CHAR_BIT ) {
72+ return const_args & (1 << offset );
73+ }
74+ return false;
75+ }
76+
6977static zend_never_inline ZEND_COLD void zp_args_underflow (
7078 const zend_function * function , uint32_t args , uint32_t expected )
7179{
@@ -179,7 +187,7 @@ static zend_string *zp_get_func_param_name(const zend_function *function, uint32
179187 * including params and used vars. */
180188static zp_names * zp_assign_names (uint32_t argc , zval * argv ,
181189 zend_function * function , bool variadic_partial ,
182- zend_array * extra_named_params )
190+ zend_array * extra_named_params , uint32_t const_args )
183191{
184192 zp_names * names = zend_arena_calloc (& CG (ast_arena ),
185193 1 , zend_safe_address_guarded (argc , sizeof (* names -> params ), offsetof(zp_names , params )));
@@ -226,7 +234,7 @@ static zp_names *zp_assign_names(uint32_t argc, zval *argv,
226234 /* Assign names for pre-bound params (lexical vars).
227235 * There may be clashes, we ensure to generate unique names. */
228236 for (uint32_t offset = 0 ; offset < argc ; offset ++ ) {
229- if (Z_IS_PLACEHOLDER_P (& argv [offset ]) || Z_ISUNDEF (argv [offset ])) {
237+ if (Z_IS_PLACEHOLDER_P (& argv [offset ]) || Z_ISUNDEF (argv [offset ]) || zp_is_const_arg ( const_args , offset ) ) {
230238 continue ;
231239 }
232240 uint32_t n = 2 ;
@@ -510,7 +518,7 @@ static zend_ast *zp_compile_forwarding_call(
510518 zp_names * var_names , bool uses_variadic_placeholder , uint32_t num_args ,
511519 zend_class_entry * called_scope , zend_type return_type ,
512520 bool forward_superfluous_args ,
513- zend_ast * stmts_ast )
521+ zend_ast * stmts_ast , uint32_t const_args )
514522{
515523 bool is_assert = zend_string_equals (function -> common .function_name ,
516524 ZSTR_KNOWN (ZEND_STR_ASSERT ));
@@ -550,6 +558,9 @@ static zend_ast *zp_compile_forwarding_call(
550558 default_value_ast = zend_ast_create_zval (& default_value );
551559 }
552560 args_ast = zend_ast_list_add (args_ast , default_value_ast );
561+ } else if (zp_is_const_arg (const_args , offset )) {
562+ ZEND_ASSERT (Z_TYPE (argv [offset ]) < IS_OBJECT );
563+ args_ast = zend_ast_list_add (args_ast , zend_ast_create_zval (& argv [offset ]));
553564 } else {
554565 args_ast = zend_ast_list_add (args_ast , zend_ast_create (ZEND_AST_VAR ,
555566 zend_ast_create_zval_from_str (zend_string_copy (var_names -> params [offset ]))));
@@ -660,7 +671,7 @@ static zend_op_array *zp_compile(zval *this_ptr, zend_function *function,
660671 const zend_array * named_positions ,
661672 zend_string * declaring_filename ,
662673 const uint32_t * declaring_lineno_ptr , void * * cache_slot ,
663- zend_string * pfa_name , uint32_t flags ) {
674+ zend_string * pfa_name , uint32_t flags , uint32_t const_args ) {
664675
665676 zend_op_array * op_array = NULL ;
666677
@@ -770,7 +781,7 @@ static zend_op_array *zp_compile(zval *this_ptr, zend_function *function,
770781 /* Assign variable names */
771782
772783 zp_names * var_names = zp_assign_names (argc , argv , function ,
773- uses_variadic_placeholder , extra_named_params );
784+ uses_variadic_placeholder , extra_named_params , const_args );
774785
775786 /* Generate AST */
776787
@@ -824,15 +835,17 @@ static zend_op_array *zp_compile(zval *this_ptr, zend_function *function,
824835 default_value_ast , attributes_ast , NULL , NULL );
825836
826837 } else if (!Z_ISUNDEF (argv [offset ])) {
827- // TODO: If the pre-bound parameter is a literal, it can be a
828- // literal in the function body instead of a lexical var.
829- zend_ast * lexical_var_ast = zend_ast_create_zval_from_str (
830- zend_string_copy (var_names -> params [offset ]));
831- if (zp_arg_must_be_sent_by_ref (function , offset + 1 )) {
832- lexical_var_ast -> attr = ZEND_BIND_REF ;
838+ if (zp_is_const_arg (const_args , offset )) {
839+ /* Will be burned into the op_array */
840+ } else {
841+ zend_ast * lexical_var_ast = zend_ast_create_zval_from_str (
842+ zend_string_copy (var_names -> params [offset ]));
843+ if (zp_arg_must_be_sent_by_ref (function , offset + 1 )) {
844+ lexical_var_ast -> attr = ZEND_BIND_REF ;
845+ }
846+ lexical_vars_ast = zend_ast_list_add (
847+ lexical_vars_ast , lexical_var_ast );
833848 }
834- lexical_vars_ast = zend_ast_list_add (
835- lexical_vars_ast , lexical_var_ast );
836849 }
837850 }
838851
@@ -893,7 +906,7 @@ static zend_op_array *zp_compile(zval *this_ptr, zend_function *function,
893906 no_forwarding_ast = zp_compile_forwarding_call (this_ptr , function ,
894907 argc , argv , extra_named_params ,
895908 var_names , uses_variadic_placeholder , num_params ,
896- called_scope , return_type , false, no_forwarding_ast );
909+ called_scope , return_type , false, no_forwarding_ast , const_args );
897910
898911 if (!no_forwarding_ast ) {
899912 ZEND_ASSERT (EG (exception ));
@@ -903,7 +916,7 @@ static zend_op_array *zp_compile(zval *this_ptr, zend_function *function,
903916 forwarding_ast = zp_compile_forwarding_call (this_ptr , function ,
904917 argc , argv , extra_named_params ,
905918 var_names , uses_variadic_placeholder , num_params ,
906- called_scope , return_type , true, forwarding_ast );
919+ called_scope , return_type , true, forwarding_ast , const_args );
907920
908921 if (!forwarding_ast ) {
909922 ZEND_ASSERT (EG (exception ));
@@ -930,7 +943,7 @@ static zend_op_array *zp_compile(zval *this_ptr, zend_function *function,
930943 stmts_ast = zp_compile_forwarding_call (this_ptr , function ,
931944 argc , argv , extra_named_params ,
932945 var_names , uses_variadic_placeholder , num_params ,
933- called_scope , return_type , false, stmts_ast );
946+ called_scope , return_type , false, stmts_ast , const_args );
934947
935948 if (!stmts_ast ) {
936949 ZEND_ASSERT (EG (exception ));
@@ -999,7 +1012,7 @@ static const zend_op_array *zp_get_op_array(zval *this_ptr, zend_function *funct
9991012 const zend_array * named_positions ,
10001013 zend_string * declaring_filename ,
10011014 const uint32_t * declaring_lineno_ptr , void * * cache_slot ,
1002- zend_string * pfa_name , uint32_t flags ) {
1015+ zend_string * pfa_name , uint32_t flags , uint32_t const_args ) {
10031016
10041017 if (EXPECTED (function -> type == ZEND_INTERNAL_FUNCTION
10051018 ? cache_slot [0 ] == function
@@ -1014,7 +1027,7 @@ static const zend_op_array *zp_get_op_array(zval *this_ptr, zend_function *funct
10141027 if (UNEXPECTED (!op_array )) {
10151028 op_array = zp_compile (this_ptr , function , argc , argv ,
10161029 extra_named_params , named_positions , declaring_filename , declaring_lineno_ptr ,
1017- cache_slot , pfa_name , flags );
1030+ cache_slot , pfa_name , flags , const_args );
10181031 }
10191032
10201033 if (EXPECTED (op_array ) && !(function -> common .fn_flags & ZEND_ACC_NEVER_CACHE )) {
@@ -1029,7 +1042,7 @@ static const zend_op_array *zp_get_op_array(zval *this_ptr, zend_function *funct
10291042
10301043/* Bind pre-bound arguments as lexical vars */
10311044static void zp_bind (zval * result , zend_function * function , uint32_t argc , zval * argv ,
1032- zend_array * extra_named_params ) {
1045+ zend_array * extra_named_params , uint32_t const_args ) {
10331046
10341047 zend_arg_info * arg_infos = function -> common .arg_info ;
10351048 uint32_t bind_offset = 0 ;
@@ -1044,7 +1057,7 @@ static void zp_bind(zval *result, zend_function *function, uint32_t argc, zval *
10441057
10451058 for (uint32_t offset = 0 ; offset < argc ; offset ++ ) {
10461059 zval * var = & argv [offset ];
1047- if (Z_IS_PLACEHOLDER_P (var ) || Z_ISUNDEF_P (var )) {
1060+ if (Z_IS_PLACEHOLDER_P (var ) || Z_ISUNDEF_P (var ) || zp_is_const_arg ( const_args , offset ) ) {
10481061 continue ;
10491062 }
10501063 zend_arg_info * arg_info ;
@@ -1080,14 +1093,14 @@ void zend_partial_create(zval *result, zval *this_ptr, zend_function *function,
10801093 const zend_array * named_positions ,
10811094 zend_string * declaring_filename ,
10821095 const uint32_t * declaring_lineno_ptr , void * * cache_slot ,
1083- zend_string * pfa_name , uint32_t flags ) {
1096+ zend_string * pfa_name , uint32_t flags , uint32_t const_args ) {
10841097
10851098 ZEND_ASSERT (pfa_name );
10861099
10871100 const zend_op_array * op_array = zp_get_op_array (this_ptr , function , argc , argv ,
10881101 extra_named_params , named_positions ,
10891102 declaring_filename , declaring_lineno_ptr ,
1090- cache_slot , pfa_name , flags );
1103+ cache_slot , pfa_name , flags , const_args );
10911104
10921105 if (UNEXPECTED (!op_array )) {
10931106 ZEND_ASSERT (EG (exception ));
@@ -1114,7 +1127,7 @@ void zend_partial_create(zval *result, zval *this_ptr, zend_function *function,
11141127 function -> common .scope , called_scope , & object ,
11151128 (function -> common .fn_flags & ZEND_ACC_CLOSURE ) != 0 );
11161129
1117- zp_bind (result , function , argc , argv , extra_named_params );
1130+ zp_bind (result , function , argc , argv , extra_named_params , const_args );
11181131}
11191132
11201133void zend_partial_op_array_dtor (zval * pDest )
0 commit comments