@@ -328,6 +328,7 @@ typedef struct _zend_fcall_info_cache {
328
328
zend_class_backed_enum_table(ce)
329
329
330
330
#define ZEND_FCI_INITIALIZED (fci ) ((fci).size != 0)
331
+ #define ZEND_FCC_INITIALIZED (fcc ) ((fcc).function_handler != NULL)
331
332
332
333
ZEND_API int zend_next_free_module (void );
333
334
@@ -729,6 +730,57 @@ ZEND_API void zend_fcall_info_argn(zend_fcall_info *fci, uint32_t argc, ...);
729
730
*/
730
731
ZEND_API zend_result zend_fcall_info_call (zend_fcall_info * fci , zend_fcall_info_cache * fcc , zval * retval , zval * args );
731
732
733
+ /* Zend FCC API to store and handle PHP userland functions */
734
+ static zend_always_inline bool zend_fcc_equals (const zend_fcall_info_cache * a , const zend_fcall_info_cache * b )
735
+ {
736
+ return a -> function_handler == b -> function_handler
737
+ && a -> object == b -> object
738
+ && a -> calling_scope == b -> calling_scope
739
+ && a -> closure == b -> closure
740
+ ;
741
+ }
742
+
743
+ static zend_always_inline void zend_fcc_addref (zend_fcall_info_cache * fcc )
744
+ {
745
+ if (fcc -> object ) {
746
+ GC_ADDREF (fcc -> object );
747
+ }
748
+ if (fcc -> closure ) {
749
+ GC_ADDREF (fcc -> closure );
750
+ }
751
+ }
752
+
753
+ static zend_always_inline void zend_fcc_dup (/* restrict */ zend_fcall_info_cache * dest , const zend_fcall_info_cache * src )
754
+ {
755
+ memcpy (dest , src , sizeof (zend_fcall_info_cache ));
756
+ zend_fcc_addref (dest );
757
+ }
758
+
759
+ static zend_always_inline void zend_fcc_dtor (zend_fcall_info_cache * fcc )
760
+ {
761
+ if (fcc -> object ) {
762
+ OBJ_RELEASE (fcc -> object );
763
+ }
764
+ if (fcc -> closure ) {
765
+ OBJ_RELEASE (fcc -> closure );
766
+ }
767
+ memcpy (fcc , & empty_fcall_info_cache , sizeof (zend_fcall_info_cache ));
768
+ }
769
+
770
+ ZEND_API void zend_get_callable_zval_from_fcc (const zend_fcall_info_cache * fcc , zval * callable );
771
+
772
+ /* Moved out of zend_gc.h because zend_fcall_info_cache is an unknown type in that header */
773
+ static zend_always_inline void zend_get_gc_buffer_add_fcc (zend_get_gc_buffer * gc_buffer , zend_fcall_info_cache * fcc )
774
+ {
775
+ ZEND_ASSERT (ZEND_FCC_INITIALIZED (* fcc ));
776
+ if (fcc -> object ) {
777
+ zend_get_gc_buffer_add_obj (gc_buffer , fcc -> object );
778
+ }
779
+ if (fcc -> closure ) {
780
+ zend_get_gc_buffer_add_obj (gc_buffer , fcc -> closure );
781
+ }
782
+ }
783
+
732
784
/* Can only return FAILURE if EG(active) is false during late engine shutdown.
733
785
* If the call or call setup throws, EG(exception) will be set and the retval
734
786
* will be UNDEF. Otherwise, the retval will be a non-UNDEF value. */
@@ -751,6 +803,12 @@ ZEND_API void zend_call_known_function(
751
803
zend_function * fn , zend_object * object , zend_class_entry * called_scope , zval * retval_ptr ,
752
804
uint32_t param_count , zval * params , HashTable * named_params );
753
805
806
+ static zend_always_inline void zend_call_known_fcc (
807
+ zend_fcall_info_cache * fcc , zval * retval_ptr , uint32_t param_count , zval * params , HashTable * named_params )
808
+ {
809
+ zend_call_known_function (fcc -> function_handler , fcc -> object , fcc -> called_scope , retval_ptr , param_count , params , named_params );
810
+ }
811
+
754
812
/* Call the provided zend_function instance method on an object. */
755
813
static zend_always_inline void zend_call_known_instance_method (
756
814
zend_function * fn , zend_object * object , zval * retval_ptr ,
0 commit comments