@@ -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 ));
@@ -551,6 +559,9 @@ static zend_ast *zp_compile_forwarding_call(
551559 default_value_ast = zend_ast_create_zval (& default_value );
552560 }
553561 args_ast = zend_ast_list_add (args_ast , default_value_ast );
562+ } else if (zp_is_const_arg (const_args , offset )) {
563+ ZEND_ASSERT (Z_TYPE (argv [offset ]) < IS_OBJECT );
564+ args_ast = zend_ast_list_add (args_ast , zend_ast_create_zval (& argv [offset ]));
554565 } else {
555566 args_ast = zend_ast_list_add (args_ast , zend_ast_create (ZEND_AST_VAR ,
556567 zend_ast_create_zval_from_str (zend_string_copy (var_names -> params [offset ]))));
@@ -661,7 +672,7 @@ static zend_op_array *zp_compile(zval *this_ptr, zend_function *function,
661672 const zend_array * named_positions ,
662673 zend_string * declaring_filename ,
663674 const uint32_t * declaring_lineno_ptr , void * * cache_slot ,
664- zend_string * pfa_name , uint32_t flags ) {
675+ zend_string * pfa_name , uint32_t flags , uint32_t const_args ) {
665676
666677 zend_op_array * op_array = NULL ;
667678
@@ -771,7 +782,7 @@ static zend_op_array *zp_compile(zval *this_ptr, zend_function *function,
771782 /* Assign variable names */
772783
773784 zp_names * var_names = zp_assign_names (argc , argv , function ,
774- uses_variadic_placeholder , extra_named_params );
785+ uses_variadic_placeholder , extra_named_params , const_args );
775786
776787 /* Generate AST */
777788
@@ -825,15 +836,17 @@ static zend_op_array *zp_compile(zval *this_ptr, zend_function *function,
825836 default_value_ast , attributes_ast , NULL , NULL );
826837
827838 } else if (!Z_ISUNDEF (argv [offset ])) {
828- // TODO: If the pre-bound parameter is a literal, it can be a
829- // literal in the function body instead of a lexical var.
830- zend_ast * lexical_var_ast = zend_ast_create_zval_from_str (
831- zend_string_copy (var_names -> params [offset ]));
832- if (zp_arg_must_be_sent_by_ref (function , offset + 1 )) {
833- lexical_var_ast -> attr = ZEND_BIND_REF ;
839+ if (zp_is_const_arg (const_args , offset )) {
840+ /* Will be burned into the op_array */
841+ } else {
842+ zend_ast * lexical_var_ast = zend_ast_create_zval_from_str (
843+ zend_string_copy (var_names -> params [offset ]));
844+ if (zp_arg_must_be_sent_by_ref (function , offset + 1 )) {
845+ lexical_var_ast -> attr = ZEND_BIND_REF ;
846+ }
847+ lexical_vars_ast = zend_ast_list_add (
848+ lexical_vars_ast , lexical_var_ast );
834849 }
835- lexical_vars_ast = zend_ast_list_add (
836- lexical_vars_ast , lexical_var_ast );
837850 }
838851 }
839852
@@ -894,7 +907,7 @@ static zend_op_array *zp_compile(zval *this_ptr, zend_function *function,
894907 no_forwarding_ast = zp_compile_forwarding_call (this_ptr , function ,
895908 argc , argv , extra_named_params ,
896909 var_names , uses_variadic_placeholder , num_params ,
897- called_scope , return_type , false, no_forwarding_ast );
910+ called_scope , return_type , false, no_forwarding_ast , const_args );
898911
899912 if (!no_forwarding_ast ) {
900913 ZEND_ASSERT (EG (exception ));
@@ -904,7 +917,7 @@ static zend_op_array *zp_compile(zval *this_ptr, zend_function *function,
904917 forwarding_ast = zp_compile_forwarding_call (this_ptr , function ,
905918 argc , argv , extra_named_params ,
906919 var_names , uses_variadic_placeholder , num_params ,
907- called_scope , return_type , true, forwarding_ast );
920+ called_scope , return_type , true, forwarding_ast , const_args );
908921
909922 if (!forwarding_ast ) {
910923 ZEND_ASSERT (EG (exception ));
@@ -931,7 +944,7 @@ static zend_op_array *zp_compile(zval *this_ptr, zend_function *function,
931944 stmts_ast = zp_compile_forwarding_call (this_ptr , function ,
932945 argc , argv , extra_named_params ,
933946 var_names , uses_variadic_placeholder , num_params ,
934- called_scope , return_type , false, stmts_ast );
947+ called_scope , return_type , false, stmts_ast , const_args );
935948
936949 if (!stmts_ast ) {
937950 ZEND_ASSERT (EG (exception ));
@@ -1000,7 +1013,7 @@ static const zend_op_array *zp_get_op_array(zval *this_ptr, zend_function *funct
10001013 const zend_array * named_positions ,
10011014 zend_string * declaring_filename ,
10021015 const uint32_t * declaring_lineno_ptr , void * * cache_slot ,
1003- zend_string * pfa_name , uint32_t flags ) {
1016+ zend_string * pfa_name , uint32_t flags , uint32_t const_args ) {
10041017
10051018 if (EXPECTED (function -> type == ZEND_INTERNAL_FUNCTION
10061019 ? cache_slot [0 ] == function
@@ -1015,7 +1028,7 @@ static const zend_op_array *zp_get_op_array(zval *this_ptr, zend_function *funct
10151028 if (UNEXPECTED (!op_array )) {
10161029 op_array = zp_compile (this_ptr , function , argc , argv ,
10171030 extra_named_params , named_positions , declaring_filename , declaring_lineno_ptr ,
1018- cache_slot , pfa_name , flags );
1031+ cache_slot , pfa_name , flags , const_args );
10191032 }
10201033
10211034 if (EXPECTED (op_array ) && !(function -> common .fn_flags & ZEND_ACC_NEVER_CACHE )) {
@@ -1037,7 +1050,7 @@ static void zp_free_unbound_args(uint32_t start, uint32_t argc, zval *argv)
10371050
10381051/* Bind pre-bound arguments as lexical vars */
10391052static void zp_bind (zval * result , zend_function * function , uint32_t argc , zval * argv ,
1040- zend_array * extra_named_params ) {
1053+ zend_array * extra_named_params , uint32_t const_args ) {
10411054
10421055 zend_arg_info * arg_infos = function -> common .arg_info ;
10431056 uint32_t bind_offset = 0 ;
@@ -1052,7 +1065,7 @@ static void zp_bind(zval *result, zend_function *function, uint32_t argc, zval *
10521065
10531066 for (uint32_t offset = 0 ; offset < argc ; offset ++ ) {
10541067 zval * var = & argv [offset ];
1055- if (Z_IS_PLACEHOLDER_P (var ) || Z_ISUNDEF_P (var )) {
1068+ if (Z_IS_PLACEHOLDER_P (var ) || Z_ISUNDEF_P (var ) || zp_is_const_arg ( const_args , offset ) ) {
10561069 continue ;
10571070 }
10581071 zend_arg_info * arg_info ;
@@ -1095,14 +1108,14 @@ void zend_partial_create(zval *result, zval *this_ptr, zend_function *function,
10951108 const zend_array * named_positions ,
10961109 zend_string * declaring_filename ,
10971110 const uint32_t * declaring_lineno_ptr , void * * cache_slot ,
1098- zend_string * pfa_name , uint32_t flags ) {
1111+ zend_string * pfa_name , uint32_t flags , uint32_t const_args ) {
10991112
11001113 ZEND_ASSERT (pfa_name );
11011114
11021115 const zend_op_array * op_array = zp_get_op_array (this_ptr , function , argc , argv ,
11031116 extra_named_params , named_positions ,
11041117 declaring_filename , declaring_lineno_ptr ,
1105- cache_slot , pfa_name , flags );
1118+ cache_slot , pfa_name , flags , const_args );
11061119
11071120 if (UNEXPECTED (!op_array )) {
11081121 ZEND_ASSERT (EG (exception ));
@@ -1130,7 +1143,7 @@ void zend_partial_create(zval *result, zval *this_ptr, zend_function *function,
11301143 function -> common .scope , called_scope , & object ,
11311144 (function -> common .fn_flags & ZEND_ACC_CLOSURE ) != 0 );
11321145
1133- zp_bind (result , function , argc , argv , extra_named_params );
1146+ zp_bind (result , function , argc , argv , extra_named_params , const_args );
11341147}
11351148
11361149void zend_partial_op_array_dtor (zval * pDest )
0 commit comments