@@ -101,6 +101,8 @@ static zend_op *zend_delayed_compile_var(znode *result, zend_ast *ast, uint32_t
101101static void zend_compile_expr (znode * result , zend_ast * ast );
102102static void zend_compile_stmt (zend_ast * ast );
103103static void zend_compile_assign (znode * result , zend_ast * ast );
104+ static zend_result zend_try_compile_special_func (znode * result , zend_string * lcname , zend_ast_list * args , zend_function * fbc , uint32_t type );
105+ static bool zend_is_special_func (const zend_string * name );
104106
105107#ifdef ZEND_CHECK_STACK_LIMIT
106108zend_never_inline static void zend_stack_limit_error (void )
@@ -4709,6 +4711,7 @@ static uint32_t zend_compile_frameless_icall(znode *result, zend_ast_list *args,
47094711static void zend_compile_ns_call (znode * result , znode * name_node , zend_ast * args_ast , uint32_t lineno , uint32_t type ) /* {{{ */
47104712{
47114713 int name_constants = zend_add_ns_func_name_literal (Z_STR (name_node -> u .constant ));
4714+ bool special_func_handler = false;
47124715
47134716 /* Find frameless function with same name. */
47144717 zend_function * frameless_function = NULL ;
@@ -4725,7 +4728,13 @@ static void zend_compile_ns_call(znode *result, znode *name_node, zend_ast *args
47254728 const zend_frameless_function_info * frameless_function_info = NULL ;
47264729 if (frameless_function ) {
47274730 frameless_function_info = find_frameless_function_info (zend_ast_get_list (args_ast ), frameless_function , type );
4728- if (frameless_function_info ) {
4731+
4732+ if (!frameless_function_info ) {
4733+ /* Check for dedicated special function. */
4734+ special_func_handler = zend_is_special_func (frameless_function -> common .function_name );
4735+ }
4736+
4737+ if (frameless_function_info || special_func_handler ) {
47294738 CG (context ).in_jmp_frameless_branch = true;
47304739 znode op1 ;
47314740 op1 .op_type = IS_CONST ;
@@ -4759,6 +4768,44 @@ static void zend_compile_ns_call(znode *result, znode *name_node, zend_ast *args
47594768 SET_NODE (flf_icall -> result , result );
47604769 zend_update_jump_target_to_next (jmp_end_opnum );
47614770
4771+ CG (context ).in_jmp_frameless_branch = false;
4772+ } else if (special_func_handler ) {
4773+ CG (zend_lineno ) = lineno ;
4774+
4775+ uint32_t jmp_end_opnum = zend_emit_jump (0 );
4776+ uint32_t jmp_fl_target = get_next_op_number ();
4777+
4778+ znode tmp_result ;
4779+ if (zend_try_compile_special_func (& tmp_result , frameless_function -> common .function_name , zend_ast_get_list (args_ast ), frameless_function , type ) != SUCCESS ) {
4780+ zend_op * ops = CG (active_op_array )-> opcodes ;
4781+
4782+ /* Undo work */
4783+ zend_op * jmp_fl = & ops [jmp_fl_opnum ];
4784+ jmp_fl -> opcode = ZEND_NOP ;
4785+ SET_UNUSED (jmp_fl -> op1 );
4786+ zend_op * jmp_end = & ops [jmp_end_opnum ];
4787+ jmp_end -> opcode = ZEND_NOP ;
4788+ SET_UNUSED (jmp_end -> op1 );
4789+ } else {
4790+ uint32_t result_target = get_next_op_number () - 1 ;
4791+
4792+ zend_op * jmp_fl = & CG (active_op_array )-> opcodes [jmp_fl_opnum ];
4793+ jmp_fl -> op2 .opline_num = jmp_fl_target ;
4794+ jmp_fl -> extended_value = zend_alloc_cache_slot ();
4795+
4796+ if (tmp_result .op_type == IS_CONST || 1 /* TODO ? */ ) {
4797+ zend_op * qm_assign = zend_emit_op (NULL , ZEND_QM_ASSIGN , & tmp_result , NULL );
4798+ SET_NODE (qm_assign -> result , result );
4799+ } else {
4800+ // TODO: we're left with a useless tmp?
4801+ zend_op * res_op = & CG (active_op_array )-> opcodes [result_target ];
4802+ res_op -> result_type = result -> op_type ;
4803+ res_op -> result = result -> u .op ;
4804+ }
4805+
4806+ zend_update_jump_target_to_next (jmp_end_opnum );
4807+ }
4808+
47624809 CG (context ).in_jmp_frameless_branch = false;
47634810 }
47644811}
@@ -4936,6 +4983,62 @@ static zend_result zend_compile_func_sprintf(znode *result, zend_ast_list *args)
49364983 return SUCCESS ;
49374984}
49384985
4986+ typedef struct zend_special_func {
4987+ const char * name ;
4988+ size_t name_len ;
4989+ // zend_result (*handler)(znode *, zend_ast_list *);
4990+ } zend_special_func ;
4991+
4992+ static const zend_special_func zend_special_func_compile_handlers [] = {
4993+ {ZEND_STRL ("strlen" )},
4994+ {ZEND_STRL ("is_null" )},
4995+ {ZEND_STRL ("is_bool" )},
4996+ {ZEND_STRL ("is_long" )},
4997+ {ZEND_STRL ("is_int" )},
4998+ {ZEND_STRL ("is_integer" )},
4999+ {ZEND_STRL ("is_float" )},
5000+ {ZEND_STRL ("is_double" )},
5001+ {ZEND_STRL ("is_string" )},
5002+ {ZEND_STRL ("is_array" )},
5003+ {ZEND_STRL ("is_object" )},
5004+ {ZEND_STRL ("is_resource" )},
5005+ {ZEND_STRL ("is_scalar" )},
5006+ {ZEND_STRL ("boolval" )},
5007+ {ZEND_STRL ("intval" )},
5008+ {ZEND_STRL ("floatval" )},
5009+ {ZEND_STRL ("doubleval" )},
5010+ {ZEND_STRL ("strval" )},
5011+ {ZEND_STRL ("defined" )},
5012+ {ZEND_STRL ("chr" )},
5013+ {ZEND_STRL ("ord" )},
5014+ {ZEND_STRL ("call_user_func_array" )},
5015+ {ZEND_STRL ("call_user_func" )},
5016+ {ZEND_STRL ("in_array" )},
5017+ {ZEND_STRL ("count" )},
5018+ {ZEND_STRL ("sizeof" )},
5019+ {ZEND_STRL ("get_class" )},
5020+ {ZEND_STRL ("get_called_class" )},
5021+ {ZEND_STRL ("gettype" )},
5022+ {ZEND_STRL ("func_num_args" )},
5023+ {ZEND_STRL ("func_get_args" )},
5024+ {ZEND_STRL ("array_slice" )},
5025+ {ZEND_STRL ("array_key_exists" )},
5026+ {ZEND_STRL ("sprintf" )},
5027+ {NULL , 0 },
5028+ };
5029+
5030+ static bool zend_is_special_func (const zend_string * name )
5031+ {
5032+ const zend_special_func * entry = & zend_special_func_compile_handlers [0 ];
5033+ for (; entry -> name ; entry ++ ) {
5034+ if (zend_string_equals_cstr (name , entry -> name , entry -> name_len )) {
5035+ return true;
5036+ }
5037+ }
5038+ return false;
5039+ }
5040+
5041+ // TODO: maybe this can migrate to use 'zend_special_func_compile_handlers'
49395042static zend_result zend_try_compile_special_func_ex (znode * result , zend_string * lcname , zend_ast_list * args , zend_function * fbc , uint32_t type ) /* {{{ */
49405043{
49415044 if (zend_string_equals_literal (lcname , "strlen" )) {
0 commit comments