1999-04-07 18:10:10 +00:00
/*
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Zend Engine |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2019-01-30 09:23:29 +00:00
| Copyright ( c ) Zend Technologies Ltd . ( http : //www.zend.com) |
1999-04-07 18:10:10 +00:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2001-12-11 15:16:21 +00:00
| This source file is subject to version 2.00 of the Zend license , |
2013-01-28 02:02:51 +00:00
| that is bundled with this package in the file LICENSE , and is |
2003-06-10 20:04:29 +00:00
| available through the world - wide - web at the following url : |
2001-12-11 15:16:21 +00:00
| http : //www.zend.com/license/2_00.txt. |
1999-07-16 14:58:16 +00:00
| If you did not receive a copy of the Zend license and are unable to |
| obtain it through the world - wide - web , please send a note to |
| license @ zend . com so we can mail you a copy immediately . |
1999-04-07 18:10:10 +00:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2018-11-01 15:20:07 +00:00
| Authors : Andi Gutmans < andi @ php . net > |
| Zeev Suraski < zeev @ php . net > |
2014-07-27 11:25:32 +00:00
| Nikita Popov < nikic @ php . net > |
1999-04-07 18:10:10 +00:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
*/
2004-12-30 15:18:24 +00:00
# include <zend_language_parser.h>
1999-04-07 18:10:10 +00:00
# include "zend.h"
2020-05-24 18:57:00 +00:00
# include "zend_attributes.h"
1999-04-07 18:10:10 +00:00
# include "zend_compile.h"
2003-04-10 17:02:31 +00:00
# include "zend_constants.h"
1999-04-07 18:10:10 +00:00
# include "zend_llist.h"
# include "zend_API.h"
2007-02-24 02:17:47 +00:00
# include "zend_exceptions.h"
2015-04-26 13:02:57 +00:00
# include "zend_interfaces.h"
2013-10-17 07:43:52 +00:00
# include "zend_virtual_cwd.h"
2008-06-29 08:21:35 +00:00
# include "zend_multibyte.h"
2015-05-26 02:36:52 +00:00
# include "zend_language_scanner.h"
2014-09-18 22:01:05 +00:00
# include "zend_inheritance.h"
2015-07-10 01:44:21 +00:00
# include "zend_vm.h"
2008-06-29 08:21:35 +00:00
2010-04-20 10:57:45 +00:00
# define SET_NODE(target, src) do { \
target # # _type = ( src ) - > op_type ; \
if ( ( src ) - > op_type = = IS_CONST ) { \
2018-12-07 14:47:56 +00:00
target . constant = zend_add_literal ( & ( src ) - > u . constant ) ; \
2010-04-20 10:57:45 +00:00
} else { \
target = ( src ) - > u . op ; \
} \
} while ( 0 )
# define GET_NODE(target, src) do { \
( target ) - > op_type = src # # _type ; \
if ( ( target ) - > op_type = = IS_CONST ) { \
2014-12-12 07:19:41 +00:00
ZVAL_COPY_VALUE ( & ( target ) - > u . constant , CT_CONSTANT ( src ) ) ; \
2010-04-20 10:57:45 +00:00
} else { \
( target ) - > u . op = src ; \
} \
} while ( 0 )
2015-04-20 18:16:58 +00:00
# define FC(member) (CG(file_context).member)
2015-07-10 11:30:25 +00:00
typedef struct _zend_loop_var {
zend_uchar opcode ;
2015-08-04 04:37:06 +00:00
zend_uchar var_type ;
uint32_t var_num ;
2019-01-17 15:07:17 +00:00
uint32_t try_catch_offset ;
2015-07-10 11:30:25 +00:00
} zend_loop_var ;
2019-01-07 11:28:51 +00:00
static inline uint32_t zend_alloc_cache_slots ( unsigned count ) {
2019-09-25 11:21:13 +00:00
if ( count = = 0 ) {
2020-08-28 15:24:21 +00:00
/* Even if no cache slots are desired, the VM handler may still want to acquire
* CACHE_ADDR ( ) unconditionally . Returning zero makes sure that the address
* calculation is still legal and ubsan does not complain . */
return 0 ;
2019-09-25 11:21:13 +00:00
}
2014-08-15 15:10:06 +00:00
zend_op_array * op_array = CG ( active_op_array ) ;
2018-02-05 16:41:47 +00:00
uint32_t ret = op_array - > cache_size ;
2019-01-07 11:28:51 +00:00
op_array - > cache_size + = count * sizeof ( void * ) ;
2018-02-05 16:41:47 +00:00
return ret ;
2014-08-15 15:10:06 +00:00
}
2010-05-24 14:11:39 +00:00
2019-01-07 11:28:51 +00:00
static inline uint32_t zend_alloc_cache_slot ( void ) {
return zend_alloc_cache_slots ( 1 ) ;
2014-08-15 15:10:06 +00:00
}
2010-05-24 14:11:39 +00:00
2014-12-13 22:06:14 +00:00
ZEND_API zend_op_array * ( * zend_compile_file ) ( zend_file_handle * file_handle , int type ) ;
2020-09-07 09:42:21 +00:00
ZEND_API zend_op_array * ( * zend_compile_string ) ( zend_string * source_string , const char * filename ) ;
1999-04-07 18:10:10 +00:00
# ifndef ZTS
ZEND_API zend_compiler_globals compiler_globals ;
ZEND_API zend_executor_globals executor_globals ;
# endif
2015-11-13 12:35:07 +00:00
static zend_op * zend_emit_op ( znode * result , zend_uchar opcode , znode * op1 , znode * op2 ) ;
2017-05-24 20:00:48 +00:00
static zend_bool zend_try_ct_eval_array ( zval * result , zend_ast * ast ) ;
2015-11-13 12:35:07 +00:00
2018-03-13 10:49:58 +00:00
static void init_op ( zend_op * op )
{
MAKE_NOP ( op ) ;
op - > extended_value = 0 ;
op - > lineno = CG ( zend_lineno ) ;
}
2018-12-07 14:47:56 +00:00
static zend_always_inline uint32_t get_next_op_number ( void )
2018-03-13 10:49:58 +00:00
{
2018-12-07 14:47:56 +00:00
return CG ( active_op_array ) - > last ;
}
static zend_op * get_next_op ( void )
{
zend_op_array * op_array = CG ( active_op_array ) ;
2018-03-13 10:49:58 +00:00
uint32_t next_op_num = op_array - > last + + ;
zend_op * next_op ;
if ( UNEXPECTED ( next_op_num > = CG ( context ) . opcodes_size ) ) {
CG ( context ) . opcodes_size * = 4 ;
op_array - > opcodes = erealloc ( op_array - > opcodes , CG ( context ) . opcodes_size * sizeof ( zend_op ) ) ;
}
next_op = & ( op_array - > opcodes [ next_op_num ] ) ;
init_op ( next_op ) ;
return next_op ;
}
static zend_brk_cont_element * get_next_brk_cont_element ( void )
{
CG ( context ) . last_brk_cont + + ;
CG ( context ) . brk_cont_array = erealloc ( CG ( context ) . brk_cont_array , sizeof ( zend_brk_cont_element ) * CG ( context ) . last_brk_cont ) ;
return & CG ( context ) . brk_cont_array [ CG ( context ) . last_brk_cont - 1 ] ;
}
2014-02-17 07:50:32 +00:00
static void zend_destroy_property_info_internal ( zval * zv ) /* { { { */
2003-08-23 19:37:39 +00:00
{
2014-02-17 07:50:32 +00:00
zend_property_info * property_info = Z_PTR_P ( zv ) ;
2019-12-17 07:10:11 +00:00
zend_string_release ( property_info - > name ) ;
2019-09-25 11:21:13 +00:00
zend_type_release ( property_info - > type , /* persistent */ 1 ) ;
2014-02-17 13:59:18 +00:00
free ( property_info ) ;
2003-08-23 19:37:39 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
2003-08-23 19:37:39 +00:00
2019-12-11 16:11:30 +00:00
static zend_string * zend_build_runtime_definition_key ( zend_string * name , uint32_t start_lineno ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2015-05-24 19:50:46 +00:00
zend_string * filename = CG ( active_op_array ) - > filename ;
2019-12-11 16:11:30 +00:00
zend_string * result = zend_strpprintf ( 0 , " %c%s%s:% " PRIu32 " $% " PRIx32 ,
' \0 ' , ZSTR_VAL ( name ) , ZSTR_VAL ( filename ) , start_lineno , CG ( rtd_key_counter ) + + ) ;
2014-12-13 22:06:14 +00:00
return zend_new_interned_string ( result ) ;
1999-09-02 21:06:05 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-09-02 21:06:05 +00:00
2014-09-28 21:17:29 +00:00
static zend_bool zend_get_unqualified_name ( const zend_string * name , const char * * result , size_t * result_len ) /* { { { */
{
2015-06-30 10:59:27 +00:00
const char * ns_separator = zend_memrchr ( ZSTR_VAL ( name ) , ' \\ ' , ZSTR_LEN ( name ) ) ;
2014-09-28 21:17:29 +00:00
if ( ns_separator ! = NULL ) {
* result = ns_separator + 1 ;
2015-06-30 10:59:27 +00:00
* result_len = ZSTR_VAL ( name ) + ZSTR_LEN ( name ) - * result ;
2014-09-28 21:17:29 +00:00
return 1 ;
}
return 0 ;
}
/* }}} */
2015-03-30 20:05:26 +00:00
struct reserved_class_name {
const char * name ;
size_t len ;
} ;
static const struct reserved_class_name reserved_class_names [ ] = {
{ ZEND_STRL ( " bool " ) } ,
{ ZEND_STRL ( " false " ) } ,
{ ZEND_STRL ( " float " ) } ,
{ ZEND_STRL ( " int " ) } ,
{ ZEND_STRL ( " null " ) } ,
{ ZEND_STRL ( " parent " ) } ,
{ ZEND_STRL ( " self " ) } ,
{ ZEND_STRL ( " static " ) } ,
{ ZEND_STRL ( " string " ) } ,
{ ZEND_STRL ( " true " ) } ,
2015-10-14 18:15:32 +00:00
{ ZEND_STRL ( " void " ) } ,
2016-06-03 22:42:04 +00:00
{ ZEND_STRL ( " iterable " ) } ,
2017-06-25 19:43:25 +00:00
{ ZEND_STRL ( " object " ) } ,
2020-03-27 22:39:49 +00:00
{ ZEND_STRL ( " mixed " ) } ,
2015-03-30 20:05:26 +00:00
{ NULL , 0 }
} ;
static zend_bool zend_is_reserved_class_name ( const zend_string * name ) /* { { { */
{
const struct reserved_class_name * reserved = reserved_class_names ;
2015-06-30 10:59:27 +00:00
const char * uqname = ZSTR_VAL ( name ) ;
size_t uqname_len = ZSTR_LEN ( name ) ;
2015-03-30 20:05:26 +00:00
zend_get_unqualified_name ( name , & uqname , & uqname_len ) ;
for ( ; reserved - > name ; + + reserved ) {
if ( uqname_len = = reserved - > len
& & zend_binary_strcasecmp ( uqname , uqname_len , reserved - > name , reserved - > len ) = = 0
) {
return 1 ;
}
}
return 0 ;
}
/* }}} */
2017-04-29 15:09:08 +00:00
void zend_assert_valid_class_name ( const zend_string * name ) /* { { { */
2015-03-30 20:05:26 +00:00
{
if ( zend_is_reserved_class_name ( name ) ) {
zend_error_noreturn ( E_COMPILE_ERROR ,
2015-06-30 10:59:27 +00:00
" Cannot use '%s' as class name as it is reserved " , ZSTR_VAL ( name ) ) ;
2015-03-30 20:05:26 +00:00
}
}
/* }}} */
2015-05-21 01:39:31 +00:00
typedef struct _builtin_type_info {
2015-02-01 14:22:48 +00:00
const char * name ;
const size_t name_len ;
const zend_uchar type ;
2015-05-21 01:39:31 +00:00
} builtin_type_info ;
2015-02-01 14:22:48 +00:00
2015-05-21 01:39:31 +00:00
static const builtin_type_info builtin_types [ ] = {
2019-09-25 11:21:13 +00:00
{ ZEND_STRL ( " null " ) , IS_NULL } ,
{ ZEND_STRL ( " false " ) , IS_FALSE } ,
2015-11-09 11:15:58 +00:00
{ ZEND_STRL ( " int " ) , IS_LONG } ,
{ ZEND_STRL ( " float " ) , IS_DOUBLE } ,
{ ZEND_STRL ( " string " ) , IS_STRING } ,
{ ZEND_STRL ( " bool " ) , _IS_BOOL } ,
2015-10-14 18:15:32 +00:00
{ ZEND_STRL ( " void " ) , IS_VOID } ,
2016-06-03 22:42:04 +00:00
{ ZEND_STRL ( " iterable " ) , IS_ITERABLE } ,
2017-06-25 19:43:25 +00:00
{ ZEND_STRL ( " object " ) , IS_OBJECT } ,
2020-03-27 22:39:49 +00:00
{ ZEND_STRL ( " mixed " ) , IS_MIXED } ,
2015-02-01 14:22:48 +00:00
{ NULL , 0 , IS_UNDEF }
} ;
2019-10-11 13:32:02 +00:00
typedef struct {
const char * name ;
size_t name_len ;
const char * correct_name ;
} confusable_type_info ;
static const confusable_type_info confusable_types [ ] = {
{ ZEND_STRL ( " boolean " ) , " bool " } ,
{ ZEND_STRL ( " integer " ) , " int " } ,
{ ZEND_STRL ( " double " ) , " float " } ,
{ ZEND_STRL ( " resource " ) , NULL } ,
{ NULL , 0 , NULL } ,
} ;
2015-05-21 01:54:11 +00:00
static zend_always_inline zend_uchar zend_lookup_builtin_type_by_name ( const zend_string * name ) /* { { { */
2015-02-01 14:22:48 +00:00
{
2015-05-21 01:39:31 +00:00
const builtin_type_info * info = & builtin_types [ 0 ] ;
2015-03-19 18:07:03 +00:00
2015-03-30 20:05:26 +00:00
for ( ; info - > name ; + + info ) {
2015-06-30 10:59:27 +00:00
if ( ZSTR_LEN ( name ) = = info - > name_len
& & zend_binary_strcasecmp ( ZSTR_VAL ( name ) , ZSTR_LEN ( name ) , info - > name , info - > name_len ) = = 0
2015-03-30 20:05:26 +00:00
) {
2015-05-21 01:54:11 +00:00
return info - > type ;
2015-02-01 14:22:48 +00:00
}
}
2015-05-21 01:54:11 +00:00
return 0 ;
2015-02-01 14:22:48 +00:00
}
/* }}} */
2019-10-11 13:32:02 +00:00
static zend_always_inline zend_bool zend_is_confusable_type ( const zend_string * name , const char * * correct_name ) /* { { { */
{
const confusable_type_info * info = confusable_types ;
/* Intentionally using case-sensitive comparison here, because "integer" is likely intended
* as a scalar type , while " Integer " is likely a class type . */
for ( ; info - > name ; + + info ) {
if ( ZSTR_LEN ( name ) = = info - > name_len
& & memcmp ( ZSTR_VAL ( name ) , info - > name , info - > name_len ) = = 0
) {
* correct_name = info - > correct_name ;
return 1 ;
}
}
return 0 ;
}
/* }}} */
static zend_bool zend_is_not_imported ( zend_string * name ) {
/* Assuming "name" is unqualified here. */
2020-04-24 21:00:13 +00:00
return ! FC ( imports ) | | zend_hash_find_ptr_lc ( FC ( imports ) , name ) = = NULL ;
2019-10-11 13:32:02 +00:00
}
2015-02-01 14:22:48 +00:00
2015-04-20 15:39:32 +00:00
void zend_oparray_context_begin ( zend_oparray_context * prev_context ) /* { { { */
2010-09-15 07:38:52 +00:00
{
2015-04-20 15:39:32 +00:00
* prev_context = CG ( context ) ;
2014-08-25 21:45:02 +00:00
CG ( context ) . opcodes_size = INITIAL_OP_ARRAY_SIZE ;
2010-09-15 07:38:52 +00:00
CG ( context ) . vars_size = 0 ;
CG ( context ) . literals_size = 0 ;
2014-11-27 06:56:43 +00:00
CG ( context ) . fast_call_var = - 1 ;
2016-05-24 22:25:12 +00:00
CG ( context ) . try_catch_offset = - 1 ;
2015-11-10 18:48:03 +00:00
CG ( context ) . current_brk_cont = - 1 ;
CG ( context ) . last_brk_cont = 0 ;
CG ( context ) . brk_cont_array = NULL ;
2010-09-15 07:38:52 +00:00
CG ( context ) . labels = NULL ;
}
/* }}} */
2000-01-24 19:00:30 +00:00
2015-04-20 15:39:32 +00:00
void zend_oparray_context_end ( zend_oparray_context * prev_context ) /* { { { */
{
2015-11-10 18:48:03 +00:00
if ( CG ( context ) . brk_cont_array ) {
efree ( CG ( context ) . brk_cont_array ) ;
CG ( context ) . brk_cont_array = NULL ;
}
2015-04-20 15:39:32 +00:00
if ( CG ( context ) . labels ) {
zend_hash_destroy ( CG ( context ) . labels ) ;
FREE_HASHTABLE ( CG ( context ) . labels ) ;
CG ( context ) . labels = NULL ;
}
CG ( context ) = * prev_context ;
}
/* }}} */
static void zend_reset_import_tables ( void ) /* { { { */
{
2015-04-20 18:16:58 +00:00
if ( FC ( imports ) ) {
zend_hash_destroy ( FC ( imports ) ) ;
efree ( FC ( imports ) ) ;
FC ( imports ) = NULL ;
2015-04-20 15:39:32 +00:00
}
2015-04-20 18:16:58 +00:00
if ( FC ( imports_function ) ) {
zend_hash_destroy ( FC ( imports_function ) ) ;
efree ( FC ( imports_function ) ) ;
FC ( imports_function ) = NULL ;
2015-04-20 15:39:32 +00:00
}
2015-04-20 18:16:58 +00:00
if ( FC ( imports_const ) ) {
zend_hash_destroy ( FC ( imports_const ) ) ;
efree ( FC ( imports_const ) ) ;
FC ( imports_const ) = NULL ;
}
}
/* }}} */
static void zend_end_namespace ( void ) /* { { { */ {
FC ( in_namespace ) = 0 ;
zend_reset_import_tables ( ) ;
if ( FC ( current_namespace ) ) {
2018-05-28 13:27:12 +00:00
zend_string_release_ex ( FC ( current_namespace ) , 0 ) ;
2015-04-20 18:16:58 +00:00
FC ( current_namespace ) = NULL ;
2015-04-20 15:39:32 +00:00
}
}
/* }}} */
void zend_file_context_begin ( zend_file_context * prev_context ) /* { { { */
{
* prev_context = CG ( file_context ) ;
2015-04-20 18:16:58 +00:00
FC ( imports ) = NULL ;
FC ( imports_function ) = NULL ;
FC ( imports_const ) = NULL ;
FC ( current_namespace ) = NULL ;
FC ( in_namespace ) = 0 ;
FC ( has_bracketed_namespaces ) = 0 ;
FC ( declarables ) . ticks = 0 ;
2016-10-06 21:09:41 +00:00
zend_hash_init ( & FC ( seen_symbols ) , 8 , NULL , NULL , 0 ) ;
2015-04-20 15:39:32 +00:00
}
/* }}} */
void zend_file_context_end ( zend_file_context * prev_context ) /* { { { */
{
2015-04-20 18:16:58 +00:00
zend_end_namespace ( ) ;
2016-10-06 21:09:41 +00:00
zend_hash_destroy ( & FC ( seen_symbols ) ) ;
2015-04-20 15:39:32 +00:00
CG ( file_context ) = * prev_context ;
}
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_init_compiler_data_structures ( void ) /* { { { */
1999-04-07 18:10:10 +00:00
{
2015-07-10 11:30:25 +00:00
zend_stack_init ( & CG ( loop_var_stack ) , sizeof ( zend_loop_var ) ) ;
2014-08-15 15:10:06 +00:00
zend_stack_init ( & CG ( delayed_oplines_stack ) , sizeof ( zend_op ) ) ;
2020-05-24 10:42:48 +00:00
zend_stack_init ( & CG ( short_circuiting_opnums ) , sizeof ( uint32_t ) ) ;
1999-04-07 18:10:10 +00:00
CG ( active_class_entry ) = NULL ;
2000-02-04 14:45:58 +00:00
CG ( in_compilation ) = 0 ;
2019-07-15 14:21:46 +00:00
CG ( skip_shebang ) = 0 ;
2008-06-29 08:21:35 +00:00
2009-11-16 22:52:00 +00:00
CG ( encoding_declared ) = 0 ;
2019-01-15 16:04:24 +00:00
CG ( memoized_exprs ) = NULL ;
CG ( memoize_mode ) = 0 ;
2008-03-16 21:06:55 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
2008-03-16 21:06:55 +00:00
2016-10-06 21:09:41 +00:00
static void zend_register_seen_symbol ( zend_string * name , uint32_t kind ) {
zval * zv = zend_hash_find ( & FC ( seen_symbols ) , name ) ;
if ( zv ) {
Z_LVAL_P ( zv ) | = kind ;
} else {
zval tmp ;
ZVAL_LONG ( & tmp , kind ) ;
zend_hash_add_new ( & FC ( seen_symbols ) , name , & tmp ) ;
}
}
static zend_bool zend_have_seen_symbol ( zend_string * name , uint32_t kind ) {
zval * zv = zend_hash_find ( & FC ( seen_symbols ) , name ) ;
return zv & & ( Z_LVAL_P ( zv ) & kind ) ! = 0 ;
}
2009-07-27 14:11:53 +00:00
ZEND_API void file_handle_dtor ( zend_file_handle * fh ) /* { { { */
2008-03-16 21:06:55 +00:00
{
2014-10-15 07:37:55 +00:00
2014-12-13 22:06:14 +00:00
zend_file_handle_dtor ( fh ) ;
2001-05-06 19:30:31 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
2001-05-06 19:30:31 +00:00
2014-12-13 22:06:14 +00:00
void init_compiler ( void ) /* { { { */
2001-05-06 19:30:31 +00:00
{
2014-06-17 22:47:01 +00:00
CG ( arena ) = zend_arena_create ( 64 * 1024 ) ;
2006-05-02 15:49:26 +00:00
CG ( active_op_array ) = NULL ;
2012-11-14 13:45:10 +00:00
memset ( & CG ( context ) , 0 , sizeof ( CG ( context ) ) ) ;
2014-12-13 22:06:14 +00:00
zend_init_compiler_data_structures ( ) ;
zend_init_rsrc_list ( ) ;
2008-03-16 21:06:55 +00:00
zend_llist_init ( & CG ( open_files ) , sizeof ( zend_file_handle ) , ( void ( * ) ( void * ) ) file_handle_dtor , 0 ) ;
2001-05-06 19:30:31 +00:00
CG ( unclean_shutdown ) = 0 ;
2019-05-27 09:39:56 +00:00
CG ( delayed_variance_obligations ) = NULL ;
CG ( delayed_autoloads ) = NULL ;
1999-04-07 18:10:10 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
void shutdown_compiler ( void ) /* { { { */
1999-04-07 18:10:10 +00:00
{
2015-07-10 00:31:52 +00:00
zend_stack_destroy ( & CG ( loop_var_stack ) ) ;
2014-08-15 15:10:06 +00:00
zend_stack_destroy ( & CG ( delayed_oplines_stack ) ) ;
2020-05-24 10:42:48 +00:00
zend_stack_destroy ( & CG ( short_circuiting_opnums ) ) ;
2014-06-17 22:47:01 +00:00
zend_arena_destroy ( CG ( arena ) ) ;
2019-05-27 09:39:56 +00:00
if ( CG ( delayed_variance_obligations ) ) {
zend_hash_destroy ( CG ( delayed_variance_obligations ) ) ;
FREE_HASHTABLE ( CG ( delayed_variance_obligations ) ) ;
CG ( delayed_variance_obligations ) = NULL ;
}
if ( CG ( delayed_autoloads ) ) {
zend_hash_destroy ( CG ( delayed_autoloads ) ) ;
FREE_HASHTABLE ( CG ( delayed_autoloads ) ) ;
CG ( delayed_autoloads ) = NULL ;
}
2020-09-03 10:59:30 +00:00
zend_restore_compiled_filename ( NULL ) ;
1999-04-07 18:10:10 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
ZEND_API zend_string * zend_set_compiled_filename ( zend_string * new_compiled_filename ) /* { { { */
1999-04-07 18:10:10 +00:00
{
2020-09-03 09:56:55 +00:00
CG ( compiled_filename ) = zend_string_copy ( new_compiled_filename ) ;
2015-09-11 02:58:24 +00:00
return new_compiled_filename ;
1999-04-07 18:10:10 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
ZEND_API void zend_restore_compiled_filename ( zend_string * original_compiled_filename ) /* { { { */
1999-04-07 18:10:10 +00:00
{
2020-09-03 09:56:55 +00:00
if ( CG ( compiled_filename ) ) {
zend_string_release ( CG ( compiled_filename ) ) ;
CG ( compiled_filename ) = NULL ;
}
1999-04-07 18:10:10 +00:00
CG ( compiled_filename ) = original_compiled_filename ;
}
2009-07-27 14:11:53 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
ZEND_API zend_string * zend_get_compiled_filename ( void ) /* { { { */
2000-02-04 14:45:58 +00:00
{
return CG ( compiled_filename ) ;
}
2009-07-27 14:11:53 +00:00
/* }}} */
2000-02-04 14:45:58 +00:00
2014-12-13 22:06:14 +00:00
ZEND_API int zend_get_compiled_lineno ( void ) /* { { { */
2000-02-04 14:45:58 +00:00
{
return CG ( zend_lineno ) ;
}
2009-07-27 14:11:53 +00:00
/* }}} */
2000-02-04 14:45:58 +00:00
2014-12-13 22:06:14 +00:00
ZEND_API zend_bool zend_is_compiling ( void ) /* { { { */
1999-04-07 18:10:10 +00:00
{
2000-02-04 14:45:58 +00:00
return CG ( in_compilation ) ;
1999-04-07 18:10:10 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2018-12-07 14:47:56 +00:00
static zend_always_inline uint32_t get_temporary_variable ( void ) /* { { { */
1999-04-07 18:10:10 +00:00
{
2018-12-07 14:47:56 +00:00
return ( uint32_t ) CG ( active_op_array ) - > T + + ;
1999-04-07 18:10:10 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2018-12-07 14:47:56 +00:00
static int lookup_cv ( zend_string * name ) /* { { { */ {
zend_op_array * op_array = CG ( active_op_array ) ;
2004-10-04 19:54:35 +00:00
int i = 0 ;
2014-08-25 17:24:55 +00:00
zend_ulong hash_value = zend_string_hash_val ( name ) ;
2004-10-04 19:54:35 +00:00
while ( i < op_array - > last_var ) {
2018-12-07 16:21:26 +00:00
if ( ZSTR_H ( op_array - > vars [ i ] ) = = hash_value
& & zend_string_equals ( op_array - > vars [ i ] , name ) ) {
2020-02-27 12:13:01 +00:00
return EX_NUM_TO_VAR ( i ) ;
2004-10-04 19:54:35 +00:00
}
i + + ;
}
i = op_array - > last_var ;
op_array - > last_var + + ;
2010-09-15 07:38:52 +00:00
if ( op_array - > last_var > CG ( context ) . vars_size ) {
CG ( context ) . vars_size + = 16 ; /* FIXME */
2014-02-10 06:04:30 +00:00
op_array - > vars = erealloc ( op_array - > vars , CG ( context ) . vars_size * sizeof ( zend_string * ) ) ;
2004-10-04 19:54:35 +00:00
}
2014-02-10 06:04:30 +00:00
2017-10-31 22:10:21 +00:00
op_array - > vars [ i ] = zend_string_copy ( name ) ;
2020-02-27 12:13:01 +00:00
return EX_NUM_TO_VAR ( i ) ;
2004-10-04 19:54:35 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
2004-10-04 19:54:35 +00:00
2017-10-31 22:10:21 +00:00
static inline zend_string * zval_make_interned_string ( zval * zv ) /* { { { */
2017-10-31 12:36:55 +00:00
{
ZEND_ASSERT ( Z_TYPE_P ( zv ) = = IS_STRING ) ;
Z_STR_P ( zv ) = zend_new_interned_string ( Z_STR_P ( zv ) ) ;
if ( ZSTR_IS_INTERNED ( Z_STR_P ( zv ) ) ) {
2018-01-16 22:58:51 +00:00
Z_TYPE_FLAGS_P ( zv ) = 0 ;
2017-10-31 12:36:55 +00:00
}
2017-10-31 22:10:21 +00:00
return Z_STR_P ( zv ) ;
2017-10-31 12:36:55 +00:00
}
2011-08-15 09:54:06 +00:00
/* Common part of zend_add_literal and zend_append_individual_literal */
2014-12-13 22:06:14 +00:00
static inline void zend_insert_literal ( zend_op_array * op_array , zval * zv , int literal_position ) /* { { { */
2011-08-15 09:54:06 +00:00
{
2018-12-10 12:33:48 +00:00
zval * lit = CT_CONSTANT_EX ( op_array , literal_position ) ;
2017-10-10 07:11:05 +00:00
if ( Z_TYPE_P ( zv ) = = IS_STRING ) {
2017-10-31 12:36:55 +00:00
zval_make_interned_string ( zv ) ;
2011-08-15 09:54:06 +00:00
}
2018-12-10 12:33:48 +00:00
ZVAL_COPY_VALUE ( lit , zv ) ;
Z_EXTRA_P ( lit ) = 0 ;
2011-08-15 09:54:06 +00:00
}
/* }}} */
/* Is used while compiling a function, using the context to keep track
of an approximate size to avoid to relocate to often .
Literals are truncated to actual size in the second compiler pass ( pass_two ( ) ) . */
2018-12-07 14:47:56 +00:00
static int zend_add_literal ( zval * zv ) /* { { { */
2010-04-20 10:57:45 +00:00
{
2018-12-07 14:47:56 +00:00
zend_op_array * op_array = CG ( active_op_array ) ;
2010-04-20 10:57:45 +00:00
int i = op_array - > last_literal ;
op_array - > last_literal + + ;
2010-09-15 07:38:52 +00:00
if ( i > = CG ( context ) . literals_size ) {
2011-08-15 09:54:06 +00:00
while ( i > = CG ( context ) . literals_size ) {
CG ( context ) . literals_size + = 16 ; /* FIXME */
}
2014-04-17 11:40:45 +00:00
op_array - > literals = ( zval * ) erealloc ( op_array - > literals , CG ( context ) . literals_size * sizeof ( zval ) ) ;
2010-04-20 10:57:45 +00:00
}
2014-12-13 22:06:14 +00:00
zend_insert_literal ( op_array , zv , i ) ;
2011-08-15 09:54:06 +00:00
return i ;
}
/* }}} */
2010-04-20 11:05:54 +00:00
2018-12-07 14:47:56 +00:00
static inline int zend_add_literal_string ( zend_string * * str ) /* { { { */
2010-04-21 14:58:33 +00:00
{
int ret ;
2014-09-23 18:21:28 +00:00
zval zv ;
ZVAL_STR ( & zv , * str ) ;
2018-12-07 14:47:56 +00:00
ret = zend_add_literal ( & zv ) ;
2014-09-23 18:21:28 +00:00
* str = Z_STR ( zv ) ;
return ret ;
}
2014-12-02 14:21:19 +00:00
/* }}} */
2010-04-21 14:58:33 +00:00
2018-12-07 14:47:56 +00:00
static int zend_add_func_name_literal ( zend_string * name ) /* { { { */
2014-09-23 18:21:28 +00:00
{
2014-09-28 21:17:29 +00:00
/* Original name */
2018-12-07 14:47:56 +00:00
int ret = zend_add_literal_string ( & name ) ;
2013-01-28 02:02:51 +00:00
2014-09-28 21:17:29 +00:00
/* Lowercased name */
2014-12-24 12:04:51 +00:00
zend_string * lc_name = zend_string_tolower ( name ) ;
2018-12-07 14:47:56 +00:00
zend_add_literal_string ( & lc_name ) ;
2010-04-21 14:58:33 +00:00
return ret ;
}
/* }}} */
2018-12-07 14:47:56 +00:00
static int zend_add_ns_func_name_literal ( zend_string * name ) /* { { { */
2010-04-27 12:09:13 +00:00
{
2014-09-28 21:17:29 +00:00
const char * unqualified_name ;
size_t unqualified_name_len ;
2010-04-27 12:09:13 +00:00
2014-09-28 21:17:29 +00:00
/* Original name */
2018-12-07 14:47:56 +00:00
int ret = zend_add_literal_string ( & name ) ;
2010-04-27 12:09:13 +00:00
2014-09-28 21:17:29 +00:00
/* Lowercased name */
2014-12-24 12:04:51 +00:00
zend_string * lc_name = zend_string_tolower ( name ) ;
2018-12-07 14:47:56 +00:00
zend_add_literal_string ( & lc_name ) ;
2013-08-22 01:24:59 +00:00
2014-09-28 21:17:29 +00:00
/* Lowercased unqualfied name */
if ( zend_get_unqualified_name ( name , & unqualified_name , & unqualified_name_len ) ) {
lc_name = zend_string_alloc ( unqualified_name_len , 0 ) ;
2015-06-30 10:59:27 +00:00
zend_str_tolower_copy ( ZSTR_VAL ( lc_name ) , unqualified_name , unqualified_name_len ) ;
2018-12-07 14:47:56 +00:00
zend_add_literal_string ( & lc_name ) ;
2013-08-22 01:24:59 +00:00
}
2010-04-27 12:09:13 +00:00
return ret ;
}
/* }}} */
2010-04-21 14:58:33 +00:00
2018-12-07 14:47:56 +00:00
static int zend_add_class_name_literal ( zend_string * name ) /* { { { */
2014-09-23 17:32:02 +00:00
{
2014-09-28 21:17:29 +00:00
/* Original name */
2018-12-07 14:47:56 +00:00
int ret = zend_add_literal_string ( & name ) ;
2014-07-19 21:30:07 +00:00
2014-09-28 21:17:29 +00:00
/* Lowercased name */
2014-12-24 12:04:51 +00:00
zend_string * lc_name = zend_string_tolower ( name ) ;
2018-12-07 14:47:56 +00:00
zend_add_literal_string ( & lc_name ) ;
2010-04-21 14:58:33 +00:00
return ret ;
}
/* }}} */
2018-12-07 14:47:56 +00:00
static int zend_add_const_name_literal ( zend_string * name , zend_bool unqualified ) /* { { { */
2010-04-22 15:03:17 +00:00
{
2014-02-10 06:04:30 +00:00
zend_string * tmp_name ;
2010-04-22 15:03:17 +00:00
2018-12-07 14:47:56 +00:00
int ret = zend_add_literal_string ( & name ) ;
2010-04-22 15:03:17 +00:00
2015-06-30 10:59:27 +00:00
size_t ns_len = 0 , after_ns_len = ZSTR_LEN ( name ) ;
const char * after_ns = zend_memrchr ( ZSTR_VAL ( name ) , ' \\ ' , ZSTR_LEN ( name ) ) ;
2014-09-23 18:21:28 +00:00
if ( after_ns ) {
after_ns + = 1 ;
2015-06-30 10:59:27 +00:00
ns_len = after_ns - ZSTR_VAL ( name ) - 1 ;
after_ns_len = ZSTR_LEN ( name ) - ns_len - 1 ;
2010-04-22 15:03:17 +00:00
/* lowercased namespace name & original constant name */
2015-06-30 10:59:27 +00:00
tmp_name = zend_string_init ( ZSTR_VAL ( name ) , ZSTR_LEN ( name ) , 0 ) ;
zend_str_tolower ( ZSTR_VAL ( tmp_name ) , ns_len ) ;
2018-12-07 14:47:56 +00:00
zend_add_literal_string ( & tmp_name ) ;
2010-04-22 15:03:17 +00:00
if ( ! unqualified ) {
return ret ;
}
2014-09-23 18:21:28 +00:00
} else {
2015-06-30 10:59:27 +00:00
after_ns = ZSTR_VAL ( name ) ;
2010-04-22 15:03:17 +00:00
}
2014-09-23 18:21:28 +00:00
/* original unqualified constant name */
tmp_name = zend_string_init ( after_ns , after_ns_len , 0 ) ;
2018-12-07 14:47:56 +00:00
zend_add_literal_string ( & tmp_name ) ;
2010-04-22 15:03:17 +00:00
return ret ;
}
/* }}} */
2014-02-10 06:04:30 +00:00
# define LITERAL_STR(op, str) do { \
2010-04-20 10:57:45 +00:00
zval _c ; \
2014-02-10 06:04:30 +00:00
ZVAL_STR ( & _c , str ) ; \
2018-12-07 14:47:56 +00:00
op . constant = zend_add_literal ( & _c ) ; \
2014-02-10 06:04:30 +00:00
} while ( 0 )
2015-04-05 11:50:35 +00:00
void zend_stop_lexing ( void )
{
2016-07-22 22:12:11 +00:00
if ( LANG_SCNG ( on_event ) ) {
2020-06-05 14:55:20 +00:00
LANG_SCNG ( on_event ) ( ON_STOP , END , 0 , NULL , 0 , LANG_SCNG ( on_event_context ) ) ;
2016-07-22 22:12:11 +00:00
}
2015-04-05 11:50:35 +00:00
2014-07-22 13:50:23 +00:00
LANG_SCNG ( yy_cursor ) = LANG_SCNG ( yy_limit ) ;
}
2010-04-21 14:58:33 +00:00
2018-06-24 14:55:22 +00:00
static inline void zend_begin_loop (
zend_uchar free_opcode , const znode * loop_var , zend_bool is_switch ) /* {{{ */
2010-08-25 09:14:36 +00:00
{
1999-04-07 18:10:10 +00:00
zend_brk_cont_element * brk_cont_element ;
2015-05-22 19:35:33 +00:00
int parent = CG ( context ) . current_brk_cont ;
2015-07-10 11:30:25 +00:00
zend_loop_var info = { 0 } ;
2010-08-25 09:14:36 +00:00
2015-11-10 18:48:03 +00:00
CG ( context ) . current_brk_cont = CG ( context ) . last_brk_cont ;
brk_cont_element = get_next_brk_cont_element ( ) ;
1999-04-07 18:10:10 +00:00
brk_cont_element - > parent = parent ;
2018-06-24 14:55:22 +00:00
brk_cont_element - > is_switch = is_switch ;
2015-07-10 00:31:52 +00:00
2015-07-10 11:30:25 +00:00
if ( loop_var & & ( loop_var - > op_type & ( IS_VAR | IS_TMP_VAR ) ) ) {
2018-12-07 14:47:56 +00:00
uint32_t start = get_next_op_number ( ) ;
2015-11-11 08:12:44 +00:00
2015-08-04 04:37:06 +00:00
info . opcode = free_opcode ;
info . var_type = loop_var - > op_type ;
info . var_num = loop_var - > u . op . var ;
2015-11-11 08:12:44 +00:00
brk_cont_element - > start = start ;
2015-05-22 19:35:33 +00:00
} else {
2015-07-10 11:30:25 +00:00
info . opcode = ZEND_NOP ;
2015-07-10 00:31:52 +00:00
/* The start field is used to free temporary variables in case of exceptions.
* We won ' t try to free something of we don ' t have loop variable . */
brk_cont_element - > start = - 1 ;
2015-05-22 19:35:33 +00:00
}
2015-07-10 11:30:25 +00:00
zend_stack_push ( & CG ( loop_var_stack ) , & info ) ;
2010-08-25 09:14:36 +00:00
}
/* }}} */
2015-11-13 12:35:07 +00:00
static inline void zend_end_loop ( int cont_addr , const znode * var_node ) /* { { { */
1999-04-07 18:10:10 +00:00
{
2018-12-07 14:47:56 +00:00
uint32_t end = get_next_op_number ( ) ;
2015-05-22 19:35:33 +00:00
zend_brk_cont_element * brk_cont_element
2015-11-10 18:48:03 +00:00
= & CG ( context ) . brk_cont_array [ CG ( context ) . current_brk_cont ] ;
2015-05-22 19:35:33 +00:00
brk_cont_element - > cont = cont_addr ;
2015-11-11 08:12:44 +00:00
brk_cont_element - > brk = end ;
2015-05-22 19:35:33 +00:00
CG ( context ) . current_brk_cont = brk_cont_element - > parent ;
2015-07-10 00:31:52 +00:00
2015-07-10 11:30:25 +00:00
zend_stack_del_top ( & CG ( loop_var_stack ) ) ;
1999-04-07 18:10:10 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
void zend_do_free ( znode * op1 ) /* { { { */
1999-04-07 18:10:10 +00:00
{
2016-03-17 13:10:08 +00:00
if ( op1 - > op_type = = IS_TMP_VAR ) {
1999-04-07 18:10:10 +00:00
zend_op * opline = & CG ( active_op_array ) - > opcodes [ CG ( active_op_array ) - > last - 1 ] ;
2002-03-10 13:42:37 +00:00
2020-02-07 10:36:52 +00:00
while ( opline - > opcode = = ZEND_END_SILENCE | |
opline - > opcode = = ZEND_OP_DATA ) {
2016-03-17 13:10:08 +00:00
opline - - ;
}
if ( opline - > result_type = = IS_TMP_VAR & & opline - > result . var = = op1 - > u . op . var ) {
2019-10-03 11:57:20 +00:00
switch ( opline - > opcode ) {
case ZEND_BOOL :
case ZEND_BOOL_NOT :
/* boolean resuls don't have to be freed */
return ;
case ZEND_POST_INC_STATIC_PROP :
case ZEND_POST_DEC_STATIC_PROP :
case ZEND_POST_INC_OBJ :
case ZEND_POST_DEC_OBJ :
case ZEND_POST_INC :
case ZEND_POST_DEC :
/* convert $i++ to ++$i */
opline - > opcode - = 2 ;
opline - > result_type = IS_UNUSED ;
return ;
2020-02-07 10:36:52 +00:00
case ZEND_ASSIGN :
case ZEND_ASSIGN_DIM :
case ZEND_ASSIGN_OBJ :
case ZEND_ASSIGN_STATIC_PROP :
case ZEND_ASSIGN_OP :
case ZEND_ASSIGN_DIM_OP :
case ZEND_ASSIGN_OBJ_OP :
case ZEND_ASSIGN_STATIC_PROP_OP :
case ZEND_PRE_INC_STATIC_PROP :
case ZEND_PRE_DEC_STATIC_PROP :
case ZEND_PRE_INC_OBJ :
case ZEND_PRE_DEC_OBJ :
case ZEND_PRE_INC :
case ZEND_PRE_DEC :
opline - > result_type = IS_UNUSED ;
return ;
2016-03-17 13:10:08 +00:00
}
}
2016-03-20 00:34:56 +00:00
zend_emit_op ( NULL , ZEND_FREE , op1 , NULL ) ;
2016-03-17 13:10:08 +00:00
} else if ( op1 - > op_type = = IS_VAR ) {
1999-04-07 18:10:10 +00:00
zend_op * opline = & CG ( active_op_array ) - > opcodes [ CG ( active_op_array ) - > last - 1 ] ;
2016-03-17 13:10:08 +00:00
while ( opline - > opcode = = ZEND_END_SILENCE | |
opline - > opcode = = ZEND_EXT_FCALL_END | |
opline - > opcode = = ZEND_OP_DATA ) {
1999-12-20 20:01:19 +00:00
opline - - ;
}
2010-04-20 10:57:45 +00:00
if ( opline - > result_type = = IS_VAR
& & opline - > result . var = = op1 - > u . op . var ) {
2018-06-26 13:18:30 +00:00
if ( opline - > opcode = = ZEND_FETCH_THIS ) {
2016-06-15 23:30:23 +00:00
opline - > opcode = ZEND_NOP ;
opline - > result_type = IS_UNUSED ;
2010-07-16 13:38:09 +00:00
} else {
2016-02-05 14:23:23 +00:00
opline - > result_type = IS_UNUSED ;
2010-07-16 13:38:09 +00:00
}
1999-04-07 18:10:10 +00:00
} else {
2014-10-23 07:52:34 +00:00
while ( opline > = CG ( active_op_array ) - > opcodes ) {
2017-10-06 23:30:58 +00:00
if ( ( opline - > opcode = = ZEND_FETCH_LIST_R | |
opline - > opcode = = ZEND_FETCH_LIST_W ) & &
2014-10-05 09:02:58 +00:00
opline - > op1_type = = IS_VAR & &
opline - > op1 . var = = op1 - > u . op . var ) {
2015-11-13 12:35:07 +00:00
zend_emit_op ( NULL , ZEND_FREE , op1 , NULL ) ;
2014-10-05 09:02:58 +00:00
return ;
}
2016-03-17 13:10:08 +00:00
if ( opline - > result_type = = IS_VAR
2010-04-20 10:57:45 +00:00
& & opline - > result . var = = op1 - > u . op . var ) {
2005-06-10 07:56:40 +00:00
if ( opline - > opcode = = ZEND_NEW ) {
2016-02-11 19:42:49 +00:00
zend_emit_op ( NULL , ZEND_FREE , op1 , NULL ) ;
2005-06-10 07:56:40 +00:00
}
2000-02-02 16:47:43 +00:00
break ;
1999-04-07 18:10:10 +00:00
}
opline - - ;
}
}
2000-12-18 13:28:32 +00:00
} else if ( op1 - > op_type = = IS_CONST ) {
2014-08-17 19:45:29 +00:00
/* Destroy value without using GC: When opcache moves arrays into SHM it will
* free the zend_array structure , so references to it from outside the op array
* become invalid . GC would cause such a reference in the root buffer . */
2014-09-03 13:16:32 +00:00
zval_ptr_dtor_nogc ( & op1 - > u . constant ) ;
2006-05-09 23:53:23 +00:00
}
2002-03-10 13:42:37 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-01 18:44:07 +00:00
uint32_t zend_add_class_modifier ( uint32_t flags , uint32_t new_flag ) /* { { { */
{
uint32_t new_flags = flags | new_flag ;
if ( ( flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS ) & & ( new_flag & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS ) ) {
2017-09-24 13:24:51 +00:00
zend_throw_exception ( zend_ce_compile_error ,
" Multiple abstract modifiers are not allowed " , 0 ) ;
return 0 ;
2014-12-01 18:44:07 +00:00
}
if ( ( flags & ZEND_ACC_FINAL ) & & ( new_flag & ZEND_ACC_FINAL ) ) {
2017-09-24 13:24:51 +00:00
zend_throw_exception ( zend_ce_compile_error , " Multiple final modifiers are not allowed " , 0 ) ;
return 0 ;
2014-12-01 18:44:07 +00:00
}
if ( ( new_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS ) & & ( new_flags & ZEND_ACC_FINAL ) ) {
2017-09-24 13:24:51 +00:00
zend_throw_exception ( zend_ce_compile_error ,
" Cannot use the final modifier on an abstract class " , 0 ) ;
return 0 ;
2014-12-01 18:44:07 +00:00
}
return new_flags ;
}
/* }}} */
2014-08-29 05:05:58 +00:00
uint32_t zend_add_member_modifier ( uint32_t flags , uint32_t new_flag ) /* { { { */
{
2014-08-25 19:21:16 +00:00
uint32_t new_flags = flags | new_flag ;
2014-07-27 10:17:36 +00:00
if ( ( flags & ZEND_ACC_PPP_MASK ) & & ( new_flag & ZEND_ACC_PPP_MASK ) ) {
2017-09-24 13:24:51 +00:00
zend_throw_exception ( zend_ce_compile_error ,
" Multiple access type modifiers are not allowed " , 0 ) ;
return 0 ;
2002-12-06 17:09:44 +00:00
}
2014-07-27 10:17:36 +00:00
if ( ( flags & ZEND_ACC_ABSTRACT ) & & ( new_flag & ZEND_ACC_ABSTRACT ) ) {
2017-09-24 13:24:51 +00:00
zend_throw_exception ( zend_ce_compile_error , " Multiple abstract modifiers are not allowed " , 0 ) ;
return 0 ;
2007-11-13 16:52:14 +00:00
}
2014-07-27 10:17:36 +00:00
if ( ( flags & ZEND_ACC_STATIC ) & & ( new_flag & ZEND_ACC_STATIC ) ) {
2017-09-24 13:24:51 +00:00
zend_throw_exception ( zend_ce_compile_error , " Multiple static modifiers are not allowed " , 0 ) ;
return 0 ;
2007-11-13 16:52:14 +00:00
}
2014-07-27 10:17:36 +00:00
if ( ( flags & ZEND_ACC_FINAL ) & & ( new_flag & ZEND_ACC_FINAL ) ) {
2017-09-24 13:24:51 +00:00
zend_throw_exception ( zend_ce_compile_error , " Multiple final modifiers are not allowed " , 0 ) ;
return 0 ;
2007-11-13 16:52:14 +00:00
}
2014-07-27 10:17:36 +00:00
if ( ( new_flags & ZEND_ACC_ABSTRACT ) & & ( new_flags & ZEND_ACC_FINAL ) ) {
2017-09-24 13:24:51 +00:00
zend_throw_exception ( zend_ce_compile_error ,
" Cannot use the final modifier on an abstract class member " , 0 ) ;
return 0 ;
2003-03-01 14:57:49 +00:00
}
2014-07-27 10:17:36 +00:00
return new_flags ;
2002-12-06 17:09:44 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2006-05-09 23:53:23 +00:00
2020-04-14 14:52:13 +00:00
ZEND_API zend_string * zend_create_member_string ( zend_string * class_name , zend_string * member_name ) {
return zend_string_concat3 (
ZSTR_VAL ( class_name ) , ZSTR_LEN ( class_name ) ,
" :: " , sizeof ( " :: " ) - 1 ,
ZSTR_VAL ( member_name ) , ZSTR_LEN ( member_name ) ) ;
}
2014-07-16 21:23:25 +00:00
zend_string * zend_concat_names ( char * name1 , size_t name1_len , char * name2 , size_t name2_len ) {
2020-04-09 13:06:53 +00:00
return zend_string_concat3 ( name1 , name1_len , " \\ " , 1 , name2 , name2_len ) ;
2014-07-16 21:23:25 +00:00
}
2004-10-04 19:54:35 +00:00
2014-12-13 22:06:14 +00:00
zend_string * zend_prefix_with_ns ( zend_string * name ) {
2015-04-20 18:16:58 +00:00
if ( FC ( current_namespace ) ) {
zend_string * ns = FC ( current_namespace ) ;
2015-06-30 10:59:27 +00:00
return zend_concat_names ( ZSTR_VAL ( ns ) , ZSTR_LEN ( ns ) , ZSTR_VAL ( name ) , ZSTR_LEN ( name ) ) ;
1999-09-20 15:44:30 +00:00
} else {
2014-08-25 19:21:16 +00:00
return zend_string_copy ( name ) ;
1999-09-20 15:44:30 +00:00
}
2014-07-22 11:30:26 +00:00
}
1999-09-20 15:44:30 +00:00
2014-06-28 20:27:06 +00:00
zend_string * zend_resolve_non_class_name (
2014-08-25 19:21:16 +00:00
zend_string * name , uint32_t type , zend_bool * is_fully_qualified ,
2014-12-14 13:07:59 +00:00
zend_bool case_sensitive , HashTable * current_import_sub
2014-06-28 20:27:06 +00:00
) {
char * compound ;
2014-07-22 11:25:47 +00:00
* is_fully_qualified = 0 ;
2008-11-04 15:58:55 +00:00
2015-06-30 10:59:27 +00:00
if ( ZSTR_VAL ( name ) [ 0 ] = = ' \\ ' ) {
2014-07-04 22:11:00 +00:00
/* Remove \ prefix (only relevant if this is a string rather than a label) */
2016-05-01 11:04:08 +00:00
* is_fully_qualified = 1 ;
2015-06-30 10:59:27 +00:00
return zend_string_init ( ZSTR_VAL ( name ) + 1 , ZSTR_LEN ( name ) - 1 , 0 ) ;
2001-08-08 17:18:16 +00:00
}
1999-04-07 18:10:10 +00:00
2014-07-22 11:25:47 +00:00
if ( type = = ZEND_NAME_FQ ) {
* is_fully_qualified = 1 ;
2014-08-25 19:21:16 +00:00
return zend_string_copy ( name ) ;
1999-04-07 18:10:10 +00:00
}
2014-07-22 11:25:47 +00:00
if ( type = = ZEND_NAME_RELATIVE ) {
* is_fully_qualified = 1 ;
2014-12-13 22:06:14 +00:00
return zend_prefix_with_ns ( name ) ;
2014-07-22 11:25:47 +00:00
}
1999-09-20 14:45:36 +00:00
2013-07-23 19:08:49 +00:00
if ( current_import_sub ) {
2014-07-04 22:11:00 +00:00
/* If an unqualified name is a function/const alias, replace it. */
zend_string * import_name ;
2013-08-25 14:21:51 +00:00
if ( case_sensitive ) {
2014-07-04 22:11:00 +00:00
import_name = zend_hash_find_ptr ( current_import_sub , name ) ;
2010-05-06 10:27:35 +00:00
} else {
2020-04-24 21:00:13 +00:00
import_name = zend_hash_find_ptr_lc ( current_import_sub , name ) ;
2010-05-06 10:27:35 +00:00
}
2004-10-04 19:54:35 +00:00
2014-07-04 22:11:00 +00:00
if ( import_name ) {
2014-06-28 20:27:06 +00:00
* is_fully_qualified = 1 ;
2014-08-25 19:21:16 +00:00
return zend_string_copy ( import_name ) ;
2013-07-16 18:39:33 +00:00
}
2014-06-28 20:27:06 +00:00
}
2004-10-04 19:54:35 +00:00
2015-06-30 10:59:27 +00:00
compound = memchr ( ZSTR_VAL ( name ) , ' \\ ' , ZSTR_LEN ( name ) ) ;
2014-06-28 20:27:06 +00:00
if ( compound ) {
* is_fully_qualified = 1 ;
2013-07-16 18:39:33 +00:00
}
2015-04-20 18:16:58 +00:00
if ( compound & & FC ( imports ) ) {
2014-07-04 22:11:00 +00:00
/* If the first part of a qualified name is an alias, substitute it. */
2015-06-30 10:59:27 +00:00
size_t len = compound - ZSTR_VAL ( name ) ;
2020-04-24 21:00:13 +00:00
zend_string * import_name = zend_hash_str_find_ptr_lc ( FC ( imports ) , ZSTR_VAL ( name ) , len ) ;
2014-06-28 20:27:06 +00:00
2014-07-04 22:11:00 +00:00
if ( import_name ) {
2014-06-28 20:27:06 +00:00
return zend_concat_names (
2015-06-30 10:59:27 +00:00
ZSTR_VAL ( import_name ) , ZSTR_LEN ( import_name ) , ZSTR_VAL ( name ) + len + 1 , ZSTR_LEN ( name ) - len - 1 ) ;
2004-10-04 19:54:35 +00:00
}
}
2008-11-04 15:58:55 +00:00
2014-12-13 22:06:14 +00:00
return zend_prefix_with_ns ( name ) ;
2001-11-25 08:49:09 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
zend_string * zend_resolve_function_name ( zend_string * name , uint32_t type , zend_bool * is_fully_qualified ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-28 20:27:06 +00:00
return zend_resolve_non_class_name (
2015-04-20 18:16:58 +00:00
name , type , is_fully_qualified , 0 , FC ( imports_function ) ) ;
2013-07-23 19:08:49 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
zend_string * zend_resolve_const_name ( zend_string * name , uint32_t type , zend_bool * is_fully_qualified ) /* { { { */ {
2014-06-28 20:27:06 +00:00
return zend_resolve_non_class_name (
2015-04-20 18:16:58 +00:00
name , type , is_fully_qualified , 1 , FC ( imports_const ) ) ;
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
zend_string * zend_resolve_class_name ( zend_string * name , uint32_t type ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2007-09-28 19:52:53 +00:00
char * compound ;
2010-04-20 10:57:45 +00:00
2014-07-22 11:25:47 +00:00
if ( type = = ZEND_NAME_RELATIVE ) {
2014-12-13 22:06:14 +00:00
return zend_prefix_with_ns ( name ) ;
2014-07-22 11:25:47 +00:00
}
2015-06-30 10:59:27 +00:00
if ( type = = ZEND_NAME_FQ | | ZSTR_VAL ( name ) [ 0 ] = = ' \\ ' ) {
2014-07-04 21:45:20 +00:00
/* Remove \ prefix (only relevant if this is a string rather than a label) */
2015-06-30 10:59:27 +00:00
if ( ZSTR_VAL ( name ) [ 0 ] = = ' \\ ' ) {
name = zend_string_init ( ZSTR_VAL ( name ) + 1 , ZSTR_LEN ( name ) - 1 , 0 ) ;
2013-01-28 02:02:51 +00:00
} else {
2014-08-25 19:21:16 +00:00
zend_string_addref ( name ) ;
2014-07-04 21:45:20 +00:00
}
/* Ensure that \self, \parent and \static are not used */
2014-07-28 13:39:43 +00:00
if ( ZEND_FETCH_CLASS_DEFAULT ! = zend_get_class_fetch_type ( name ) ) {
2015-06-30 10:59:27 +00:00
zend_error_noreturn ( E_COMPILE_ERROR , " ' \\ %s' is an invalid class name " , ZSTR_VAL ( name ) ) ;
2010-04-20 10:57:45 +00:00
}
2014-07-04 21:45:20 +00:00
return name ;
2010-04-20 10:57:45 +00:00
}
2013-01-28 02:02:51 +00:00
2015-04-20 18:16:58 +00:00
if ( FC ( imports ) ) {
2015-06-30 10:59:27 +00:00
compound = memchr ( ZSTR_VAL ( name ) , ' \\ ' , ZSTR_LEN ( name ) ) ;
2014-07-04 21:45:20 +00:00
if ( compound ) {
/* If the first part of a qualified name is an alias, substitute it. */
2015-06-30 10:59:27 +00:00
size_t len = compound - ZSTR_VAL ( name ) ;
2015-04-20 15:39:32 +00:00
zend_string * import_name =
2020-04-24 21:00:13 +00:00
zend_hash_str_find_ptr_lc ( FC ( imports ) , ZSTR_VAL ( name ) , len ) ;
2014-07-04 21:45:20 +00:00
2014-07-04 22:11:00 +00:00
if ( import_name ) {
2014-07-04 21:45:20 +00:00
return zend_concat_names (
2015-06-30 10:59:27 +00:00
ZSTR_VAL ( import_name ) , ZSTR_LEN ( import_name ) , ZSTR_VAL ( name ) + len + 1 , ZSTR_LEN ( name ) - len - 1 ) ;
2007-12-03 14:15:43 +00:00
}
2014-07-04 21:45:20 +00:00
} else {
/* If an unqualified name is an alias, replace it. */
2014-07-04 22:11:00 +00:00
zend_string * import_name
2020-04-24 21:00:13 +00:00
= zend_hash_find_ptr_lc ( FC ( imports ) , name ) ;
2014-07-04 21:45:20 +00:00
2014-07-04 22:11:00 +00:00
if ( import_name ) {
2014-08-25 19:21:16 +00:00
return zend_string_copy ( import_name ) ;
2007-09-28 19:52:53 +00:00
}
}
2014-07-04 21:45:20 +00:00
}
1999-04-07 18:10:10 +00:00
2014-07-04 21:45:20 +00:00
/* If not fully qualified and not an alias, prepend the current namespace */
2014-12-13 22:06:14 +00:00
return zend_prefix_with_ns ( name ) ;
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
zend_string * zend_resolve_class_name_ast ( zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2015-06-12 13:07:23 +00:00
zval * class_name = zend_ast_get_zval ( ast ) ;
if ( Z_TYPE_P ( class_name ) ! = IS_STRING ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Illegal class name " ) ;
}
return zend_resolve_class_name ( Z_STR_P ( class_name ) , ast - > attr ) ;
2000-01-29 10:16:04 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2000-01-29 10:16:04 +00:00
2015-08-12 03:15:09 +00:00
static void label_ptr_dtor ( zval * zv ) /* { { { */
1999-04-07 18:10:10 +00:00
{
2015-08-12 03:15:09 +00:00
efree_size ( Z_PTR_P ( zv ) , sizeof ( zend_label ) ) ;
1999-04-07 18:10:10 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-08-29 05:05:58 +00:00
static void str_dtor ( zval * zv ) /* { { { */ {
2018-05-28 13:27:12 +00:00
zend_string_release_ex ( Z_STR_P ( zv ) , 0 ) ;
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2015-07-10 00:31:52 +00:00
static zend_bool zend_is_call ( zend_ast * ast ) ;
2014-12-13 22:06:14 +00:00
static uint32_t zend_add_try_element ( uint32_t try_op ) /* { { { */
1999-04-07 18:10:10 +00:00
{
2014-07-12 11:50:58 +00:00
zend_op_array * op_array = CG ( active_op_array ) ;
2014-08-25 19:21:16 +00:00
uint32_t try_catch_offset = op_array - > last_try_catch + + ;
2014-07-12 11:50:58 +00:00
zend_try_catch_element * elem ;
1999-04-07 18:10:10 +00:00
2014-07-12 11:50:58 +00:00
op_array - > try_catch_array = safe_erealloc (
op_array - > try_catch_array , sizeof ( zend_try_catch_element ) , op_array - > last_try_catch , 0 ) ;
1999-04-07 18:10:10 +00:00
2014-07-12 11:50:58 +00:00
elem = & op_array - > try_catch_array [ try_catch_offset ] ;
elem - > try_op = try_op ;
elem - > catch_op = 0 ;
elem - > finally_op = 0 ;
elem - > finally_end = 0 ;
2004-07-20 08:58:18 +00:00
2004-02-03 12:17:09 +00:00
return try_catch_offset ;
2001-12-16 19:45:49 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2009-07-27 14:11:53 +00:00
ZEND_API void function_add_ref ( zend_function * function ) /* { { { */
1999-04-07 18:10:10 +00:00
{
1999-07-08 16:55:27 +00:00
if ( function - > type = = ZEND_USER_FUNCTION ) {
1999-12-23 19:23:36 +00:00
zend_op_array * op_array = & function - > op_array ;
1999-04-07 18:10:10 +00:00
2015-02-20 11:59:30 +00:00
if ( op_array - > refcount ) {
( * op_array - > refcount ) + + ;
}
2019-03-06 09:42:02 +00:00
if ( op_array - > static_variables
& & ! ( GC_FLAGS ( op_array - > static_variables ) & IS_ARRAY_IMMUTABLE ) ) {
GC_ADDREF ( op_array - > static_variables ) ;
2005-07-19 07:33:00 +00:00
}
2019-12-12 10:19:07 +00:00
if ( CG ( compiler_options ) & ZEND_COMPILE_PRELOAD ) {
ZEND_ASSERT ( op_array - > fn_flags & ZEND_ACC_PRELOADED ) ;
ZEND_MAP_PTR_NEW ( op_array - > run_time_cache ) ;
ZEND_MAP_PTR_NEW ( op_array - > static_variables_ptr ) ;
} else {
ZEND_MAP_PTR_INIT ( op_array - > static_variables_ptr , & op_array - > static_variables ) ;
ZEND_MAP_PTR_INIT ( op_array - > run_time_cache , zend_arena_alloc ( & CG ( arena ) , sizeof ( void * ) ) ) ;
ZEND_MAP_PTR_SET ( op_array - > run_time_cache , NULL ) ;
}
2020-03-02 10:07:57 +00:00
}
if ( function - > common . function_name ) {
zend_string_addref ( function - > common . function_name ) ;
1999-04-07 18:10:10 +00:00
}
}
2009-07-27 14:11:53 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2018-08-24 12:18:38 +00:00
static zend_never_inline ZEND_COLD ZEND_NORETURN void do_bind_function_error ( zend_string * lcname , zend_op_array * op_array , zend_bool compile_time ) /* { { { */
{
zval * zv = zend_hash_find_ex ( compile_time ? CG ( function_table ) : EG ( function_table ) , lcname , 1 ) ;
int error_level = compile_time ? E_COMPILE_ERROR : E_ERROR ;
zend_function * old_function ;
ZEND_ASSERT ( zv ! = NULL ) ;
old_function = ( zend_function * ) Z_PTR_P ( zv ) ;
if ( old_function - > type = = ZEND_USER_FUNCTION
& & old_function - > op_array . last > 0 ) {
zend_error_noreturn ( error_level , " Cannot redeclare %s() (previously declared in %s:%d) " ,
2018-08-28 21:35:07 +00:00
op_array ? ZSTR_VAL ( op_array - > function_name ) : ZSTR_VAL ( old_function - > common . function_name ) ,
2018-08-24 12:18:38 +00:00
ZSTR_VAL ( old_function - > op_array . filename ) ,
old_function - > op_array . opcodes [ 0 ] . lineno ) ;
} else {
2018-08-28 21:35:07 +00:00
zend_error_noreturn ( error_level , " Cannot redeclare %s() " ,
op_array ? ZSTR_VAL ( op_array - > function_name ) : ZSTR_VAL ( old_function - > common . function_name ) ) ;
2018-08-24 12:18:38 +00:00
}
}
2020-08-28 13:41:27 +00:00
ZEND_API zend_result do_bind_function ( zval * lcname ) /* { { { */
2004-02-03 12:17:09 +00:00
{
2018-08-28 21:35:07 +00:00
zend_function * function ;
2018-08-22 23:02:26 +00:00
zval * rtd_key , * zv ;
2007-01-09 15:06:07 +00:00
2018-08-22 23:02:26 +00:00
rtd_key = lcname + 1 ;
2018-08-24 12:18:38 +00:00
zv = zend_hash_find_ex ( EG ( function_table ) , Z_STR_P ( rtd_key ) , 1 ) ;
2018-08-28 21:35:07 +00:00
if ( UNEXPECTED ( ! zv ) ) {
do_bind_function_error ( Z_STR_P ( lcname ) , NULL , 0 ) ;
return FAILURE ;
2004-02-03 12:17:09 +00:00
}
2018-08-28 21:35:07 +00:00
function = ( zend_function * ) Z_PTR_P ( zv ) ;
zv = zend_hash_set_bucket_key ( EG ( function_table ) , ( Bucket * ) zv , Z_STR_P ( lcname ) ) ;
if ( UNEXPECTED ( ! zv ) ) {
do_bind_function_error ( Z_STR_P ( lcname ) , & function - > op_array , 0 ) ;
2018-08-27 09:47:32 +00:00
return FAILURE ;
}
return SUCCESS ;
2001-08-30 15:26:30 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
2001-08-30 15:26:30 +00:00
2020-08-28 13:41:27 +00:00
ZEND_API zend_result do_bind_class ( zval * lcname , zend_string * lc_parent_name ) /* { { { */
2001-08-30 15:26:30 +00:00
{
2014-02-10 06:04:30 +00:00
zend_class_entry * ce ;
2018-08-22 23:02:26 +00:00
zval * rtd_key , * zv ;
2006-05-09 23:53:23 +00:00
2018-08-22 23:02:26 +00:00
rtd_key = lcname + 1 ;
2007-09-28 19:52:53 +00:00
2018-08-24 12:18:38 +00:00
zv = zend_hash_find_ex ( EG ( class_table ) , Z_STR_P ( rtd_key ) , 1 ) ;
2001-08-30 15:26:30 +00:00
2018-08-28 21:35:07 +00:00
if ( UNEXPECTED ( ! zv ) ) {
2019-09-11 15:04:13 +00:00
ce = zend_hash_find_ptr ( EG ( class_table ) , Z_STR_P ( lcname ) ) ;
2019-12-10 21:46:30 +00:00
if ( ce ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot declare %s %s, because the name is already in use " , zend_get_object_type ( ce ) , ZSTR_VAL ( ce - > name ) ) ;
2020-03-12 13:31:24 +00:00
return FAILURE ;
2019-12-10 21:46:30 +00:00
} else {
2020-03-12 13:31:24 +00:00
do {
2020-03-12 19:26:30 +00:00
ZEND_ASSERT ( EG ( current_execute_data ) - > func - > op_array . fn_flags & ZEND_ACC_PRELOADED ) ;
2020-03-12 13:31:24 +00:00
if ( zend_preload_autoload
& & zend_preload_autoload ( EG ( current_execute_data ) - > func - > op_array . filename ) = = SUCCESS ) {
zv = zend_hash_find_ex ( EG ( class_table ) , Z_STR_P ( rtd_key ) , 1 ) ;
if ( EXPECTED ( zv ! = NULL ) ) {
break ;
}
}
zend_error_noreturn ( E_ERROR , " Class %s wasn't preloaded " , Z_STRVAL_P ( lcname ) ) ;
return FAILURE ;
} while ( 0 ) ;
2019-12-10 21:46:30 +00:00
}
2002-09-24 19:05:53 +00:00
}
2007-01-09 15:06:07 +00:00
2002-09-24 19:05:53 +00:00
/* Register the derived class */
2018-08-28 21:35:07 +00:00
ce = ( zend_class_entry * ) Z_PTR_P ( zv ) ;
zv = zend_hash_set_bucket_key ( EG ( class_table ) , ( Bucket * ) zv , Z_STR_P ( lcname ) ) ;
if ( UNEXPECTED ( ! zv ) ) {
2015-06-30 10:59:27 +00:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot declare %s %s, because the name is already in use " , zend_get_object_type ( ce ) , ZSTR_VAL ( ce - > name ) ) ;
2018-08-28 21:35:07 +00:00
return FAILURE ;
2012-08-14 00:59:40 +00:00
}
2018-08-22 23:02:26 +00:00
2019-09-11 13:31:04 +00:00
if ( zend_do_link_class ( ce , lc_parent_name ) = = FAILURE ) {
2019-12-09 08:15:27 +00:00
/* Reload bucket pointer, the hash table may have been reallocated */
zv = zend_hash_find ( EG ( class_table ) , Z_STR_P ( lcname ) ) ;
2019-09-11 13:31:04 +00:00
zend_hash_set_bucket_key ( EG ( class_table ) , ( Bucket * ) zv , Z_STR_P ( rtd_key ) ) ;
return FAILURE ;
}
2018-08-24 12:40:53 +00:00
return SUCCESS ;
2001-08-30 15:26:30 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
2001-08-30 15:26:30 +00:00
2019-09-25 11:21:13 +00:00
static zend_string * add_type_string ( zend_string * type , zend_string * new_type ) {
zend_string * result ;
if ( type = = NULL ) {
return zend_string_copy ( new_type ) ;
}
2020-04-14 15:17:38 +00:00
result = zend_string_concat3 (
ZSTR_VAL ( type ) , ZSTR_LEN ( type ) , " | " , 1 , ZSTR_VAL ( new_type ) , ZSTR_LEN ( new_type ) ) ;
2019-09-25 11:21:13 +00:00
zend_string_release ( type ) ;
return result ;
}
static zend_string * resolve_class_name ( zend_string * name , zend_class_entry * scope ) {
if ( scope ) {
if ( zend_string_equals_literal_ci ( name , " self " ) ) {
name = scope - > name ;
} else if ( zend_string_equals_literal_ci ( name , " parent " ) & & scope - > parent ) {
name = scope - > parent - > name ;
}
}
return name ;
}
2019-09-19 10:11:29 +00:00
zend_string * zend_type_to_string_resolved ( zend_type type , zend_class_entry * scope ) {
2019-09-25 11:21:13 +00:00
zend_string * str = NULL ;
2020-03-27 22:39:49 +00:00
2019-09-25 11:21:13 +00:00
if ( ZEND_TYPE_HAS_LIST ( type ) ) {
2020-01-16 16:04:11 +00:00
zend_type * list_type ;
ZEND_TYPE_LIST_FOREACH ( ZEND_TYPE_LIST ( type ) , list_type ) {
if ( ZEND_TYPE_HAS_CE ( * list_type ) ) {
str = add_type_string ( str , ZEND_TYPE_CE ( * list_type ) - > name ) ;
2019-09-25 11:21:13 +00:00
} else {
2020-01-16 16:04:11 +00:00
str = add_type_string ( str , resolve_class_name ( ZEND_TYPE_NAME ( * list_type ) , scope ) ) ;
2019-09-19 10:11:29 +00:00
}
2019-09-25 11:21:13 +00:00
} ZEND_TYPE_LIST_FOREACH_END ( ) ;
} else if ( ZEND_TYPE_HAS_NAME ( type ) ) {
str = zend_string_copy ( resolve_class_name ( ZEND_TYPE_NAME ( type ) , scope ) ) ;
} else if ( ZEND_TYPE_HAS_CE ( type ) ) {
2019-09-19 10:11:29 +00:00
str = zend_string_copy ( ZEND_TYPE_CE ( type ) - > name ) ;
}
2020-05-29 20:31:37 +00:00
uint32_t type_mask = ZEND_TYPE_PURE_MASK ( type ) ;
2020-03-27 22:39:49 +00:00
if ( type_mask = = MAY_BE_ANY ) {
str = add_type_string ( str , ZSTR_KNOWN ( ZEND_STR_MIXED ) ) ;
return str ;
}
2020-01-07 14:06:36 +00:00
if ( type_mask & MAY_BE_STATIC ) {
zend_string * name = ZSTR_KNOWN ( ZEND_STR_STATIC ) ;
if ( scope ) {
zend_class_entry * called_scope = zend_get_called_scope ( EG ( current_execute_data ) ) ;
if ( called_scope ) {
name = called_scope - > name ;
}
}
str = add_type_string ( str , name ) ;
}
2019-09-25 11:21:13 +00:00
if ( type_mask & MAY_BE_CALLABLE ) {
str = add_type_string ( str , ZSTR_KNOWN ( ZEND_STR_CALLABLE ) ) ;
}
if ( type_mask & MAY_BE_ITERABLE ) {
str = add_type_string ( str , ZSTR_KNOWN ( ZEND_STR_ITERABLE ) ) ;
}
if ( type_mask & MAY_BE_OBJECT ) {
str = add_type_string ( str , ZSTR_KNOWN ( ZEND_STR_OBJECT ) ) ;
}
if ( type_mask & MAY_BE_ARRAY ) {
str = add_type_string ( str , ZSTR_KNOWN ( ZEND_STR_ARRAY ) ) ;
}
if ( type_mask & MAY_BE_STRING ) {
str = add_type_string ( str , ZSTR_KNOWN ( ZEND_STR_STRING ) ) ;
}
if ( type_mask & MAY_BE_LONG ) {
str = add_type_string ( str , ZSTR_KNOWN ( ZEND_STR_INT ) ) ;
}
if ( type_mask & MAY_BE_DOUBLE ) {
str = add_type_string ( str , ZSTR_KNOWN ( ZEND_STR_FLOAT ) ) ;
}
if ( ( type_mask & MAY_BE_BOOL ) = = MAY_BE_BOOL ) {
str = add_type_string ( str , ZSTR_KNOWN ( ZEND_STR_BOOL ) ) ;
} else if ( type_mask & MAY_BE_FALSE ) {
str = add_type_string ( str , ZSTR_KNOWN ( ZEND_STR_FALSE ) ) ;
}
if ( type_mask & MAY_BE_VOID ) {
str = add_type_string ( str , ZSTR_KNOWN ( ZEND_STR_VOID ) ) ;
}
if ( type_mask & MAY_BE_NULL ) {
zend_bool is_union = ! str | | memchr ( ZSTR_VAL ( str ) , ' | ' , ZSTR_LEN ( str ) ) ! = NULL ;
if ( ! is_union ) {
2020-04-14 15:17:38 +00:00
zend_string * nullable_str = zend_string_concat2 ( " ? " , 1 , ZSTR_VAL ( str ) , ZSTR_LEN ( str ) ) ;
2019-09-25 11:21:13 +00:00
zend_string_release ( str ) ;
return nullable_str ;
}
str = add_type_string ( str , ZSTR_KNOWN ( ZEND_STR_NULL_LOWERCASE ) ) ;
2019-09-19 10:11:29 +00:00
}
return str ;
}
2020-02-03 10:26:20 +00:00
ZEND_API zend_string * zend_type_to_string ( zend_type type ) {
2019-09-19 10:11:29 +00:00
return zend_type_to_string_resolved ( type , NULL ) ;
}
2019-09-25 11:21:13 +00:00
static zend_bool is_generator_compatible_class_type ( zend_string * name ) {
return zend_string_equals_literal_ci ( name , " Traversable " )
| | zend_string_equals_literal_ci ( name , " Iterator " )
| | zend_string_equals_literal_ci ( name , " Generator " ) ;
}
2015-08-11 20:12:06 +00:00
static void zend_mark_function_as_generator ( ) /* { { { */
{
if ( ! CG ( active_op_array ) - > function_name ) {
zend_error_noreturn ( E_COMPILE_ERROR ,
" The \" yield \" expression can only be used inside a function " ) ;
}
2015-10-19 07:25:16 +00:00
2015-08-11 20:12:06 +00:00
if ( CG ( active_op_array ) - > fn_flags & ZEND_ACC_HAS_RETURN_TYPE ) {
2019-09-25 11:21:13 +00:00
zend_type return_type = CG ( active_op_array ) - > arg_info [ - 1 ] . type ;
2020-05-25 20:38:08 +00:00
zend_bool valid_type = ( ZEND_TYPE_FULL_MASK ( return_type ) & ( MAY_BE_ITERABLE | MAY_BE_OBJECT ) ) ! = 0 ;
2020-01-16 16:04:11 +00:00
if ( ! valid_type ) {
zend_type * single_type ;
ZEND_TYPE_FOREACH ( return_type , single_type ) {
if ( ZEND_TYPE_HAS_NAME ( * single_type )
& & is_generator_compatible_class_type ( ZEND_TYPE_NAME ( * single_type ) ) ) {
valid_type = 1 ;
break ;
}
} ZEND_TYPE_FOREACH_END ( ) ;
2019-09-19 10:11:29 +00:00
}
2015-10-19 07:25:16 +00:00
2019-09-19 10:11:29 +00:00
if ( ! valid_type ) {
2019-09-25 11:21:13 +00:00
zend_string * str = zend_type_to_string ( return_type ) ;
2019-09-19 10:11:29 +00:00
zend_error_noreturn ( E_COMPILE_ERROR ,
2020-05-25 20:38:08 +00:00
" Generator return type must be a supertype of Generator, %s given " ,
2019-09-19 10:11:29 +00:00
ZSTR_VAL ( str ) ) ;
2015-08-11 20:12:06 +00:00
}
}
CG ( active_op_array ) - > fn_flags | = ZEND_ACC_GENERATOR ;
}
/* }}} */
2018-01-11 16:15:52 +00:00
ZEND_API uint32_t zend_build_delayed_early_binding_list ( const zend_op_array * op_array ) /* { { { */
{
if ( op_array - > fn_flags & ZEND_ACC_EARLY_BINDING ) {
uint32_t first_early_binding_opline = ( uint32_t ) - 1 ;
uint32_t * prev_opline_num = & first_early_binding_opline ;
zend_op * opline = op_array - > opcodes ;
zend_op * end = opline + op_array - > last ;
while ( opline < end ) {
2019-05-24 12:28:44 +00:00
if ( opline - > opcode = = ZEND_DECLARE_CLASS_DELAYED ) {
2018-01-11 16:15:52 +00:00
* prev_opline_num = opline - op_array - > opcodes ;
prev_opline_num = & opline - > result . opline_num ;
}
+ + opline ;
}
* prev_opline_num = - 1 ;
return first_early_binding_opline ;
}
return ( uint32_t ) - 1 ;
}
/* }}} */
2019-07-19 08:46:03 +00:00
ZEND_API void zend_do_delayed_early_binding ( zend_op_array * op_array , uint32_t first_early_binding_opline ) /* { { { */
2001-08-30 15:26:30 +00:00
{
2018-01-11 16:15:52 +00:00
if ( first_early_binding_opline ! = ( uint32_t ) - 1 ) {
2008-03-18 08:36:30 +00:00
zend_bool orig_in_compilation = CG ( in_compilation ) ;
2018-01-11 16:15:52 +00:00
uint32_t opline_num = first_early_binding_opline ;
2019-07-19 08:46:03 +00:00
void * * run_time_cache ;
if ( ! ZEND_MAP_PTR ( op_array - > run_time_cache ) ) {
void * ptr ;
ZEND_ASSERT ( op_array - > fn_flags & ZEND_ACC_HEAP_RT_CACHE ) ;
ptr = emalloc ( op_array - > cache_size + sizeof ( void * ) ) ;
ZEND_MAP_PTR_INIT ( op_array - > run_time_cache , ptr ) ;
ptr = ( char * ) ptr + sizeof ( void * ) ;
ZEND_MAP_PTR_SET ( op_array - > run_time_cache , ptr ) ;
memset ( ptr , 0 , op_array - > cache_size ) ;
}
run_time_cache = RUN_TIME_CACHE ( op_array ) ;
2006-05-09 23:53:23 +00:00
2008-03-18 08:36:30 +00:00
CG ( in_compilation ) = 1 ;
2014-12-12 18:57:34 +00:00
while ( opline_num ! = ( uint32_t ) - 1 ) {
2018-07-25 10:40:47 +00:00
const zend_op * opline = & op_array - > opcodes [ opline_num ] ;
2019-05-09 08:41:06 +00:00
zval * lcname = RT_CONSTANT ( opline , opline - > op1 ) ;
2019-06-25 11:20:41 +00:00
zval * zv = zend_hash_find_ex ( EG ( class_table ) , Z_STR_P ( lcname + 1 ) , 1 ) ;
if ( zv ) {
zend_class_entry * ce = Z_CE_P ( zv ) ;
zend_string * lc_parent_name = Z_STR_P ( RT_CONSTANT ( opline , opline - > op2 ) ) ;
zend_class_entry * parent_ce = zend_hash_find_ex_ptr ( EG ( class_table ) , lc_parent_name , 1 ) ;
2019-06-26 23:13:06 +00:00
if ( parent_ce ) {
2019-07-19 08:46:03 +00:00
if ( zend_try_early_bind ( ce , parent_ce , Z_STR_P ( lcname ) , zv ) ) {
/* Store in run-time cache */
( ( void * * ) ( ( char * ) run_time_cache + opline - > extended_value ) ) [ 0 ] = ce ;
}
2019-06-25 11:20:41 +00:00
}
2008-03-18 08:36:30 +00:00
}
2010-04-20 10:57:45 +00:00
opline_num = op_array - > opcodes [ opline_num ] . result . opline_num ;
2008-03-18 08:36:30 +00:00
}
CG ( in_compilation ) = orig_in_compilation ;
}
2001-08-30 15:26:30 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
2001-08-30 15:26:30 +00:00
2020-08-28 13:41:27 +00:00
ZEND_API zend_string * zend_mangle_property_name ( const char * src1 , size_t src1_length , const char * src2 , size_t src2_length , bool internal ) /* { { { */
1999-07-08 16:55:27 +00:00
{
2014-09-15 22:23:58 +00:00
size_t prop_name_length = 1 + src1_length + 1 + src2_length ;
zend_string * prop_name = zend_string_alloc ( prop_name_length , internal ) ;
1999-12-23 19:23:36 +00:00
2015-06-30 10:59:27 +00:00
ZSTR_VAL ( prop_name ) [ 0 ] = ' \0 ' ;
memcpy ( ZSTR_VAL ( prop_name ) + 1 , src1 , src1_length + 1 ) ;
memcpy ( ZSTR_VAL ( prop_name ) + 1 + src1_length + 1 , src2 , src2_length + 1 ) ;
2014-02-17 13:59:18 +00:00
return prop_name ;
2002-02-21 11:50:44 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
1999-12-23 19:23:36 +00:00
2015-04-28 03:30:25 +00:00
static zend_always_inline size_t zend_strnlen ( const char * s , size_t maxlen ) /* { { { */
2005-09-16 17:05:09 +00:00
{
2014-09-15 22:23:58 +00:00
size_t len = 0 ;
2006-07-24 17:58:32 +00:00
while ( * s + + & & maxlen - - ) len + + ;
return len ;
1999-07-08 16:55:27 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
1999-07-08 16:55:27 +00:00
2020-08-28 13:41:27 +00:00
ZEND_API zend_result zend_unmangle_property_name_ex ( const zend_string * name , const char * * class_name , const char * * prop_name , size_t * prop_len ) /* { { { */
1999-07-27 20:34:31 +00:00
{
2014-09-15 22:23:58 +00:00
size_t class_name_len ;
2015-08-06 15:17:53 +00:00
size_t anonclass_src_len ;
2003-09-03 21:21:18 +00:00
2006-07-24 17:58:32 +00:00
* class_name = NULL ;
2005-02-23 11:15:51 +00:00
2016-04-03 11:38:25 +00:00
if ( ! ZSTR_LEN ( name ) | | ZSTR_VAL ( name ) [ 0 ] ! = ' \0 ' ) {
2015-06-30 10:59:27 +00:00
* prop_name = ZSTR_VAL ( name ) ;
2013-01-14 08:23:22 +00:00
if ( prop_len ) {
2015-06-30 10:59:27 +00:00
* prop_len = ZSTR_LEN ( name ) ;
2005-12-17 15:51:52 +00:00
}
2006-07-24 17:58:32 +00:00
return SUCCESS ;
2002-06-23 15:46:58 +00:00
}
2015-06-30 10:59:27 +00:00
if ( ZSTR_LEN ( name ) < 3 | | ZSTR_VAL ( name ) [ 1 ] = = ' \0 ' ) {
2006-07-24 17:58:32 +00:00
zend_error ( E_NOTICE , " Illegal member variable name " ) ;
2015-06-30 10:59:27 +00:00
* prop_name = ZSTR_VAL ( name ) ;
2013-01-14 08:23:22 +00:00
if ( prop_len ) {
2015-06-30 10:59:27 +00:00
* prop_len = ZSTR_LEN ( name ) ;
2014-02-17 13:59:18 +00:00
}
2006-07-24 17:58:32 +00:00
return FAILURE ;
2003-06-08 18:53:58 +00:00
}
2014-02-10 06:04:30 +00:00
2015-06-30 10:59:27 +00:00
class_name_len = zend_strnlen ( ZSTR_VAL ( name ) + 1 , ZSTR_LEN ( name ) - 2 ) ;
if ( class_name_len > = ZSTR_LEN ( name ) - 2 | | ZSTR_VAL ( name ) [ class_name_len + 1 ] ! = ' \0 ' ) {
2006-07-24 17:58:32 +00:00
zend_error ( E_NOTICE , " Corrupt member variable name " ) ;
2015-06-30 10:59:27 +00:00
* prop_name = ZSTR_VAL ( name ) ;
2013-01-14 08:23:22 +00:00
if ( prop_len ) {
2015-06-30 10:59:27 +00:00
* prop_len = ZSTR_LEN ( name ) ;
2003-09-03 21:21:18 +00:00
}
2006-07-24 17:58:32 +00:00
return FAILURE ;
2003-09-03 21:21:18 +00:00
}
2014-09-15 22:23:58 +00:00
2015-06-30 10:59:27 +00:00
* class_name = ZSTR_VAL ( name ) + 1 ;
2015-08-06 15:17:53 +00:00
anonclass_src_len = zend_strnlen ( * class_name + class_name_len + 1 , ZSTR_LEN ( name ) - class_name_len - 2 ) ;
if ( class_name_len + anonclass_src_len + 2 ! = ZSTR_LEN ( name ) ) {
class_name_len + = anonclass_src_len + 1 ;
}
2015-06-30 10:59:27 +00:00
* prop_name = ZSTR_VAL ( name ) + class_name_len + 2 ;
2013-01-14 08:23:22 +00:00
if ( prop_len ) {
2015-06-30 10:59:27 +00:00
* prop_len = ZSTR_LEN ( name ) - class_name_len - 2 ;
2013-01-14 08:23:22 +00:00
}
2006-07-24 17:58:32 +00:00
return SUCCESS ;
1999-07-27 20:34:31 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
1999-07-27 20:34:31 +00:00
2020-01-10 10:34:05 +00:00
static zend_bool can_ct_eval_const ( zend_constant * c ) {
if ( ZEND_CONSTANT_FLAGS ( c ) & CONST_DEPRECATED ) {
return 0 ;
}
if ( ( ZEND_CONSTANT_FLAGS ( c ) & CONST_PERSISTENT )
& & ! ( CG ( compiler_options ) & ZEND_COMPILE_NO_PERSISTENT_CONSTANT_SUBSTITUTION )
& & ! ( ( ZEND_CONSTANT_FLAGS ( c ) & CONST_NO_FILE_CACHE )
& & ( CG ( compiler_options ) & ZEND_COMPILE_WITH_FILE_CACHE ) ) ) {
return 1 ;
}
if ( Z_TYPE ( c - > value ) < IS_OBJECT
& & ! ( CG ( compiler_options ) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION ) ) {
return 1 ;
}
return 0 ;
}
2014-12-13 22:06:14 +00:00
static zend_bool zend_try_ct_eval_const ( zval * zv , zend_string * name , zend_bool is_fully_qualified ) /* { { { */
2002-12-06 17:09:44 +00:00
{
2019-01-30 16:16:09 +00:00
zend_constant * c = zend_hash_find_ptr ( EG ( zend_constants ) , name ) ;
2020-01-10 10:34:05 +00:00
if ( c & & can_ct_eval_const ( c ) ) {
2017-10-30 20:13:10 +00:00
ZVAL_COPY_OR_DUP ( zv , & c - > value ) ;
2015-02-10 14:43:23 +00:00
return 1 ;
2014-02-17 13:59:18 +00:00
}
2014-09-28 21:17:29 +00:00
{
/* Substitute true, false and null (including unqualified usage in namespaces) */
2015-06-30 10:59:27 +00:00
const char * lookup_name = ZSTR_VAL ( name ) ;
size_t lookup_len = ZSTR_LEN ( name ) ;
2014-09-28 21:17:29 +00:00
if ( ! is_fully_qualified ) {
zend_get_unqualified_name ( name , & lookup_name , & lookup_len ) ;
}
2020-01-10 10:34:05 +00:00
if ( ( c = zend_get_special_const ( lookup_name , lookup_len ) ) ) {
ZVAL_COPY_VALUE ( zv , & c - > value ) ;
2014-09-28 21:17:29 +00:00
return 1 ;
}
2019-01-30 16:16:09 +00:00
return 0 ;
}
2002-12-06 17:09:44 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
2002-12-06 17:09:44 +00:00
2015-05-05 17:52:03 +00:00
static inline zend_bool zend_is_scope_known ( ) /* { { { */
{
if ( CG ( active_op_array ) - > fn_flags & ZEND_ACC_CLOSURE ) {
/* Closures can be rebound to a different scope */
return 0 ;
}
if ( ! CG ( active_class_entry ) ) {
2015-05-21 19:07:05 +00:00
/* The scope is known if we're in a free function (no scope), but not if we're in
* a file / eval ( which inherits including / eval ' ing scope ) . */
return CG ( active_op_array ) - > function_name ! = NULL ;
2015-05-05 17:52:03 +00:00
}
/* For traits self etc refers to the using class, not the trait itself */
return ( CG ( active_class_entry ) - > ce_flags & ZEND_ACC_TRAIT ) = = 0 ;
}
/* }}} */
static inline zend_bool class_name_refers_to_active_ce ( zend_string * class_name , uint32_t fetch_type ) /* { { { */
{
if ( ! CG ( active_class_entry ) ) {
return 0 ;
}
if ( fetch_type = = ZEND_FETCH_CLASS_SELF & & zend_is_scope_known ( ) ) {
return 1 ;
}
return fetch_type = = ZEND_FETCH_CLASS_DEFAULT
& & zend_string_equals_ci ( class_name , CG ( active_class_entry ) - > name ) ;
}
/* }}} */
2015-05-25 20:58:30 +00:00
uint32_t zend_get_class_fetch_type ( zend_string * name ) /* { { { */
{
if ( zend_string_equals_literal_ci ( name , " self " ) ) {
return ZEND_FETCH_CLASS_SELF ;
} else if ( zend_string_equals_literal_ci ( name , " parent " ) ) {
return ZEND_FETCH_CLASS_PARENT ;
} else if ( zend_string_equals_literal_ci ( name , " static " ) ) {
return ZEND_FETCH_CLASS_STATIC ;
} else {
return ZEND_FETCH_CLASS_DEFAULT ;
}
}
/* }}} */
static uint32_t zend_get_class_fetch_type_ast ( zend_ast * name_ast ) /* { { { */
{
/* Fully qualified names are always default refs */
if ( name_ast - > attr = = ZEND_NAME_FQ ) {
return ZEND_FETCH_CLASS_DEFAULT ;
}
return zend_get_class_fetch_type ( zend_ast_get_str ( name_ast ) ) ;
}
/* }}} */
2020-01-13 10:34:04 +00:00
static zend_string * zend_resolve_const_class_name_reference ( zend_ast * ast , const char * type )
{
zend_string * class_name = zend_ast_get_str ( ast ) ;
if ( ZEND_FETCH_CLASS_DEFAULT ! = zend_get_class_fetch_type_ast ( ast ) ) {
zend_error_noreturn ( E_COMPILE_ERROR ,
" Cannot use '%s' as %s, as it is reserved " ,
ZSTR_VAL ( class_name ) , type ) ;
}
return zend_resolve_class_name ( class_name , ast - > attr ) ;
}
2015-05-25 20:58:30 +00:00
static void zend_ensure_valid_class_fetch_type ( uint32_t fetch_type ) /* { { { */
{
2019-05-24 07:49:44 +00:00
if ( fetch_type ! = ZEND_FETCH_CLASS_DEFAULT & & zend_is_scope_known ( ) ) {
zend_class_entry * ce = CG ( active_class_entry ) ;
if ( ! ce ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use \" %s \" when no class scope is active " ,
fetch_type = = ZEND_FETCH_CLASS_SELF ? " self " :
fetch_type = = ZEND_FETCH_CLASS_PARENT ? " parent " : " static " ) ;
} else if ( fetch_type = = ZEND_FETCH_CLASS_PARENT & & ! ce - > parent_name ) {
2019-10-15 09:46:48 +00:00
zend_error_noreturn ( E_COMPILE_ERROR ,
2019-05-24 07:49:44 +00:00
" Cannot use \" parent \" when current class scope has no parent " ) ;
}
2015-05-25 20:58:30 +00:00
}
}
/* }}} */
2019-01-04 10:16:59 +00:00
static zend_bool zend_try_compile_const_expr_resolve_class_name ( zval * zv , zend_ast * class_ast ) /* { { { */
2015-05-25 20:58:30 +00:00
{
uint32_t fetch_type ;
2019-01-28 06:46:29 +00:00
zval * class_name ;
2015-05-25 20:58:30 +00:00
if ( class_ast - > kind ! = ZEND_AST_ZVAL ) {
2020-01-08 14:57:13 +00:00
return 0 ;
2015-05-25 20:58:30 +00:00
}
2019-01-28 06:46:29 +00:00
class_name = zend_ast_get_zval ( class_ast ) ;
if ( Z_TYPE_P ( class_name ) ! = IS_STRING ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Illegal class name " ) ;
}
fetch_type = zend_get_class_fetch_type ( Z_STR_P ( class_name ) ) ;
2015-05-25 20:58:30 +00:00
zend_ensure_valid_class_fetch_type ( fetch_type ) ;
switch ( fetch_type ) {
case ZEND_FETCH_CLASS_SELF :
2019-01-04 08:52:04 +00:00
if ( CG ( active_class_entry ) & & zend_is_scope_known ( ) ) {
2015-05-25 20:58:30 +00:00
ZVAL_STR_COPY ( zv , CG ( active_class_entry ) - > name ) ;
2019-01-04 09:49:23 +00:00
return 1 ;
2015-05-25 20:58:30 +00:00
}
2019-01-04 09:49:23 +00:00
return 0 ;
2015-05-25 20:58:30 +00:00
case ZEND_FETCH_CLASS_PARENT :
2019-01-04 11:10:22 +00:00
if ( CG ( active_class_entry ) & & CG ( active_class_entry ) - > parent_name
& & zend_is_scope_known ( ) ) {
ZVAL_STR_COPY ( zv , CG ( active_class_entry ) - > parent_name ) ;
return 1 ;
}
return 0 ;
case ZEND_FETCH_CLASS_STATIC :
2019-01-04 09:49:23 +00:00
return 0 ;
2015-05-25 20:58:30 +00:00
case ZEND_FETCH_CLASS_DEFAULT :
ZVAL_STR ( zv , zend_resolve_class_name_ast ( class_ast ) ) ;
return 1 ;
EMPTY_SWITCH_DEFAULT_CASE ( )
}
}
/* }}} */
2019-07-29 09:12:00 +00:00
/* We don't use zend_verify_const_access because we need to deal with unlinked classes. */
static zend_bool zend_verify_ct_const_access ( zend_class_constant * c , zend_class_entry * scope )
{
if ( Z_ACCESS_FLAGS ( c - > value ) & ZEND_ACC_PUBLIC ) {
return 1 ;
} else if ( Z_ACCESS_FLAGS ( c - > value ) & ZEND_ACC_PRIVATE ) {
return c - > ce = = scope ;
} else {
zend_class_entry * ce = c - > ce ;
while ( 1 ) {
if ( ce = = scope ) {
return 1 ;
}
if ( ! ce - > parent ) {
break ;
}
if ( ce - > ce_flags & ZEND_ACC_RESOLVED_PARENT ) {
ce = ce - > parent ;
} else {
2020-04-24 21:00:13 +00:00
ce = zend_hash_find_ptr_lc ( CG ( class_table ) , ce - > parent_name ) ;
2019-07-29 09:12:00 +00:00
if ( ! ce ) {
break ;
}
}
}
/* Reverse case cannot be true during compilation */
return 0 ;
}
}
2015-02-10 14:43:23 +00:00
static zend_bool zend_try_ct_eval_class_const ( zval * zv , zend_string * class_name , zend_string * name ) /* { { { */
{
uint32_t fetch_type = zend_get_class_fetch_type ( class_name ) ;
2015-12-08 09:40:42 +00:00
zend_class_constant * cc ;
2015-02-10 14:43:23 +00:00
zval * c ;
2015-05-05 17:52:03 +00:00
if ( class_name_refers_to_active_ce ( class_name , fetch_type ) ) {
2015-12-08 09:40:42 +00:00
cc = zend_hash_find_ptr ( & CG ( active_class_entry ) - > constants_table , name ) ;
2015-02-10 14:43:23 +00:00
} else if ( fetch_type = = ZEND_FETCH_CLASS_DEFAULT & & ! ( CG ( compiler_options ) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION ) ) {
2020-04-24 21:00:13 +00:00
zend_class_entry * ce = zend_hash_find_ptr_lc ( CG ( class_table ) , class_name ) ;
2015-02-10 14:43:23 +00:00
if ( ce ) {
2015-12-08 09:40:42 +00:00
cc = zend_hash_find_ptr ( & ce - > constants_table , name ) ;
2015-02-10 14:43:23 +00:00
} else {
return 0 ;
}
} else {
return 0 ;
}
2015-02-10 21:17:43 +00:00
if ( CG ( compiler_options ) & ZEND_COMPILE_NO_PERSISTENT_CONSTANT_SUBSTITUTION ) {
return 0 ;
}
2019-07-29 09:12:00 +00:00
if ( ! cc | | ! zend_verify_ct_const_access ( cc , CG ( active_class_entry ) ) ) {
2015-12-08 09:40:42 +00:00
return 0 ;
}
c = & cc - > value ;
2015-02-10 14:43:23 +00:00
/* Substitute case-sensitive (or lowercase) persistent class constants */
2015-12-08 09:40:42 +00:00
if ( Z_TYPE_P ( c ) < IS_OBJECT ) {
2017-10-30 20:13:10 +00:00
ZVAL_COPY_OR_DUP ( zv , c ) ;
2015-02-10 14:43:23 +00:00
return 1 ;
}
return 0 ;
}
2015-02-13 05:18:14 +00:00
/* }}} */
2015-02-10 14:43:23 +00:00
2015-05-24 19:56:49 +00:00
static void zend_add_to_list ( void * result , void * item ) /* { { { */
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
{
void * * list = * ( void * * ) result ;
size_t n = 0 ;
2012-08-28 12:06:18 +00:00
2012-12-25 06:23:08 +00:00
if ( list ) {
while ( list [ n ] ) {
n + + ;
}
2004-02-25 09:25:37 +00:00
}
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
list = erealloc ( list , sizeof ( void * ) * ( n + 2 ) ) ;
2004-02-12 13:49:55 +00:00
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
list [ n ] = item ;
list [ n + 1 ] = NULL ;
2013-09-26 16:39:17 +00:00
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
* ( void * * ) result = list ;
}
/* }}} */
2013-09-26 16:39:17 +00:00
2019-02-19 08:08:38 +00:00
void zend_do_extended_stmt ( void ) /* { { { */
1999-04-07 18:10:10 +00:00
{
zend_op * opline ;
2013-09-26 16:39:17 +00:00
2019-02-19 08:08:38 +00:00
if ( ! ( CG ( compiler_options ) & ZEND_COMPILE_EXTENDED_STMT ) ) {
1999-04-07 18:10:10 +00:00
return ;
}
2013-09-26 16:39:17 +00:00
2018-12-07 14:47:56 +00:00
opline = get_next_op ( ) ;
2007-11-09 13:34:39 +00:00
1999-04-07 18:10:10 +00:00
opline - > opcode = ZEND_EXT_STMT ;
}
2009-07-27 14:11:53 +00:00
/* }}} */
2012-03-02 03:32:12 +00:00
2014-12-13 22:06:14 +00:00
void zend_do_extended_fcall_begin ( void ) /* { { { */
1999-04-07 18:10:10 +00:00
{
zend_op * opline ;
2012-03-02 03:32:12 +00:00
2019-02-19 08:08:38 +00:00
if ( ! ( CG ( compiler_options ) & ZEND_COMPILE_EXTENDED_FCALL ) ) {
1999-04-07 18:10:10 +00:00
return ;
}
2012-03-02 03:32:12 +00:00
2018-12-07 14:47:56 +00:00
opline = get_next_op ( ) ;
2012-03-02 03:32:12 +00:00
1999-04-07 18:10:10 +00:00
opline - > opcode = ZEND_EXT_FCALL_BEGIN ;
}
2009-07-27 14:11:53 +00:00
/* }}} */
2012-03-02 03:32:12 +00:00
2014-12-13 22:06:14 +00:00
void zend_do_extended_fcall_end ( void ) /* { { { */
1999-04-07 18:10:10 +00:00
{
zend_op * opline ;
2012-03-02 03:32:12 +00:00
2019-02-19 08:08:38 +00:00
if ( ! ( CG ( compiler_options ) & ZEND_COMPILE_EXTENDED_FCALL ) ) {
1999-04-07 18:10:10 +00:00
return ;
}
2006-05-09 23:53:23 +00:00
2018-12-07 14:47:56 +00:00
opline = get_next_op ( ) ;
1999-04-07 18:10:10 +00:00
opline - > opcode = ZEND_EXT_FCALL_END ;
}
2009-07-27 14:11:53 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2020-06-07 09:01:19 +00:00
zend_bool zend_is_auto_global_str ( const char * name , size_t len ) /* { { { */ {
2015-02-13 05:18:14 +00:00
zend_auto_global * auto_global ;
2004-02-02 12:28:19 +00:00
2015-02-13 05:18:14 +00:00
if ( ( auto_global = zend_hash_str_find_ptr ( CG ( auto_globals ) , name , len ) ) ! = NULL ) {
if ( auto_global - > armed ) {
auto_global - > armed = auto_global - > auto_global_callback ( auto_global - > name ) ;
2013-01-28 02:02:51 +00:00
}
2015-02-13 05:18:14 +00:00
return 1 ;
2004-02-02 12:28:19 +00:00
}
2015-02-13 05:18:14 +00:00
return 0 ;
1999-04-07 18:10:10 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
zend_bool zend_is_auto_global ( zend_string * name ) /* { { { */
2003-03-02 13:33:31 +00:00
{
zend_auto_global * auto_global ;
2014-02-10 06:04:30 +00:00
if ( ( auto_global = zend_hash_find_ptr ( CG ( auto_globals ) , name ) ) ! = NULL ) {
2003-03-02 13:33:31 +00:00
if ( auto_global - > armed ) {
2014-12-13 22:06:14 +00:00
auto_global - > armed = auto_global - > auto_global_callback ( auto_global - > name ) ;
2013-01-28 02:02:51 +00:00
}
2003-03-02 13:33:31 +00:00
return 1 ;
}
return 0 ;
}
2009-07-27 14:11:53 +00:00
/* }}} */
2003-03-02 13:33:31 +00:00
2020-08-28 13:41:27 +00:00
zend_result zend_register_auto_global ( zend_string * name , zend_bool jit , zend_auto_global_callback auto_global_callback ) /* { { { */
2001-08-08 17:18:16 +00:00
{
2003-03-02 10:04:53 +00:00
zend_auto_global auto_global ;
2020-08-28 13:41:27 +00:00
zend_result retval ;
2003-03-02 10:04:53 +00:00
2017-11-29 14:10:51 +00:00
auto_global . name = name ;
2003-03-02 10:04:53 +00:00
auto_global . auto_global_callback = auto_global_callback ;
2010-07-08 14:05:11 +00:00
auto_global . jit = jit ;
2003-03-02 10:04:53 +00:00
2014-12-29 06:35:08 +00:00
retval = zend_hash_add_mem ( CG ( auto_globals ) , auto_global . name , & auto_global , sizeof ( zend_auto_global ) ) ! = NULL ? SUCCESS : FAILURE ;
2014-04-10 11:50:25 +00:00
return retval ;
2001-08-08 17:18:16 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
2001-08-08 17:18:16 +00:00
2014-12-13 22:06:14 +00:00
ZEND_API void zend_activate_auto_globals ( void ) /* { { { */
2010-07-08 14:05:11 +00:00
{
2014-07-22 14:55:34 +00:00
zend_auto_global * auto_global ;
ZEND_HASH_FOREACH_PTR ( CG ( auto_globals ) , auto_global ) {
if ( auto_global - > jit ) {
auto_global - > armed = 1 ;
} else if ( auto_global - > auto_global_callback ) {
2014-12-13 22:06:14 +00:00
auto_global - > armed = auto_global - > auto_global_callback ( auto_global - > name ) ;
2002-11-23 20:44:12 +00:00
} else {
2014-07-22 14:55:34 +00:00
auto_global - > armed = 0 ;
2005-05-26 13:46:17 +00:00
}
2014-07-22 14:55:34 +00:00
} ZEND_HASH_FOREACH_END ( ) ;
2010-07-08 14:05:11 +00:00
}
/* }}} */
2010-11-03 15:40:24 +00:00
2019-03-28 08:29:08 +00:00
int ZEND_FASTCALL zendlex ( zend_parser_stack_elem * elem ) /* { { { */
1999-04-07 18:10:10 +00:00
{
2014-07-26 18:54:41 +00:00
zval zv ;
2019-10-04 20:42:14 +00:00
int ret ;
2019-03-28 08:29:08 +00:00
if ( CG ( increment_lineno ) ) {
CG ( zend_lineno ) + + ;
CG ( increment_lineno ) = 0 ;
}
2019-10-04 20:42:14 +00:00
ret = lex_scan ( & zv , elem ) ;
ZEND_ASSERT ( ! EG ( exception ) | | ret = = T_ERROR ) ;
return ret ;
1999-04-07 18:10:10 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
2003-02-01 01:49:15 +00:00
2014-12-13 22:06:14 +00:00
ZEND_API void zend_initialize_class_data ( zend_class_entry * ce , zend_bool nullify_handlers ) /* { { { */
2003-02-10 16:11:24 +00:00
{
2018-08-19 04:32:00 +00:00
zend_bool persistent_hashes = ce - > type = = ZEND_INTERNAL_CLASS ;
2003-02-10 16:46:05 +00:00
2003-02-10 16:11:24 +00:00
ce - > refcount = 1 ;
2014-07-22 14:55:34 +00:00
ce - > ce_flags = ZEND_ACC_CONSTANTS_UPDATED ;
2003-03-31 20:42:01 +00:00
2015-09-20 05:23:36 +00:00
if ( CG ( compiler_options ) & ZEND_COMPILE_GUARDS ) {
ce - > ce_flags | = ZEND_ACC_USE_GUARDS ;
}
2010-05-24 14:11:39 +00:00
ce - > default_properties_table = NULL ;
ce - > default_static_members_table = NULL ;
2020-08-26 10:57:24 +00:00
zend_hash_init ( & ce - > properties_info , 8 , NULL , ( persistent_hashes ? zend_destroy_property_info_internal : NULL ) , persistent_hashes ) ;
zend_hash_init ( & ce - > constants_table , 8 , NULL , NULL , persistent_hashes ) ;
zend_hash_init ( & ce - > function_table , 8 , NULL , ZEND_FUNCTION_DTOR , persistent_hashes ) ;
2003-02-10 16:11:24 +00:00
2005-12-01 11:48:17 +00:00
if ( ce - > type = = ZEND_INTERNAL_CLASS ) {
2018-10-17 12:52:50 +00:00
ZEND_MAP_PTR_INIT ( ce - > static_members_table , NULL ) ;
2005-12-01 11:48:17 +00:00
} else {
2018-10-17 12:52:50 +00:00
ZEND_MAP_PTR_INIT ( ce - > static_members_table , & ce - > default_static_members_table ) ;
2010-09-15 07:38:52 +00:00
ce - > info . user . doc_comment = NULL ;
2003-07-16 09:13:47 +00:00
}
2004-02-25 09:25:37 +00:00
2010-05-24 14:11:39 +00:00
ce - > default_properties_count = 0 ;
ce - > default_static_members_count = 0 ;
2019-01-07 11:28:51 +00:00
ce - > properties_info_table = NULL ;
2020-05-24 18:57:00 +00:00
ce - > attributes = NULL ;
2010-05-24 14:11:39 +00:00
2003-02-10 16:11:24 +00:00
if ( nullify_handlers ) {
ce - > constructor = NULL ;
ce - > destructor = NULL ;
ce - > clone = NULL ;
ce - > __get = NULL ;
ce - > __set = NULL ;
2005-07-07 16:07:09 +00:00
ce - > __unset = NULL ;
ce - > __isset = NULL ;
2003-02-10 16:11:24 +00:00
ce - > __call = NULL ;
2007-09-29 08:52:40 +00:00
ce - > __callstatic = NULL ;
2006-05-09 23:53:23 +00:00
ce - > __tostring = NULL ;
2020-06-26 08:54:40 +00:00
ce - > __serialize = NULL ;
ce - > __unserialize = NULL ;
ce - > __debugInfo = NULL ;
2003-02-10 16:11:24 +00:00
ce - > create_object = NULL ;
2003-12-28 15:18:05 +00:00
ce - > get_iterator = NULL ;
2018-07-12 11:04:14 +00:00
ce - > iterator_funcs_ptr = NULL ;
2007-09-29 09:34:24 +00:00
ce - > get_static_method = NULL ;
2003-12-28 15:18:05 +00:00
ce - > parent = NULL ;
2018-10-07 09:20:38 +00:00
ce - > parent_name = NULL ;
2003-12-28 15:18:05 +00:00
ce - > num_interfaces = 0 ;
ce - > interfaces = NULL ;
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
ce - > num_traits = 0 ;
2018-08-22 23:02:26 +00:00
ce - > trait_names = NULL ;
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
ce - > trait_aliases = NULL ;
ce - > trait_precedences = NULL ;
2005-02-23 11:15:51 +00:00
ce - > serialize = NULL ;
ce - > unserialize = NULL ;
2010-09-15 07:38:52 +00:00
if ( ce - > type = = ZEND_INTERNAL_CLASS ) {
ce - > info . internal . module = NULL ;
ce - > info . internal . builtin_functions = NULL ;
}
2003-02-10 16:11:24 +00:00
}
2003-03-29 11:19:38 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
2003-03-29 11:19:38 +00:00
2014-08-25 19:21:16 +00:00
ZEND_API zend_string * zend_get_compiled_variable_name ( const zend_op_array * op_array , uint32_t var ) /* { { { */
2011-09-23 15:08:11 +00:00
{
2014-03-27 12:00:25 +00:00
return op_array - > vars [ EX_VAR_TO_NUM ( var ) ] ;
2005-01-22 02:29:18 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
2011-09-23 15:08:11 +00:00
2014-08-29 05:05:58 +00:00
zend_ast * zend_ast_append_str ( zend_ast * left_ast , zend_ast * right_ast ) /* { { { */
{
2014-07-26 19:53:50 +00:00
zval * left_zv = zend_ast_get_zval ( left_ast ) ;
zend_string * left = Z_STR_P ( left_zv ) ;
zend_string * right = zend_ast_get_str ( right_ast ) ;
2007-12-07 17:11:24 +00:00
2014-07-26 19:53:50 +00:00
zend_string * result ;
2015-06-30 10:59:27 +00:00
size_t left_len = ZSTR_LEN ( left ) ;
size_t len = left_len + ZSTR_LEN ( right ) + 1 ; /* left\right */
2014-07-26 19:53:50 +00:00
2015-03-19 23:02:42 +00:00
result = zend_string_extend ( left , len , 0 ) ;
2015-06-30 10:59:27 +00:00
ZSTR_VAL ( result ) [ left_len ] = ' \\ ' ;
memcpy ( & ZSTR_VAL ( result ) [ left_len + 1 ] , ZSTR_VAL ( right ) , ZSTR_LEN ( right ) ) ;
ZSTR_VAL ( result ) [ len ] = ' \0 ' ;
2018-05-28 13:27:12 +00:00
zend_string_release_ex ( right , 0 ) ;
2014-07-26 19:53:50 +00:00
ZVAL_STR ( left_zv , result ) ;
return left_ast ;
2007-09-28 19:52:53 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2007-09-28 19:52:53 +00:00
2016-12-11 12:31:37 +00:00
zend_ast * zend_negate_num_string ( zend_ast * ast ) /* { { { */
{
zval * zv = zend_ast_get_zval ( ast ) ;
if ( Z_TYPE_P ( zv ) = = IS_LONG ) {
if ( Z_LVAL_P ( zv ) = = 0 ) {
ZVAL_NEW_STR ( zv , zend_string_init ( " -0 " , sizeof ( " -0 " ) - 1 , 0 ) ) ;
} else {
ZEND_ASSERT ( Z_LVAL_P ( zv ) > 0 ) ;
Z_LVAL_P ( zv ) * = - 1 ;
}
} else if ( Z_TYPE_P ( zv ) = = IS_STRING ) {
size_t orig_len = Z_STRLEN_P ( zv ) ;
2016-12-21 21:11:17 +00:00
Z_STR_P ( zv ) = zend_string_extend ( Z_STR_P ( zv ) , orig_len + 1 , 0 ) ;
2016-12-11 12:31:37 +00:00
memmove ( Z_STRVAL_P ( zv ) + 1 , Z_STRVAL_P ( zv ) , orig_len + 1 ) ;
Z_STRVAL_P ( zv ) [ 0 ] = ' - ' ;
} else {
2020-06-16 14:29:05 +00:00
ZEND_UNREACHABLE ( ) ;
2016-12-11 12:31:37 +00:00
}
return ast ;
}
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_verify_namespace ( void ) /* { { { */
2007-09-28 19:52:53 +00:00
{
2015-04-20 18:16:58 +00:00
if ( FC ( has_bracketed_namespaces ) & & ! FC ( in_namespace ) ) {
2013-10-19 21:22:20 +00:00
zend_error_noreturn ( E_COMPILE_ERROR , " No code may exist outside of namespace {} " ) ;
2011-09-23 15:08:11 +00:00
}
2008-11-25 09:56:32 +00:00
}
/* }}} */
2013-01-28 02:02:51 +00:00
2008-02-12 01:17:48 +00:00
/* {{{ zend_dirname
Returns directory name component of path */
2008-02-12 00:21:15 +00:00
ZEND_API size_t zend_dirname ( char * path , size_t len )
{
register char * end = path + len - 1 ;
unsigned int len_adjust = 0 ;
2011-09-23 15:08:11 +00:00
2015-07-04 16:55:22 +00:00
# ifdef ZEND_WIN32
2008-02-12 00:21:15 +00:00
/* Note that on Win32 CWD is per drive (heritage from CP/M).
* This means dirname ( " c:foo " ) maps to " c:. " or " c: " - which means CWD on C : drive .
*/
if ( ( 2 < = len ) & & isalpha ( ( int ) ( ( unsigned char * ) path ) [ 0 ] ) & & ( ' : ' = = path [ 1 ] ) ) {
/* Skip over the drive spec (if any) so as not to change */
path + = 2 ;
len_adjust + = 2 ;
if ( 2 = = len ) {
/* Return "c:" on Win32 for dirname("c:").
2013-01-28 02:02:51 +00:00
* It would be more consistent to return " c:. "
2008-02-12 00:21:15 +00:00
* but that would require making the string * longer * .
*/
return len ;
}
}
# endif
if ( len = = 0 ) {
/* Illegal use of this function */
return 0 ;
}
/* Strip trailing slashes */
while ( end > = path & & IS_SLASH_P ( end ) ) {
end - - ;
}
if ( end < path ) {
/* The path only contained slashes */
path [ 0 ] = DEFAULT_SLASH ;
path [ 1 ] = ' \0 ' ;
return 1 + len_adjust ;
}
/* Strip filename */
while ( end > = path & & ! IS_SLASH_P ( end ) ) {
end - - ;
}
if ( end < path ) {
/* No slash found, therefore return '.' */
path [ 0 ] = ' . ' ;
path [ 1 ] = ' \0 ' ;
return 1 + len_adjust ;
}
/* Strip slashes which came before the file name */
while ( end > = path & & IS_SLASH_P ( end ) ) {
end - - ;
}
if ( end < path ) {
path [ 0 ] = DEFAULT_SLASH ;
path [ 1 ] = ' \0 ' ;
return 1 + len_adjust ;
}
* ( end + 1 ) = ' \0 ' ;
return ( size_t ) ( end + 1 - path ) + len_adjust ;
}
/* }}} */
2008-02-12 01:17:48 +00:00
2018-06-25 20:43:23 +00:00
static void zend_adjust_for_fetch_type ( zend_op * opline , znode * result , uint32_t type ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2015-10-27 12:47:58 +00:00
zend_uchar factor = ( opline - > opcode = = ZEND_FETCH_STATIC_PROP_R ) ? 1 : 3 ;
2016-06-15 23:30:23 +00:00
2018-02-05 16:40:06 +00:00
switch ( type ) {
2014-06-07 11:06:53 +00:00
case BP_VAR_R :
2018-06-25 20:43:23 +00:00
opline - > result_type = IS_TMP_VAR ;
result - > op_type = IS_TMP_VAR ;
2014-06-07 11:06:53 +00:00
return ;
case BP_VAR_W :
2015-10-27 12:47:58 +00:00
opline - > opcode + = 1 * factor ;
2014-06-07 11:06:53 +00:00
return ;
case BP_VAR_RW :
2015-10-27 12:47:58 +00:00
opline - > opcode + = 2 * factor ;
2014-06-07 11:06:53 +00:00
return ;
case BP_VAR_IS :
2018-06-25 20:43:23 +00:00
opline - > result_type = IS_TMP_VAR ;
result - > op_type = IS_TMP_VAR ;
2015-10-27 12:47:58 +00:00
opline - > opcode + = 3 * factor ;
2014-06-07 11:06:53 +00:00
return ;
case BP_VAR_FUNC_ARG :
2015-10-27 12:47:58 +00:00
opline - > opcode + = 4 * factor ;
2014-06-07 11:06:53 +00:00
return ;
case BP_VAR_UNSET :
2015-10-27 12:47:58 +00:00
opline - > opcode + = 5 * factor ;
2014-06-07 11:06:53 +00:00
return ;
EMPTY_SWITCH_DEFAULT_CASE ( )
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-06-07 11:06:53 +00:00
2015-01-03 09:22:58 +00:00
static inline void zend_make_var_result ( znode * result , zend_op * opline ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-08-15 15:10:06 +00:00
opline - > result_type = IS_VAR ;
2018-12-07 14:47:56 +00:00
opline - > result . var = get_temporary_variable ( ) ;
2014-08-15 15:10:06 +00:00
GET_NODE ( result , opline - > result ) ;
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-08-15 15:10:06 +00:00
2014-12-13 22:06:14 +00:00
static inline void zend_make_tmp_result ( znode * result , zend_op * opline ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-08-15 15:10:06 +00:00
opline - > result_type = IS_TMP_VAR ;
2018-12-07 14:47:56 +00:00
opline - > result . var = get_temporary_variable ( ) ;
2014-08-15 15:10:06 +00:00
GET_NODE ( result , opline - > result ) ;
}
2014-08-29 05:05:58 +00:00
/* }}} */
2011-09-23 15:08:11 +00:00
2015-01-03 09:22:58 +00:00
static zend_op * zend_emit_op ( znode * result , zend_uchar opcode , znode * op1 , znode * op2 ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2018-12-07 14:47:56 +00:00
zend_op * opline = get_next_op ( ) ;
2014-06-07 11:06:53 +00:00
opline - > opcode = opcode ;
2014-02-10 06:04:30 +00:00
2018-03-13 11:34:48 +00:00
if ( op1 ! = NULL ) {
2014-06-07 11:06:53 +00:00
SET_NODE ( opline - > op1 , op1 ) ;
}
2011-09-23 15:08:11 +00:00
2018-03-13 11:34:48 +00:00
if ( op2 ! = NULL ) {
2014-06-07 11:06:53 +00:00
SET_NODE ( opline - > op2 , op2 ) ;
2011-09-23 15:08:11 +00:00
}
2014-08-15 15:10:06 +00:00
if ( result ) {
2014-12-13 22:06:14 +00:00
zend_make_var_result ( result , opline ) ;
2014-06-07 11:06:53 +00:00
}
return opline ;
2013-01-28 02:02:51 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2011-09-23 15:08:11 +00:00
2014-12-13 22:06:14 +00:00
static zend_op * zend_emit_op_tmp ( znode * result , zend_uchar opcode , znode * op1 , znode * op2 ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2018-12-07 14:47:56 +00:00
zend_op * opline = get_next_op ( ) ;
2014-06-14 16:30:18 +00:00
opline - > opcode = opcode ;
2011-01-19 17:17:52 +00:00
2018-03-13 11:34:48 +00:00
if ( op1 ! = NULL ) {
2014-06-19 11:57:29 +00:00
SET_NODE ( opline - > op1 , op1 ) ;
2004-01-28 10:25:45 +00:00
}
2018-03-13 11:34:48 +00:00
if ( op2 ! = NULL ) {
2014-06-14 16:30:18 +00:00
SET_NODE ( opline - > op2 , op2 ) ;
2003-02-24 12:05:58 +00:00
}
2014-09-23 21:57:40 +00:00
if ( result ) {
2014-12-13 22:06:14 +00:00
zend_make_tmp_result ( result , opline ) ;
2014-09-23 21:57:40 +00:00
}
2014-06-14 16:30:18 +00:00
return opline ;
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-06-14 16:30:18 +00:00
2014-12-13 22:06:14 +00:00
static void zend_emit_tick ( void ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2015-07-07 16:26:14 +00:00
zend_op * opline ;
2015-07-07 13:03:58 +00:00
/* This prevents a double TICK generated by the parser statement of "declare()" */
if ( CG ( active_op_array ) - > last & & CG ( active_op_array ) - > opcodes [ CG ( active_op_array ) - > last - 1 ] . opcode = = ZEND_TICKS ) {
return ;
2008-11-04 15:58:55 +00:00
}
2017-12-31 04:35:25 +00:00
2018-12-07 14:47:56 +00:00
opline = get_next_op ( ) ;
2014-07-09 22:00:48 +00:00
opline - > opcode = ZEND_TICKS ;
2015-04-20 18:16:58 +00:00
opline - > extended_value = FC ( declarables ) . ticks ;
2014-07-09 22:00:48 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-07-09 22:00:48 +00:00
2014-12-13 22:06:14 +00:00
static inline zend_op * zend_emit_op_data ( znode * value ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-12-13 22:06:14 +00:00
return zend_emit_op ( NULL , ZEND_OP_DATA , value , NULL ) ;
2014-07-28 10:55:37 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-07-28 10:55:37 +00:00
2014-12-13 22:06:14 +00:00
static inline uint32_t zend_emit_jump ( uint32_t opnum_target ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2018-12-07 14:47:56 +00:00
uint32_t opnum = get_next_op_number ( ) ;
2014-12-13 22:06:14 +00:00
zend_op * opline = zend_emit_op ( NULL , ZEND_JMP , NULL , NULL ) ;
2014-07-18 17:57:38 +00:00
opline - > op1 . opline_num = opnum_target ;
return opnum ;
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-07-18 17:57:38 +00:00
2020-08-28 13:41:27 +00:00
ZEND_API bool zend_is_smart_branch ( const zend_op * opline ) /* { { { */
2016-08-29 09:02:50 +00:00
{
switch ( opline - > opcode ) {
case ZEND_IS_IDENTICAL :
case ZEND_IS_NOT_IDENTICAL :
case ZEND_IS_EQUAL :
case ZEND_IS_NOT_EQUAL :
case ZEND_IS_SMALLER :
case ZEND_IS_SMALLER_OR_EQUAL :
case ZEND_CASE :
2020-04-09 20:36:37 +00:00
case ZEND_CASE_STRICT :
2017-07-17 11:11:50 +00:00
case ZEND_ISSET_ISEMPTY_CV :
2016-08-29 09:02:50 +00:00
case ZEND_ISSET_ISEMPTY_VAR :
case ZEND_ISSET_ISEMPTY_DIM_OBJ :
case ZEND_ISSET_ISEMPTY_PROP_OBJ :
2016-09-06 20:19:34 +00:00
case ZEND_ISSET_ISEMPTY_STATIC_PROP :
2016-08-29 09:02:50 +00:00
case ZEND_INSTANCEOF :
case ZEND_TYPE_CHECK :
case ZEND_DEFINED :
2017-05-24 20:00:48 +00:00
case ZEND_IN_ARRAY :
2018-07-02 21:00:32 +00:00
case ZEND_ARRAY_KEY_EXISTS :
2016-08-29 09:02:50 +00:00
return 1 ;
default :
return 0 ;
}
}
/* }}} */
2014-12-13 22:06:14 +00:00
static inline uint32_t zend_emit_cond_jump ( zend_uchar opcode , znode * cond , uint32_t opnum_target ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2018-12-07 14:47:56 +00:00
uint32_t opnum = get_next_op_number ( ) ;
2019-10-09 14:58:35 +00:00
zend_op * opline ;
2019-10-09 10:48:39 +00:00
if ( cond - > op_type = = IS_TMP_VAR & & opnum > 0 ) {
opline = CG ( active_op_array ) - > opcodes + opnum - 1 ;
if ( opline - > result_type = = IS_TMP_VAR
& & opline - > result . var = = cond - > u . op . var
& & zend_is_smart_branch ( opline ) ) {
if ( opcode = = ZEND_JMPZ ) {
opline - > result_type = IS_TMP_VAR | IS_SMART_BRANCH_JMPZ ;
} else {
ZEND_ASSERT ( opcode = = ZEND_JMPNZ ) ;
opline - > result_type = IS_TMP_VAR | IS_SMART_BRANCH_JMPNZ ;
}
}
2016-08-29 09:02:50 +00:00
}
opline = zend_emit_op ( NULL , opcode , cond , NULL ) ;
2014-07-18 17:57:38 +00:00
opline - > op2 . opline_num = opnum_target ;
return opnum ;
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-07-18 17:57:38 +00:00
2014-12-13 22:06:14 +00:00
static inline void zend_update_jump_target ( uint32_t opnum_jump , uint32_t opnum_target ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-18 14:11:43 +00:00
zend_op * opline = & CG ( active_op_array ) - > opcodes [ opnum_jump ] ;
switch ( opline - > opcode ) {
case ZEND_JMP :
opline - > op1 . opline_num = opnum_target ;
break ;
case ZEND_JMPZ :
case ZEND_JMPNZ :
case ZEND_JMPZ_EX :
case ZEND_JMPNZ_EX :
2015-07-06 15:41:29 +00:00
case ZEND_JMP_SET :
2019-01-15 16:04:24 +00:00
case ZEND_COALESCE :
2020-05-24 10:42:48 +00:00
case ZEND_JMP_NULL :
2014-07-18 14:11:43 +00:00
opline - > op2 . opline_num = opnum_target ;
break ;
EMPTY_SWITCH_DEFAULT_CASE ( )
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-07-18 14:11:43 +00:00
2015-01-03 09:22:58 +00:00
static inline void zend_update_jump_target_to_next ( uint32_t opnum_jump ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2018-12-07 14:47:56 +00:00
zend_update_jump_target ( opnum_jump , get_next_op_number ( ) ) ;
2014-07-18 14:11:43 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-07-18 14:11:43 +00:00
2014-12-13 22:06:14 +00:00
static inline zend_op * zend_delayed_emit_op ( znode * result , zend_uchar opcode , znode * op1 , znode * op2 ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-08-15 15:10:06 +00:00
zend_op tmp_opline ;
2018-03-13 11:34:48 +00:00
2014-12-13 22:06:14 +00:00
init_op ( & tmp_opline ) ;
2018-03-13 11:34:48 +00:00
2014-08-15 15:10:06 +00:00
tmp_opline . opcode = opcode ;
2018-03-13 11:34:48 +00:00
if ( op1 ! = NULL ) {
2015-02-02 17:44:16 +00:00
SET_NODE ( tmp_opline . op1 , op1 ) ;
}
2018-03-13 11:34:48 +00:00
if ( op2 ! = NULL ) {
2015-02-02 17:44:16 +00:00
SET_NODE ( tmp_opline . op2 , op2 ) ;
}
2014-08-15 15:10:06 +00:00
if ( result ) {
2014-12-13 22:06:14 +00:00
zend_make_var_result ( result , & tmp_opline ) ;
2002-11-23 20:44:12 +00:00
}
2002-12-07 21:46:12 +00:00
2014-08-15 15:10:06 +00:00
zend_stack_push ( & CG ( delayed_oplines_stack ) , & tmp_opline ) ;
return zend_stack_top ( & CG ( delayed_oplines_stack ) ) ;
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-08-15 15:10:06 +00:00
2014-12-13 22:06:14 +00:00
static inline uint32_t zend_delayed_compile_begin ( void ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-08-15 15:10:06 +00:00
return zend_stack_count ( & CG ( delayed_oplines_stack ) ) ;
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-08-15 15:10:06 +00:00
2014-12-13 22:06:14 +00:00
static zend_op * zend_delayed_compile_end ( uint32_t offset ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-11-27 09:52:31 +00:00
zend_op * opline = NULL , * oplines = zend_stack_base ( & CG ( delayed_oplines_stack ) ) ;
2014-08-25 19:21:16 +00:00
uint32_t i , count = zend_stack_count ( & CG ( delayed_oplines_stack ) ) ;
2014-08-15 15:10:06 +00:00
2016-01-07 15:05:17 +00:00
ZEND_ASSERT ( count > = offset ) ;
2014-08-15 15:10:06 +00:00
for ( i = offset ; i < count ; + + i ) {
2018-12-07 14:47:56 +00:00
opline = get_next_op ( ) ;
2014-08-15 15:10:06 +00:00
memcpy ( opline , & oplines [ i ] , sizeof ( zend_op ) ) ;
2020-08-31 13:31:18 +00:00
if ( opline - > opcode = = ZEND_JMP_NULL ) {
uint32_t opnum = get_next_op_number ( ) - 1 ;
zend_stack_push ( & CG ( short_circuiting_opnums ) , & opnum ) ;
}
2002-11-23 20:44:12 +00:00
}
2020-08-31 13:31:18 +00:00
2014-08-15 15:10:06 +00:00
CG ( delayed_oplines_stack ) . top = offset ;
return opline ;
}
2014-08-29 05:05:58 +00:00
/* }}} */
2002-12-09 12:10:17 +00:00
2020-05-24 10:42:48 +00:00
static zend_bool zend_ast_kind_is_short_circuited ( zend_ast_kind ast_kind )
{
switch ( ast_kind ) {
case ZEND_AST_DIM :
case ZEND_AST_PROP :
case ZEND_AST_NULLSAFE_PROP :
case ZEND_AST_STATIC_PROP :
case ZEND_AST_METHOD_CALL :
case ZEND_AST_NULLSAFE_METHOD_CALL :
case ZEND_AST_STATIC_CALL :
return 1 ;
default :
return 0 ;
}
}
static zend_bool zend_ast_is_short_circuited ( const zend_ast * ast )
{
switch ( ast - > kind ) {
case ZEND_AST_DIM :
case ZEND_AST_PROP :
case ZEND_AST_STATIC_PROP :
case ZEND_AST_METHOD_CALL :
case ZEND_AST_STATIC_CALL :
return zend_ast_is_short_circuited ( ast - > child [ 0 ] ) ;
case ZEND_AST_NULLSAFE_PROP :
case ZEND_AST_NULLSAFE_METHOD_CALL :
return 1 ;
default :
return 0 ;
}
}
/* Mark nodes that are an inner part of a short-circuiting chain.
* We should not perform a " commit " on them , as it will be performed by the outer - most node .
* We do this to avoid passing down an argument in various compile functions . */
# define ZEND_SHORT_CIRCUITING_INNER 0x8000
static void zend_short_circuiting_mark_inner ( zend_ast * ast ) {
if ( zend_ast_kind_is_short_circuited ( ast - > kind ) ) {
ast - > attr | = ZEND_SHORT_CIRCUITING_INNER ;
}
}
static uint32_t zend_short_circuiting_checkpoint ( )
{
return zend_stack_count ( & CG ( short_circuiting_opnums ) ) ;
}
static void zend_short_circuiting_commit ( uint32_t checkpoint , znode * result , zend_ast * ast )
{
zend_bool is_short_circuited = zend_ast_kind_is_short_circuited ( ast - > kind )
| | ast - > kind = = ZEND_AST_ISSET | | ast - > kind = = ZEND_AST_EMPTY ;
if ( ! is_short_circuited ) {
ZEND_ASSERT ( zend_stack_count ( & CG ( short_circuiting_opnums ) ) = = checkpoint
& & " Short circuiting stack should be empty " ) ;
return ;
}
if ( ast - > attr & ZEND_SHORT_CIRCUITING_INNER ) {
/* Outer-most node will commit. */
return ;
}
while ( zend_stack_count ( & CG ( short_circuiting_opnums ) ) ! = checkpoint ) {
uint32_t opnum = * ( uint32_t * ) zend_stack_top ( & CG ( short_circuiting_opnums ) ) ;
zend_op * opline = & CG ( active_op_array ) - > opcodes [ opnum ] ;
opline - > op2 . opline_num = get_next_op_number ( ) ;
SET_NODE ( opline - > result , result ) ;
opline - > extended_value =
ast - > kind = = ZEND_AST_ISSET ? ZEND_SHORT_CIRCUITING_CHAIN_ISSET :
ast - > kind = = ZEND_AST_EMPTY ? ZEND_SHORT_CIRCUITING_CHAIN_EMPTY :
ZEND_SHORT_CIRCUITING_CHAIN_EXPR ;
zend_stack_del_top ( & CG ( short_circuiting_opnums ) ) ;
}
}
static void zend_emit_jmp_null ( znode * obj_node )
{
uint32_t jmp_null_opnum = get_next_op_number ( ) ;
2020-07-29 13:51:47 +00:00
zend_op * opline = zend_emit_op ( NULL , ZEND_JMP_NULL , obj_node , NULL ) ;
if ( opline - > op1_type = = IS_CONST ) {
Z_TRY_ADDREF_P ( CT_CONSTANT ( opline - > op1 ) ) ;
2020-07-28 07:48:13 +00:00
}
2020-05-24 10:42:48 +00:00
zend_stack_push ( & CG ( short_circuiting_opnums ) , & jmp_null_opnum ) ;
}
2019-01-15 16:04:24 +00:00
# define ZEND_MEMOIZE_NONE 0
# define ZEND_MEMOIZE_COMPILE 1
# define ZEND_MEMOIZE_FETCH 2
static void zend_compile_memoized_expr ( znode * result , zend_ast * expr ) /* { { { */
{
int memoize_mode = CG ( memoize_mode ) ;
if ( memoize_mode = = ZEND_MEMOIZE_COMPILE ) {
znode memoized_result ;
/* Go through normal compilation */
CG ( memoize_mode ) = ZEND_MEMOIZE_NONE ;
zend_compile_expr ( result , expr ) ;
CG ( memoize_mode ) = ZEND_MEMOIZE_COMPILE ;
if ( result - > op_type = = IS_VAR ) {
zend_emit_op ( & memoized_result , ZEND_COPY_TMP , result , NULL ) ;
} else if ( result - > op_type = = IS_TMP_VAR ) {
zend_emit_op_tmp ( & memoized_result , ZEND_COPY_TMP , result , NULL ) ;
} else {
2019-10-04 08:38:11 +00:00
if ( result - > op_type = = IS_CONST ) {
Z_TRY_ADDREF ( result - > u . constant ) ;
}
2019-01-15 16:04:24 +00:00
memoized_result = * result ;
}
zend_hash_index_update_mem (
CG ( memoized_exprs ) , ( uintptr_t ) expr , & memoized_result , sizeof ( znode ) ) ;
} else if ( memoize_mode = = ZEND_MEMOIZE_FETCH ) {
znode * memoized_result = zend_hash_index_find_ptr ( CG ( memoized_exprs ) , ( uintptr_t ) expr ) ;
* result = * memoized_result ;
if ( result - > op_type = = IS_CONST ) {
Z_TRY_ADDREF ( result - > u . constant ) ;
}
} else {
2020-06-16 14:29:05 +00:00
ZEND_UNREACHABLE ( ) ;
2019-01-15 16:04:24 +00:00
}
}
/* }}} */
2019-09-25 11:21:13 +00:00
static size_t zend_type_get_num_classes ( zend_type type ) {
if ( ! ZEND_TYPE_HAS_CLASS ( type ) ) {
return 0 ;
}
if ( ZEND_TYPE_HAS_LIST ( type ) ) {
return ZEND_TYPE_LIST ( type ) - > num_types ;
}
return 1 ;
}
2016-06-04 11:13:25 +00:00
static void zend_emit_return_type_check (
znode * expr , zend_arg_info * return_info , zend_bool implicit ) /* {{{ */
2015-01-08 20:40:36 +00:00
{
2019-09-19 10:11:29 +00:00
zend_type type = return_info - > type ;
if ( ZEND_TYPE_IS_SET ( type ) ) {
2017-01-13 08:37:46 +00:00
zend_op * opline ;
/* `return ...;` is illegal in a void function (but `return;` isn't) */
2019-09-20 15:01:19 +00:00
if ( ZEND_TYPE_CONTAINS_CODE ( type , IS_VOID ) ) {
2017-01-13 08:37:46 +00:00
if ( expr ) {
if ( expr - > op_type = = IS_CONST & & Z_TYPE ( expr - > u . constant ) = = IS_NULL ) {
zend_error_noreturn ( E_COMPILE_ERROR ,
" A void function must not return a value "
" (did you mean \" return; \" instead of \" return null; \" ?) " ) ;
} else {
zend_error_noreturn ( E_COMPILE_ERROR , " A void function must not return a value " ) ;
}
2016-06-04 11:25:52 +00:00
}
2017-01-13 08:37:46 +00:00
/* we don't need run-time check */
return ;
2016-04-07 14:34:53 +00:00
}
2016-06-04 11:13:25 +00:00
if ( ! expr & & ! implicit ) {
2019-09-19 10:11:29 +00:00
if ( ZEND_TYPE_ALLOW_NULL ( type ) ) {
2016-06-04 11:25:52 +00:00
zend_error_noreturn ( E_COMPILE_ERROR ,
" A function with return type must return a value "
" (did you mean \" return null; \" instead of \" return; \" ?) " ) ;
} else {
zend_error_noreturn ( E_COMPILE_ERROR ,
" A function with return type must return a value " ) ;
}
2016-06-04 11:13:25 +00:00
}
2020-03-27 22:39:49 +00:00
if ( expr & & ZEND_TYPE_PURE_MASK ( type ) = = MAY_BE_ANY ) {
/* we don't need run-time check for mixed return type */
return ;
}
if ( expr & & expr - > op_type = = IS_CONST & & ZEND_TYPE_CONTAINS_CODE ( type , Z_TYPE ( expr - > u . constant ) ) ) {
/* we don't need run-time check */
return ;
2016-04-07 14:34:53 +00:00
}
opline = zend_emit_op ( NULL , ZEND_VERIFY_RETURN_TYPE , expr , NULL ) ;
2015-03-20 15:36:43 +00:00
if ( expr & & expr - > op_type = = IS_CONST ) {
opline - > result_type = expr - > op_type = IS_TMP_VAR ;
2018-12-07 14:47:56 +00:00
opline - > result . var = expr - > u . op . var = get_temporary_variable ( ) ;
2015-03-20 15:36:43 +00:00
}
2019-09-25 11:21:13 +00:00
opline - > op2 . num = zend_alloc_cache_slots ( zend_type_get_num_classes ( return_info - > type ) ) ;
2015-01-08 20:40:36 +00:00
}
}
/* }}} */
2020-08-28 13:41:27 +00:00
void zend_emit_final_return ( bool return_one ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-26 19:32:48 +00:00
znode zn ;
2015-10-02 09:43:52 +00:00
zend_op * ret ;
2014-07-26 19:32:48 +00:00
zend_bool returns_reference = ( CG ( active_op_array ) - > fn_flags & ZEND_ACC_RETURN_REFERENCE ) ! = 0 ;
2020-06-07 00:38:13 +00:00
if ( ( CG ( active_op_array ) - > fn_flags & ZEND_ACC_HAS_RETURN_TYPE )
2016-06-10 13:57:18 +00:00
& & ! ( CG ( active_op_array ) - > fn_flags & ZEND_ACC_GENERATOR ) ) {
2016-06-04 11:13:25 +00:00
zend_emit_return_type_check ( NULL , CG ( active_op_array ) - > arg_info - 1 , 1 ) ;
2015-01-08 20:40:36 +00:00
}
2014-07-26 19:32:48 +00:00
zn . op_type = IS_CONST ;
2015-11-12 13:59:44 +00:00
if ( return_one ) {
ZVAL_LONG ( & zn . u . constant , 1 ) ;
2003-01-02 13:58:08 +00:00
} else {
2014-07-26 19:32:48 +00:00
ZVAL_NULL ( & zn . u . constant ) ;
2002-12-09 12:10:17 +00:00
}
2002-12-26 16:27:59 +00:00
2015-10-02 09:43:52 +00:00
ret = zend_emit_op ( NULL , returns_reference ? ZEND_RETURN_BY_REF : ZEND_RETURN , & zn , NULL ) ;
ret - > extended_value = - 1 ;
2014-07-26 19:32:48 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-07-26 19:32:48 +00:00
2014-08-29 05:05:58 +00:00
static inline zend_bool zend_is_variable ( zend_ast * ast ) /* { { { */
{
2020-05-24 10:42:48 +00:00
return ast - > kind = = ZEND_AST_VAR
| | ast - > kind = = ZEND_AST_DIM
| | ast - > kind = = ZEND_AST_PROP
| | ast - > kind = = ZEND_AST_NULLSAFE_PROP
| | ast - > kind = = ZEND_AST_STATIC_PROP ;
2014-06-07 11:06:53 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-06-07 11:06:53 +00:00
2014-08-29 05:05:58 +00:00
static inline zend_bool zend_is_call ( zend_ast * ast ) /* { { { */
{
2014-06-07 11:06:53 +00:00
return ast - > kind = = ZEND_AST_CALL
| | ast - > kind = = ZEND_AST_METHOD_CALL
2020-05-24 10:42:48 +00:00
| | ast - > kind = = ZEND_AST_NULLSAFE_METHOD_CALL
2014-06-07 11:06:53 +00:00
| | ast - > kind = = ZEND_AST_STATIC_CALL ;
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-06-07 11:06:53 +00:00
2019-01-26 11:10:03 +00:00
static inline zend_bool zend_is_variable_or_call ( zend_ast * ast ) /* { { { */
{
return zend_is_variable ( ast ) | | zend_is_call ( ast ) ;
}
/* }}} */
2014-08-29 05:05:58 +00:00
static inline zend_bool zend_is_unticked_stmt ( zend_ast * ast ) /* { { { */
{
2015-07-22 11:12:54 +00:00
return ast - > kind = = ZEND_AST_STMT_LIST | | ast - > kind = = ZEND_AST_LABEL
2020-05-24 18:57:00 +00:00
| | ast - > kind = = ZEND_AST_PROP_DECL | | ast - > kind = = ZEND_AST_CLASS_CONST_GROUP
2015-07-22 11:12:54 +00:00
| | ast - > kind = = ZEND_AST_USE_TRAIT | | ast - > kind = = ZEND_AST_METHOD ;
2014-07-09 22:00:48 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-07-09 22:00:48 +00:00
2014-08-29 05:05:58 +00:00
static inline zend_bool zend_can_write_to_variable ( zend_ast * ast ) /* { { { */
{
2020-05-24 10:42:48 +00:00
while (
ast - > kind = = ZEND_AST_DIM
| | ast - > kind = = ZEND_AST_PROP
) {
2014-06-19 11:57:29 +00:00
ast = ast - > child [ 0 ] ;
2003-03-29 11:19:38 +00:00
}
2020-05-24 10:42:48 +00:00
return zend_is_variable_or_call ( ast ) & & ! zend_ast_is_short_circuited ( ast ) ;
2014-06-19 11:57:29 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-06-19 11:57:29 +00:00
2014-08-29 05:05:58 +00:00
static inline zend_bool zend_is_const_default_class_ref ( zend_ast * name_ast ) /* { { { */
{
2014-06-28 16:03:26 +00:00
if ( name_ast - > kind ! = ZEND_AST_ZVAL ) {
2014-06-14 16:30:18 +00:00
return 0 ;
}
2015-04-27 19:14:58 +00:00
return ZEND_FETCH_CLASS_DEFAULT = = zend_get_class_fetch_type_ast ( name_ast ) ;
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2003-03-29 11:19:38 +00:00
2014-12-13 22:06:14 +00:00
static inline void zend_handle_numeric_op ( znode * node ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-08-15 15:10:06 +00:00
if ( node - > op_type = = IS_CONST & & Z_TYPE ( node - > u . constant ) = = IS_STRING ) {
zend_ulong index ;
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2014-08-15 15:10:06 +00:00
if ( ZEND_HANDLE_NUMERIC ( Z_STR ( node - > u . constant ) , index ) ) {
zval_ptr_dtor ( & node - > u . constant ) ;
ZVAL_LONG ( & node - > u . constant , index ) ;
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
}
2014-06-19 11:57:29 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2013-01-28 02:02:51 +00:00
2018-07-02 22:09:58 +00:00
static inline void zend_handle_numeric_dim ( zend_op * opline , znode * dim_node ) /* { { { */
{
if ( Z_TYPE ( dim_node - > u . constant ) = = IS_STRING ) {
zend_ulong index ;
if ( ZEND_HANDLE_NUMERIC ( Z_STR ( dim_node - > u . constant ) , index ) ) {
2019-02-18 16:35:35 +00:00
/* For numeric indexes we also keep the original value to use by ArrayAccess
2018-07-02 22:09:58 +00:00
* See bug # 63217
*/
2018-12-07 14:47:56 +00:00
int c = zend_add_literal ( & dim_node - > u . constant ) ;
2018-07-02 22:09:58 +00:00
ZEND_ASSERT ( opline - > op2 . constant + 1 = = c ) ;
ZVAL_LONG ( CT_CONSTANT ( opline - > op2 ) , index ) ;
Z_EXTRA_P ( CT_CONSTANT ( opline - > op2 ) ) = ZEND_EXTRA_VALUE ;
return ;
}
}
}
/* }}} */
2014-12-13 22:06:14 +00:00
static inline void zend_set_class_name_op1 ( zend_op * opline , znode * class_node ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-19 11:57:29 +00:00
if ( class_node - > op_type = = IS_CONST ) {
opline - > op1_type = IS_CONST ;
2014-07-19 21:30:07 +00:00
opline - > op1 . constant = zend_add_class_name_literal (
2018-12-07 14:47:56 +00:00
Z_STR ( class_node - > u . constant ) ) ;
2014-06-19 11:57:29 +00:00
} else {
SET_NODE ( opline - > op1 , class_node ) ;
}
2002-11-23 20:44:12 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2002-11-23 20:44:12 +00:00
2019-01-02 08:48:29 +00:00
static void zend_compile_class_ref ( znode * result , zend_ast * name_ast , uint32_t fetch_flags ) /* { { { */
2015-10-27 12:47:58 +00:00
{
uint32_t fetch_type ;
if ( name_ast - > kind ! = ZEND_AST_ZVAL ) {
znode name_node ;
zend_compile_expr ( & name_node , name_ast ) ;
if ( name_node . op_type = = IS_CONST ) {
zend_string * name ;
if ( Z_TYPE ( name_node . u . constant ) ! = IS_STRING ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Illegal class name " ) ;
}
name = Z_STR ( name_node . u . constant ) ;
fetch_type = zend_get_class_fetch_type ( name ) ;
if ( fetch_type = = ZEND_FETCH_CLASS_DEFAULT ) {
result - > op_type = IS_CONST ;
ZVAL_STR ( & result - > u . constant , zend_resolve_class_name ( name , ZEND_NAME_FQ ) ) ;
} else {
zend_ensure_valid_class_fetch_type ( fetch_type ) ;
result - > op_type = IS_UNUSED ;
result - > u . op . num = fetch_type | fetch_flags ;
}
2018-05-28 13:27:12 +00:00
zend_string_release_ex ( name , 0 ) ;
2015-10-27 12:47:58 +00:00
} else {
zend_op * opline = zend_emit_op ( result , ZEND_FETCH_CLASS , NULL , & name_node ) ;
2018-01-31 15:14:43 +00:00
opline - > op1 . num = ZEND_FETCH_CLASS_DEFAULT | fetch_flags ;
2015-10-27 12:47:58 +00:00
}
return ;
}
/* Fully qualified names are always default refs */
if ( name_ast - > attr = = ZEND_NAME_FQ ) {
result - > op_type = IS_CONST ;
ZVAL_STR ( & result - > u . constant , zend_resolve_class_name_ast ( name_ast ) ) ;
return ;
}
fetch_type = zend_get_class_fetch_type ( zend_ast_get_str ( name_ast ) ) ;
if ( ZEND_FETCH_CLASS_DEFAULT = = fetch_type ) {
result - > op_type = IS_CONST ;
ZVAL_STR ( & result - > u . constant , zend_resolve_class_name_ast ( name_ast ) ) ;
} else {
zend_ensure_valid_class_fetch_type ( fetch_type ) ;
result - > op_type = IS_UNUSED ;
result - > u . op . num = fetch_type | fetch_flags ;
}
}
/* }}} */
2020-08-28 13:41:27 +00:00
static zend_result zend_try_compile_cv ( znode * result , zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-07 11:06:53 +00:00
zend_ast * name_ast = ast - > child [ 0 ] ;
2014-06-28 16:03:26 +00:00
if ( name_ast - > kind = = ZEND_AST_ZVAL ) {
2017-10-31 22:10:21 +00:00
zval * zv = zend_ast_get_zval ( name_ast ) ;
zend_string * name ;
if ( EXPECTED ( Z_TYPE_P ( zv ) = = IS_STRING ) ) {
name = zval_make_interned_string ( zv ) ;
} else {
2017-12-07 16:24:55 +00:00
name = zend_new_interned_string ( zval_get_string_func ( zv ) ) ;
2017-10-31 22:10:21 +00:00
}
2014-06-07 11:06:53 +00:00
2014-12-13 22:06:14 +00:00
if ( zend_is_auto_global ( name ) ) {
2014-06-07 11:06:53 +00:00
return FAILURE ;
2003-09-03 19:28:46 +00:00
}
2006-05-11 21:07:39 +00:00
2014-06-07 11:06:53 +00:00
result - > op_type = IS_CV ;
2018-12-07 14:47:56 +00:00
result - > u . op . var = lookup_cv ( name ) ;
2014-06-07 11:06:53 +00:00
2017-10-31 22:10:21 +00:00
if ( UNEXPECTED ( Z_TYPE_P ( zv ) ! = IS_STRING ) ) {
2018-05-28 13:27:12 +00:00
zend_string_release_ex ( name , 0 ) ;
2017-10-31 22:10:21 +00:00
}
2015-01-04 16:57:23 +00:00
2014-06-07 11:06:53 +00:00
return SUCCESS ;
}
return FAILURE ;
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-06-07 11:06:53 +00:00
2020-08-28 13:41:27 +00:00
static zend_op * zend_compile_simple_var_no_cv ( znode * result , zend_ast * ast , uint32_t type , bool delayed ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-07 11:06:53 +00:00
zend_ast * name_ast = ast - > child [ 0 ] ;
znode name_node ;
zend_op * opline ;
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & name_node , name_ast ) ;
2015-01-04 17:07:44 +00:00
if ( name_node . op_type = = IS_CONST ) {
convert_to_string ( & name_node . u . constant ) ;
}
2006-05-11 21:07:39 +00:00
2015-02-02 17:44:16 +00:00
if ( delayed ) {
opline = zend_delayed_emit_op ( result , ZEND_FETCH_R , & name_node , NULL ) ;
} else {
opline = zend_emit_op ( result , ZEND_FETCH_R , & name_node , NULL ) ;
}
2014-06-07 11:06:53 +00:00
2017-12-31 04:35:25 +00:00
if ( name_node . op_type = = IS_CONST & &
2015-05-25 16:59:25 +00:00
zend_is_auto_global ( Z_STR ( name_node . u . constant ) ) ) {
opline - > extended_value = ZEND_FETCH_GLOBAL ;
} else {
opline - > extended_value = ZEND_FETCH_LOCAL ;
2003-02-04 12:12:34 +00:00
}
2014-06-07 11:06:53 +00:00
2018-06-25 20:43:23 +00:00
zend_adjust_for_fetch_type ( opline , result , type ) ;
2014-06-07 11:06:53 +00:00
return opline ;
2003-02-04 12:12:34 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2003-02-04 12:12:34 +00:00
2016-06-15 23:30:23 +00:00
static zend_bool is_this_fetch ( zend_ast * ast ) /* { { { */
{
if ( ast - > kind = = ZEND_AST_VAR & & ast - > child [ 0 ] - > kind = = ZEND_AST_ZVAL ) {
zval * name = zend_ast_get_zval ( ast - > child [ 0 ] ) ;
return Z_TYPE_P ( name ) = = IS_STRING & & zend_string_equals_literal ( Z_STR_P ( name ) , " this " ) ;
}
return 0 ;
}
/* }}} */
2019-02-13 10:37:32 +00:00
static zend_bool this_guaranteed_exists ( ) /* { { { */
{
zend_op_array * op_array = CG ( active_op_array ) ;
/* Instance methods always have a $this.
* This also includes closures that have a scope and use $ this . */
return op_array - > scope ! = NULL
& & ( op_array - > fn_flags & ZEND_ACC_STATIC ) = = 0 ;
}
/* }}} */
2020-08-28 13:41:27 +00:00
static zend_op * zend_compile_simple_var ( znode * result , zend_ast * ast , uint32_t type , bool delayed ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2016-06-15 23:30:23 +00:00
if ( is_this_fetch ( ast ) ) {
2018-06-25 20:43:23 +00:00
zend_op * opline = zend_emit_op ( result , ZEND_FETCH_THIS , NULL , NULL ) ;
if ( ( type = = BP_VAR_R ) | | ( type = = BP_VAR_IS ) ) {
opline - > result_type = IS_TMP_VAR ;
result - > op_type = IS_TMP_VAR ;
}
2019-08-16 10:55:28 +00:00
CG ( active_op_array ) - > fn_flags | = ZEND_ACC_USES_THIS ;
2019-01-07 11:28:51 +00:00
return opline ;
2016-06-15 23:30:23 +00:00
} else if ( zend_try_compile_cv ( result , ast ) = = FAILURE ) {
2019-01-07 11:28:51 +00:00
return zend_compile_simple_var_no_cv ( result , ast , type , delayed ) ;
2003-10-22 19:59:58 +00:00
}
2019-01-07 11:28:51 +00:00
return NULL ;
2014-06-07 11:06:53 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-06-07 11:06:53 +00:00
2014-12-13 22:06:14 +00:00
static void zend_separate_if_call_and_write ( znode * node , zend_ast * ast , uint32_t type ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-07 11:06:53 +00:00
if ( type ! = BP_VAR_R & & type ! = BP_VAR_IS & & zend_is_call ( ast ) ) {
2014-09-03 12:30:48 +00:00
if ( node - > op_type = = IS_VAR ) {
2014-12-13 22:06:14 +00:00
zend_op * opline = zend_emit_op ( NULL , ZEND_SEPARATE , node , NULL ) ;
2014-09-03 12:30:48 +00:00
opline - > result_type = IS_VAR ;
opline - > result . var = opline - > op1 . var ;
} else {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use result of built-in function in write context " ) ;
}
2004-12-06 11:53:30 +00:00
}
2003-10-22 19:59:58 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2003-05-29 19:00:40 +00:00
2019-01-07 11:28:51 +00:00
zend_op * zend_delayed_compile_var ( znode * result , zend_ast * ast , uint32_t type , zend_bool by_ref ) ;
2014-12-13 22:06:14 +00:00
void zend_compile_assign ( znode * result , zend_ast * ast ) ;
2014-09-22 16:34:09 +00:00
2014-12-13 22:06:14 +00:00
static inline void zend_emit_assign_znode ( zend_ast * var_ast , znode * value_node ) /* { { { */
2014-09-22 16:34:09 +00:00
{
znode dummy_node ;
2019-03-28 08:29:08 +00:00
zend_ast * assign_ast = zend_ast_create ( ZEND_AST_ASSIGN , var_ast ,
zend_ast_create_znode ( value_node ) ) ;
2020-05-24 10:42:48 +00:00
zend_compile_expr ( & dummy_node , assign_ast ) ;
2014-12-13 22:06:14 +00:00
zend_do_free ( & dummy_node ) ;
2014-09-22 16:34:09 +00:00
}
/* }}} */
2003-10-22 19:59:58 +00:00
2014-12-13 22:06:14 +00:00
static zend_op * zend_delayed_compile_dim ( znode * result , zend_ast * ast , uint32_t type ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2019-03-13 10:51:31 +00:00
if ( ast - > attr = = ZEND_DIM_ALTERNATIVE_SYNTAX ) {
2020-05-22 14:52:17 +00:00
zend_error ( E_COMPILE_ERROR , " Array and string offset access syntax with curly braces is no longer supported " ) ;
2019-03-13 10:51:31 +00:00
}
2014-06-07 11:06:53 +00:00
zend_ast * var_ast = ast - > child [ 0 ] ;
zend_ast * dim_ast = ast - > child [ 1 ] ;
2017-11-16 21:28:29 +00:00
zend_op * opline ;
2003-10-22 19:59:58 +00:00
2014-06-07 11:06:53 +00:00
znode var_node , dim_node ;
2004-01-28 09:13:41 +00:00
2020-05-24 10:42:48 +00:00
zend_short_circuiting_mark_inner ( var_ast ) ;
2019-01-07 11:28:51 +00:00
opline = zend_delayed_compile_var ( & var_node , var_ast , type , 0 ) ;
if ( opline & & type = = BP_VAR_W & & ( opline - > opcode = = ZEND_FETCH_STATIC_PROP_W | | opline - > opcode = = ZEND_FETCH_OBJ_W ) ) {
opline - > extended_value | = ZEND_FETCH_DIM_WRITE ;
}
2014-12-13 22:06:14 +00:00
zend_separate_if_call_and_write ( & var_node , var_ast , type ) ;
2014-06-07 11:06:53 +00:00
if ( dim_ast = = NULL ) {
if ( type = = BP_VAR_R | | type = = BP_VAR_IS ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use [] for reading " ) ;
2003-10-22 19:59:58 +00:00
}
2014-06-07 11:06:53 +00:00
if ( type = = BP_VAR_UNSET ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use [] for unsetting " ) ;
2003-05-29 19:00:40 +00:00
}
2014-06-07 11:06:53 +00:00
dim_node . op_type = IS_UNUSED ;
} else {
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & dim_node , dim_ast ) ;
2003-05-29 19:00:40 +00:00
}
2004-01-28 09:13:41 +00:00
2017-11-16 21:28:29 +00:00
opline = zend_delayed_emit_op ( result , ZEND_FETCH_DIM_R , & var_node , & dim_node ) ;
2018-06-25 20:43:23 +00:00
zend_adjust_for_fetch_type ( opline , result , type ) ;
2018-07-02 22:09:58 +00:00
if ( dim_node . op_type = = IS_CONST ) {
zend_handle_numeric_dim ( opline , & dim_node ) ;
}
2017-11-16 21:28:29 +00:00
return opline ;
2003-05-29 19:00:40 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2003-05-29 19:00:40 +00:00
2017-11-16 21:28:29 +00:00
static zend_op * zend_compile_dim ( znode * result , zend_ast * ast , uint32_t type ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-12-13 22:06:14 +00:00
uint32_t offset = zend_delayed_compile_begin ( ) ;
zend_delayed_compile_dim ( result , ast , type ) ;
return zend_delayed_compile_end ( offset ) ;
2014-06-07 11:06:53 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2010-08-11 09:38:41 +00:00
2014-12-13 22:06:14 +00:00
static zend_op * zend_delayed_compile_prop ( znode * result , zend_ast * ast , uint32_t type ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-07 11:06:53 +00:00
zend_ast * obj_ast = ast - > child [ 0 ] ;
zend_ast * prop_ast = ast - > child [ 1 ] ;
2010-05-24 14:11:39 +00:00
2014-06-07 11:06:53 +00:00
znode obj_node , prop_node ;
zend_op * opline ;
2020-05-24 10:42:48 +00:00
zend_bool nullsafe = ast - > kind = = ZEND_AST_NULLSAFE_PROP ;
2003-03-05 11:14:44 +00:00
2014-06-07 11:06:53 +00:00
if ( is_this_fetch ( obj_ast ) ) {
2019-02-13 10:37:32 +00:00
if ( this_guaranteed_exists ( ) ) {
obj_node . op_type = IS_UNUSED ;
} else {
zend_emit_op ( & obj_node , ZEND_FETCH_THIS , NULL , NULL ) ;
}
2019-08-16 10:55:28 +00:00
CG ( active_op_array ) - > fn_flags | = ZEND_ACC_USES_THIS ;
2020-08-11 13:22:14 +00:00
/* We will throw if $this doesn't exist, so there's no need to emit a JMP_NULL
* check for a nullsafe access . */
2014-06-07 11:06:53 +00:00
} else {
2020-05-24 10:42:48 +00:00
zend_short_circuiting_mark_inner ( obj_ast ) ;
2020-03-18 13:52:22 +00:00
opline = zend_delayed_compile_var ( & obj_node , obj_ast , type , 0 ) ;
2014-12-13 22:06:14 +00:00
zend_separate_if_call_and_write ( & obj_node , obj_ast , type ) ;
2020-08-11 13:22:14 +00:00
if ( nullsafe ) {
2020-08-31 13:31:18 +00:00
/* We will push to the short_cirtcuiting_opnums stack in zend_delayed_compile_end(). */
opline = zend_delayed_emit_op ( NULL , ZEND_JMP_NULL , & obj_node , NULL ) ;
if ( opline - > op1_type = = IS_CONST ) {
Z_TRY_ADDREF_P ( CT_CONSTANT ( opline - > op1 ) ) ;
}
2020-08-11 13:22:14 +00:00
}
2020-05-24 10:42:48 +00:00
}
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & prop_node , prop_ast ) ;
2014-06-07 11:06:53 +00:00
2014-12-13 22:06:14 +00:00
opline = zend_delayed_emit_op ( result , ZEND_FETCH_OBJ_R , & obj_node , & prop_node ) ;
2014-11-10 15:35:45 +00:00
if ( opline - > op2_type = = IS_CONST ) {
2014-12-12 07:19:41 +00:00
convert_to_string ( CT_CONSTANT ( opline - > op2 ) ) ;
2019-01-07 11:28:51 +00:00
opline - > extended_value = zend_alloc_cache_slots ( 3 ) ;
2008-08-24 18:22:33 +00:00
}
2018-06-25 20:43:23 +00:00
zend_adjust_for_fetch_type ( opline , result , type ) ;
2020-05-24 10:42:48 +00:00
2014-06-07 11:06:53 +00:00
return opline ;
}
2014-08-29 05:05:58 +00:00
/* }}} */
2000-06-09 14:40:14 +00:00
2020-08-28 13:41:27 +00:00
static zend_op * zend_compile_prop ( znode * result , zend_ast * ast , uint32_t type , bool by_ref ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-12-13 22:06:14 +00:00
uint32_t offset = zend_delayed_compile_begin ( ) ;
2019-01-07 11:28:51 +00:00
zend_op * opline = zend_delayed_compile_prop ( result , ast , type ) ;
if ( by_ref ) { /* shared with cache_slot */
opline - > extended_value | = ZEND_FETCH_REF ;
}
2014-12-13 22:06:14 +00:00
return zend_delayed_compile_end ( offset ) ;
2014-08-15 15:10:06 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2010-05-24 14:11:39 +00:00
2020-08-28 13:41:27 +00:00
zend_op * zend_compile_static_prop ( znode * result , zend_ast * ast , uint32_t type , bool by_ref , bool delayed ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-07 11:06:53 +00:00
zend_ast * class_ast = ast - > child [ 0 ] ;
zend_ast * prop_ast = ast - > child [ 1 ] ;
2010-05-24 14:11:39 +00:00
2014-06-14 16:30:18 +00:00
znode class_node , prop_node ;
2014-06-07 11:06:53 +00:00
zend_op * opline ;
2010-05-24 14:11:39 +00:00
2020-05-24 10:42:48 +00:00
zend_short_circuiting_mark_inner ( class_ast ) ;
2019-01-02 08:48:29 +00:00
zend_compile_class_ref ( & class_node , class_ast , ZEND_FETCH_CLASS_EXCEPTION ) ;
2011-01-19 17:17:52 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & prop_node , prop_ast ) ;
2002-07-15 18:09:56 +00:00
2015-02-02 17:44:16 +00:00
if ( delayed ) {
2015-10-27 12:47:58 +00:00
opline = zend_delayed_emit_op ( result , ZEND_FETCH_STATIC_PROP_R , & prop_node , NULL ) ;
2015-02-02 17:44:16 +00:00
} else {
2015-10-27 12:47:58 +00:00
opline = zend_emit_op ( result , ZEND_FETCH_STATIC_PROP_R , & prop_node , NULL ) ;
2015-02-02 17:44:16 +00:00
}
2014-06-07 11:06:53 +00:00
if ( opline - > op1_type = = IS_CONST ) {
2015-12-10 17:12:59 +00:00
convert_to_string ( CT_CONSTANT ( opline - > op1 ) ) ;
2019-01-07 11:28:51 +00:00
opline - > extended_value = zend_alloc_cache_slots ( 3 ) ;
2014-06-07 11:06:53 +00:00
}
if ( class_node . op_type = = IS_CONST ) {
opline - > op2_type = IS_CONST ;
2014-07-19 21:30:07 +00:00
opline - > op2 . constant = zend_add_class_name_literal (
2018-12-07 14:47:56 +00:00
Z_STR ( class_node . u . constant ) ) ;
2018-02-05 16:41:47 +00:00
if ( opline - > op1_type ! = IS_CONST ) {
2018-02-05 17:40:21 +00:00
opline - > extended_value = zend_alloc_cache_slot ( ) ;
2018-02-05 16:41:47 +00:00
}
2014-06-07 11:06:53 +00:00
} else {
SET_NODE ( opline - > op2 , & class_node ) ;
}
2014-05-26 17:29:35 +00:00
2019-01-07 11:28:51 +00:00
if ( by_ref & & ( type = = BP_VAR_W | | type = = BP_VAR_FUNC_ARG ) ) { /* shared with cache_slot */
opline - > extended_value | = ZEND_FETCH_REF ;
}
2018-06-25 20:43:23 +00:00
zend_adjust_for_fetch_type ( opline , result , type ) ;
2017-11-16 21:28:29 +00:00
return opline ;
2014-06-07 11:06:53 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2006-05-11 21:07:39 +00:00
2020-05-26 13:58:00 +00:00
static void zend_verify_list_assign_target ( zend_ast * var_ast , zend_ast_attr array_style ) /* { { { */ {
2016-04-04 22:34:42 +00:00
if ( var_ast - > kind = = ZEND_AST_ARRAY ) {
2016-07-06 19:15:05 +00:00
if ( var_ast - > attr = = ZEND_ARRAY_SYNTAX_LONG ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot assign to array(), use [] instead " ) ;
}
2020-05-26 13:58:00 +00:00
if ( array_style ! = var_ast - > attr ) {
2016-07-06 19:15:05 +00:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot mix [] and list() " ) ;
2016-04-04 22:34:42 +00:00
}
} else if ( ! zend_can_write_to_variable ( var_ast ) ) {
2016-07-06 19:15:05 +00:00
zend_error_noreturn ( E_COMPILE_ERROR , " Assignments can only happen to writable values " ) ;
2016-04-04 22:34:42 +00:00
}
}
/* }}} */
2017-10-06 23:30:58 +00:00
static inline void zend_emit_assign_ref_znode ( zend_ast * var_ast , znode * value_node ) ;
/* Propagate refs used on leaf elements to the surrounding list() structures. */
static zend_bool zend_propagate_list_refs ( zend_ast * ast ) { /* {{{ */
zend_ast_list * list = zend_ast_get_list ( ast ) ;
zend_bool has_refs = 0 ;
uint32_t i ;
for ( i = 0 ; i < list - > children ; + + i ) {
zend_ast * elem_ast = list - > child [ i ] ;
if ( elem_ast ) {
zend_ast * var_ast = elem_ast - > child [ 0 ] ;
if ( var_ast - > kind = = ZEND_AST_ARRAY ) {
elem_ast - > attr = zend_propagate_list_refs ( var_ast ) ;
}
has_refs | = elem_ast - > attr ;
}
}
return has_refs ;
}
/* }}} */
2016-09-28 19:41:56 +00:00
static void zend_compile_list_assign (
2020-05-26 13:58:00 +00:00
znode * result , zend_ast * ast , znode * expr_node , zend_ast_attr array_style ) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2016-09-28 19:41:56 +00:00
zend_ast_list * list = zend_ast_get_list ( ast ) ;
2014-08-25 19:21:16 +00:00
uint32_t i ;
2015-01-09 17:27:06 +00:00
zend_bool has_elems = 0 ;
2016-09-28 19:41:56 +00:00
zend_bool is_keyed =
list - > children > 0 & & list - > child [ 0 ] ! = NULL & & list - > child [ 0 ] - > child [ 1 ] ! = NULL ;
2004-01-28 11:53:52 +00:00
2017-11-03 18:02:27 +00:00
if ( list - > children & & expr_node - > op_type = = IS_CONST & & Z_TYPE ( expr_node - > u . constant ) = = IS_STRING ) {
zval_make_interned_string ( & expr_node - > u . constant ) ;
}
2014-07-27 20:26:06 +00:00
for ( i = 0 ; i < list - > children ; + + i ) {
2016-04-04 22:34:42 +00:00
zend_ast * elem_ast = list - > child [ i ] ;
2016-09-28 19:41:56 +00:00
zend_ast * var_ast , * key_ast ;
2014-09-22 16:34:09 +00:00
znode fetch_result , dim_node ;
2018-07-02 22:09:58 +00:00
zend_op * opline ;
2014-06-07 11:06:53 +00:00
2016-04-04 22:34:42 +00:00
if ( elem_ast = = NULL ) {
2016-09-28 19:41:56 +00:00
if ( is_keyed ) {
zend_error ( E_COMPILE_ERROR ,
" Cannot use empty array entries in keyed array assignment " ) ;
} else {
continue ;
}
2014-06-07 11:06:53 +00:00
}
2019-11-12 07:51:55 +00:00
2018-10-06 14:04:41 +00:00
if ( elem_ast - > kind = = ZEND_AST_UNPACK ) {
zend_error ( E_COMPILE_ERROR ,
" Spread operator is not supported in assignments " ) ;
}
2016-09-28 19:41:56 +00:00
2016-04-04 22:34:42 +00:00
var_ast = elem_ast - > child [ 0 ] ;
2016-09-28 19:41:56 +00:00
key_ast = elem_ast - > child [ 1 ] ;
2015-01-09 17:27:06 +00:00
has_elems = 1 ;
2014-06-07 11:06:53 +00:00
2016-09-28 19:41:56 +00:00
if ( is_keyed ) {
if ( key_ast = = NULL ) {
zend_error ( E_COMPILE_ERROR ,
" Cannot mix keyed and unkeyed array entries in assignments " ) ;
}
2016-04-04 22:34:42 +00:00
2016-09-28 19:41:56 +00:00
zend_compile_expr ( & dim_node , key_ast ) ;
} else {
if ( key_ast ! = NULL ) {
zend_error ( E_COMPILE_ERROR ,
" Cannot mix keyed and unkeyed array entries in assignments " ) ;
}
2016-09-28 19:31:06 +00:00
2016-09-28 19:41:56 +00:00
dim_node . op_type = IS_CONST ;
ZVAL_LONG ( & dim_node . u . constant , i ) ;
2016-06-17 16:34:15 +00:00
}
2016-03-25 17:18:42 +00:00
if ( expr_node - > op_type = = IS_CONST ) {
Z_TRY_ADDREF ( expr_node - > u . constant ) ;
}
2020-05-26 13:58:00 +00:00
zend_verify_list_assign_target ( var_ast , array_style ) ;
2016-04-04 22:34:42 +00:00
2018-07-02 22:09:58 +00:00
opline = zend_emit_op ( & fetch_result ,
2018-07-30 07:53:39 +00:00
elem_ast - > attr ? ( expr_node - > op_type = = IS_CV ? ZEND_FETCH_DIM_W : ZEND_FETCH_LIST_W ) : ZEND_FETCH_LIST_R , expr_node , & dim_node ) ;
2017-10-06 23:30:58 +00:00
2018-07-02 22:09:58 +00:00
if ( dim_node . op_type = = IS_CONST ) {
zend_handle_numeric_dim ( opline , & dim_node ) ;
}
2020-09-02 08:23:44 +00:00
if ( elem_ast - > attr ) {
zend_emit_op ( & fetch_result , ZEND_MAKE_REF , & fetch_result , NULL ) ;
}
2017-10-06 23:30:58 +00:00
if ( var_ast - > kind = = ZEND_AST_ARRAY ) {
zend_compile_list_assign ( NULL , var_ast , & fetch_result , var_ast - > attr ) ;
} else if ( elem_ast - > attr ) {
zend_emit_assign_ref_znode ( var_ast , & fetch_result ) ;
} else {
zend_emit_assign_znode ( var_ast , & fetch_result ) ;
}
2016-03-25 17:18:42 +00:00
}
2016-09-28 19:41:56 +00:00
if ( has_elems = = 0 ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use empty list " ) ;
2016-03-25 17:18:42 +00:00
}
2015-01-09 17:27:06 +00:00
2017-10-06 23:30:58 +00:00
if ( result ) {
* result = * expr_node ;
} else {
zend_do_free ( expr_node ) ;
}
2014-04-14 09:24:43 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-04-14 09:24:43 +00:00
2015-03-27 15:40:04 +00:00
static void zend_ensure_writable_variable ( const zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-07 11:06:53 +00:00
if ( ast - > kind = = ZEND_AST_CALL ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Can't use function return value in write context " ) ;
}
2020-05-24 10:42:48 +00:00
if (
ast - > kind = = ZEND_AST_METHOD_CALL
| | ast - > kind = = ZEND_AST_NULLSAFE_METHOD_CALL
| | ast - > kind = = ZEND_AST_STATIC_CALL
) {
2014-06-07 11:06:53 +00:00
zend_error_noreturn ( E_COMPILE_ERROR , " Can't use method return value in write context " ) ;
}
2020-05-24 10:42:48 +00:00
if ( zend_ast_is_short_circuited ( ast ) ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Can't use nullsafe operator in write context " ) ;
}
2014-06-07 11:06:53 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2006-06-07 09:21:06 +00:00
2014-06-14 16:30:18 +00:00
/* Detects $a... = $a pattern */
2014-12-13 22:06:14 +00:00
zend_bool zend_is_assign_to_self ( zend_ast * var_ast , zend_ast * expr_ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-28 16:03:26 +00:00
if ( expr_ast - > kind ! = ZEND_AST_VAR | | expr_ast - > child [ 0 ] - > kind ! = ZEND_AST_ZVAL ) {
2014-06-07 11:06:53 +00:00
return 0 ;
2006-06-07 09:21:06 +00:00
}
2013-01-28 02:02:51 +00:00
2019-01-27 19:50:08 +00:00
while ( zend_is_variable ( var_ast ) & & var_ast - > kind ! = ZEND_AST_VAR ) {
2014-06-07 11:06:53 +00:00
var_ast = var_ast - > child [ 0 ] ;
}
2014-05-26 17:29:35 +00:00
2014-06-28 16:03:26 +00:00
if ( var_ast - > kind ! = ZEND_AST_VAR | | var_ast - > child [ 0 ] - > kind ! = ZEND_AST_ZVAL ) {
2014-06-07 11:06:53 +00:00
return 0 ;
}
2013-01-28 02:02:51 +00:00
2014-06-07 11:06:53 +00:00
{
zend_string * name1 = zval_get_string ( zend_ast_get_zval ( var_ast - > child [ 0 ] ) ) ;
zend_string * name2 = zval_get_string ( zend_ast_get_zval ( expr_ast - > child [ 0 ] ) ) ;
2014-08-25 20:40:58 +00:00
zend_bool result = zend_string_equals ( name1 , name2 ) ;
2018-05-28 13:27:12 +00:00
zend_string_release_ex ( name1 , 0 ) ;
zend_string_release_ex ( name2 , 0 ) ;
2014-06-07 11:06:53 +00:00
return result ;
2006-06-07 09:21:06 +00:00
}
2003-03-05 11:14:44 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2003-03-05 11:14:44 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_assign ( znode * result , zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-07 11:06:53 +00:00
zend_ast * var_ast = ast - > child [ 0 ] ;
zend_ast * expr_ast = ast - > child [ 1 ] ;
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2014-06-07 11:06:53 +00:00
znode var_node , expr_node ;
zend_op * opline ;
2014-08-25 19:21:16 +00:00
uint32_t offset ;
2014-06-07 11:06:53 +00:00
if ( is_this_fetch ( var_ast ) ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot re-assign $this " ) ;
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
2014-06-07 11:06:53 +00:00
zend_ensure_writable_variable ( var_ast ) ;
switch ( var_ast - > kind ) {
case ZEND_AST_VAR :
2016-01-07 15:05:17 +00:00
offset = zend_delayed_compile_begin ( ) ;
2019-01-07 11:28:51 +00:00
zend_delayed_compile_var ( & var_node , var_ast , BP_VAR_W , 0 ) ;
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & expr_node , expr_ast ) ;
2016-01-07 15:05:17 +00:00
zend_delayed_compile_end ( offset ) ;
2020-09-05 14:33:22 +00:00
CG ( zend_lineno ) = zend_ast_get_lineno ( var_ast ) ;
2020-02-07 10:36:52 +00:00
zend_emit_op_tmp ( result , ZEND_ASSIGN , & var_node , & expr_node ) ;
2014-06-07 11:06:53 +00:00
return ;
2019-01-07 11:28:51 +00:00
case ZEND_AST_STATIC_PROP :
offset = zend_delayed_compile_begin ( ) ;
zend_delayed_compile_var ( result , var_ast , BP_VAR_W , 0 ) ;
zend_compile_expr ( & expr_node , expr_ast ) ;
opline = zend_delayed_compile_end ( offset ) ;
opline - > opcode = ZEND_ASSIGN_STATIC_PROP ;
2020-02-07 10:36:52 +00:00
opline - > result_type = IS_TMP_VAR ;
result - > op_type = IS_TMP_VAR ;
2019-01-07 11:28:51 +00:00
zend_emit_op_data ( & expr_node ) ;
return ;
2014-06-07 11:06:53 +00:00
case ZEND_AST_DIM :
2014-12-13 22:06:14 +00:00
offset = zend_delayed_compile_begin ( ) ;
zend_delayed_compile_dim ( result , var_ast , BP_VAR_W ) ;
2014-08-15 15:10:06 +00:00
2016-06-15 23:30:23 +00:00
if ( zend_is_assign_to_self ( var_ast , expr_ast )
& & ! is_this_fetch ( expr_ast ) ) {
2014-08-15 15:10:06 +00:00
/* $a[0] = $a should evaluate the right $a first */
2017-10-12 13:23:45 +00:00
znode cv_node ;
if ( zend_try_compile_cv ( & cv_node , expr_ast ) = = FAILURE ) {
zend_compile_simple_var_no_cv ( & expr_node , expr_ast , BP_VAR_R , 0 ) ;
} else {
2019-09-13 09:08:59 +00:00
zend_emit_op_tmp ( & expr_node , ZEND_QM_ASSIGN , & cv_node , NULL ) ;
2017-10-12 13:23:45 +00:00
}
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
} else {
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & expr_node , expr_ast ) ;
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
2014-08-15 15:10:06 +00:00
2014-12-13 22:06:14 +00:00
opline = zend_delayed_compile_end ( offset ) ;
2014-06-07 11:06:53 +00:00
opline - > opcode = ZEND_ASSIGN_DIM ;
2020-02-07 10:36:52 +00:00
opline - > result_type = IS_TMP_VAR ;
result - > op_type = IS_TMP_VAR ;
2014-06-07 11:06:53 +00:00
2014-12-13 22:06:14 +00:00
opline = zend_emit_op_data ( & expr_node ) ;
2014-06-07 11:06:53 +00:00
return ;
case ZEND_AST_PROP :
2020-05-24 10:42:48 +00:00
case ZEND_AST_NULLSAFE_PROP :
2014-12-13 22:06:14 +00:00
offset = zend_delayed_compile_begin ( ) ;
zend_delayed_compile_prop ( result , var_ast , BP_VAR_W ) ;
zend_compile_expr ( & expr_node , expr_ast ) ;
2014-08-15 15:10:06 +00:00
2014-12-13 22:06:14 +00:00
opline = zend_delayed_compile_end ( offset ) ;
2014-06-07 11:06:53 +00:00
opline - > opcode = ZEND_ASSIGN_OBJ ;
2020-02-07 10:36:52 +00:00
opline - > result_type = IS_TMP_VAR ;
result - > op_type = IS_TMP_VAR ;
2014-06-07 11:06:53 +00:00
2014-12-13 22:06:14 +00:00
zend_emit_op_data ( & expr_node ) ;
2014-06-07 11:06:53 +00:00
return ;
2016-04-04 22:34:42 +00:00
case ZEND_AST_ARRAY :
2017-10-06 23:30:58 +00:00
if ( zend_propagate_list_refs ( var_ast ) ) {
2019-01-26 11:10:03 +00:00
if ( ! zend_is_variable_or_call ( expr_ast ) ) {
2017-10-06 23:30:58 +00:00
zend_error_noreturn ( E_COMPILE_ERROR ,
" Cannot assign reference to non referencable value " ) ;
}
2017-10-12 13:23:45 +00:00
2019-01-07 11:28:51 +00:00
zend_compile_var ( & expr_node , expr_ast , BP_VAR_W , 1 ) ;
2017-10-06 23:30:58 +00:00
/* MAKE_REF is usually not necessary for CVs. However, if there are
* self - assignments , this forces the RHS to evaluate first . */
2019-05-09 12:19:53 +00:00
zend_emit_op ( & expr_node , ZEND_MAKE_REF , & expr_node , NULL ) ;
2015-02-24 17:57:14 +00:00
} else {
2019-05-09 12:19:53 +00:00
if ( expr_ast - > kind = = ZEND_AST_VAR ) {
2017-10-06 23:30:58 +00:00
/* list($a, $b) = $a should evaluate the right $a first */
znode cv_node ;
if ( zend_try_compile_cv ( & cv_node , expr_ast ) = = FAILURE ) {
zend_compile_simple_var_no_cv ( & expr_node , expr_ast , BP_VAR_R , 0 ) ;
} else {
2019-09-13 09:08:59 +00:00
zend_emit_op_tmp ( & expr_node , ZEND_QM_ASSIGN , & cv_node , NULL ) ;
2017-10-06 23:30:58 +00:00
}
} else {
zend_compile_expr ( & expr_node , expr_ast ) ;
}
2015-02-24 17:57:14 +00:00
}
2016-04-04 22:34:42 +00:00
zend_compile_list_assign ( result , var_ast , & expr_node , var_ast - > attr ) ;
2014-06-07 11:06:53 +00:00
return ;
EMPTY_SWITCH_DEFAULT_CASE ( ) ;
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
2013-01-28 02:02:51 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_assign_ref ( znode * result , zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-07 11:06:53 +00:00
zend_ast * target_ast = ast - > child [ 0 ] ;
zend_ast * source_ast = ast - > child [ 1 ] ;
2014-08-15 15:10:06 +00:00
znode target_node , source_node ;
2014-06-07 11:06:53 +00:00
zend_op * opline ;
2019-09-13 15:09:24 +00:00
uint32_t offset , flags ;
2014-06-07 11:06:53 +00:00
2014-08-15 15:10:06 +00:00
if ( is_this_fetch ( target_ast ) ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot re-assign $this " ) ;
}
zend_ensure_writable_variable ( target_ast ) ;
2020-05-24 10:42:48 +00:00
if ( zend_ast_is_short_circuited ( source_ast ) ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot take reference of a nullsafe chain " ) ;
}
2014-08-15 15:10:06 +00:00
2016-02-06 15:38:59 +00:00
offset = zend_delayed_compile_begin ( ) ;
2019-01-07 11:28:51 +00:00
zend_delayed_compile_var ( & target_node , target_ast , BP_VAR_W , 1 ) ;
zend_compile_var ( & source_node , source_ast , BP_VAR_W , 1 ) ;
2016-07-06 21:59:44 +00:00
if ( ( target_ast - > kind ! = ZEND_AST_VAR
| | target_ast - > child [ 0 ] - > kind ! = ZEND_AST_ZVAL )
2020-09-02 08:23:44 +00:00
& & source_ast - > kind ! = ZEND_AST_ZNODE
2016-07-06 21:59:44 +00:00
& & source_node . op_type ! = IS_CV ) {
/* Both LHS and RHS expressions may modify the same data structure,
* and the modification during RHS evaluation may dangle the pointer
* to the result of the LHS evaluation .
* Use MAKE_REF instruction to replace direct pointer with REFERENCE .
* See : Bug # 71539
*/
zend_emit_op ( & source_node , ZEND_MAKE_REF , & source_node , NULL ) ;
}
2019-01-07 11:28:51 +00:00
opline = zend_delayed_compile_end ( offset ) ;
2014-08-15 15:10:06 +00:00
2014-09-23 18:42:22 +00:00
if ( source_node . op_type ! = IS_VAR & & zend_is_call ( source_ast ) ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use result of built-in function in write context " ) ;
}
2019-09-13 15:09:24 +00:00
flags = zend_is_call ( source_ast ) ? ZEND_RETURNS_FUNCTION : 0 ;
2019-01-07 11:28:51 +00:00
if ( opline & & opline - > opcode = = ZEND_FETCH_OBJ_W ) {
opline - > opcode = ZEND_ASSIGN_OBJ_REF ;
opline - > extended_value & = ~ ZEND_FETCH_REF ;
2019-09-13 15:09:24 +00:00
opline - > extended_value | = flags ;
2019-01-07 11:28:51 +00:00
zend_emit_op_data ( & source_node ) ;
if ( result ! = NULL ) {
* result = target_node ;
}
} else if ( opline & & opline - > opcode = = ZEND_FETCH_STATIC_PROP_W ) {
opline - > opcode = ZEND_ASSIGN_STATIC_PROP_REF ;
opline - > extended_value & = ~ ZEND_FETCH_REF ;
2019-09-13 15:09:24 +00:00
opline - > extended_value | = flags ;
2019-01-07 11:28:51 +00:00
zend_emit_op_data ( & source_node ) ;
if ( result ! = NULL ) {
* result = target_node ;
}
} else {
opline = zend_emit_op ( result , ZEND_ASSIGN_REF , & target_node , & source_node ) ;
2019-09-13 15:09:24 +00:00
opline - > extended_value = flags ;
2011-10-09 11:13:27 +00:00
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2014-12-13 22:06:14 +00:00
static inline void zend_emit_assign_ref_znode ( zend_ast * var_ast , znode * value_node ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2019-03-28 08:29:08 +00:00
zend_ast * assign_ast = zend_ast_create ( ZEND_AST_ASSIGN_REF , var_ast ,
zend_ast_create_znode ( value_node ) ) ;
2020-05-24 10:42:48 +00:00
zend_compile_expr ( NULL , assign_ast ) ;
2014-08-15 15:10:06 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2011-11-05 02:05:28 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_compound_assign ( znode * result , zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-07 11:06:53 +00:00
zend_ast * var_ast = ast - > child [ 0 ] ;
zend_ast * expr_ast = ast - > child [ 1 ] ;
2014-08-25 19:21:16 +00:00
uint32_t opcode = ast - > attr ;
2014-06-07 11:06:53 +00:00
znode var_node , expr_node ;
zend_op * opline ;
2018-02-05 16:41:47 +00:00
uint32_t offset , cache_slot ;
2014-06-07 11:06:53 +00:00
zend_ensure_writable_variable ( var_ast ) ;
switch ( var_ast - > kind ) {
case ZEND_AST_VAR :
2016-01-07 15:05:17 +00:00
offset = zend_delayed_compile_begin ( ) ;
2019-01-07 11:28:51 +00:00
zend_delayed_compile_var ( & var_node , var_ast , BP_VAR_RW , 0 ) ;
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & expr_node , expr_ast ) ;
2016-01-07 15:05:17 +00:00
zend_delayed_compile_end ( offset ) ;
2020-02-07 10:36:52 +00:00
opline = zend_emit_op_tmp ( result , ZEND_ASSIGN_OP , & var_node , & expr_node ) ;
2019-07-05 09:03:25 +00:00
opline - > extended_value = opcode ;
2012-12-25 06:23:08 +00:00
return ;
2019-01-07 11:28:51 +00:00
case ZEND_AST_STATIC_PROP :
offset = zend_delayed_compile_begin ( ) ;
zend_delayed_compile_var ( result , var_ast , BP_VAR_RW , 0 ) ;
zend_compile_expr ( & expr_node , expr_ast ) ;
opline = zend_delayed_compile_end ( offset ) ;
cache_slot = opline - > extended_value ;
2019-07-05 09:03:25 +00:00
opline - > opcode = ZEND_ASSIGN_STATIC_PROP_OP ;
opline - > extended_value = opcode ;
2020-02-07 10:36:52 +00:00
opline - > result_type = IS_TMP_VAR ;
result - > op_type = IS_TMP_VAR ;
2019-01-07 11:28:51 +00:00
opline = zend_emit_op_data ( & expr_node ) ;
opline - > extended_value = cache_slot ;
return ;
2014-06-07 11:06:53 +00:00
case ZEND_AST_DIM :
2014-12-13 22:06:14 +00:00
offset = zend_delayed_compile_begin ( ) ;
zend_delayed_compile_dim ( result , var_ast , BP_VAR_RW ) ;
zend_compile_expr ( & expr_node , expr_ast ) ;
2014-08-15 15:10:06 +00:00
2014-12-13 22:06:14 +00:00
opline = zend_delayed_compile_end ( offset ) ;
2019-07-05 09:03:25 +00:00
opline - > opcode = ZEND_ASSIGN_DIM_OP ;
opline - > extended_value = opcode ;
2020-02-07 10:36:52 +00:00
opline - > result_type = IS_TMP_VAR ;
result - > op_type = IS_TMP_VAR ;
2014-06-07 11:06:53 +00:00
2019-01-07 11:28:51 +00:00
zend_emit_op_data ( & expr_node ) ;
2012-12-25 06:23:08 +00:00
return ;
2014-06-07 11:06:53 +00:00
case ZEND_AST_PROP :
2020-05-24 10:42:48 +00:00
case ZEND_AST_NULLSAFE_PROP :
2014-12-13 22:06:14 +00:00
offset = zend_delayed_compile_begin ( ) ;
zend_delayed_compile_prop ( result , var_ast , BP_VAR_RW ) ;
zend_compile_expr ( & expr_node , expr_ast ) ;
2011-11-01 15:25:24 +00:00
2014-12-13 22:06:14 +00:00
opline = zend_delayed_compile_end ( offset ) ;
2018-02-05 16:41:47 +00:00
cache_slot = opline - > extended_value ;
2019-07-05 09:03:25 +00:00
opline - > opcode = ZEND_ASSIGN_OBJ_OP ;
opline - > extended_value = opcode ;
2020-02-07 10:36:52 +00:00
opline - > result_type = IS_TMP_VAR ;
result - > op_type = IS_TMP_VAR ;
2014-06-07 11:06:53 +00:00
2018-02-05 16:41:47 +00:00
opline = zend_emit_op_data ( & expr_node ) ;
opline - > extended_value = cache_slot ;
2014-06-07 11:06:53 +00:00
return ;
EMPTY_SWITCH_DEFAULT_CASE ( )
}
2012-12-25 06:23:08 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2011-11-01 15:25:24 +00:00
2020-04-06 10:46:52 +00:00
static uint32_t zend_get_arg_num ( zend_function * fn , zend_string * arg_name ) {
// TODO: Caching?
if ( fn - > type = = ZEND_USER_FUNCTION ) {
for ( uint32_t i = 0 ; i < fn - > common . num_args ; i + + ) {
zend_arg_info * arg_info = & fn - > op_array . arg_info [ i ] ;
if ( zend_string_equals ( arg_info - > name , arg_name ) ) {
return i + 1 ;
}
}
} else {
for ( uint32_t i = 0 ; i < fn - > common . num_args ; i + + ) {
zend_internal_arg_info * arg_info = & fn - > internal_function . arg_info [ i ] ;
size_t len = strlen ( arg_info - > name ) ;
if ( len = = ZSTR_LEN ( arg_name ) & & ! memcmp ( arg_info - > name , ZSTR_VAL ( arg_name ) , len ) ) {
return i + 1 ;
}
}
}
/* Either an invalid argument name, or collected into a variadic argument. */
return ( uint32_t ) - 1 ;
}
uint32_t zend_compile_args (
zend_ast * ast , zend_function * fbc , bool * may_have_extra_named_args ) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-07-27 20:26:06 +00:00
zend_ast_list * args = zend_ast_get_list ( ast ) ;
2014-08-25 19:21:16 +00:00
uint32_t i ;
2014-06-07 11:06:53 +00:00
zend_bool uses_arg_unpack = 0 ;
2014-08-25 19:21:16 +00:00
uint32_t arg_count = 0 ; /* number of arguments not including unpacks */
2012-12-25 06:23:08 +00:00
2020-04-06 10:46:52 +00:00
/* Whether named arguments are used syntactically, to enforce language level limitations.
* May not actually use named argument passing . */
zend_bool uses_named_args = 0 ;
/* Whether there may be any undef arguments due to the use of named arguments. */
zend_bool may_have_undef = 0 ;
/* Whether there may be any extra named arguments collected into a variadic. */
* may_have_extra_named_args = 0 ;
2014-07-13 11:11:55 +00:00
for ( i = 0 ; i < args - > children ; + + i ) {
zend_ast * arg = args - > child [ i ] ;
2020-04-06 10:46:52 +00:00
zend_string * arg_name = NULL ;
2014-08-25 19:21:16 +00:00
uint32_t arg_num = i + 1 ;
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2014-07-13 11:11:55 +00:00
znode arg_node ;
2014-06-07 11:06:53 +00:00
zend_op * opline ;
zend_uchar opcode ;
2014-07-13 11:11:55 +00:00
if ( arg - > kind = = ZEND_AST_UNPACK ) {
2020-04-06 10:46:52 +00:00
if ( uses_named_args ) {
zend_error_noreturn ( E_COMPILE_ERROR ,
" Cannot combine named arguments and argument unpacking " ) ;
}
2014-06-07 11:06:53 +00:00
uses_arg_unpack = 1 ;
2014-07-22 18:41:45 +00:00
fbc = NULL ;
2015-01-03 09:22:58 +00:00
2019-08-01 08:06:23 +00:00
zend_compile_expr ( & arg_node , arg - > child [ 0 ] ) ;
2014-12-13 22:06:14 +00:00
opline = zend_emit_op ( NULL , ZEND_SEND_UNPACK , & arg_node , NULL ) ;
2014-06-07 11:06:53 +00:00
opline - > op2 . num = arg_count ;
2020-02-27 13:48:43 +00:00
opline - > result . var = EX_NUM_TO_VAR ( arg_count - 1 ) ;
2020-04-06 10:46:52 +00:00
/* Unpack may contain named arguments. */
may_have_undef = 1 ;
if ( ! fbc | | ( fbc - > common . fn_flags & ZEND_ACC_VARIADIC ) ) {
* may_have_extra_named_args = 1 ;
}
2014-06-07 11:06:53 +00:00
continue ;
}
2020-04-06 10:46:52 +00:00
if ( arg - > kind = = ZEND_AST_NAMED_ARG ) {
if ( uses_arg_unpack ) {
zend_error_noreturn ( E_COMPILE_ERROR ,
" Cannot combine named arguments and argument unpacking " ) ;
}
uses_named_args = 1 ;
arg_name = zval_make_interned_string ( zend_ast_get_zval ( arg - > child [ 0 ] ) ) ;
arg = arg - > child [ 1 ] ;
if ( fbc ) {
arg_num = zend_get_arg_num ( fbc , arg_name ) ;
2020-08-26 09:01:15 +00:00
if ( arg_num = = arg_count + 1 & & ! may_have_undef ) {
2020-04-06 10:46:52 +00:00
/* Using named arguments, but passing in order. */
arg_name = NULL ;
arg_count + + ;
} else {
// TODO: We could track which arguments were passed, even if out of order.
may_have_undef = 1 ;
if ( arg_num = = ( uint32_t ) - 1 & & ( fbc - > common . fn_flags & ZEND_ACC_VARIADIC ) ) {
* may_have_extra_named_args = 1 ;
}
}
} else {
arg_num = ( uint32_t ) - 1 ;
may_have_undef = 1 ;
* may_have_extra_named_args = 1 ;
}
} else {
if ( uses_arg_unpack ) {
zend_error_noreturn ( E_COMPILE_ERROR ,
" Cannot use positional argument after argument unpacking " ) ;
}
if ( uses_named_args ) {
zend_error_noreturn ( E_COMPILE_ERROR ,
" Cannot use positional argument after named argument " ) ;
}
arg_count + + ;
2014-06-07 11:06:53 +00:00
}
2019-03-06 09:42:02 +00:00
if ( zend_is_call ( arg ) ) {
zend_compile_var ( & arg_node , arg , BP_VAR_R , 0 ) ;
if ( arg_node . op_type & ( IS_CONST | IS_TMP_VAR ) ) {
/* Function call was converted into builtin instruction */
2020-07-07 07:57:07 +00:00
if ( ! fbc | | ARG_MUST_BE_SENT_BY_REF ( fbc , arg_num ) ) {
opcode = ZEND_SEND_VAL_EX ;
2014-08-26 10:22:03 +00:00
} else {
2020-07-07 07:57:07 +00:00
opcode = ZEND_SEND_VAL ;
}
2019-03-06 09:42:02 +00:00
} else {
2020-04-06 10:46:52 +00:00
if ( fbc & & arg_num ! = ( uint32_t ) - 1 ) {
2019-03-06 09:42:02 +00:00
if ( ARG_MUST_BE_SENT_BY_REF ( fbc , arg_num ) ) {
opcode = ZEND_SEND_VAR_NO_REF ;
} else if ( ARG_MAY_BE_SENT_BY_REF ( fbc , arg_num ) ) {
opcode = ZEND_SEND_VAL ;
2016-05-31 01:06:00 +00:00
} else {
2019-03-06 09:42:02 +00:00
opcode = ZEND_SEND_VAR ;
2014-06-07 11:06:53 +00:00
}
2019-03-06 09:42:02 +00:00
} else {
opcode = ZEND_SEND_VAR_NO_REF_EX ;
2014-06-07 11:06:53 +00:00
}
2019-03-06 09:42:02 +00:00
}
2020-05-24 10:42:48 +00:00
} else if ( zend_is_variable ( arg ) & & ! zend_ast_is_short_circuited ( arg ) ) {
2020-04-06 10:46:52 +00:00
if ( fbc & & arg_num ! = ( uint32_t ) - 1 ) {
2014-06-07 11:06:53 +00:00
if ( ARG_SHOULD_BE_SENT_BY_REF ( fbc , arg_num ) ) {
2019-01-07 11:28:51 +00:00
zend_compile_var ( & arg_node , arg , BP_VAR_W , 1 ) ;
2014-06-07 11:06:53 +00:00
opcode = ZEND_SEND_REF ;
} else {
2019-01-07 11:28:51 +00:00
zend_compile_var ( & arg_node , arg , BP_VAR_R , 0 ) ;
2018-06-25 20:43:23 +00:00
opcode = ( arg_node . op_type = = IS_TMP_VAR ) ? ZEND_SEND_VAL : ZEND_SEND_VAR ;
2014-06-07 11:06:53 +00:00
}
} else {
2018-02-05 16:40:06 +00:00
do {
if ( arg - > kind = = ZEND_AST_VAR ) {
CG ( zend_lineno ) = zend_ast_get_lineno ( ast ) ;
if ( is_this_fetch ( arg ) ) {
zend_emit_op ( & arg_node , ZEND_FETCH_THIS , NULL , NULL ) ;
opcode = ZEND_SEND_VAR_EX ;
2019-08-16 10:55:28 +00:00
CG ( active_op_array ) - > fn_flags | = ZEND_ACC_USES_THIS ;
2018-02-05 16:40:06 +00:00
break ;
} else if ( zend_try_compile_cv ( & arg_node , arg ) = = SUCCESS ) {
opcode = ZEND_SEND_VAR_EX ;
break ;
}
}
opline = zend_emit_op ( NULL , ZEND_CHECK_FUNC_ARG , NULL , NULL ) ;
2020-04-06 10:46:52 +00:00
if ( arg_name ) {
opline - > op2_type = IS_CONST ;
zend_string_addref ( arg_name ) ;
opline - > op2 . constant = zend_add_literal_string ( & arg_name ) ;
opline - > result . num = zend_alloc_cache_slots ( 2 ) ;
} else {
opline - > op2 . num = arg_num ;
}
2019-01-07 11:28:51 +00:00
zend_compile_var ( & arg_node , arg , BP_VAR_FUNC_ARG , 1 ) ;
2018-02-05 16:40:06 +00:00
opcode = ZEND_SEND_FUNC_ARG ;
} while ( 0 ) ;
2014-06-07 11:06:53 +00:00
}
} else {
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & arg_node , arg ) ;
2015-07-08 15:33:58 +00:00
if ( arg_node . op_type = = IS_VAR ) {
2016-05-31 01:06:00 +00:00
/* pass ++$a or something similar */
2020-04-06 10:46:52 +00:00
if ( fbc & & arg_num ! = ( uint32_t ) - 1 ) {
2016-05-31 01:06:00 +00:00
if ( ARG_MUST_BE_SENT_BY_REF ( fbc , arg_num ) ) {
opcode = ZEND_SEND_VAR_NO_REF ;
} else if ( ARG_MAY_BE_SENT_BY_REF ( fbc , arg_num ) ) {
opcode = ZEND_SEND_VAL ;
} else {
opcode = ZEND_SEND_VAR ;
}
} else {
opcode = ZEND_SEND_VAR_NO_REF_EX ;
2014-06-07 11:06:53 +00:00
}
2016-12-06 09:17:59 +00:00
} else if ( arg_node . op_type = = IS_CV ) {
2020-04-06 10:46:52 +00:00
if ( fbc & & arg_num ! = ( uint32_t ) - 1 ) {
2016-12-06 09:17:59 +00:00
if ( ARG_SHOULD_BE_SENT_BY_REF ( fbc , arg_num ) ) {
opcode = ZEND_SEND_REF ;
} else {
opcode = ZEND_SEND_VAR ;
}
} else {
opcode = ZEND_SEND_VAR_EX ;
}
2014-06-07 11:06:53 +00:00
} else {
2020-02-07 10:36:52 +00:00
/* Delay "Only variables can be passed by reference" error to execution */
2020-04-06 10:46:52 +00:00
if ( fbc & & arg_num ! = ( uint32_t ) - 1 & & ! ARG_MUST_BE_SENT_BY_REF ( fbc , arg_num ) ) {
2014-07-22 14:55:34 +00:00
opcode = ZEND_SEND_VAL ;
} else {
opcode = ZEND_SEND_VAL_EX ;
2014-06-07 11:06:53 +00:00
}
}
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
2014-06-07 11:06:53 +00:00
2015-11-13 12:35:07 +00:00
opline = zend_emit_op ( NULL , opcode , & arg_node , NULL ) ;
2020-04-06 10:46:52 +00:00
if ( arg_name ) {
opline - > op2_type = IS_CONST ;
zend_string_addref ( arg_name ) ;
opline - > op2 . constant = zend_add_literal_string ( & arg_name ) ;
opline - > result . num = zend_alloc_cache_slots ( 2 ) ;
} else {
opline - > op2 . opline_num = arg_num ;
opline - > result . var = EX_NUM_TO_VAR ( arg_num - 1 ) ;
}
}
if ( may_have_undef ) {
zend_emit_op ( NULL , ZEND_CHECK_UNDEF_ARGS , NULL , NULL ) ;
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
2014-06-07 11:06:53 +00:00
return arg_count ;
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2016-04-14 13:07:28 +00:00
ZEND_API zend_uchar zend_get_call_op ( const zend_op * init_op , zend_function * fbc ) /* { { { */
2015-02-25 07:37:21 +00:00
{
2016-06-28 09:57:04 +00:00
if ( fbc ) {
2019-02-21 22:54:26 +00:00
if ( fbc - > type = = ZEND_INTERNAL_FUNCTION & & ! ( CG ( compiler_options ) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS ) ) {
2016-06-28 09:57:04 +00:00
if ( init_op - > opcode = = ZEND_INIT_FCALL & & ! zend_execute_internal ) {
2019-09-02 09:11:18 +00:00
if ( ! ( fbc - > common . fn_flags & ( ZEND_ACC_ABSTRACT | ZEND_ACC_DEPRECATED ) ) ) {
2016-04-14 13:07:28 +00:00
return ZEND_DO_ICALL ;
} else {
return ZEND_DO_FCALL_BY_NAME ;
}
2015-02-25 07:37:21 +00:00
}
2019-02-21 22:54:26 +00:00
} else if ( ! ( CG ( compiler_options ) & ZEND_COMPILE_IGNORE_USER_FUNCTIONS ) ) {
2016-06-28 09:57:04 +00:00
if ( zend_execute_ex = = execute_ex & & ! ( fbc - > common . fn_flags & ZEND_ACC_ABSTRACT ) ) {
2016-06-04 10:59:35 +00:00
return ZEND_DO_UCALL ;
2015-02-25 07:37:21 +00:00
}
}
} else if ( zend_execute_ex = = execute_ex & &
! zend_execute_internal & &
2016-04-14 13:07:28 +00:00
( init_op - > opcode = = ZEND_INIT_FCALL_BY_NAME | |
init_op - > opcode = = ZEND_INIT_NS_FCALL_BY_NAME ) ) {
2015-02-25 07:37:21 +00:00
return ZEND_DO_FCALL_BY_NAME ;
}
return ZEND_DO_FCALL ;
}
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_call_common ( znode * result , zend_ast * args_ast , zend_function * fbc ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-07 11:06:53 +00:00
zend_op * opline ;
2018-12-07 14:47:56 +00:00
uint32_t opnum_init = get_next_op_number ( ) - 1 ;
2014-08-25 19:21:16 +00:00
uint32_t arg_count ;
2020-04-06 10:46:52 +00:00
bool may_have_extra_named_args ;
2012-12-25 06:23:08 +00:00
2020-04-06 10:46:52 +00:00
arg_count = zend_compile_args ( args_ast , fbc , & may_have_extra_named_args ) ;
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2019-02-19 16:45:13 +00:00
zend_do_extended_fcall_begin ( ) ;
2014-07-22 14:55:34 +00:00
opline = & CG ( active_op_array ) - > opcodes [ opnum_init ] ;
2014-06-07 11:06:53 +00:00
opline - > extended_value = arg_count ;
2011-11-17 21:04:15 +00:00
2014-12-12 06:01:42 +00:00
if ( opline - > opcode = = ZEND_INIT_FCALL ) {
opline - > op1 . num = zend_vm_calc_used_stack ( arg_count , fbc ) ;
}
2016-04-14 13:07:28 +00:00
opline = zend_emit_op ( result , zend_get_call_op ( opline , fbc ) , NULL , NULL ) ;
2020-04-06 10:46:52 +00:00
if ( may_have_extra_named_args ) {
opline - > extended_value = ZEND_FCALL_MAY_HAVE_EXTRA_NAMED_PARAMS ;
}
2014-12-13 22:06:14 +00:00
zend_do_extended_fcall_end ( ) ;
2014-06-07 11:06:53 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2012-12-25 06:23:08 +00:00
2014-12-13 22:06:14 +00:00
zend_bool zend_compile_function_name ( znode * name_node , zend_ast * name_ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-28 13:16:35 +00:00
zend_string * orig_name = zend_ast_get_str ( name_ast ) ;
2014-07-22 11:25:47 +00:00
zend_bool is_fully_qualified ;
2012-12-25 06:23:08 +00:00
2014-06-28 20:27:06 +00:00
name_node - > op_type = IS_CONST ;
ZVAL_STR ( & name_node - > u . constant , zend_resolve_function_name (
2014-12-13 22:06:14 +00:00
orig_name , name_ast - > attr , & is_fully_qualified ) ) ;
2011-11-17 21:04:15 +00:00
2015-04-20 18:16:58 +00:00
return ! is_fully_qualified & & FC ( current_namespace ) ;
2014-06-07 11:06:53 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_ns_call ( znode * result , znode * name_node , zend_ast * args_ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2018-12-07 14:47:56 +00:00
zend_op * opline = get_next_op ( ) ;
2014-06-07 11:06:53 +00:00
opline - > opcode = ZEND_INIT_NS_FCALL_BY_NAME ;
opline - > op2_type = IS_CONST ;
opline - > op2 . constant = zend_add_ns_func_name_literal (
2018-12-07 14:47:56 +00:00
Z_STR ( name_node - > u . constant ) ) ;
2018-02-05 16:41:47 +00:00
opline - > result . num = zend_alloc_cache_slot ( ) ;
2014-06-07 11:06:53 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_call_common ( result , args_ast , NULL ) ;
2014-06-07 11:06:53 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-06-07 11:06:53 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_dynamic_call ( znode * result , znode * name_node , zend_ast * args_ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-07 11:06:53 +00:00
if ( name_node - > op_type = = IS_CONST & & Z_TYPE ( name_node - > u . constant ) = = IS_STRING ) {
2015-06-26 17:55:13 +00:00
const char * colon ;
zend_string * str = Z_STR ( name_node - > u . constant ) ;
2015-06-30 10:59:27 +00:00
if ( ( colon = zend_memrchr ( ZSTR_VAL ( str ) , ' : ' , ZSTR_LEN ( str ) ) ) ! = NULL & & colon > ZSTR_VAL ( str ) & & * ( colon - 1 ) = = ' : ' ) {
zend_string * class = zend_string_init ( ZSTR_VAL ( str ) , colon - ZSTR_VAL ( str ) - 1 , 0 ) ;
zend_string * method = zend_string_init ( colon + 1 , ZSTR_LEN ( str ) - ( colon - ZSTR_VAL ( str ) ) - 1 , 0 ) ;
2018-12-07 14:47:56 +00:00
zend_op * opline = get_next_op ( ) ;
2015-11-13 12:35:07 +00:00
2015-06-26 17:55:13 +00:00
opline - > opcode = ZEND_INIT_STATIC_METHOD_CALL ;
opline - > op1_type = IS_CONST ;
2018-12-07 14:47:56 +00:00
opline - > op1 . constant = zend_add_class_name_literal ( class ) ;
2015-06-26 17:55:13 +00:00
opline - > op2_type = IS_CONST ;
2018-12-07 14:47:56 +00:00
opline - > op2 . constant = zend_add_func_name_literal ( method ) ;
2018-02-05 16:41:47 +00:00
/* 2 slots, for class and method */
2019-01-07 11:28:51 +00:00
opline - > result . num = zend_alloc_cache_slots ( 2 ) ;
2015-06-26 17:55:13 +00:00
zval_ptr_dtor ( & name_node - > u . constant ) ;
} else {
2018-12-07 14:47:56 +00:00
zend_op * opline = get_next_op ( ) ;
2015-11-13 12:35:07 +00:00
2015-06-26 17:55:13 +00:00
opline - > opcode = ZEND_INIT_FCALL_BY_NAME ;
opline - > op2_type = IS_CONST ;
2018-12-07 14:47:56 +00:00
opline - > op2 . constant = zend_add_func_name_literal ( str ) ;
2018-02-05 16:41:47 +00:00
opline - > result . num = zend_alloc_cache_slot ( ) ;
2015-06-26 17:55:13 +00:00
}
2014-06-07 11:06:53 +00:00
} else {
2015-11-13 12:35:07 +00:00
zend_emit_op ( NULL , ZEND_INIT_DYNAMIC_CALL , NULL , name_node ) ;
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
2014-12-13 22:06:14 +00:00
zend_compile_call_common ( result , args_ast , NULL ) ;
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2020-04-06 10:46:52 +00:00
static inline zend_bool zend_args_contain_unpack_or_named ( zend_ast_list * args ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-08-25 17:28:33 +00:00
uint32_t i ;
2014-07-13 11:11:55 +00:00
for ( i = 0 ; i < args - > children ; + + i ) {
2020-04-06 10:46:52 +00:00
zend_ast * arg = args - > child [ i ] ;
if ( arg - > kind = = ZEND_AST_UNPACK | | arg - > kind = = ZEND_AST_NAMED_ARG ) {
2014-06-07 11:06:53 +00:00
return 1 ;
}
2013-02-21 10:18:41 +00:00
}
2014-06-07 11:06:53 +00:00
return 0 ;
}
2014-08-29 05:05:58 +00:00
/* }}} */
2013-02-21 10:18:41 +00:00
2020-08-28 13:41:27 +00:00
zend_result zend_compile_func_strlen ( znode * result , zend_ast_list * args ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-22 21:11:12 +00:00
znode arg_node ;
2019-01-28 12:13:24 +00:00
if ( args - > children ! = 1 ) {
2014-07-22 21:11:12 +00:00
return FAILURE ;
2012-12-25 06:23:08 +00:00
}
2014-07-22 21:11:12 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & arg_node , args - > child [ 0 ] ) ;
2015-06-10 22:57:37 +00:00
if ( arg_node . op_type = = IS_CONST & & Z_TYPE ( arg_node . u . constant ) = = IS_STRING ) {
result - > op_type = IS_CONST ;
ZVAL_LONG ( & result - > u . constant , Z_STRLEN ( arg_node . u . constant ) ) ;
2018-07-04 16:22:24 +00:00
zval_ptr_dtor_str ( & arg_node . u . constant ) ;
2015-06-10 22:57:37 +00:00
} else {
zend_emit_op_tmp ( result , ZEND_STRLEN , & arg_node , NULL ) ;
}
2014-07-22 21:11:12 +00:00
return SUCCESS ;
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2020-08-28 13:41:27 +00:00
zend_result zend_compile_func_typecheck ( znode * result , zend_ast_list * args , uint32_t type ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-22 21:11:12 +00:00
znode arg_node ;
zend_op * opline ;
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2018-08-22 09:38:28 +00:00
if ( args - > children ! = 1 ) {
2014-07-22 21:11:12 +00:00
return FAILURE ;
}
2015-01-03 09:22:58 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & arg_node , args - > child [ 0 ] ) ;
opline = zend_emit_op_tmp ( result , ZEND_TYPE_CHECK , & arg_node , NULL ) ;
2017-11-23 12:58:34 +00:00
if ( type ! = _IS_BOOL ) {
opline - > extended_value = ( 1 < < type ) ;
} else {
opline - > extended_value = ( 1 < < IS_FALSE ) | ( 1 < < IS_TRUE ) ;
}
2014-07-22 21:11:12 +00:00
return SUCCESS ;
}
2014-08-29 05:05:58 +00:00
/* }}} */
2011-11-17 21:04:15 +00:00
2020-08-28 13:41:27 +00:00
static zend_result zend_compile_func_is_scalar ( znode * result , zend_ast_list * args ) /* { { { */
2019-11-12 00:56:20 +00:00
{
znode arg_node ;
zend_op * opline ;
if ( args - > children ! = 1 ) {
return FAILURE ;
}
zend_compile_expr ( & arg_node , args - > child [ 0 ] ) ;
opline = zend_emit_op_tmp ( result , ZEND_TYPE_CHECK , & arg_node , NULL ) ;
opline - > extended_value = ( 1 < < IS_FALSE | 1 < < IS_TRUE | 1 < < IS_DOUBLE | 1 < < IS_LONG | 1 < < IS_STRING ) ;
return SUCCESS ;
}
2020-08-28 13:41:27 +00:00
zend_result zend_compile_func_cast ( znode * result , zend_ast_list * args , uint32_t type ) /* { { { */
2016-09-09 13:45:46 +00:00
{
znode arg_node ;
zend_op * opline ;
2018-08-22 09:38:28 +00:00
if ( args - > children ! = 1 ) {
2016-09-09 13:45:46 +00:00
return FAILURE ;
}
zend_compile_expr ( & arg_node , args - > child [ 0 ] ) ;
2019-10-03 11:57:20 +00:00
if ( type = = _IS_BOOL ) {
opline = zend_emit_op_tmp ( result , ZEND_BOOL , & arg_node , NULL ) ;
} else {
opline = zend_emit_op_tmp ( result , ZEND_CAST , & arg_node , NULL ) ;
opline - > extended_value = type ;
}
2016-09-09 13:45:46 +00:00
return SUCCESS ;
}
/* }}} */
2020-08-28 13:41:27 +00:00
zend_result zend_compile_func_defined ( znode * result , zend_ast_list * args ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-22 21:27:00 +00:00
zend_string * name ;
zend_op * opline ;
2013-01-28 02:02:51 +00:00
2014-07-27 20:26:06 +00:00
if ( args - > children ! = 1 | | args - > child [ 0 ] - > kind ! = ZEND_AST_ZVAL ) {
2014-07-22 21:27:00 +00:00
return FAILURE ;
}
2010-05-02 18:47:27 +00:00
2014-07-27 20:26:06 +00:00
name = zval_get_string ( zend_ast_get_zval ( args - > child [ 0 ] ) ) ;
2015-06-30 10:59:27 +00:00
if ( zend_memrchr ( ZSTR_VAL ( name ) , ' \\ ' , ZSTR_LEN ( name ) ) | | zend_memrchr ( ZSTR_VAL ( name ) , ' : ' , ZSTR_LEN ( name ) ) ) {
2018-05-28 13:27:12 +00:00
zend_string_release_ex ( name , 0 ) ;
2014-07-22 21:27:00 +00:00
return FAILURE ;
}
2012-12-25 06:23:08 +00:00
2016-02-19 11:14:27 +00:00
if ( zend_try_ct_eval_const ( & result - > u . constant , name , 0 ) ) {
2018-05-28 13:27:12 +00:00
zend_string_release_ex ( name , 0 ) ;
2016-02-19 11:14:27 +00:00
zval_ptr_dtor ( & result - > u . constant ) ;
ZVAL_TRUE ( & result - > u . constant ) ;
result - > op_type = IS_CONST ;
return SUCCESS ;
}
2014-12-13 22:06:14 +00:00
opline = zend_emit_op_tmp ( result , ZEND_DEFINED , NULL , NULL ) ;
2014-07-22 21:27:00 +00:00
opline - > op1_type = IS_CONST ;
LITERAL_STR ( opline - > op1 , name ) ;
2018-02-05 16:41:47 +00:00
opline - > extended_value = zend_alloc_cache_slot ( ) ;
2013-01-28 02:02:51 +00:00
2014-07-22 21:27:00 +00:00
return SUCCESS ;
}
2014-08-29 05:05:58 +00:00
/* }}} */
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2020-08-28 13:41:27 +00:00
zend_result zend_compile_func_chr ( znode * result , zend_ast_list * args ) /* { { { */
2016-02-19 11:14:27 +00:00
{
if ( args - > children = = 1 & &
args - > child [ 0 ] - > kind = = ZEND_AST_ZVAL & &
Z_TYPE_P ( zend_ast_get_zval ( args - > child [ 0 ] ) ) = = IS_LONG ) {
zend_long c = Z_LVAL_P ( zend_ast_get_zval ( args - > child [ 0 ] ) ) & 0xff ;
result - > op_type = IS_CONST ;
2020-06-08 10:45:01 +00:00
ZVAL_CHAR ( & result - > u . constant , c ) ;
2016-02-19 11:14:27 +00:00
return SUCCESS ;
} else {
return FAILURE ;
}
}
/* }}} */
2020-08-28 13:41:27 +00:00
zend_result zend_compile_func_ord ( znode * result , zend_ast_list * args ) /* { { { */
2016-02-19 11:14:27 +00:00
{
if ( args - > children = = 1 & &
args - > child [ 0 ] - > kind = = ZEND_AST_ZVAL & &
Z_TYPE_P ( zend_ast_get_zval ( args - > child [ 0 ] ) ) = = IS_STRING ) {
result - > op_type = IS_CONST ;
ZVAL_LONG ( & result - > u . constant , ( unsigned char ) Z_STRVAL_P ( zend_ast_get_zval ( args - > child [ 0 ] ) ) [ 0 ] ) ;
return SUCCESS ;
} else {
return FAILURE ;
}
}
/* }}} */
2019-09-06 09:30:01 +00:00
/* We can only calculate the stack size for functions that have been fully compiled, otherwise
* additional CV or TMP slots may still be added . This prevents the use of INIT_FCALL for
* directly or indirectly recursive function calls . */
static zend_bool fbc_is_finalized ( zend_function * fbc ) {
return ! ZEND_USER_CODE ( fbc - > type ) | | ( fbc - > common . fn_flags & ZEND_ACC_DONE_PASS_TWO ) ;
}
2016-02-19 11:14:27 +00:00
2020-08-28 13:41:27 +00:00
static zend_result zend_try_compile_ct_bound_init_user_func ( zend_ast * name_ast , uint32_t num_args ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-24 17:22:46 +00:00
zend_string * name , * lcname ;
zend_function * fbc ;
zend_op * opline ;
2011-11-17 21:04:15 +00:00
2014-09-23 19:02:32 +00:00
if ( name_ast - > kind ! = ZEND_AST_ZVAL | | Z_TYPE_P ( zend_ast_get_zval ( name_ast ) ) ! = IS_STRING ) {
2014-07-24 17:22:46 +00:00
return FAILURE ;
}
2011-11-17 21:04:15 +00:00
2014-07-28 13:16:35 +00:00
name = zend_ast_get_str ( name_ast ) ;
2014-12-24 12:04:51 +00:00
lcname = zend_string_tolower ( name ) ;
2014-07-24 17:22:46 +00:00
fbc = zend_hash_find_ptr ( CG ( function_table ) , lcname ) ;
2019-09-06 09:30:01 +00:00
if ( ! fbc | | ! fbc_is_finalized ( fbc )
2015-07-21 14:39:22 +00:00
| | ( fbc - > type = = ZEND_INTERNAL_FUNCTION & & ( CG ( compiler_options ) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS ) )
| | ( fbc - > type = = ZEND_USER_FUNCTION & & ( CG ( compiler_options ) & ZEND_COMPILE_IGNORE_USER_FUNCTIONS ) )
2018-08-22 10:45:56 +00:00
| | ( fbc - > type = = ZEND_USER_FUNCTION & & ( CG ( compiler_options ) & ZEND_COMPILE_IGNORE_OTHER_FILES ) & & fbc - > op_array . filename ! = CG ( active_op_array ) - > filename )
2014-07-24 17:22:46 +00:00
) {
2018-05-28 13:27:12 +00:00
zend_string_release_ex ( lcname , 0 ) ;
2014-07-24 17:22:46 +00:00
return FAILURE ;
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
2014-07-24 17:22:46 +00:00
2014-12-13 22:06:14 +00:00
opline = zend_emit_op ( NULL , ZEND_INIT_FCALL , NULL , NULL ) ;
2014-09-23 19:02:32 +00:00
opline - > extended_value = num_args ;
2014-12-12 06:01:42 +00:00
opline - > op1 . num = zend_vm_calc_used_stack ( num_args , fbc ) ;
2014-07-24 17:22:46 +00:00
opline - > op2_type = IS_CONST ;
LITERAL_STR ( opline - > op2 , lcname ) ;
2018-02-05 16:41:47 +00:00
opline - > result . num = zend_alloc_cache_slot ( ) ;
2014-07-24 17:22:46 +00:00
return SUCCESS ;
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2014-12-13 22:06:14 +00:00
static void zend_compile_init_user_func ( zend_ast * name_ast , uint32_t num_args , zend_string * orig_func_name ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-24 17:22:46 +00:00
zend_op * opline ;
znode name_node ;
2013-01-28 02:02:51 +00:00
2014-12-13 22:06:14 +00:00
if ( zend_try_compile_ct_bound_init_user_func ( name_ast , num_args ) = = SUCCESS ) {
2011-06-20 01:36:23 +00:00
return ;
}
2014-07-24 17:22:46 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & name_node , name_ast ) ;
2014-07-24 17:22:46 +00:00
2014-12-13 22:06:14 +00:00
opline = zend_emit_op ( NULL , ZEND_INIT_USER_CALL , NULL , & name_node ) ;
2014-07-24 17:22:46 +00:00
opline - > op1_type = IS_CONST ;
2014-08-25 19:21:16 +00:00
LITERAL_STR ( opline - > op1 , zend_string_copy ( orig_func_name ) ) ;
2014-07-24 17:22:46 +00:00
opline - > extended_value = num_args ;
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-07-24 17:22:46 +00:00
2014-07-24 18:35:18 +00:00
/* cufa = call_user_func_array */
2020-08-28 13:41:27 +00:00
zend_result zend_compile_func_cufa ( znode * result , zend_ast_list * args , zend_string * lcname ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-24 17:22:46 +00:00
znode arg_node ;
2018-08-22 09:38:28 +00:00
if ( args - > children ! = 2 ) {
2014-07-24 17:22:46 +00:00
return FAILURE ;
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
2014-07-24 17:22:46 +00:00
2014-12-16 16:13:47 +00:00
zend_compile_init_user_func ( args - > child [ 0 ] , 0 , lcname ) ;
2017-05-30 09:25:46 +00:00
if ( args - > child [ 1 ] - > kind = = ZEND_AST_CALL
& & args - > child [ 1 ] - > child [ 0 ] - > kind = = ZEND_AST_ZVAL
2017-05-30 18:48:16 +00:00
& & Z_TYPE_P ( zend_ast_get_zval ( args - > child [ 1 ] - > child [ 0 ] ) ) = = IS_STRING
2017-05-30 09:25:46 +00:00
& & args - > child [ 1 ] - > child [ 1 ] - > kind = = ZEND_AST_ARG_LIST ) {
2017-05-30 18:48:16 +00:00
zend_string * orig_name = zend_ast_get_str ( args - > child [ 1 ] - > child [ 0 ] ) ;
2017-05-30 09:25:46 +00:00
zend_ast_list * list = zend_ast_get_list ( args - > child [ 1 ] - > child [ 1 ] ) ;
2017-05-30 18:48:16 +00:00
zend_bool is_fully_qualified ;
zend_string * name = zend_resolve_function_name ( orig_name , args - > child [ 1 ] - > child [ 0 ] - > attr , & is_fully_qualified ) ;
2017-05-30 09:25:46 +00:00
2017-05-30 18:48:16 +00:00
if ( zend_string_equals_literal_ci ( name , " array_slice " )
2017-05-30 09:25:46 +00:00
& & list - > children = = 3
& & list - > child [ 1 ] - > kind = = ZEND_AST_ZVAL ) {
zval * zv = zend_ast_get_zval ( list - > child [ 1 ] ) ;
if ( Z_TYPE_P ( zv ) = = IS_LONG
& & Z_LVAL_P ( zv ) > = 0
& & Z_LVAL_P ( zv ) < = 0x7fffffff ) {
zend_op * opline ;
znode len_node ;
zend_compile_expr ( & arg_node , list - > child [ 0 ] ) ;
zend_compile_expr ( & len_node , list - > child [ 2 ] ) ;
opline = zend_emit_op ( NULL , ZEND_SEND_ARRAY , & arg_node , & len_node ) ;
opline - > extended_value = Z_LVAL_P ( zv ) ;
zend_emit_op ( result , ZEND_DO_FCALL , NULL , NULL ) ;
2018-05-28 13:27:12 +00:00
zend_string_release_ex ( name , 0 ) ;
2017-05-30 09:25:46 +00:00
return SUCCESS ;
}
}
2018-05-28 13:27:12 +00:00
zend_string_release_ex ( name , 0 ) ;
2017-05-30 09:25:46 +00:00
}
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & arg_node , args - > child [ 1 ] ) ;
zend_emit_op ( NULL , ZEND_SEND_ARRAY , & arg_node , NULL ) ;
2020-04-06 10:46:52 +00:00
zend_emit_op ( NULL , ZEND_CHECK_UNDEF_ARGS , NULL , NULL ) ;
2014-12-13 22:06:14 +00:00
zend_emit_op ( result , ZEND_DO_FCALL , NULL , NULL ) ;
2014-07-24 17:22:46 +00:00
return SUCCESS ;
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2014-07-24 18:35:18 +00:00
/* cuf = call_user_func */
2020-08-28 13:41:27 +00:00
zend_result zend_compile_func_cuf ( znode * result , zend_ast_list * args , zend_string * lcname ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-08-25 17:28:33 +00:00
uint32_t i ;
2012-12-25 06:23:08 +00:00
2018-08-22 09:38:28 +00:00
if ( args - > children < 1 ) {
2014-07-24 18:35:18 +00:00
return FAILURE ;
}
2011-01-19 17:17:52 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_init_user_func ( args - > child [ 0 ] , args - > children - 1 , lcname ) ;
2014-07-27 20:26:06 +00:00
for ( i = 1 ; i < args - > children ; + + i ) {
zend_ast * arg_ast = args - > child [ i ] ;
2014-07-24 18:35:18 +00:00
znode arg_node ;
zend_op * opline ;
2012-12-25 06:23:08 +00:00
2016-06-28 19:34:20 +00:00
zend_compile_expr ( & arg_node , arg_ast ) ;
2014-07-24 18:35:18 +00:00
2016-09-25 10:30:32 +00:00
opline = zend_emit_op ( NULL , ZEND_SEND_USER , & arg_node , NULL ) ;
2014-12-16 15:40:52 +00:00
opline - > op2 . num = i ;
2020-02-27 13:48:43 +00:00
opline - > result . var = EX_NUM_TO_VAR ( i - 1 ) ;
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
2014-12-13 22:06:14 +00:00
zend_emit_op ( result , ZEND_DO_FCALL , NULL , NULL ) ;
2013-01-28 02:02:51 +00:00
2014-07-24 18:35:18 +00:00
return SUCCESS ;
}
2014-08-29 05:05:58 +00:00
/* }}} */
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2019-01-29 08:39:12 +00:00
static void zend_compile_assert ( znode * result , zend_ast_list * args , zend_string * name , zend_function * fbc ) /* { { { */
2015-03-02 09:25:40 +00:00
{
if ( EG ( assertions ) > = 0 ) {
znode name_node ;
zend_op * opline ;
2018-12-07 14:47:56 +00:00
uint32_t check_op_number = get_next_op_number ( ) ;
2015-03-02 09:25:40 +00:00
zend_emit_op ( NULL , ZEND_ASSERT_CHECK , NULL , NULL ) ;
2019-09-06 09:30:01 +00:00
if ( fbc & & fbc_is_finalized ( fbc ) ) {
2015-03-02 09:25:40 +00:00
name_node . op_type = IS_CONST ;
ZVAL_STR_COPY ( & name_node . u . constant , name ) ;
opline = zend_emit_op ( NULL , ZEND_INIT_FCALL , NULL , & name_node ) ;
} else {
opline = zend_emit_op ( NULL , ZEND_INIT_NS_FCALL_BY_NAME , NULL , NULL ) ;
opline - > op2_type = IS_CONST ;
2018-12-07 14:47:56 +00:00
opline - > op2 . constant = zend_add_ns_func_name_literal ( name ) ;
2015-03-02 09:25:40 +00:00
}
2018-02-05 16:41:47 +00:00
opline - > result . num = zend_alloc_cache_slot ( ) ;
2015-03-02 09:25:40 +00:00
if ( args - > children = = 1 & &
( args - > child [ 0 ] - > kind ! = ZEND_AST_ZVAL | |
Z_TYPE_P ( zend_ast_get_zval ( args - > child [ 0 ] ) ) ! = IS_STRING ) ) {
/* add "assert(condition) as assertion message */
zend_ast_list_add ( ( zend_ast * ) args ,
zend_ast_create_zval_from_str (
2019-03-28 08:29:08 +00:00
zend_ast_export ( " assert( " , args - > child [ 0 ] , " ) " ) ) ) ;
2015-03-02 09:25:40 +00:00
}
zend_compile_call_common ( result , ( zend_ast * ) args , fbc ) ;
2015-12-14 11:31:00 +00:00
opline = & CG ( active_op_array ) - > opcodes [ check_op_number ] ;
2018-12-07 14:47:56 +00:00
opline - > op2 . opline_num = get_next_op_number ( ) ;
2015-12-14 11:31:00 +00:00
SET_NODE ( opline - > result , result ) ;
2015-03-02 09:25:40 +00:00
} else {
if ( ! fbc ) {
2018-05-28 13:27:12 +00:00
zend_string_release_ex ( name , 0 ) ;
2015-03-02 09:25:40 +00:00
}
result - > op_type = IS_CONST ;
ZVAL_TRUE ( & result - > u . constant ) ;
}
}
/* }}} */
2020-08-28 13:41:27 +00:00
static zend_result zend_compile_func_in_array ( znode * result , zend_ast_list * args ) /* { { { */
2017-05-24 20:00:48 +00:00
{
zend_bool strict = 0 ;
znode array , needly ;
zend_op * opline ;
if ( args - > children = = 3 ) {
2017-05-25 07:26:42 +00:00
if ( args - > child [ 2 ] - > kind = = ZEND_AST_ZVAL ) {
strict = zend_is_true ( zend_ast_get_zval ( args - > child [ 2 ] ) ) ;
} else if ( args - > child [ 2 ] - > kind = = ZEND_AST_CONST ) {
zval value ;
zend_ast * name_ast = args - > child [ 2 ] - > child [ 0 ] ;
zend_bool is_fully_qualified ;
zend_string * resolved_name = zend_resolve_const_name (
zend_ast_get_str ( name_ast ) , name_ast - > attr , & is_fully_qualified ) ;
if ( ! zend_try_ct_eval_const ( & value , resolved_name , is_fully_qualified ) ) {
2018-05-28 13:27:12 +00:00
zend_string_release_ex ( resolved_name , 0 ) ;
2017-05-25 07:26:42 +00:00
return FAILURE ;
}
2018-05-28 13:27:12 +00:00
zend_string_release_ex ( resolved_name , 0 ) ;
2017-05-25 07:26:42 +00:00
strict = zend_is_true ( & value ) ;
zval_ptr_dtor ( & value ) ;
} else {
2017-05-24 20:00:48 +00:00
return FAILURE ;
}
2017-05-25 07:26:42 +00:00
} else if ( args - > children ! = 2 ) {
return FAILURE ;
2017-05-24 20:00:48 +00:00
}
2017-05-25 07:26:42 +00:00
if ( args - > child [ 1 ] - > kind ! = ZEND_AST_ARRAY
2017-05-24 20:00:48 +00:00
| | ! zend_try_ct_eval_array ( & array . u . constant , args - > child [ 1 ] ) ) {
return FAILURE ;
}
if ( zend_hash_num_elements ( Z_ARRVAL ( array . u . constant ) ) > 0 ) {
zend_bool ok = 1 ;
zval * val , tmp ;
HashTable * src = Z_ARRVAL ( array . u . constant ) ;
2017-09-19 23:25:56 +00:00
HashTable * dst = zend_new_array ( zend_hash_num_elements ( src ) ) ;
2017-05-24 20:00:48 +00:00
ZVAL_TRUE ( & tmp ) ;
if ( strict ) {
ZEND_HASH_FOREACH_VAL ( src , val ) {
if ( Z_TYPE_P ( val ) = = IS_STRING ) {
zend_hash_add ( dst , Z_STR_P ( val ) , & tmp ) ;
} else if ( Z_TYPE_P ( val ) = = IS_LONG ) {
zend_hash_index_add ( dst , Z_LVAL_P ( val ) , & tmp ) ;
} else {
zend_array_destroy ( dst ) ;
ok = 0 ;
break ;
}
} ZEND_HASH_FOREACH_END ( ) ;
} else {
ZEND_HASH_FOREACH_VAL ( src , val ) {
2017-05-25 07:26:42 +00:00
if ( Z_TYPE_P ( val ) ! = IS_STRING
| | is_numeric_string ( Z_STRVAL_P ( val ) , Z_STRLEN_P ( val ) , NULL , NULL , 0 ) ) {
2017-05-24 20:00:48 +00:00
zend_array_destroy ( dst ) ;
ok = 0 ;
break ;
}
zend_hash_add ( dst , Z_STR_P ( val ) , & tmp ) ;
} ZEND_HASH_FOREACH_END ( ) ;
}
zend_array_destroy ( src ) ;
if ( ! ok ) {
return FAILURE ;
}
Z_ARRVAL ( array . u . constant ) = dst ;
}
array . op_type = IS_CONST ;
zend_compile_expr ( & needly , args - > child [ 0 ] ) ;
opline = zend_emit_op_tmp ( result , ZEND_IN_ARRAY , & needly , & array ) ;
opline - > extended_value = strict ;
return SUCCESS ;
}
/* }}} */
2020-08-28 13:41:27 +00:00
zend_result zend_compile_func_count ( znode * result , zend_ast_list * args , zend_string * lcname ) /* { { { */
2017-05-25 09:52:34 +00:00
{
znode arg_node ;
2019-04-11 08:48:52 +00:00
zend_op * opline ;
2017-05-25 09:52:34 +00:00
2018-08-22 09:38:28 +00:00
if ( args - > children ! = 1 ) {
2017-05-25 09:52:34 +00:00
return FAILURE ;
}
zend_compile_expr ( & arg_node , args - > child [ 0 ] ) ;
2019-04-11 08:48:52 +00:00
opline = zend_emit_op_tmp ( result , ZEND_COUNT , & arg_node , NULL ) ;
opline - > extended_value = zend_string_equals_literal ( lcname , " sizeof " ) ;
2017-05-25 09:52:34 +00:00
return SUCCESS ;
}
/* }}} */
2020-08-28 13:41:27 +00:00
zend_result zend_compile_func_get_class ( znode * result , zend_ast_list * args ) /* { { { */
2017-05-25 15:41:28 +00:00
{
if ( args - > children = = 0 ) {
zend_emit_op_tmp ( result , ZEND_GET_CLASS , NULL , NULL ) ;
} else {
znode arg_node ;
2018-08-22 09:38:28 +00:00
if ( args - > children ! = 1 ) {
2017-05-25 15:41:28 +00:00
return FAILURE ;
}
zend_compile_expr ( & arg_node , args - > child [ 0 ] ) ;
zend_emit_op_tmp ( result , ZEND_GET_CLASS , & arg_node , NULL ) ;
}
return SUCCESS ;
}
/* }}} */
2020-08-28 13:41:27 +00:00
zend_result zend_compile_func_get_called_class ( znode * result , zend_ast_list * args ) /* { { { */
2017-05-25 15:41:28 +00:00
{
if ( args - > children ! = 0 ) {
return FAILURE ;
}
2017-05-25 17:20:57 +00:00
zend_emit_op_tmp ( result , ZEND_GET_CALLED_CLASS , NULL , NULL ) ;
2017-05-25 15:41:28 +00:00
return SUCCESS ;
}
/* }}} */
2020-08-28 13:41:27 +00:00
zend_result zend_compile_func_gettype ( znode * result , zend_ast_list * args ) /* { { { */
2017-05-25 15:41:28 +00:00
{
znode arg_node ;
2018-08-22 09:38:28 +00:00
if ( args - > children ! = 1 ) {
2017-05-25 15:41:28 +00:00
return FAILURE ;
}
zend_compile_expr ( & arg_node , args - > child [ 0 ] ) ;
zend_emit_op_tmp ( result , ZEND_GET_TYPE , & arg_node , NULL ) ;
return SUCCESS ;
}
/* }}} */
2020-08-28 13:41:27 +00:00
zend_result zend_compile_func_num_args ( znode * result , zend_ast_list * args ) /* { { { */
2017-05-30 10:23:17 +00:00
{
if ( CG ( active_op_array ) - > function_name & & args - > children = = 0 ) {
zend_emit_op_tmp ( result , ZEND_FUNC_NUM_ARGS , NULL , NULL ) ;
return SUCCESS ;
} else {
return FAILURE ;
}
}
/* }}} */
2020-08-28 13:41:27 +00:00
zend_result zend_compile_func_get_args ( znode * result , zend_ast_list * args ) /* { { { */
2017-05-30 10:23:17 +00:00
{
if ( CG ( active_op_array ) - > function_name & & args - > children = = 0 ) {
zend_emit_op_tmp ( result , ZEND_FUNC_GET_ARGS , NULL , NULL ) ;
return SUCCESS ;
} else {
return FAILURE ;
}
}
/* }}} */
2020-08-28 13:41:27 +00:00
zend_result zend_compile_func_array_key_exists ( znode * result , zend_ast_list * args ) /* { { { */
2018-07-02 21:00:32 +00:00
{
znode subject , needle ;
if ( args - > children ! = 2 ) {
return FAILURE ;
}
zend_compile_expr ( & needle , args - > child [ 0 ] ) ;
zend_compile_expr ( & subject , args - > child [ 1 ] ) ;
zend_emit_op_tmp ( result , ZEND_ARRAY_KEY_EXISTS , & needle , & subject ) ;
return SUCCESS ;
}
/* }}} */
2020-08-28 13:41:27 +00:00
zend_result zend_compile_func_array_slice ( znode * result , zend_ast_list * args ) /* { { { */
2017-05-30 10:23:17 +00:00
{
if ( CG ( active_op_array ) - > function_name
& & args - > children = = 2
& & args - > child [ 0 ] - > kind = = ZEND_AST_CALL
& & args - > child [ 0 ] - > child [ 0 ] - > kind = = ZEND_AST_ZVAL
2017-05-30 18:48:16 +00:00
& & Z_TYPE_P ( zend_ast_get_zval ( args - > child [ 0 ] - > child [ 0 ] ) ) = = IS_STRING
2017-05-30 10:23:17 +00:00
& & args - > child [ 0 ] - > child [ 1 ] - > kind = = ZEND_AST_ARG_LIST
& & args - > child [ 1 ] - > kind = = ZEND_AST_ZVAL ) {
2017-05-30 18:48:16 +00:00
zend_string * orig_name = zend_ast_get_str ( args - > child [ 0 ] - > child [ 0 ] ) ;
zend_bool is_fully_qualified ;
zend_string * name = zend_resolve_function_name ( orig_name , args - > child [ 0 ] - > child [ 0 ] - > attr , & is_fully_qualified ) ;
2017-05-30 10:23:17 +00:00
zend_ast_list * list = zend_ast_get_list ( args - > child [ 0 ] - > child [ 1 ] ) ;
zval * zv = zend_ast_get_zval ( args - > child [ 1 ] ) ;
znode first ;
2017-05-30 18:48:16 +00:00
if ( zend_string_equals_literal_ci ( name , " func_get_args " )
2017-05-30 10:23:17 +00:00
& & list - > children = = 0
& & Z_TYPE_P ( zv ) = = IS_LONG
& & Z_LVAL_P ( zv ) > = 0 ) {
first . op_type = IS_CONST ;
ZVAL_LONG ( & first . u . constant , Z_LVAL_P ( zv ) ) ;
zend_emit_op_tmp ( result , ZEND_FUNC_GET_ARGS , & first , NULL ) ;
2018-05-28 13:27:12 +00:00
zend_string_release_ex ( name , 0 ) ;
2017-05-30 10:23:17 +00:00
return SUCCESS ;
}
2018-05-28 13:27:12 +00:00
zend_string_release_ex ( name , 0 ) ;
2017-05-30 10:23:17 +00:00
}
return FAILURE ;
}
/* }}} */
2020-08-28 13:41:27 +00:00
zend_result zend_try_compile_special_func ( znode * result , zend_string * lcname , zend_ast_list * args , zend_function * fbc , uint32_t type ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2016-05-04 09:53:59 +00:00
if ( CG ( compiler_options ) & ZEND_COMPILE_NO_BUILTINS ) {
return FAILURE ;
}
2020-07-08 08:10:32 +00:00
if ( fbc - > type ! = ZEND_INTERNAL_FUNCTION ) {
/* If the function is part of disabled_functions, it may be redeclared as a userland
* function with a different implementation . Don ' t use the VM builtin in that case . */
return FAILURE ;
}
2020-04-06 10:46:52 +00:00
if ( zend_args_contain_unpack_or_named ( args ) ) {
2018-08-22 09:38:28 +00:00
return FAILURE ;
}
2014-08-25 20:40:58 +00:00
if ( zend_string_equals_literal ( lcname , " strlen " ) ) {
2014-12-13 22:06:14 +00:00
return zend_compile_func_strlen ( result , args ) ;
2014-08-25 20:40:58 +00:00
} else if ( zend_string_equals_literal ( lcname , " is_null " ) ) {
2014-12-13 22:06:14 +00:00
return zend_compile_func_typecheck ( result , args , IS_NULL ) ;
2014-08-25 20:40:58 +00:00
} else if ( zend_string_equals_literal ( lcname , " is_bool " ) ) {
2014-12-13 22:06:14 +00:00
return zend_compile_func_typecheck ( result , args , _IS_BOOL ) ;
2014-08-28 19:53:32 +00:00
} else if ( zend_string_equals_literal ( lcname , " is_long " )
| | zend_string_equals_literal ( lcname , " is_int " )
| | zend_string_equals_literal ( lcname , " is_integer " )
) {
2014-12-13 22:06:14 +00:00
return zend_compile_func_typecheck ( result , args , IS_LONG ) ;
2014-08-28 19:53:32 +00:00
} else if ( zend_string_equals_literal ( lcname , " is_float " )
| | zend_string_equals_literal ( lcname , " is_double " )
) {
2014-12-13 22:06:14 +00:00
return zend_compile_func_typecheck ( result , args , IS_DOUBLE ) ;
2014-08-25 20:40:58 +00:00
} else if ( zend_string_equals_literal ( lcname , " is_string " ) ) {
2014-12-13 22:06:14 +00:00
return zend_compile_func_typecheck ( result , args , IS_STRING ) ;
2014-08-25 20:40:58 +00:00
} else if ( zend_string_equals_literal ( lcname , " is_array " ) ) {
2014-12-13 22:06:14 +00:00
return zend_compile_func_typecheck ( result , args , IS_ARRAY ) ;
2014-08-25 20:40:58 +00:00
} else if ( zend_string_equals_literal ( lcname , " is_object " ) ) {
2014-12-13 22:06:14 +00:00
return zend_compile_func_typecheck ( result , args , IS_OBJECT ) ;
2014-08-25 20:40:58 +00:00
} else if ( zend_string_equals_literal ( lcname , " is_resource " ) ) {
2014-12-13 22:06:14 +00:00
return zend_compile_func_typecheck ( result , args , IS_RESOURCE ) ;
2019-11-12 00:56:20 +00:00
} else if ( zend_string_equals_literal ( lcname , " is_scalar " ) ) {
return zend_compile_func_is_scalar ( result , args ) ;
2016-09-09 13:45:46 +00:00
} else if ( zend_string_equals_literal ( lcname , " boolval " ) ) {
return zend_compile_func_cast ( result , args , _IS_BOOL ) ;
} else if ( zend_string_equals_literal ( lcname , " intval " ) ) {
return zend_compile_func_cast ( result , args , IS_LONG ) ;
} else if ( zend_string_equals_literal ( lcname , " floatval " )
| | zend_string_equals_literal ( lcname , " doubleval " )
) {
return zend_compile_func_cast ( result , args , IS_DOUBLE ) ;
} else if ( zend_string_equals_literal ( lcname , " strval " ) ) {
return zend_compile_func_cast ( result , args , IS_STRING ) ;
2014-08-25 20:40:58 +00:00
} else if ( zend_string_equals_literal ( lcname , " defined " ) ) {
2014-12-13 22:06:14 +00:00
return zend_compile_func_defined ( result , args ) ;
2016-02-19 11:14:27 +00:00
} else if ( zend_string_equals_literal ( lcname , " chr " ) & & type = = BP_VAR_R ) {
return zend_compile_func_chr ( result , args ) ;
} else if ( zend_string_equals_literal ( lcname , " ord " ) & & type = = BP_VAR_R ) {
return zend_compile_func_ord ( result , args ) ;
2014-08-25 20:40:58 +00:00
} else if ( zend_string_equals_literal ( lcname , " call_user_func_array " ) ) {
2014-12-13 22:06:14 +00:00
return zend_compile_func_cufa ( result , args , lcname ) ;
2014-08-25 20:40:58 +00:00
} else if ( zend_string_equals_literal ( lcname , " call_user_func " ) ) {
2014-12-13 22:06:14 +00:00
return zend_compile_func_cuf ( result , args , lcname ) ;
2017-05-24 20:00:48 +00:00
} else if ( zend_string_equals_literal ( lcname , " in_array " ) ) {
return zend_compile_func_in_array ( result , args ) ;
2019-04-11 08:48:52 +00:00
} else if ( zend_string_equals_literal ( lcname , " count " )
| | zend_string_equals_literal ( lcname , " sizeof " ) ) {
return zend_compile_func_count ( result , args , lcname ) ;
2017-05-25 15:41:28 +00:00
} else if ( zend_string_equals_literal ( lcname , " get_class " ) ) {
return zend_compile_func_get_class ( result , args ) ;
} else if ( zend_string_equals_literal ( lcname , " get_called_class " ) ) {
return zend_compile_func_get_called_class ( result , args ) ;
} else if ( zend_string_equals_literal ( lcname , " gettype " ) ) {
return zend_compile_func_gettype ( result , args ) ;
2017-05-30 10:23:17 +00:00
} else if ( zend_string_equals_literal ( lcname , " func_num_args " ) ) {
return zend_compile_func_num_args ( result , args ) ;
} else if ( zend_string_equals_literal ( lcname , " func_get_args " ) ) {
return zend_compile_func_get_args ( result , args ) ;
} else if ( zend_string_equals_literal ( lcname , " array_slice " ) ) {
return zend_compile_func_array_slice ( result , args ) ;
2018-07-02 21:00:32 +00:00
} else if ( zend_string_equals_literal ( lcname , " array_key_exists " ) ) {
return zend_compile_func_array_key_exists ( result , args ) ;
2014-07-22 21:27:00 +00:00
} else {
return FAILURE ;
2012-12-25 06:23:08 +00:00
}
2010-12-20 00:52:40 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2010-12-20 00:52:40 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_call ( znode * result , zend_ast * ast , uint32_t type ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-07 11:06:53 +00:00
zend_ast * name_ast = ast - > child [ 0 ] ;
2014-07-13 11:11:55 +00:00
zend_ast * args_ast = ast - > child [ 1 ] ;
2010-12-20 00:52:40 +00:00
2014-06-07 11:06:53 +00:00
znode name_node ;
2014-06-28 20:27:06 +00:00
if ( name_ast - > kind ! = ZEND_AST_ZVAL | | Z_TYPE_P ( zend_ast_get_zval ( name_ast ) ) ! = IS_STRING ) {
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & name_node , name_ast ) ;
zend_compile_dynamic_call ( result , & name_node , args_ast ) ;
2014-06-07 11:06:53 +00:00
return ;
2012-01-20 12:30:57 +00:00
}
2014-06-07 11:06:53 +00:00
{
2014-12-13 22:06:14 +00:00
zend_bool runtime_resolution = zend_compile_function_name ( & name_node , name_ast ) ;
2014-07-28 20:03:16 +00:00
if ( runtime_resolution ) {
2015-03-02 09:25:40 +00:00
if ( zend_string_equals_literal_ci ( zend_ast_get_str ( name_ast ) , " assert " ) ) {
2015-03-04 02:55:14 +00:00
zend_compile_assert ( result , zend_ast_get_list ( args_ast ) , Z_STR ( name_node . u . constant ) , NULL ) ;
2015-03-02 09:25:40 +00:00
} else {
zend_compile_ns_call ( result , & name_node , args_ast ) ;
}
2014-06-07 11:06:53 +00:00
return ;
}
}
2011-12-19 16:48:18 +00:00
2014-06-07 11:06:53 +00:00
{
zval * name = & name_node . u . constant ;
2014-12-24 12:04:51 +00:00
zend_string * lcname ;
2014-06-07 11:06:53 +00:00
zend_function * fbc ;
zend_op * opline ;
2012-12-25 06:23:08 +00:00
2014-12-24 12:04:51 +00:00
lcname = zend_string_tolower ( Z_STR_P ( name ) ) ;
2014-07-24 17:22:46 +00:00
fbc = zend_hash_find_ptr ( CG ( function_table ) , lcname ) ;
2019-01-29 08:39:12 +00:00
/* Special assert() handling should apply independently of compiler flags. */
if ( fbc & & zend_string_equals_literal ( lcname , " assert " ) ) {
zend_compile_assert ( result , zend_ast_get_list ( args_ast ) , lcname , fbc ) ;
zend_string_release ( lcname ) ;
zval_ptr_dtor ( & name_node . u . constant ) ;
return ;
}
2019-09-06 09:30:01 +00:00
if ( ! fbc | | ! fbc_is_finalized ( fbc )
2015-07-21 14:39:22 +00:00
| | ( fbc - > type = = ZEND_INTERNAL_FUNCTION & & ( CG ( compiler_options ) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS ) )
| | ( fbc - > type = = ZEND_USER_FUNCTION & & ( CG ( compiler_options ) & ZEND_COMPILE_IGNORE_USER_FUNCTIONS ) )
2018-08-22 10:45:56 +00:00
| | ( fbc - > type = = ZEND_USER_FUNCTION & & ( CG ( compiler_options ) & ZEND_COMPILE_IGNORE_OTHER_FILES ) & & fbc - > op_array . filename ! = CG ( active_op_array ) - > filename )
2014-07-24 17:22:46 +00:00
) {
2018-05-28 13:27:12 +00:00
zend_string_release_ex ( lcname , 0 ) ;
2014-12-13 22:06:14 +00:00
zend_compile_dynamic_call ( result , & name_node , args_ast ) ;
2014-07-22 21:11:12 +00:00
return ;
2014-07-22 20:57:38 +00:00
}
2011-01-19 17:17:52 +00:00
2014-07-27 20:26:06 +00:00
if ( zend_try_compile_special_func ( result , lcname ,
2016-02-19 11:14:27 +00:00
zend_ast_get_list ( args_ast ) , fbc , type ) = = SUCCESS
2014-07-27 20:26:06 +00:00
) {
2018-05-28 13:27:12 +00:00
zend_string_release_ex ( lcname , 0 ) ;
2014-07-24 17:22:46 +00:00
zval_ptr_dtor ( & name_node . u . constant ) ;
2014-06-07 11:06:53 +00:00
return ;
}
2011-12-19 16:48:18 +00:00
2014-06-07 11:06:53 +00:00
zval_ptr_dtor ( & name_node . u . constant ) ;
ZVAL_NEW_STR ( & name_node . u . constant , lcname ) ;
2011-01-19 17:17:52 +00:00
2014-12-13 22:06:14 +00:00
opline = zend_emit_op ( NULL , ZEND_INIT_FCALL , NULL , & name_node ) ;
2018-02-05 16:41:47 +00:00
opline - > result . num = zend_alloc_cache_slot ( ) ;
2010-12-20 00:52:40 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_call_common ( result , args_ast , fbc ) ;
2010-12-20 00:52:40 +00:00
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
2013-01-28 02:02:51 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_method_call ( znode * result , zend_ast * ast , uint32_t type ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-08-15 15:10:06 +00:00
zend_ast * obj_ast = ast - > child [ 0 ] ;
zend_ast * method_ast = ast - > child [ 1 ] ;
2014-07-13 11:11:55 +00:00
zend_ast * args_ast = ast - > child [ 2 ] ;
2013-01-28 02:02:51 +00:00
2014-08-15 15:10:06 +00:00
znode obj_node , method_node ;
zend_op * opline ;
2016-04-07 23:41:48 +00:00
zend_function * fbc = NULL ;
2020-05-24 10:42:48 +00:00
zend_bool nullsafe = ast - > kind = = ZEND_AST_NULLSAFE_METHOD_CALL ;
2011-11-18 13:49:07 +00:00
2014-08-15 15:10:06 +00:00
if ( is_this_fetch ( obj_ast ) ) {
2019-02-13 10:37:32 +00:00
if ( this_guaranteed_exists ( ) ) {
obj_node . op_type = IS_UNUSED ;
} else {
zend_emit_op ( & obj_node , ZEND_FETCH_THIS , NULL , NULL ) ;
}
2019-08-16 10:55:28 +00:00
CG ( active_op_array ) - > fn_flags | = ZEND_ACC_USES_THIS ;
2020-08-11 13:22:14 +00:00
/* We will throw if $this doesn't exist, so there's no need to emit a JMP_NULL
* check for a nullsafe access . */
2014-08-15 15:10:06 +00:00
} else {
2020-05-24 10:42:48 +00:00
zend_short_circuiting_mark_inner ( obj_ast ) ;
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & obj_node , obj_ast ) ;
2020-08-11 13:22:14 +00:00
if ( nullsafe ) {
zend_emit_jmp_null ( & obj_node ) ;
}
2020-05-24 10:42:48 +00:00
}
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & method_node , method_ast ) ;
opline = zend_emit_op ( NULL , ZEND_INIT_METHOD_CALL , & obj_node , NULL ) ;
2015-01-03 09:22:58 +00:00
2014-08-15 15:10:06 +00:00
if ( method_node . op_type = = IS_CONST ) {
if ( Z_TYPE ( method_node . u . constant ) ! = IS_STRING ) {
2014-06-07 11:06:53 +00:00
zend_error_noreturn ( E_COMPILE_ERROR , " Method name must be a string " ) ;
}
2010-12-20 00:52:40 +00:00
2014-08-15 15:10:06 +00:00
opline - > op2_type = IS_CONST ;
2018-12-07 14:47:56 +00:00
opline - > op2 . constant = zend_add_func_name_literal (
2014-12-13 22:06:14 +00:00
Z_STR ( method_node . u . constant ) ) ;
2019-01-07 11:28:51 +00:00
opline - > result . num = zend_alloc_cache_slots ( 2 ) ;
2014-08-15 15:10:06 +00:00
} else {
SET_NODE ( opline - > op2 , & method_node ) ;
2010-12-20 00:52:40 +00:00
}
2016-04-07 23:41:48 +00:00
/* Check if this calls a known method on $this */
if ( opline - > op1_type = = IS_UNUSED & & opline - > op2_type = = IS_CONST & &
CG ( active_class_entry ) & & zend_is_scope_known ( ) ) {
zend_string * lcname = Z_STR_P ( CT_CONSTANT ( opline - > op2 ) + 1 ) ;
fbc = zend_hash_find_ptr ( & CG ( active_class_entry ) - > function_table , lcname ) ;
/* We only know the exact method that is being called if it is either private or final.
* Otherwise an overriding method in a child class may be called . */
if ( fbc & & ! ( fbc - > common . fn_flags & ( ZEND_ACC_PRIVATE | ZEND_ACC_FINAL ) ) ) {
fbc = NULL ;
}
}
zend_compile_call_common ( result , args_ast , fbc ) ;
2014-06-07 11:06:53 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2013-01-28 02:02:51 +00:00
2015-03-31 14:10:22 +00:00
static zend_bool zend_is_constructor ( zend_string * name ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-08-25 20:40:58 +00:00
return zend_string_equals_literal_ci ( name , ZEND_CONSTRUCTOR_FUNC_NAME ) ;
2014-06-07 11:06:53 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2010-12-20 00:52:40 +00:00
2019-03-06 09:42:02 +00:00
static zend_function * zend_get_compatible_func_or_null ( zend_class_entry * ce , zend_string * lcname ) /* { { { */
{
zend_function * fbc = zend_hash_find_ptr ( & ce - > function_table , lcname ) ;
if ( ! fbc | | ( fbc - > common . fn_flags & ZEND_ACC_PUBLIC ) | | ce = = CG ( active_class_entry ) ) {
return fbc ;
}
if ( ! ( fbc - > common . fn_flags & ZEND_ACC_PRIVATE )
& & ( fbc - > common . scope - > ce_flags & ZEND_ACC_LINKED )
& & ( ! CG ( active_class_entry ) | | ( CG ( active_class_entry ) - > ce_flags & ZEND_ACC_LINKED ) )
& & zend_check_protected ( zend_get_function_root_class ( fbc ) , CG ( active_class_entry ) ) ) {
return fbc ;
}
return NULL ;
}
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_static_call ( znode * result , zend_ast * ast , uint32_t type ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-07 11:06:53 +00:00
zend_ast * class_ast = ast - > child [ 0 ] ;
zend_ast * method_ast = ast - > child [ 1 ] ;
2014-07-13 11:11:55 +00:00
zend_ast * args_ast = ast - > child [ 2 ] ;
2010-12-20 00:52:40 +00:00
2014-06-14 16:30:18 +00:00
znode class_node , method_node ;
2014-06-07 11:06:53 +00:00
zend_op * opline ;
2016-03-13 17:01:51 +00:00
zend_function * fbc = NULL ;
2013-01-28 02:02:51 +00:00
2020-05-24 10:42:48 +00:00
zend_short_circuiting_mark_inner ( class_ast ) ;
2019-01-02 08:48:29 +00:00
zend_compile_class_ref ( & class_node , class_ast , ZEND_FETCH_CLASS_EXCEPTION ) ;
2010-04-20 10:57:45 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & method_node , method_ast ) ;
2020-05-24 10:42:48 +00:00
2014-06-07 11:06:53 +00:00
if ( method_node . op_type = = IS_CONST ) {
zval * name = & method_node . u . constant ;
if ( Z_TYPE_P ( name ) ! = IS_STRING ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Method name must be a string " ) ;
}
if ( zend_is_constructor ( Z_STR_P ( name ) ) ) {
zval_ptr_dtor ( name ) ;
method_node . op_type = IS_UNUSED ;
}
2010-04-20 10:57:45 +00:00
}
1999-05-15 15:47:24 +00:00
2018-12-07 14:47:56 +00:00
opline = get_next_op ( ) ;
2014-06-07 11:06:53 +00:00
opline - > opcode = ZEND_INIT_STATIC_METHOD_CALL ;
2002-09-24 19:05:53 +00:00
2014-12-13 22:06:14 +00:00
zend_set_class_name_op1 ( opline , & class_node ) ;
2014-06-07 11:06:53 +00:00
if ( method_node . op_type = = IS_CONST ) {
opline - > op2_type = IS_CONST ;
2018-12-07 14:47:56 +00:00
opline - > op2 . constant = zend_add_func_name_literal (
2014-12-13 22:06:14 +00:00
Z_STR ( method_node . u . constant ) ) ;
2019-01-07 11:28:51 +00:00
opline - > result . num = zend_alloc_cache_slots ( 2 ) ;
2018-02-05 16:41:47 +00:00
} else {
2014-06-07 11:06:53 +00:00
if ( opline - > op1_type = = IS_CONST ) {
2018-02-05 16:41:47 +00:00
opline - > result . num = zend_alloc_cache_slot ( ) ;
2002-09-24 19:05:53 +00:00
}
2014-06-07 11:06:53 +00:00
SET_NODE ( opline - > op2 , & method_node ) ;
2002-09-24 19:05:53 +00:00
}
2014-06-07 11:06:53 +00:00
2016-03-13 17:01:51 +00:00
/* Check if we already know which method we're calling */
if ( opline - > op2_type = = IS_CONST ) {
zend_class_entry * ce = NULL ;
if ( opline - > op1_type = = IS_CONST ) {
zend_string * lcname = Z_STR_P ( CT_CONSTANT ( opline - > op1 ) + 1 ) ;
ce = zend_hash_find_ptr ( CG ( class_table ) , lcname ) ;
if ( ! ce & & CG ( active_class_entry )
& & zend_string_equals_ci ( CG ( active_class_entry ) - > name , lcname ) ) {
ce = CG ( active_class_entry ) ;
}
2016-03-26 21:43:58 +00:00
} else if ( opline - > op1_type = = IS_UNUSED
& & ( opline - > op1 . num & ZEND_FETCH_CLASS_MASK ) = = ZEND_FETCH_CLASS_SELF
2016-03-13 17:01:51 +00:00
& & zend_is_scope_known ( ) ) {
ce = CG ( active_class_entry ) ;
}
if ( ce ) {
zend_string * lcname = Z_STR_P ( CT_CONSTANT ( opline - > op2 ) + 1 ) ;
2019-03-06 09:42:02 +00:00
fbc = zend_get_compatible_func_or_null ( ce , lcname ) ;
2016-03-13 17:01:51 +00:00
}
}
zend_compile_call_common ( result , args_ast , fbc ) ;
2002-09-24 19:05:53 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2006-05-09 23:53:23 +00:00
2020-04-24 10:04:54 +00:00
void zend_compile_class_decl ( znode * result , zend_ast * ast , zend_bool toplevel ) ;
2015-04-26 13:02:57 +00:00
2015-04-26 13:24:13 +00:00
void zend_compile_new ( znode * result , zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-14 16:30:18 +00:00
zend_ast * class_ast = ast - > child [ 0 ] ;
2014-07-13 11:11:55 +00:00
zend_ast * args_ast = ast - > child [ 1 ] ;
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2014-06-14 16:30:18 +00:00
znode class_node , ctor_result ;
zend_op * opline ;
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2015-10-27 12:47:58 +00:00
if ( class_ast - > kind = = ZEND_AST_CLASS ) {
2019-07-19 07:09:26 +00:00
/* anon class declaration */
2020-04-24 10:04:54 +00:00
zend_compile_class_decl ( & class_node , class_ast , 0 ) ;
2015-04-26 13:17:53 +00:00
} else {
2019-01-02 08:48:29 +00:00
zend_compile_class_ref ( & class_node , class_ast , ZEND_FETCH_CLASS_EXCEPTION ) ;
2014-10-23 07:52:34 +00:00
}
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2014-12-13 22:06:14 +00:00
opline = zend_emit_op ( result , ZEND_NEW , NULL , NULL ) ;
2014-10-23 07:52:34 +00:00
if ( class_node . op_type = = IS_CONST ) {
opline - > op1_type = IS_CONST ;
opline - > op1 . constant = zend_add_class_name_literal (
2018-12-07 14:47:56 +00:00
Z_STR ( class_node . u . constant ) ) ;
2018-02-05 16:41:47 +00:00
opline - > op2 . num = zend_alloc_cache_slot ( ) ;
2014-10-23 07:52:34 +00:00
} else {
SET_NODE ( opline - > op1 , & class_node ) ;
}
2014-06-14 16:30:18 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_call_common ( & ctor_result , args_ast , NULL ) ;
zend_do_free ( & ctor_result ) ;
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_clone ( znode * result , zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-14 16:30:18 +00:00
zend_ast * obj_ast = ast - > child [ 0 ] ;
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2014-06-14 16:30:18 +00:00
znode obj_node ;
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & obj_node , obj_ast ) ;
2014-06-14 16:30:18 +00:00
2015-12-10 21:14:39 +00:00
zend_emit_op_tmp ( result , ZEND_CLONE , & obj_node , NULL ) ;
2014-06-14 16:30:18 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-06-14 16:30:18 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_global_var ( zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-07 11:06:53 +00:00
zend_ast * var_ast = ast - > child [ 0 ] ;
2014-07-22 18:24:47 +00:00
zend_ast * name_ast = var_ast - > child [ 0 ] ;
2014-06-07 11:06:53 +00:00
2014-07-22 18:24:47 +00:00
znode name_node , result ;
2014-06-07 11:06:53 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & name_node , name_ast ) ;
2014-07-22 18:24:47 +00:00
if ( name_node . op_type = = IS_CONST ) {
2014-11-10 15:41:55 +00:00
convert_to_string ( & name_node . u . constant ) ;
2010-05-06 19:20:12 +00:00
}
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2016-06-15 23:30:23 +00:00
if ( is_this_fetch ( var_ast ) ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use $this as global variable " ) ;
} else if ( zend_try_compile_cv ( & result , var_ast ) = = SUCCESS ) {
2014-12-13 22:06:14 +00:00
zend_op * opline = zend_emit_op ( NULL , ZEND_BIND_GLOBAL , & result , & name_node ) ;
2018-02-05 16:41:47 +00:00
opline - > extended_value = zend_alloc_cache_slot ( ) ;
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
} else {
2015-12-10 17:51:03 +00:00
/* name_ast should be evaluated only. FETCH_GLOBAL_LOCK instructs FETCH_W
* to not free the name_node operand , so it can be reused in the following
* ASSIGN_REF , which then frees it . */
zend_op * opline = zend_emit_op ( & result , ZEND_FETCH_W , & name_node , NULL ) ;
opline - > extended_value = ZEND_FETCH_GLOBAL_LOCK ;
2016-03-22 21:46:48 +00:00
if ( name_node . op_type = = IS_CONST ) {
zend_string_addref ( Z_STR ( name_node . u . constant ) ) ;
}
2015-12-10 17:51:03 +00:00
zend_emit_assign_ref_znode (
2019-03-28 08:29:08 +00:00
zend_ast_create ( ZEND_AST_VAR , zend_ast_create_znode ( & name_node ) ) ,
2015-12-10 17:51:03 +00:00
& result
) ;
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2019-05-27 15:11:44 +00:00
static void zend_compile_static_var_common ( zend_string * var_name , zval * value , uint32_t mode ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-12 15:00:53 +00:00
zend_op * opline ;
if ( ! CG ( active_op_array ) - > static_variables ) {
if ( CG ( active_op_array ) - > scope ) {
CG ( active_op_array ) - > scope - > ce_flags | = ZEND_HAS_STATIC_IN_METHODS ;
}
2017-09-19 23:25:56 +00:00
CG ( active_op_array ) - > static_variables = zend_new_array ( 8 ) ;
2014-07-12 15:00:53 +00:00
}
2018-08-20 13:10:09 +00:00
value = zend_hash_update ( CG ( active_op_array ) - > static_variables , var_name , value ) ;
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2017-10-31 22:10:21 +00:00
if ( zend_string_equals_literal ( var_name , " this " ) ) {
2016-06-15 23:30:23 +00:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use $this as static variable " ) ;
}
2018-08-21 09:22:04 +00:00
opline = zend_emit_op ( NULL , ZEND_BIND_STATIC , NULL , NULL ) ;
2016-01-12 09:20:35 +00:00
opline - > op1_type = IS_CV ;
2018-12-07 14:47:56 +00:00
opline - > op1 . var = lookup_cv ( var_name ) ;
2019-05-27 15:11:44 +00:00
opline - > extended_value = ( uint32_t ) ( ( char * ) value - ( char * ) CG ( active_op_array ) - > static_variables - > arData ) | mode ;
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_static_var ( zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-18 10:30:39 +00:00
zend_ast * var_ast = ast - > child [ 0 ] ;
zend_ast * value_ast = ast - > child [ 1 ] ;
zval value_zv ;
2002-09-24 19:05:53 +00:00
2014-07-18 10:30:39 +00:00
if ( value_ast ) {
2014-12-13 22:06:14 +00:00
zend_const_expr_to_zval ( & value_zv , value_ast ) ;
2010-04-20 10:57:45 +00:00
} else {
2014-07-18 10:30:39 +00:00
ZVAL_NULL ( & value_zv ) ;
2010-04-20 10:57:45 +00:00
}
2014-07-18 10:30:39 +00:00
2019-05-02 12:57:16 +00:00
zend_compile_static_var_common ( zend_ast_get_str ( var_ast ) , & value_zv , ZEND_BIND_REF ) ;
2014-07-12 15:00:53 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-07-12 15:00:53 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_unset ( zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-07 11:06:53 +00:00
zend_ast * var_ast = ast - > child [ 0 ] ;
znode var_node ;
zend_op * opline ;
2015-08-11 13:42:11 +00:00
zend_ensure_writable_variable ( var_ast ) ;
2014-06-07 11:06:53 +00:00
switch ( var_ast - > kind ) {
case ZEND_AST_VAR :
2016-06-15 23:30:23 +00:00
if ( is_this_fetch ( var_ast ) ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot unset $this " ) ;
} else if ( zend_try_compile_cv ( & var_node , var_ast ) = = SUCCESS ) {
2017-07-17 11:11:50 +00:00
opline = zend_emit_op ( NULL , ZEND_UNSET_CV , & var_node , NULL ) ;
2014-06-07 11:06:53 +00:00
} else {
2015-02-02 17:44:16 +00:00
opline = zend_compile_simple_var_no_cv ( NULL , var_ast , BP_VAR_UNSET , 0 ) ;
2014-06-07 11:06:53 +00:00
opline - > opcode = ZEND_UNSET_VAR ;
}
return ;
case ZEND_AST_DIM :
2017-11-16 21:28:29 +00:00
opline = zend_compile_dim ( NULL , var_ast , BP_VAR_UNSET ) ;
2014-06-07 11:06:53 +00:00
opline - > opcode = ZEND_UNSET_DIM ;
return ;
case ZEND_AST_PROP :
2020-05-24 10:42:48 +00:00
case ZEND_AST_NULLSAFE_PROP :
2019-01-07 11:28:51 +00:00
opline = zend_compile_prop ( NULL , var_ast , BP_VAR_UNSET , 0 ) ;
2014-06-07 11:06:53 +00:00
opline - > opcode = ZEND_UNSET_OBJ ;
return ;
2014-06-19 11:57:29 +00:00
case ZEND_AST_STATIC_PROP :
2019-01-07 11:28:51 +00:00
opline = zend_compile_static_prop ( NULL , var_ast , BP_VAR_UNSET , 0 , 0 ) ;
2015-10-27 12:47:58 +00:00
opline - > opcode = ZEND_UNSET_STATIC_PROP ;
2014-06-19 11:57:29 +00:00
return ;
2014-06-07 11:06:53 +00:00
EMPTY_SWITCH_DEFAULT_CASE ( )
2002-09-24 19:05:53 +00:00
}
2014-06-07 11:06:53 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-06-07 11:06:53 +00:00
2020-08-28 13:41:27 +00:00
static bool zend_handle_loops_and_finally_ex ( zend_long depth , znode * return_value ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2015-08-04 04:37:06 +00:00
zend_loop_var * base ;
2015-07-10 11:30:25 +00:00
zend_loop_var * loop_var = zend_stack_top ( & CG ( loop_var_stack ) ) ;
2015-08-04 04:37:06 +00:00
if ( ! loop_var ) {
return 1 ;
}
base = zend_stack_base ( & CG ( loop_var_stack ) ) ;
for ( ; loop_var > = base ; loop_var - - ) {
if ( loop_var - > opcode = = ZEND_FAST_CALL ) {
2018-12-07 14:47:56 +00:00
zend_op * opline = get_next_op ( ) ;
2015-08-04 04:37:06 +00:00
opline - > opcode = ZEND_FAST_CALL ;
opline - > result_type = IS_TMP_VAR ;
opline - > result . var = loop_var - > var_num ;
2016-06-07 23:20:45 +00:00
if ( return_value ) {
SET_NODE ( opline - > op2 , return_value ) ;
}
2019-01-17 15:07:17 +00:00
opline - > op1 . num = loop_var - > try_catch_offset ;
2016-05-24 22:25:12 +00:00
} else if ( loop_var - > opcode = = ZEND_DISCARD_EXCEPTION ) {
2018-12-07 14:47:56 +00:00
zend_op * opline = get_next_op ( ) ;
2016-05-24 22:25:12 +00:00
opline - > opcode = ZEND_DISCARD_EXCEPTION ;
opline - > op1_type = IS_TMP_VAR ;
opline - > op1 . var = loop_var - > var_num ;
2015-08-04 04:37:06 +00:00
} else if ( loop_var - > opcode = = ZEND_RETURN ) {
/* Stack separator */
break ;
} else if ( depth < = 1 ) {
return 1 ;
} else if ( loop_var - > opcode = = ZEND_NOP ) {
/* Loop doesn't have freeable variable */
depth - - ;
} else {
zend_op * opline ;
2016-02-11 20:11:19 +00:00
ZEND_ASSERT ( loop_var - > var_type & ( IS_VAR | IS_TMP_VAR ) ) ;
2018-12-07 14:47:56 +00:00
opline = get_next_op ( ) ;
2015-08-04 04:37:06 +00:00
opline - > opcode = loop_var - > opcode ;
opline - > op1_type = loop_var - > var_type ;
opline - > op1 . var = loop_var - > var_num ;
opline - > extended_value = ZEND_FREE_ON_RETURN ;
depth - - ;
}
2015-07-10 01:13:34 +00:00
}
2015-08-04 04:37:06 +00:00
return ( depth = = 0 ) ;
}
/* }}} */
2020-08-28 13:41:27 +00:00
static bool zend_handle_loops_and_finally ( znode * return_value ) /* { { { */
2015-08-04 04:37:06 +00:00
{
2016-06-07 23:20:45 +00:00
return zend_handle_loops_and_finally_ex ( zend_stack_count ( & CG ( loop_var_stack ) ) + 1 , return_value ) ;
2002-09-24 19:05:53 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2000-05-25 16:26:22 +00:00
2020-08-28 13:41:27 +00:00
static bool zend_has_finally_ex ( zend_long depth ) /* { { { */
2016-07-13 12:08:28 +00:00
{
zend_loop_var * base ;
zend_loop_var * loop_var = zend_stack_top ( & CG ( loop_var_stack ) ) ;
if ( ! loop_var ) {
return 0 ;
}
base = zend_stack_base ( & CG ( loop_var_stack ) ) ;
for ( ; loop_var > = base ; loop_var - - ) {
if ( loop_var - > opcode = = ZEND_FAST_CALL ) {
return 1 ;
} else if ( loop_var - > opcode = = ZEND_DISCARD_EXCEPTION ) {
} else if ( loop_var - > opcode = = ZEND_RETURN ) {
/* Stack separator */
return 0 ;
} else if ( depth < = 1 ) {
return 0 ;
} else {
depth - - ;
}
}
return 0 ;
}
/* }}} */
2020-08-28 13:41:27 +00:00
static bool zend_has_finally ( void ) /* { { { */
2016-07-13 12:08:28 +00:00
{
return zend_has_finally_ex ( zend_stack_count ( & CG ( loop_var_stack ) ) + 1 ) ;
}
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_return ( zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-07 19:06:02 +00:00
zend_ast * expr_ast = ast - > child [ 0 ] ;
2016-07-14 13:44:04 +00:00
zend_bool is_generator = ( CG ( active_op_array ) - > fn_flags & ZEND_ACC_GENERATOR ) ! = 0 ;
2014-07-07 19:06:02 +00:00
zend_bool by_ref = ( CG ( active_op_array ) - > fn_flags & ZEND_ACC_RETURN_REFERENCE ) ! = 0 ;
2010-04-20 10:57:45 +00:00
2014-07-07 19:06:02 +00:00
znode expr_node ;
zend_op * opline ;
2016-07-14 13:44:04 +00:00
if ( is_generator ) {
/* For generators the by-ref flag refers to yields, not returns */
by_ref = 0 ;
}
2014-07-07 19:06:02 +00:00
if ( ! expr_ast ) {
expr_node . op_type = IS_CONST ;
ZVAL_NULL ( & expr_node . u . constant ) ;
2019-01-26 11:10:03 +00:00
} else if ( by_ref & & zend_is_variable ( expr_ast ) ) {
2020-07-27 08:27:26 +00:00
if ( zend_ast_is_short_circuited ( expr_ast ) ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot take reference of a nullsafe chain " ) ;
}
2019-01-07 11:28:51 +00:00
zend_compile_var ( & expr_node , expr_ast , BP_VAR_W , 1 ) ;
2010-04-20 10:57:45 +00:00
} else {
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & expr_node , expr_ast ) ;
2010-04-20 10:57:45 +00:00
}
2002-09-15 07:54:01 +00:00
2016-07-13 12:08:28 +00:00
if ( ( CG ( active_op_array ) - > fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK )
& & ( expr_node . op_type = = IS_CV | | ( by_ref & & expr_node . op_type = = IS_VAR ) )
& & zend_has_finally ( ) ) {
/* Copy return value into temporary VAR to avoid modification in finally code */
if ( by_ref ) {
zend_emit_op ( & expr_node , ZEND_MAKE_REF , & expr_node , NULL ) ;
} else {
zend_emit_op_tmp ( & expr_node , ZEND_QM_ASSIGN , & expr_node , NULL ) ;
}
}
2015-07-10 00:31:52 +00:00
/* Generator return types are handled separately */
2020-06-07 00:38:13 +00:00
if ( ! is_generator & & ( CG ( active_op_array ) - > fn_flags & ZEND_ACC_HAS_RETURN_TYPE ) ) {
2016-06-04 11:13:25 +00:00
zend_emit_return_type_check (
expr_ast ? & expr_node : NULL , CG ( active_op_array ) - > arg_info - 1 , 0 ) ;
2015-07-10 00:31:52 +00:00
}
2015-12-11 17:11:28 +00:00
2016-12-21 06:24:14 +00:00
zend_handle_loops_and_finally ( ( expr_node . op_type & ( IS_TMP_VAR | IS_VAR ) ) ? & expr_node : NULL ) ;
2014-07-28 20:03:16 +00:00
opline = zend_emit_op ( NULL , by_ref ? ZEND_RETURN_BY_REF : ZEND_RETURN ,
2014-12-13 22:06:14 +00:00
& expr_node , NULL ) ;
2014-07-28 20:03:16 +00:00
2016-07-14 13:44:04 +00:00
if ( by_ref & & expr_ast ) {
2014-07-07 19:06:02 +00:00
if ( zend_is_call ( expr_ast ) ) {
opline - > extended_value = ZEND_RETURNS_FUNCTION ;
2020-05-24 10:42:48 +00:00
} else if ( ! zend_is_variable ( expr_ast ) | | zend_ast_is_short_circuited ( expr_ast ) ) {
2014-07-07 19:06:02 +00:00
opline - > extended_value = ZEND_RETURNS_VALUE ;
}
2004-08-26 22:59:25 +00:00
}
2014-07-07 19:06:02 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2004-08-26 22:59:25 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_echo ( zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2015-09-29 13:49:22 +00:00
zend_op * opline ;
2014-07-07 19:14:14 +00:00
zend_ast * expr_ast = ast - > child [ 0 ] ;
2002-09-24 19:05:53 +00:00
2014-07-07 19:14:14 +00:00
znode expr_node ;
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & expr_node , expr_ast ) ;
2002-09-24 19:32:01 +00:00
2015-09-29 13:49:22 +00:00
opline = zend_emit_op ( NULL , ZEND_ECHO , & expr_node , NULL ) ;
2015-09-30 02:41:27 +00:00
opline - > extended_value = 0 ;
1999-05-15 15:47:24 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-05-15 15:47:24 +00:00
2020-03-18 23:51:51 +00:00
void zend_compile_throw ( znode * result , zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-09 20:47:36 +00:00
zend_ast * expr_ast = ast - > child [ 0 ] ;
1999-05-15 15:47:24 +00:00
2014-07-09 20:47:36 +00:00
znode expr_node ;
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & expr_node , expr_ast ) ;
2003-01-28 11:34:24 +00:00
2020-04-24 14:12:06 +00:00
zend_op * opline = zend_emit_op ( NULL , ZEND_THROW , & expr_node , NULL ) ;
if ( result ) {
/* Mark this as an "expression throw" for opcache. */
opline - > extended_value = ZEND_THROW_IS_EXPR ;
result - > op_type = IS_CONST ;
ZVAL_BOOL ( & result - > u . constant , 1 ) ;
}
2014-07-09 20:47:36 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2008-03-18 08:36:30 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_break_continue ( zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-09 21:05:21 +00:00
zend_ast * depth_ast = ast - > child [ 0 ] ;
2008-03-18 08:36:30 +00:00
2014-07-09 21:05:21 +00:00
zend_op * opline ;
2019-02-25 07:00:14 +00:00
zend_long depth ;
2004-02-04 16:30:15 +00:00
2014-07-27 20:26:06 +00:00
ZEND_ASSERT ( ast - > kind = = ZEND_AST_BREAK | | ast - > kind = = ZEND_AST_CONTINUE ) ;
2014-07-09 21:05:21 +00:00
if ( depth_ast ) {
2015-05-22 20:08:44 +00:00
zval * depth_zv ;
2014-07-09 21:05:21 +00:00
if ( depth_ast - > kind ! = ZEND_AST_ZVAL ) {
2018-07-04 01:04:31 +00:00
zend_error_noreturn ( E_COMPILE_ERROR , " '%s' operator with non-integer operand "
2014-07-27 20:26:06 +00:00
" is no longer supported " , ast - > kind = = ZEND_AST_BREAK ? " break " : " continue " ) ;
2014-07-09 21:05:21 +00:00
}
2015-05-22 20:08:44 +00:00
depth_zv = zend_ast_get_zval ( depth_ast ) ;
if ( Z_TYPE_P ( depth_zv ) ! = IS_LONG | | Z_LVAL_P ( depth_zv ) < 1 ) {
2018-07-04 01:04:31 +00:00
zend_error_noreturn ( E_COMPILE_ERROR , " '%s' operator accepts only positive integers " ,
2014-07-27 20:26:06 +00:00
ast - > kind = = ZEND_AST_BREAK ? " break " : " continue " ) ;
2014-07-09 21:05:21 +00:00
}
2015-05-22 20:08:44 +00:00
depth = Z_LVAL_P ( depth_zv ) ;
2014-07-09 21:05:21 +00:00
} else {
2015-05-22 20:08:44 +00:00
depth = 1 ;
1999-07-26 21:18:35 +00:00
}
2002-09-24 19:05:53 +00:00
2015-04-01 12:52:26 +00:00
if ( CG ( context ) . current_brk_cont = = - 1 ) {
zend_error_noreturn ( E_COMPILE_ERROR , " '%s' not in the 'loop' or 'switch' context " ,
ast - > kind = = ZEND_AST_BREAK ? " break " : " continue " ) ;
} else {
2016-06-07 23:20:45 +00:00
if ( ! zend_handle_loops_and_finally_ex ( depth , NULL ) ) {
2019-02-25 07:00:14 +00:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot '%s' " ZEND_LONG_FMT " level%s " ,
2015-08-04 04:37:06 +00:00
ast - > kind = = ZEND_AST_BREAK ? " break " : " continue " ,
depth , depth = = 1 ? " " : " s " ) ;
}
2015-04-01 12:52:26 +00:00
}
2018-06-24 14:55:22 +00:00
if ( ast - > kind = = ZEND_AST_CONTINUE ) {
int d , cur = CG ( context ) . current_brk_cont ;
for ( d = depth - 1 ; d > 0 ; d - - ) {
cur = CG ( context ) . brk_cont_array [ cur ] . parent ;
ZEND_ASSERT ( cur ! = - 1 ) ;
}
if ( CG ( context ) . brk_cont_array [ cur ] . is_switch ) {
if ( depth = = 1 ) {
zend_error ( E_WARNING ,
" \" continue \" targeting switch is equivalent to \" break \" . " \
2019-02-25 07:04:04 +00:00
" Did you mean to use \" continue " ZEND_LONG_FMT " \" ? " ,
2018-06-24 14:55:22 +00:00
depth + 1 ) ;
} else {
zend_error ( E_WARNING ,
2019-02-25 07:04:04 +00:00
" \" continue " ZEND_LONG_FMT " \" targeting switch is equivalent to \" break " ZEND_LONG_FMT " \" . " \
" Did you mean to use \" continue " ZEND_LONG_FMT " \" ? " ,
2018-06-24 14:55:22 +00:00
depth , depth , depth + 1 ) ;
}
}
}
2015-05-22 20:08:44 +00:00
opline = zend_emit_op ( NULL , ast - > kind = = ZEND_AST_BREAK ? ZEND_BRK : ZEND_CONT , NULL , NULL ) ;
opline - > op1 . num = CG ( context ) . current_brk_cont ;
opline - > op2 . num = depth ;
1999-05-15 15:47:24 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-05-15 15:47:24 +00:00
2015-08-04 04:37:06 +00:00
void zend_resolve_goto_label ( zend_op_array * op_array , zend_op * opline ) /* { { { */
2015-07-10 01:44:21 +00:00
{
zend_label * dest ;
2015-07-10 11:30:25 +00:00
int current , remove_oplines = opline - > op1 . num ;
2015-07-10 01:44:21 +00:00
zval * label ;
2015-07-10 11:30:25 +00:00
uint32_t opnum = opline - op_array - > opcodes ;
2015-07-10 01:44:21 +00:00
2015-07-10 11:30:25 +00:00
label = CT_CONSTANT_EX ( op_array , opline - > op2 . constant ) ;
2015-07-10 01:44:21 +00:00
if ( CG ( context ) . labels = = NULL | |
2015-07-10 11:30:25 +00:00
( dest = zend_hash_find_ptr ( CG ( context ) . labels , Z_STR_P ( label ) ) ) = = NULL
) {
CG ( in_compilation ) = 1 ;
CG ( active_op_array ) = op_array ;
CG ( zend_lineno ) = opline - > lineno ;
zend_error_noreturn ( E_COMPILE_ERROR , " 'goto' to undefined label '%s' " , Z_STRVAL_P ( label ) ) ;
2015-07-10 01:44:21 +00:00
}
2018-07-04 16:22:24 +00:00
zval_ptr_dtor_str ( label ) ;
2015-07-10 01:44:21 +00:00
ZVAL_NULL ( label ) ;
2015-07-10 11:30:25 +00:00
current = opline - > extended_value ;
2015-11-10 18:48:03 +00:00
for ( ; current ! = dest - > brk_cont ; current = CG ( context ) . brk_cont_array [ current ] . parent ) {
2015-07-10 01:44:21 +00:00
if ( current = = - 1 ) {
2015-07-10 11:30:25 +00:00
CG ( in_compilation ) = 1 ;
CG ( active_op_array ) = op_array ;
CG ( zend_lineno ) = opline - > lineno ;
2015-07-10 01:44:21 +00:00
zend_error_noreturn ( E_COMPILE_ERROR , " 'goto' into loop or switch statement is disallowed " ) ;
}
2015-11-10 18:48:03 +00:00
if ( CG ( context ) . brk_cont_array [ current ] . start > = 0 ) {
2015-07-10 11:30:25 +00:00
remove_oplines - - ;
2015-07-10 01:44:21 +00:00
}
2015-07-10 11:30:25 +00:00
}
for ( current = 0 ; current < op_array - > last_try_catch ; + + current ) {
zend_try_catch_element * elem = & op_array - > try_catch_array [ current ] ;
if ( elem - > try_op > opnum ) {
break ;
2015-07-10 01:44:21 +00:00
}
2015-07-10 11:30:25 +00:00
if ( elem - > finally_op & & opnum < elem - > finally_op - 1
& & ( dest - > opline_num > elem - > finally_end | | dest - > opline_num < elem - > try_op )
) {
remove_oplines - - ;
}
}
opline - > opcode = ZEND_JMP ;
opline - > op1 . opline_num = dest - > opline_num ;
opline - > extended_value = 0 ;
SET_UNUSED ( opline - > op1 ) ;
SET_UNUSED ( opline - > op2 ) ;
SET_UNUSED ( opline - > result ) ;
2015-08-04 04:37:06 +00:00
ZEND_ASSERT ( remove_oplines > = 0 ) ;
while ( remove_oplines - - ) {
opline - - ;
MAKE_NOP ( opline ) ;
ZEND_VM_SET_OPCODE_HANDLER ( opline ) ;
}
2015-07-10 01:44:21 +00:00
}
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_goto ( zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-09 21:11:32 +00:00
zend_ast * label_ast = ast - > child [ 0 ] ;
znode label_node ;
2015-07-10 11:30:25 +00:00
zend_op * opline ;
2018-12-07 14:47:56 +00:00
uint32_t opnum_start = get_next_op_number ( ) ;
2014-07-09 21:11:32 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & label_node , label_ast ) ;
2015-07-10 11:30:25 +00:00
/* Label resolution and unwinding adjustments happen in pass two. */
2016-06-07 23:20:45 +00:00
zend_handle_loops_and_finally ( NULL ) ;
2015-07-10 11:30:25 +00:00
opline = zend_emit_op ( NULL , ZEND_GOTO , NULL , & label_node ) ;
2018-12-07 14:47:56 +00:00
opline - > op1 . num = get_next_op_number ( ) - opnum_start - 1 ;
2015-07-10 11:30:25 +00:00
opline - > extended_value = CG ( context ) . current_brk_cont ;
2014-07-09 21:11:32 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-07-09 21:11:32 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_label ( zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-09-22 22:57:00 +00:00
zend_string * label = zend_ast_get_str ( ast - > child [ 0 ] ) ;
2014-07-09 21:46:22 +00:00
zend_label dest ;
if ( ! CG ( context ) . labels ) {
ALLOC_HASHTABLE ( CG ( context ) . labels ) ;
2015-08-12 03:15:09 +00:00
zend_hash_init ( CG ( context ) . labels , 8 , NULL , label_ptr_dtor , 0 ) ;
2014-07-09 21:46:22 +00:00
}
dest . brk_cont = CG ( context ) . current_brk_cont ;
2018-12-07 14:47:56 +00:00
dest . opline_num = get_next_op_number ( ) ;
2008-03-18 08:36:30 +00:00
2014-09-22 22:57:00 +00:00
if ( ! zend_hash_add_mem ( CG ( context ) . labels , label , & dest , sizeof ( zend_label ) ) ) {
2015-06-30 10:59:27 +00:00
zend_error_noreturn ( E_COMPILE_ERROR , " Label '%s' already defined " , ZSTR_VAL ( label ) ) ;
2008-03-18 08:36:30 +00:00
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-05-15 15:47:24 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_while ( zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-10 12:35:59 +00:00
zend_ast * cond_ast = ast - > child [ 0 ] ;
zend_ast * stmt_ast = ast - > child [ 1 ] ;
znode cond_node ;
2015-01-19 10:27:44 +00:00
uint32_t opnum_start , opnum_jmp , opnum_cond ;
2006-05-09 23:53:23 +00:00
2015-01-19 10:27:44 +00:00
opnum_jmp = zend_emit_jump ( 0 ) ;
1999-04-07 18:10:10 +00:00
2018-06-24 14:55:22 +00:00
zend_begin_loop ( ZEND_NOP , NULL , 0 ) ;
1999-04-07 18:10:10 +00:00
2018-12-07 14:47:56 +00:00
opnum_start = get_next_op_number ( ) ;
2014-12-13 22:06:14 +00:00
zend_compile_stmt ( stmt_ast ) ;
1999-04-07 18:10:10 +00:00
2018-12-07 14:47:56 +00:00
opnum_cond = get_next_op_number ( ) ;
2015-01-19 10:27:44 +00:00
zend_update_jump_target ( opnum_jmp , opnum_cond ) ;
zend_compile_expr ( & cond_node , cond_ast ) ;
2014-07-10 12:35:59 +00:00
2015-01-19 10:27:44 +00:00
zend_emit_cond_jump ( ZEND_JMPNZ , & cond_node , opnum_start ) ;
1999-04-07 18:10:10 +00:00
2015-11-13 12:35:07 +00:00
zend_end_loop ( opnum_cond , NULL ) ;
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_do_while ( zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-10 12:46:22 +00:00
zend_ast * stmt_ast = ast - > child [ 0 ] ;
zend_ast * cond_ast = ast - > child [ 1 ] ;
1999-04-07 18:10:10 +00:00
2014-07-10 12:46:22 +00:00
znode cond_node ;
2014-08-25 19:21:16 +00:00
uint32_t opnum_start , opnum_cond ;
2006-05-09 23:53:23 +00:00
2018-06-24 14:55:22 +00:00
zend_begin_loop ( ZEND_NOP , NULL , 0 ) ;
1999-04-07 18:10:10 +00:00
2018-12-07 14:47:56 +00:00
opnum_start = get_next_op_number ( ) ;
2014-12-13 22:06:14 +00:00
zend_compile_stmt ( stmt_ast ) ;
1999-04-07 18:10:10 +00:00
2018-12-07 14:47:56 +00:00
opnum_cond = get_next_op_number ( ) ;
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & cond_node , cond_ast ) ;
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
zend_emit_cond_jump ( ZEND_JMPNZ , & cond_node , opnum_start ) ;
1999-04-07 18:10:10 +00:00
2015-11-13 12:35:07 +00:00
zend_end_loop ( opnum_cond , NULL ) ;
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_expr_list ( znode * result , zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-27 20:26:06 +00:00
zend_ast_list * list ;
2014-08-25 19:21:16 +00:00
uint32_t i ;
1999-04-07 18:10:10 +00:00
2014-07-19 11:21:12 +00:00
result - > op_type = IS_CONST ;
ZVAL_TRUE ( & result - > u . constant ) ;
1999-04-07 18:10:10 +00:00
2014-07-19 11:21:12 +00:00
if ( ! ast ) {
return ;
}
1999-04-07 18:10:10 +00:00
2014-07-27 20:26:06 +00:00
list = zend_ast_get_list ( ast ) ;
for ( i = 0 ; i < list - > children ; + + i ) {
zend_ast * expr_ast = list - > child [ i ] ;
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
zend_do_free ( result ) ;
zend_compile_expr ( result , expr_ast ) ;
2014-07-10 13:51:47 +00:00
}
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_for ( zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-10 13:51:47 +00:00
zend_ast * init_ast = ast - > child [ 0 ] ;
zend_ast * cond_ast = ast - > child [ 1 ] ;
zend_ast * loop_ast = ast - > child [ 2 ] ;
zend_ast * stmt_ast = ast - > child [ 3 ] ;
1999-04-07 18:10:10 +00:00
2014-07-10 13:51:47 +00:00
znode result ;
2015-01-20 03:58:40 +00:00
uint32_t opnum_start , opnum_jmp , opnum_loop ;
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr_list ( & result , init_ast ) ;
zend_do_free ( & result ) ;
2000-08-10 20:42:57 +00:00
2015-01-19 10:27:44 +00:00
opnum_jmp = zend_emit_jump ( 0 ) ;
2014-07-10 13:51:47 +00:00
2018-06-24 14:55:22 +00:00
zend_begin_loop ( ZEND_NOP , NULL , 0 ) ;
2014-07-10 13:51:47 +00:00
2018-12-07 14:47:56 +00:00
opnum_start = get_next_op_number ( ) ;
2014-12-13 22:06:14 +00:00
zend_compile_stmt ( stmt_ast ) ;
1999-04-07 18:10:10 +00:00
2018-12-07 14:47:56 +00:00
opnum_loop = get_next_op_number ( ) ;
2014-12-13 22:06:14 +00:00
zend_compile_expr_list ( & result , loop_ast ) ;
zend_do_free ( & result ) ;
1999-04-07 18:10:10 +00:00
2015-01-19 10:27:44 +00:00
zend_update_jump_target_to_next ( opnum_jmp ) ;
zend_compile_expr_list ( & result , cond_ast ) ;
2019-02-19 08:08:38 +00:00
zend_do_extended_stmt ( ) ;
2014-07-10 13:51:47 +00:00
2015-01-19 10:27:44 +00:00
zend_emit_cond_jump ( ZEND_JMPNZ , & result , opnum_start ) ;
2014-07-10 13:51:47 +00:00
2015-11-13 12:35:07 +00:00
zend_end_loop ( opnum_loop , NULL ) ;
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_foreach ( zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-11 10:16:21 +00:00
zend_ast * expr_ast = ast - > child [ 0 ] ;
zend_ast * value_ast = ast - > child [ 1 ] ;
zend_ast * key_ast = ast - > child [ 2 ] ;
zend_ast * stmt_ast = ast - > child [ 3 ] ;
zend_bool by_ref = value_ast - > kind = = ZEND_AST_REF ;
2019-01-26 11:10:03 +00:00
zend_bool is_variable = zend_is_variable ( expr_ast ) & & zend_can_write_to_variable ( expr_ast ) ;
2014-07-11 10:16:21 +00:00
2014-09-23 19:19:11 +00:00
znode expr_node , reset_node , value_node , key_node ;
1999-04-07 18:10:10 +00:00
zend_op * opline ;
2014-08-25 19:21:16 +00:00
uint32_t opnum_reset , opnum_fetch ;
1999-04-07 18:10:10 +00:00
2014-07-11 10:16:21 +00:00
if ( key_ast ) {
if ( key_ast - > kind = = ZEND_AST_REF ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Key element cannot be a reference " ) ;
}
2016-04-04 22:34:42 +00:00
if ( key_ast - > kind = = ZEND_AST_ARRAY ) {
2014-07-11 10:16:21 +00:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use list as key element " ) ;
}
2004-10-08 18:50:00 +00:00
}
2014-07-11 10:16:21 +00:00
if ( by_ref ) {
value_ast = value_ast - > child [ 0 ] ;
}
2011-01-19 17:17:52 +00:00
2017-10-06 23:30:58 +00:00
if ( value_ast - > kind = = ZEND_AST_ARRAY & & zend_propagate_list_refs ( value_ast ) ) {
by_ref = 1 ;
}
2014-07-11 10:16:21 +00:00
if ( by_ref & & is_variable ) {
2019-01-07 11:28:51 +00:00
zend_compile_var ( & expr_node , expr_ast , BP_VAR_W , 1 ) ;
2014-07-11 10:16:21 +00:00
} else {
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & expr_node , expr_ast ) ;
1999-04-07 18:10:10 +00:00
}
2014-09-20 19:58:06 +00:00
if ( by_ref ) {
2014-12-13 22:06:14 +00:00
zend_separate_if_call_and_write ( & expr_node , expr_ast , BP_VAR_W ) ;
1999-07-26 21:18:35 +00:00
}
2002-09-24 19:05:53 +00:00
2018-12-07 14:47:56 +00:00
opnum_reset = get_next_op_number ( ) ;
2015-02-12 10:57:12 +00:00
opline = zend_emit_op ( & reset_node , by_ref ? ZEND_FE_RESET_RW : ZEND_FE_RESET_R , & expr_node , NULL ) ;
1999-04-07 18:10:10 +00:00
2018-06-24 14:55:22 +00:00
zend_begin_loop ( ZEND_FE_FREE , & reset_node , 0 ) ;
2015-11-10 17:11:05 +00:00
2018-12-07 14:47:56 +00:00
opnum_fetch = get_next_op_number ( ) ;
2015-05-13 09:55:42 +00:00
opline = zend_emit_op ( NULL , by_ref ? ZEND_FE_FETCH_RW : ZEND_FE_FETCH_R , & reset_node , NULL ) ;
1999-04-07 18:10:10 +00:00
2016-06-15 23:30:23 +00:00
if ( is_this_fetch ( value_ast ) ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot re-assign $this " ) ;
} else if ( value_ast - > kind = = ZEND_AST_VAR & &
2017-10-06 23:30:58 +00:00
zend_try_compile_cv ( & value_node , value_ast ) = = SUCCESS ) {
2015-05-13 09:55:42 +00:00
SET_NODE ( opline - > op2 , & value_node ) ;
2014-07-11 10:16:21 +00:00
} else {
2015-05-13 09:55:42 +00:00
opline - > op2_type = IS_VAR ;
2018-12-07 14:47:56 +00:00
opline - > op2 . var = get_temporary_variable ( ) ;
2015-05-13 09:55:42 +00:00
GET_NODE ( & value_node , opline - > op2 ) ;
2017-10-06 23:30:58 +00:00
if ( value_ast - > kind = = ZEND_AST_ARRAY ) {
zend_compile_list_assign ( NULL , value_ast , & value_node , value_ast - > attr ) ;
} else if ( by_ref ) {
2015-05-13 09:55:42 +00:00
zend_emit_assign_ref_znode ( value_ast , & value_node ) ;
} else {
zend_emit_assign_znode ( value_ast , & value_node ) ;
}
2004-08-23 20:16:35 +00:00
}
2014-07-11 10:16:21 +00:00
if ( key_ast ) {
2015-05-13 09:55:42 +00:00
opline = & CG ( active_op_array ) - > opcodes [ opnum_fetch ] ;
zend_make_tmp_result ( & key_node , opline ) ;
2014-12-13 22:06:14 +00:00
zend_emit_assign_znode ( key_ast , & key_node ) ;
1999-04-07 18:10:10 +00:00
}
2006-05-09 23:53:23 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_stmt ( stmt_ast ) ;
1999-04-07 18:10:10 +00:00
2018-11-27 18:43:25 +00:00
/* Place JMP and FE_FREE on the line where foreach starts. It would be
* better to use the end line , but this information is not available
* currently . */
CG ( zend_lineno ) = ast - > lineno ;
2014-12-13 22:06:14 +00:00
zend_emit_jump ( opnum_fetch ) ;
1999-04-07 18:10:10 +00:00
2016-12-02 08:58:36 +00:00
opline = & CG ( active_op_array ) - > opcodes [ opnum_reset ] ;
2018-12-07 14:47:56 +00:00
opline - > op2 . opline_num = get_next_op_number ( ) ;
2016-12-02 08:58:36 +00:00
2014-07-11 10:16:21 +00:00
opline = & CG ( active_op_array ) - > opcodes [ opnum_fetch ] ;
2018-12-07 14:47:56 +00:00
opline - > extended_value = get_next_op_number ( ) ;
2014-07-11 10:16:21 +00:00
2015-11-13 12:35:07 +00:00
zend_end_loop ( opnum_fetch , & reset_node ) ;
2014-07-11 10:16:21 +00:00
2016-12-02 08:58:36 +00:00
opline = zend_emit_op ( NULL , ZEND_FE_FREE , & reset_node , NULL ) ;
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_if ( zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-27 20:26:06 +00:00
zend_ast_list * list = zend_ast_get_list ( ast ) ;
2014-08-25 19:21:16 +00:00
uint32_t i ;
2014-11-27 09:52:31 +00:00
uint32_t * jmp_opnums = NULL ;
2015-01-03 09:22:58 +00:00
2014-08-26 17:39:40 +00:00
if ( list - > children > 1 ) {
jmp_opnums = safe_emalloc ( sizeof ( uint32_t ) , list - > children - 1 , 0 ) ;
}
1999-04-07 18:10:10 +00:00
2014-07-27 20:26:06 +00:00
for ( i = 0 ; i < list - > children ; + + i ) {
zend_ast * elem_ast = list - > child [ i ] ;
2014-07-10 14:38:04 +00:00
zend_ast * cond_ast = elem_ast - > child [ 0 ] ;
zend_ast * stmt_ast = elem_ast - > child [ 1 ] ;
2004-10-08 18:50:00 +00:00
2014-07-10 14:38:04 +00:00
if ( cond_ast ) {
2019-05-31 10:55:13 +00:00
znode cond_node ;
uint32_t opnum_jmpz ;
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & cond_node , cond_ast ) ;
opnum_jmpz = zend_emit_cond_jump ( ZEND_JMPZ , & cond_node , 0 ) ;
2014-07-10 14:38:04 +00:00
2019-05-31 10:55:13 +00:00
zend_compile_stmt ( stmt_ast ) ;
2014-07-10 14:38:04 +00:00
2019-05-31 10:55:13 +00:00
if ( i ! = list - > children - 1 ) {
jmp_opnums [ i ] = zend_emit_jump ( 0 ) ;
}
2014-12-13 22:06:14 +00:00
zend_update_jump_target_to_next ( opnum_jmpz ) ;
2019-05-31 10:55:13 +00:00
} else {
/* "else" can only occur as last element. */
ZEND_ASSERT ( i = = list - > children - 1 ) ;
zend_compile_stmt ( stmt_ast ) ;
2014-07-10 14:38:04 +00:00
}
1999-04-07 18:10:10 +00:00
}
2014-07-10 14:38:04 +00:00
2014-08-26 17:39:40 +00:00
if ( list - > children > 1 ) {
for ( i = 0 ; i < list - > children - 1 ; + + i ) {
2014-12-13 22:06:14 +00:00
zend_update_jump_target_to_next ( jmp_opnums [ i ] ) ;
2014-08-26 17:39:40 +00:00
}
efree ( jmp_opnums ) ;
2014-07-10 14:38:04 +00:00
}
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2017-03-17 22:45:05 +00:00
static zend_uchar determine_switch_jumptable_type ( zend_ast_list * cases ) {
uint32_t i ;
zend_uchar common_type = IS_UNDEF ;
for ( i = 0 ; i < cases - > children ; i + + ) {
zend_ast * case_ast = cases - > child [ i ] ;
zend_ast * * cond_ast = & case_ast - > child [ 0 ] ;
zval * cond_zv ;
if ( ! case_ast - > child [ 0 ] ) {
/* Skip default clause */
continue ;
}
zend_eval_const_expr ( cond_ast ) ;
if ( ( * cond_ast ) - > kind ! = ZEND_AST_ZVAL ) {
/* Non-constant case */
return IS_UNDEF ;
}
cond_zv = zend_ast_get_zval ( case_ast - > child [ 0 ] ) ;
if ( Z_TYPE_P ( cond_zv ) ! = IS_LONG & & Z_TYPE_P ( cond_zv ) ! = IS_STRING ) {
/* We only optimize switched on integers and strings */
return IS_UNDEF ;
}
if ( common_type = = IS_UNDEF ) {
common_type = Z_TYPE_P ( cond_zv ) ;
} else if ( common_type ! = Z_TYPE_P ( cond_zv ) ) {
/* Non-uniform case types */
return IS_UNDEF ;
}
if ( Z_TYPE_P ( cond_zv ) = = IS_STRING
& & is_numeric_string ( Z_STRVAL_P ( cond_zv ) , Z_STRLEN_P ( cond_zv ) , NULL , NULL , 0 ) ) {
/* Numeric strings cannot be compared with a simple hash lookup */
return IS_UNDEF ;
}
}
return common_type ;
}
static zend_bool should_use_jumptable ( zend_ast_list * cases , zend_uchar jumptable_type ) {
2019-01-24 09:56:04 +00:00
if ( CG ( compiler_options ) & ZEND_COMPILE_NO_JUMPTABLES ) {
return 0 ;
}
2017-03-17 22:45:05 +00:00
/* Thresholds are chosen based on when the average switch time for equidistributed
* input becomes smaller when using the jumptable optimization . */
if ( jumptable_type = = IS_LONG ) {
return cases - > children > = 5 ;
} else {
ZEND_ASSERT ( jumptable_type = = IS_STRING ) ;
return cases - > children > = 2 ;
}
}
2014-12-13 22:06:14 +00:00
void zend_compile_switch ( zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-11 13:31:47 +00:00
zend_ast * expr_ast = ast - > child [ 0 ] ;
2014-07-27 20:26:06 +00:00
zend_ast_list * cases = zend_ast_get_list ( ast - > child [ 1 ] ) ;
2001-10-29 17:19:02 +00:00
2014-08-25 19:21:16 +00:00
uint32_t i ;
2014-07-11 13:31:47 +00:00
zend_bool has_default_case = 0 ;
2004-01-12 07:15:55 +00:00
2014-07-11 13:31:47 +00:00
znode expr_node , case_node ;
zend_op * opline ;
2019-04-12 12:55:37 +00:00
uint32_t * jmpnz_opnums , opnum_default_jmp , opnum_switch = ( uint32_t ) - 1 ;
2017-03-17 22:45:05 +00:00
zend_uchar jumptable_type ;
HashTable * jumptable = NULL ;
2006-12-21 02:09:36 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & expr_node , expr_ast ) ;
2003-02-10 16:11:24 +00:00
2018-06-24 14:55:22 +00:00
zend_begin_loop ( ZEND_FREE , & expr_node , 1 ) ;
2007-09-28 19:52:53 +00:00
2014-07-11 13:31:47 +00:00
case_node . op_type = IS_TMP_VAR ;
2018-12-07 14:47:56 +00:00
case_node . u . op . var = get_temporary_variable ( ) ;
2007-09-28 19:52:53 +00:00
2017-03-17 22:45:05 +00:00
jumptable_type = determine_switch_jumptable_type ( cases ) ;
if ( jumptable_type ! = IS_UNDEF & & should_use_jumptable ( cases , jumptable_type ) ) {
znode jumptable_op ;
ALLOC_HASHTABLE ( jumptable ) ;
zend_hash_init ( jumptable , cases - > children , NULL , NULL , 0 ) ;
jumptable_op . op_type = IS_CONST ;
ZVAL_ARR ( & jumptable_op . u . constant , jumptable ) ;
opline = zend_emit_op ( NULL ,
jumptable_type = = IS_LONG ? ZEND_SWITCH_LONG : ZEND_SWITCH_STRING ,
& expr_node , & jumptable_op ) ;
if ( opline - > op1_type = = IS_CONST ) {
2018-01-18 22:03:24 +00:00
Z_TRY_ADDREF_P ( CT_CONSTANT ( opline - > op1 ) ) ;
2017-03-17 22:45:05 +00:00
}
opnum_switch = opline - CG ( active_op_array ) - > opcodes ;
}
2016-06-28 07:36:50 +00:00
jmpnz_opnums = safe_emalloc ( sizeof ( uint32_t ) , cases - > children , 0 ) ;
2014-07-27 20:26:06 +00:00
for ( i = 0 ; i < cases - > children ; + + i ) {
zend_ast * case_ast = cases - > child [ i ] ;
2014-07-11 13:31:47 +00:00
zend_ast * cond_ast = case_ast - > child [ 0 ] ;
znode cond_node ;
2007-11-12 15:52:22 +00:00
2014-07-11 13:31:47 +00:00
if ( ! cond_ast ) {
2014-09-05 22:07:07 +00:00
if ( has_default_case ) {
CG ( zend_lineno ) = case_ast - > lineno ;
zend_error_noreturn ( E_COMPILE_ERROR ,
" Switch statements may only contain one default clause " ) ;
}
2014-07-11 13:31:47 +00:00
has_default_case = 1 ;
continue ;
2007-11-12 15:52:22 +00:00
}
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & cond_node , cond_ast ) ;
1999-04-07 18:10:10 +00:00
2015-01-19 14:02:17 +00:00
if ( expr_node . op_type = = IS_CONST
& & Z_TYPE ( expr_node . u . constant ) = = IS_FALSE ) {
jmpnz_opnums [ i ] = zend_emit_cond_jump ( ZEND_JMPZ , & cond_node , 0 ) ;
} else if ( expr_node . op_type = = IS_CONST
& & Z_TYPE ( expr_node . u . constant ) = = IS_TRUE ) {
jmpnz_opnums [ i ] = zend_emit_cond_jump ( ZEND_JMPNZ , & cond_node , 0 ) ;
2017-12-29 09:57:58 +00:00
} else {
opline = zend_emit_op ( NULL ,
( expr_node . op_type & ( IS_VAR | IS_TMP_VAR ) ) ? ZEND_CASE : ZEND_IS_EQUAL ,
& expr_node , & cond_node ) ;
2015-01-19 14:02:17 +00:00
SET_NODE ( opline - > result , & case_node ) ;
if ( opline - > op1_type = = IS_CONST ) {
2018-01-18 22:03:24 +00:00
Z_TRY_ADDREF_P ( CT_CONSTANT ( opline - > op1 ) ) ;
2015-01-19 14:02:17 +00:00
}
2014-07-11 13:31:47 +00:00
2015-01-19 14:02:17 +00:00
jmpnz_opnums [ i ] = zend_emit_cond_jump ( ZEND_JMPNZ , & case_node , 0 ) ;
}
2001-10-29 17:19:02 +00:00
}
2014-12-13 22:06:14 +00:00
opnum_default_jmp = zend_emit_jump ( 0 ) ;
2013-01-28 02:02:51 +00:00
2014-07-27 20:26:06 +00:00
for ( i = 0 ; i < cases - > children ; + + i ) {
zend_ast * case_ast = cases - > child [ i ] ;
2014-07-11 13:31:47 +00:00
zend_ast * cond_ast = case_ast - > child [ 0 ] ;
zend_ast * stmt_ast = case_ast - > child [ 1 ] ;
2006-05-09 23:53:23 +00:00
2014-07-11 13:31:47 +00:00
if ( cond_ast ) {
2014-12-13 22:06:14 +00:00
zend_update_jump_target_to_next ( jmpnz_opnums [ i ] ) ;
2017-03-17 22:45:05 +00:00
if ( jumptable ) {
zval * cond_zv = zend_ast_get_zval ( cond_ast ) ;
zval jmp_target ;
2018-12-07 14:47:56 +00:00
ZVAL_LONG ( & jmp_target , get_next_op_number ( ) ) ;
2017-03-17 22:45:05 +00:00
ZEND_ASSERT ( Z_TYPE_P ( cond_zv ) = = jumptable_type ) ;
if ( Z_TYPE_P ( cond_zv ) = = IS_LONG ) {
zend_hash_index_add ( jumptable , Z_LVAL_P ( cond_zv ) , & jmp_target ) ;
} else {
ZEND_ASSERT ( Z_TYPE_P ( cond_zv ) = = IS_STRING ) ;
zend_hash_add ( jumptable , Z_STR_P ( cond_zv ) , & jmp_target ) ;
}
}
2014-07-11 13:31:47 +00:00
} else {
2014-12-13 22:06:14 +00:00
zend_update_jump_target_to_next ( opnum_default_jmp ) ;
2017-03-17 22:45:05 +00:00
if ( jumptable ) {
2019-04-12 12:55:37 +00:00
ZEND_ASSERT ( opnum_switch ! = ( uint32_t ) - 1 ) ;
2017-03-17 22:45:05 +00:00
opline = & CG ( active_op_array ) - > opcodes [ opnum_switch ] ;
2018-12-07 14:47:56 +00:00
opline - > extended_value = get_next_op_number ( ) ;
2017-03-17 22:45:05 +00:00
}
2012-08-22 10:32:03 +00:00
}
2014-12-13 22:06:14 +00:00
zend_compile_stmt ( stmt_ast ) ;
1999-07-08 16:55:27 +00:00
}
2002-09-24 19:05:53 +00:00
2014-07-11 13:31:47 +00:00
if ( ! has_default_case ) {
2014-12-13 22:06:14 +00:00
zend_update_jump_target_to_next ( opnum_default_jmp ) ;
2017-03-17 22:45:05 +00:00
if ( jumptable ) {
opline = & CG ( active_op_array ) - > opcodes [ opnum_switch ] ;
2018-12-07 14:47:56 +00:00
opline - > extended_value = get_next_op_number ( ) ;
2017-03-17 22:45:05 +00:00
}
2014-07-11 13:31:47 +00:00
}
2003-03-05 11:14:44 +00:00
2018-12-07 14:47:56 +00:00
zend_end_loop ( get_next_op_number ( ) , & expr_node ) ;
2003-04-02 16:51:49 +00:00
2016-02-11 20:11:19 +00:00
if ( expr_node . op_type & ( IS_VAR | IS_TMP_VAR ) ) {
2019-01-17 15:07:17 +00:00
opline = zend_emit_op ( NULL , ZEND_FREE , & expr_node , NULL ) ;
opline - > extended_value = ZEND_FREE_SWITCH ;
2014-07-11 13:31:47 +00:00
} else if ( expr_node . op_type = = IS_CONST ) {
2018-07-04 16:22:24 +00:00
zval_ptr_dtor_nogc ( & expr_node . u . constant ) ;
2003-04-02 16:51:49 +00:00
}
2014-07-11 13:31:47 +00:00
2014-07-11 13:33:39 +00:00
efree ( jmpnz_opnums ) ;
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2020-04-09 20:36:37 +00:00
static uint32_t count_match_conds ( zend_ast_list * arms )
{
uint32_t num_conds = 0 ;
for ( uint32_t i = 0 ; i < arms - > children ; i + + ) {
zend_ast * arm_ast = arms - > child [ i ] ;
if ( arm_ast - > child [ 0 ] = = NULL ) {
continue ;
}
zend_ast_list * conds = zend_ast_get_list ( arm_ast - > child [ 0 ] ) ;
num_conds + = conds - > children ;
}
return num_conds ;
}
static zend_bool can_match_use_jumptable ( zend_ast_list * arms ) {
for ( uint32_t i = 0 ; i < arms - > children ; i + + ) {
zend_ast * arm_ast = arms - > child [ i ] ;
if ( ! arm_ast - > child [ 0 ] ) {
/* Skip default arm */
continue ;
}
zend_ast_list * conds = zend_ast_get_list ( arm_ast - > child [ 0 ] ) ;
for ( uint32_t j = 0 ; j < conds - > children ; j + + ) {
zend_ast * * cond_ast = & conds - > child [ j ] ;
zend_eval_const_expr ( cond_ast ) ;
if ( ( * cond_ast ) - > kind ! = ZEND_AST_ZVAL ) {
return 0 ;
}
zval * cond_zv = zend_ast_get_zval ( * cond_ast ) ;
if ( Z_TYPE_P ( cond_zv ) ! = IS_LONG & & Z_TYPE_P ( cond_zv ) ! = IS_STRING ) {
return 0 ;
}
}
}
return 1 ;
}
void zend_compile_match ( znode * result , zend_ast * ast )
{
zend_ast * expr_ast = ast - > child [ 0 ] ;
zend_ast_list * arms = zend_ast_get_list ( ast - > child [ 1 ] ) ;
zend_bool has_default_arm = 0 ;
uint32_t opnum_match = ( uint32_t ) - 1 ;
znode expr_node ;
zend_compile_expr ( & expr_node , expr_ast ) ;
znode case_node ;
case_node . op_type = IS_TMP_VAR ;
case_node . u . op . var = get_temporary_variable ( ) ;
uint32_t num_conds = count_match_conds ( arms ) ;
zend_uchar can_use_jumptable = can_match_use_jumptable ( arms ) ;
zend_bool uses_jumptable = can_use_jumptable & & num_conds > = 2 ;
HashTable * jumptable = NULL ;
uint32_t * jmpnz_opnums = NULL ;
for ( uint32_t i = 0 ; i < arms - > children ; + + i ) {
zend_ast * arm_ast = arms - > child [ i ] ;
if ( ! arm_ast - > child [ 0 ] ) {
if ( has_default_arm ) {
CG ( zend_lineno ) = arm_ast - > lineno ;
zend_error_noreturn ( E_COMPILE_ERROR ,
" Match expressions may only contain one default arm " ) ;
}
has_default_arm = 1 ;
}
}
if ( uses_jumptable ) {
znode jumptable_op ;
ALLOC_HASHTABLE ( jumptable ) ;
zend_hash_init ( jumptable , num_conds , NULL , NULL , 0 ) ;
jumptable_op . op_type = IS_CONST ;
ZVAL_ARR ( & jumptable_op . u . constant , jumptable ) ;
zend_op * opline = zend_emit_op ( NULL , ZEND_MATCH , & expr_node , & jumptable_op ) ;
if ( opline - > op1_type = = IS_CONST ) {
Z_TRY_ADDREF_P ( CT_CONSTANT ( opline - > op1 ) ) ;
}
opnum_match = opline - CG ( active_op_array ) - > opcodes ;
} else {
jmpnz_opnums = safe_emalloc ( sizeof ( uint32_t ) , num_conds , 0 ) ;
uint32_t cond_count = 0 ;
for ( uint32_t i = 0 ; i < arms - > children ; + + i ) {
zend_ast * arm_ast = arms - > child [ i ] ;
if ( ! arm_ast - > child [ 0 ] ) {
continue ;
}
zend_ast_list * conds = zend_ast_get_list ( arm_ast - > child [ 0 ] ) ;
for ( uint32_t j = 0 ; j < conds - > children ; j + + ) {
zend_ast * cond_ast = conds - > child [ j ] ;
znode cond_node ;
zend_compile_expr ( & cond_node , cond_ast ) ;
uint32_t opcode = ( expr_node . op_type & ( IS_VAR | IS_TMP_VAR ) ) ? ZEND_CASE_STRICT : ZEND_IS_IDENTICAL ;
zend_op * opline = zend_emit_op ( NULL , opcode , & expr_node , & cond_node ) ;
SET_NODE ( opline - > result , & case_node ) ;
if ( opline - > op1_type = = IS_CONST ) {
Z_TRY_ADDREF_P ( CT_CONSTANT ( opline - > op1 ) ) ;
}
jmpnz_opnums [ cond_count ] = zend_emit_cond_jump ( ZEND_JMPNZ , & case_node , 0 ) ;
cond_count + + ;
}
}
}
uint32_t opnum_default_jmp = 0 ;
if ( ! uses_jumptable ) {
opnum_default_jmp = zend_emit_jump ( 0 ) ;
}
zend_bool is_first_case = 1 ;
uint32_t cond_count = 0 ;
uint32_t * jmp_end_opnums = safe_emalloc ( sizeof ( uint32_t ) , arms - > children , 0 ) ;
2020-07-11 16:46:51 +00:00
// The generated default arm is emitted first to avoid live range issues where the tmpvar
// for the arm result is freed even though it has not been initialized yet.
if ( ! has_default_arm ) {
if ( ! uses_jumptable ) {
zend_update_jump_target_to_next ( opnum_default_jmp ) ;
}
if ( jumptable ) {
zend_op * opline = & CG ( active_op_array ) - > opcodes [ opnum_match ] ;
opline - > extended_value = get_next_op_number ( ) ;
}
zend_op * opline = zend_emit_op ( NULL , ZEND_MATCH_ERROR , & expr_node , NULL ) ;
if ( opline - > op1_type = = IS_CONST ) {
Z_TRY_ADDREF_P ( CT_CONSTANT ( opline - > op1 ) ) ;
}
}
2020-04-09 20:36:37 +00:00
for ( uint32_t i = 0 ; i < arms - > children ; + + i ) {
zend_ast * arm_ast = arms - > child [ i ] ;
zend_ast * body_ast = arm_ast - > child [ 1 ] ;
if ( arm_ast - > child [ 0 ] ! = NULL ) {
zend_ast_list * conds = zend_ast_get_list ( arm_ast - > child [ 0 ] ) ;
for ( uint32_t j = 0 ; j < conds - > children ; j + + ) {
zend_ast * cond_ast = conds - > child [ j ] ;
if ( jmpnz_opnums ! = NULL ) {
zend_update_jump_target_to_next ( jmpnz_opnums [ cond_count ] ) ;
}
if ( jumptable ) {
zval * cond_zv = zend_ast_get_zval ( cond_ast ) ;
zval jmp_target ;
ZVAL_LONG ( & jmp_target , get_next_op_number ( ) ) ;
if ( Z_TYPE_P ( cond_zv ) = = IS_LONG ) {
zend_hash_index_add ( jumptable , Z_LVAL_P ( cond_zv ) , & jmp_target ) ;
} else {
ZEND_ASSERT ( Z_TYPE_P ( cond_zv ) = = IS_STRING ) ;
zend_hash_add ( jumptable , Z_STR_P ( cond_zv ) , & jmp_target ) ;
}
}
cond_count + + ;
}
} else {
if ( ! uses_jumptable ) {
zend_update_jump_target_to_next ( opnum_default_jmp ) ;
}
if ( jumptable ) {
ZEND_ASSERT ( opnum_match ! = ( uint32_t ) - 1 ) ;
zend_op * opline = & CG ( active_op_array ) - > opcodes [ opnum_match ] ;
opline - > extended_value = get_next_op_number ( ) ;
}
}
znode body_node ;
zend_compile_expr ( & body_node , body_ast ) ;
if ( is_first_case ) {
zend_emit_op_tmp ( result , ZEND_QM_ASSIGN , & body_node , NULL ) ;
is_first_case = 0 ;
} else {
zend_op * opline_qm_assign = zend_emit_op ( NULL , ZEND_QM_ASSIGN , & body_node , NULL ) ;
SET_NODE ( opline_qm_assign - > result , result ) ;
}
jmp_end_opnums [ i ] = zend_emit_jump ( 0 ) ;
}
// Initialize result in case there is no arm
if ( arms - > children = = 0 ) {
result - > op_type = IS_CONST ;
ZVAL_NULL ( & result - > u . constant ) ;
}
for ( uint32_t i = 0 ; i < arms - > children ; + + i ) {
zend_update_jump_target_to_next ( jmp_end_opnums [ i ] ) ;
}
if ( expr_node . op_type & ( IS_VAR | IS_TMP_VAR ) ) {
zend_op * opline = zend_emit_op ( NULL , ZEND_FREE , & expr_node , NULL ) ;
opline - > extended_value = ZEND_FREE_SWITCH ;
} else if ( expr_node . op_type = = IS_CONST ) {
zval_ptr_dtor_nogc ( & expr_node . u . constant ) ;
}
if ( jmpnz_opnums ! = NULL ) {
efree ( jmpnz_opnums ) ;
}
efree ( jmp_end_opnums ) ;
}
2014-12-13 22:06:14 +00:00
void zend_compile_try ( zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-12 11:50:58 +00:00
zend_ast * try_ast = ast - > child [ 0 ] ;
2014-07-27 20:26:06 +00:00
zend_ast_list * catches = zend_ast_get_list ( ast - > child [ 1 ] ) ;
2014-07-12 11:50:58 +00:00
zend_ast * finally_ast = ast - > child [ 2 ] ;
2003-03-06 22:53:23 +00:00
2016-05-01 22:47:08 +00:00
uint32_t i , j ;
2014-07-12 11:50:58 +00:00
zend_op * opline ;
2015-07-10 21:29:07 +00:00
uint32_t try_catch_offset ;
2014-08-25 19:21:16 +00:00
uint32_t * jmp_opnums = safe_emalloc ( sizeof ( uint32_t ) , catches - > children , 0 ) ;
2016-05-13 11:38:43 +00:00
uint32_t orig_fast_call_var = CG ( context ) . fast_call_var ;
2016-05-24 22:25:12 +00:00
uint32_t orig_try_catch_offset = CG ( context ) . try_catch_offset ;
2003-03-06 22:53:23 +00:00
2014-07-27 20:26:06 +00:00
if ( catches - > children = = 0 & & ! finally_ast ) {
2014-07-12 11:50:58 +00:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use try without catch or finally " ) ;
}
2003-05-29 19:00:40 +00:00
2015-07-10 21:29:07 +00:00
/* label: try { } must not be equal to try { label: } */
if ( CG ( context ) . labels ) {
2015-07-11 10:59:09 +00:00
zend_label * label ;
ZEND_HASH_REVERSE_FOREACH_PTR ( CG ( context ) . labels , label ) {
2018-12-07 14:47:56 +00:00
if ( label - > opline_num = = get_next_op_number ( ) ) {
2015-07-10 21:35:05 +00:00
zend_emit_op ( NULL , ZEND_NOP , NULL , NULL ) ;
2015-07-10 21:29:07 +00:00
}
2015-07-11 10:59:09 +00:00
break ;
} ZEND_HASH_FOREACH_END ( ) ;
2015-07-10 21:29:07 +00:00
}
2018-12-07 14:47:56 +00:00
try_catch_offset = zend_add_try_element ( get_next_op_number ( ) ) ;
2015-07-10 21:29:07 +00:00
2015-07-10 11:30:25 +00:00
if ( finally_ast ) {
zend_loop_var fast_call ;
if ( ! ( CG ( active_op_array ) - > fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK ) ) {
CG ( active_op_array ) - > fn_flags | = ZEND_ACC_HAS_FINALLY_BLOCK ;
}
2018-12-07 14:47:56 +00:00
CG ( context ) . fast_call_var = get_temporary_variable ( ) ;
2015-07-10 11:30:25 +00:00
/* Push FAST_CALL on unwind stack */
fast_call . opcode = ZEND_FAST_CALL ;
2015-08-04 04:37:06 +00:00
fast_call . var_type = IS_TMP_VAR ;
fast_call . var_num = CG ( context ) . fast_call_var ;
2019-01-17 15:07:17 +00:00
fast_call . try_catch_offset = try_catch_offset ;
2015-07-10 11:30:25 +00:00
zend_stack_push ( & CG ( loop_var_stack ) , & fast_call ) ;
}
2016-05-24 22:25:12 +00:00
CG ( context ) . try_catch_offset = try_catch_offset ;
2014-12-13 22:06:14 +00:00
zend_compile_stmt ( try_ast ) ;
2014-07-12 11:50:58 +00:00
2014-07-27 20:26:06 +00:00
if ( catches - > children ! = 0 ) {
2014-12-13 22:06:14 +00:00
jmp_opnums [ 0 ] = zend_emit_jump ( 0 ) ;
2003-08-23 15:38:58 +00:00
}
2014-07-12 11:50:58 +00:00
2014-07-27 20:26:06 +00:00
for ( i = 0 ; i < catches - > children ; + + i ) {
zend_ast * catch_ast = catches - > child [ i ] ;
2016-05-01 22:47:08 +00:00
zend_ast_list * classes = zend_ast_get_list ( catch_ast - > child [ 0 ] ) ;
2014-07-12 11:50:58 +00:00
zend_ast * var_ast = catch_ast - > child [ 1 ] ;
zend_ast * stmt_ast = catch_ast - > child [ 2 ] ;
2020-04-03 21:22:17 +00:00
zend_string * var_name = var_ast ? zval_make_interned_string ( zend_ast_get_zval ( var_ast ) ) : NULL ;
2014-07-27 20:26:06 +00:00
zend_bool is_last_catch = ( i + 1 = = catches - > children ) ;
2014-07-12 11:50:58 +00:00
2016-05-01 22:47:08 +00:00
uint32_t * jmp_multicatch = safe_emalloc ( sizeof ( uint32_t ) , classes - > children - 1 , 0 ) ;
2019-04-12 12:55:37 +00:00
uint32_t opnum_catch = ( uint32_t ) - 1 ;
2014-07-12 11:50:58 +00:00
2016-05-01 22:47:08 +00:00
CG ( zend_lineno ) = catch_ast - > lineno ;
2014-07-12 11:50:58 +00:00
2016-05-01 22:47:08 +00:00
for ( j = 0 ; j < classes - > children ; j + + ) {
zend_ast * class_ast = classes - > child [ j ] ;
zend_bool is_last_class = ( j + 1 = = classes - > children ) ;
2013-01-28 02:02:51 +00:00
2016-05-01 22:47:08 +00:00
if ( ! zend_is_const_default_class_ref ( class_ast ) ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Bad class name in the catch statement " ) ;
}
2018-12-07 14:47:56 +00:00
opnum_catch = get_next_op_number ( ) ;
2016-05-01 22:47:08 +00:00
if ( i = = 0 & & j = = 0 ) {
CG ( active_op_array ) - > try_catch_array [ try_catch_offset ] . catch_op = opnum_catch ;
}
2018-12-07 14:47:56 +00:00
opline = get_next_op ( ) ;
2016-05-01 22:47:08 +00:00
opline - > opcode = ZEND_CATCH ;
opline - > op1_type = IS_CONST ;
2018-12-07 14:47:56 +00:00
opline - > op1 . constant = zend_add_class_name_literal (
2016-05-01 22:47:08 +00:00
zend_resolve_class_name_ast ( class_ast ) ) ;
2018-02-05 16:41:47 +00:00
opline - > extended_value = zend_alloc_cache_slot ( ) ;
2016-05-01 22:47:08 +00:00
2020-04-03 21:22:17 +00:00
if ( var_name & & zend_string_equals_literal ( var_name , " this " ) ) {
2016-06-15 23:30:23 +00:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot re-assign $this " ) ;
}
2020-04-03 21:22:17 +00:00
opline - > result_type = var_name ? IS_CV : IS_UNUSED ;
opline - > result . var = var_name ? lookup_cv ( var_name ) : - 1 ;
2016-05-01 22:47:08 +00:00
2018-01-31 19:39:30 +00:00
if ( is_last_catch & & is_last_class ) {
2018-02-05 16:41:47 +00:00
opline - > extended_value | = ZEND_LAST_CATCH ;
2018-01-31 19:39:30 +00:00
}
2016-05-01 22:47:08 +00:00
if ( ! is_last_class ) {
jmp_multicatch [ j ] = zend_emit_jump ( 0 ) ;
2017-04-14 22:20:06 +00:00
opline = & CG ( active_op_array ) - > opcodes [ opnum_catch ] ;
2018-12-07 14:47:56 +00:00
opline - > op2 . opline_num = get_next_op_number ( ) ;
2016-05-01 22:47:08 +00:00
}
}
for ( j = 0 ; j < classes - > children - 1 ; j + + ) {
zend_update_jump_target_to_next ( jmp_multicatch [ j ] ) ;
}
2010-05-07 16:29:15 +00:00
2016-05-01 22:47:08 +00:00
efree ( jmp_multicatch ) ;
2010-05-07 16:29:15 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_stmt ( stmt_ast ) ;
2003-03-31 20:42:01 +00:00
2014-07-12 17:08:09 +00:00
if ( ! is_last_catch ) {
2014-12-13 22:06:14 +00:00
jmp_opnums [ i + 1 ] = zend_emit_jump ( 0 ) ;
2004-02-27 09:14:55 +00:00
}
2014-07-12 11:50:58 +00:00
2019-04-12 12:55:37 +00:00
ZEND_ASSERT ( opnum_catch ! = ( uint32_t ) - 1 & & " Should have at least one class " ) ;
2014-07-12 11:50:58 +00:00
opline = & CG ( active_op_array ) - > opcodes [ opnum_catch ] ;
2015-11-18 21:47:08 +00:00
if ( ! is_last_catch ) {
2018-12-07 14:47:56 +00:00
opline - > op2 . opline_num = get_next_op_number ( ) ;
2015-11-18 21:47:08 +00:00
}
2003-03-06 22:53:23 +00:00
}
2014-07-12 11:50:58 +00:00
2014-07-27 20:26:06 +00:00
for ( i = 0 ; i < catches - > children ; + + i ) {
2014-12-13 22:06:14 +00:00
zend_update_jump_target_to_next ( jmp_opnums [ i ] ) ;
2014-07-12 11:50:58 +00:00
}
if ( finally_ast ) {
2016-05-24 22:25:12 +00:00
zend_loop_var discard_exception ;
2018-12-07 14:47:56 +00:00
uint32_t opnum_jmp = get_next_op_number ( ) + 1 ;
2017-12-31 04:35:25 +00:00
2015-07-10 11:30:25 +00:00
/* Pop FAST_CALL from unwind stack */
zend_stack_del_top ( & CG ( loop_var_stack ) ) ;
2014-11-27 06:56:43 +00:00
2016-05-24 22:25:12 +00:00
/* Push DISCARD_EXCEPTION on unwind stack */
discard_exception . opcode = ZEND_DISCARD_EXCEPTION ;
discard_exception . var_type = IS_TMP_VAR ;
discard_exception . var_num = CG ( context ) . fast_call_var ;
zend_stack_push ( & CG ( loop_var_stack ) , & discard_exception ) ;
2015-12-30 22:49:07 +00:00
CG ( zend_lineno ) = finally_ast - > lineno ;
2014-12-13 22:06:14 +00:00
opline = zend_emit_op ( NULL , ZEND_FAST_CALL , NULL , NULL ) ;
2015-08-04 05:35:40 +00:00
opline - > op1 . num = try_catch_offset ;
2014-11-27 06:56:43 +00:00
opline - > result_type = IS_TMP_VAR ;
opline - > result . var = CG ( context ) . fast_call_var ;
2014-07-12 11:50:58 +00:00
2014-12-13 22:06:14 +00:00
zend_emit_op ( NULL , ZEND_JMP , NULL , NULL ) ;
2014-07-12 11:50:58 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_stmt ( finally_ast ) ;
2014-07-12 11:50:58 +00:00
CG ( active_op_array ) - > try_catch_array [ try_catch_offset ] . finally_op = opnum_jmp + 1 ;
CG ( active_op_array ) - > try_catch_array [ try_catch_offset ] . finally_end
2018-12-07 14:47:56 +00:00
= get_next_op_number ( ) ;
2014-07-12 11:50:58 +00:00
2014-12-13 22:06:14 +00:00
opline = zend_emit_op ( NULL , ZEND_FAST_RET , NULL , NULL ) ;
2014-11-27 06:56:43 +00:00
opline - > op1_type = IS_TMP_VAR ;
opline - > op1 . var = CG ( context ) . fast_call_var ;
2016-05-24 22:25:12 +00:00
opline - > op2 . num = orig_try_catch_offset ;
2014-07-12 11:50:58 +00:00
2014-12-13 22:06:14 +00:00
zend_update_jump_target_to_next ( opnum_jmp ) ;
2016-05-13 11:38:43 +00:00
CG ( context ) . fast_call_var = orig_fast_call_var ;
2016-05-24 22:25:12 +00:00
/* Pop DISCARD_EXCEPTION from unwind stack */
zend_stack_del_top ( & CG ( loop_var_stack ) ) ;
2006-06-07 09:21:06 +00:00
}
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2016-05-24 22:25:12 +00:00
CG ( context ) . try_catch_offset = orig_try_catch_offset ;
2014-07-12 11:50:58 +00:00
efree ( jmp_opnums ) ;
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-07-12 11:50:58 +00:00
2014-08-18 14:07:18 +00:00
/* Encoding declarations must already be handled during parsing */
2017-09-24 13:24:51 +00:00
zend_bool zend_handle_encoding_declaration ( zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-08-29 18:52:26 +00:00
zend_ast_list * declares = zend_ast_get_list ( ast ) ;
2014-08-25 19:21:16 +00:00
uint32_t i ;
2014-07-27 20:26:06 +00:00
for ( i = 0 ; i < declares - > children ; + + i ) {
zend_ast * declare_ast = declares - > child [ i ] ;
2014-07-22 14:11:19 +00:00
zend_ast * name_ast = declare_ast - > child [ 0 ] ;
zend_ast * value_ast = declare_ast - > child [ 1 ] ;
2014-07-28 13:16:35 +00:00
zend_string * name = zend_ast_get_str ( name_ast ) ;
2014-07-22 14:11:19 +00:00
2014-08-25 20:40:58 +00:00
if ( zend_string_equals_literal_ci ( name , " encoding " ) ) {
2014-08-18 14:07:18 +00:00
if ( value_ast - > kind ! = ZEND_AST_ZVAL ) {
2017-09-24 13:24:51 +00:00
zend_throw_exception ( zend_ce_compile_error , " Encoding must be a literal " , 0 ) ;
return 0 ;
2014-07-22 14:11:19 +00:00
}
if ( CG ( multibyte ) ) {
2014-08-18 14:07:18 +00:00
zend_string * encoding_name = zval_get_string ( zend_ast_get_zval ( value_ast ) ) ;
2014-07-22 14:11:19 +00:00
const zend_encoding * new_encoding , * old_encoding ;
zend_encoding_filter old_input_filter ;
CG ( encoding_declared ) = 1 ;
2015-06-30 10:59:27 +00:00
new_encoding = zend_multibyte_fetch_encoding ( ZSTR_VAL ( encoding_name ) ) ;
2014-07-22 14:11:19 +00:00
if ( ! new_encoding ) {
2015-06-30 10:59:27 +00:00
zend_error ( E_COMPILE_WARNING , " Unsupported encoding [%s] " , ZSTR_VAL ( encoding_name ) ) ;
2014-07-22 14:11:19 +00:00
} else {
old_input_filter = LANG_SCNG ( input_filter ) ;
old_encoding = LANG_SCNG ( script_encoding ) ;
2014-12-13 22:06:14 +00:00
zend_multibyte_set_filter ( new_encoding ) ;
2014-07-22 14:11:19 +00:00
/* need to re-scan if input filter changed */
if ( old_input_filter ! = LANG_SCNG ( input_filter ) | |
( old_input_filter & & new_encoding ! = old_encoding ) ) {
2014-12-13 22:06:14 +00:00
zend_multibyte_yyinput_again ( old_input_filter , old_encoding ) ;
2014-07-22 14:11:19 +00:00
}
}
2014-08-18 14:07:18 +00:00
2018-05-28 13:27:12 +00:00
zend_string_release_ex ( encoding_name , 0 ) ;
2014-07-22 14:11:19 +00:00
} else {
zend_error ( E_COMPILE_WARNING , " declare(encoding=...) ignored because "
" Zend multibyte feature is turned off by settings " ) ;
}
2014-08-18 14:07:18 +00:00
}
}
2017-09-24 13:24:51 +00:00
return 1 ;
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2020-08-28 13:41:27 +00:00
static zend_result zend_declare_is_first_statement ( zend_ast * ast ) /* { { { */
2015-02-20 20:56:58 +00:00
{
uint32_t i = 0 ;
zend_ast_list * file_ast = zend_ast_get_list ( CG ( ast ) ) ;
2018-02-05 00:16:50 +00:00
/* Check to see if this declare is preceded only by declare statements */
2015-02-20 20:56:58 +00:00
while ( i < file_ast - > children ) {
if ( file_ast - > child [ i ] = = ast ) {
return SUCCESS ;
} else if ( file_ast - > child [ i ] = = NULL ) {
/* Empty statements are not allowed prior to a declare */
return FAILURE ;
} else if ( file_ast - > child [ i ] - > kind ! = ZEND_AST_DECLARE ) {
2018-02-05 00:16:50 +00:00
/* declares can only be preceded by other declares */
2015-02-20 20:56:58 +00:00
return FAILURE ;
}
i + + ;
}
return FAILURE ;
}
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_declare ( zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-08-18 14:07:18 +00:00
zend_ast_list * declares = zend_ast_get_list ( ast - > child [ 0 ] ) ;
zend_ast * stmt_ast = ast - > child [ 1 ] ;
2015-04-20 18:16:58 +00:00
zend_declarables orig_declarables = FC ( declarables ) ;
2014-08-25 19:21:16 +00:00
uint32_t i ;
2014-08-18 14:07:18 +00:00
for ( i = 0 ; i < declares - > children ; + + i ) {
zend_ast * declare_ast = declares - > child [ i ] ;
zend_ast * name_ast = declare_ast - > child [ 0 ] ;
zend_ast * value_ast = declare_ast - > child [ 1 ] ;
zend_string * name = zend_ast_get_str ( name_ast ) ;
2017-02-22 21:56:38 +00:00
if ( value_ast - > kind ! = ZEND_AST_ZVAL ) {
zend_error_noreturn ( E_COMPILE_ERROR , " declare(%s) value must be a literal " , ZSTR_VAL ( name ) ) ;
}
2014-08-25 20:40:58 +00:00
if ( zend_string_equals_literal_ci ( name , " ticks " ) ) {
2014-08-18 14:07:18 +00:00
zval value_zv ;
2014-12-13 22:06:14 +00:00
zend_const_expr_to_zval ( & value_zv , value_ast ) ;
2015-04-20 18:16:58 +00:00
FC ( declarables ) . ticks = zval_get_long ( & value_zv ) ;
2018-07-04 16:22:24 +00:00
zval_ptr_dtor_nogc ( & value_zv ) ;
2014-08-25 20:40:58 +00:00
} else if ( zend_string_equals_literal_ci ( name , " encoding " ) ) {
2015-03-20 08:10:29 +00:00
2015-02-20 20:56:58 +00:00
if ( FAILURE = = zend_declare_is_first_statement ( ast ) ) {
2014-08-18 14:07:18 +00:00
zend_error_noreturn ( E_COMPILE_ERROR , " Encoding declaration pragma must be "
" the very first statement in the script " ) ;
}
2015-01-25 01:40:54 +00:00
} else if ( zend_string_equals_literal_ci ( name , " strict_types " ) ) {
2015-01-10 03:29:41 +00:00
zval value_zv ;
2015-02-18 15:26:29 +00:00
2015-02-20 20:56:58 +00:00
if ( FAILURE = = zend_declare_is_first_statement ( ast ) ) {
zend_error_noreturn ( E_COMPILE_ERROR , " strict_types declaration must be "
" the very first statement in the script " ) ;
}
2015-02-18 15:26:29 +00:00
2015-02-20 20:56:58 +00:00
if ( ast - > child [ 1 ] ! = NULL ) {
zend_error_noreturn ( E_COMPILE_ERROR , " strict_types declaration must not "
2015-03-20 08:10:29 +00:00
" use block mode " ) ;
2015-02-20 20:56:58 +00:00
}
2015-02-18 17:43:57 +00:00
2015-02-20 20:56:58 +00:00
zend_const_expr_to_zval ( & value_zv , value_ast ) ;
2015-01-10 03:29:41 +00:00
2015-01-25 01:40:54 +00:00
if ( Z_TYPE ( value_zv ) ! = IS_LONG | | ( Z_LVAL ( value_zv ) ! = 0 & & Z_LVAL ( value_zv ) ! = 1 ) ) {
zend_error_noreturn ( E_COMPILE_ERROR , " strict_types declaration must have 0 or 1 as its value " ) ;
2015-01-10 03:29:41 +00:00
}
2015-03-19 17:30:11 +00:00
if ( Z_LVAL ( value_zv ) = = 1 ) {
CG ( active_op_array ) - > fn_flags | = ZEND_ACC_STRICT_TYPES ;
}
2015-03-20 08:10:29 +00:00
2014-07-22 14:11:19 +00:00
} else {
2015-06-30 10:59:27 +00:00
zend_error ( E_COMPILE_WARNING , " Unsupported declare '%s' " , ZSTR_VAL ( name ) ) ;
2014-07-22 14:11:19 +00:00
}
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
2014-07-22 14:11:19 +00:00
if ( stmt_ast ) {
2014-12-13 22:06:14 +00:00
zend_compile_stmt ( stmt_ast ) ;
2014-07-22 14:11:19 +00:00
2015-04-20 18:16:58 +00:00
FC ( declarables ) = orig_declarables ;
2005-06-24 08:45:17 +00:00
}
2014-07-22 14:11:19 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2006-05-09 23:53:23 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_stmt_list ( zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-27 20:26:06 +00:00
zend_ast_list * list = zend_ast_get_list ( ast ) ;
2014-08-25 19:21:16 +00:00
uint32_t i ;
2014-07-27 20:26:06 +00:00
for ( i = 0 ; i < list - > children ; + + i ) {
2014-12-13 22:06:14 +00:00
zend_compile_stmt ( list - > child [ i ] ) ;
2014-07-09 21:39:21 +00:00
}
2003-03-05 11:14:44 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2003-03-05 11:14:44 +00:00
2015-04-23 10:31:02 +00:00
ZEND_API void zend_set_function_arg_flags ( zend_function * func ) /* { { { */
2015-04-22 18:46:13 +00:00
{
uint32_t i , n ;
func - > common . arg_flags [ 0 ] = 0 ;
func - > common . arg_flags [ 1 ] = 0 ;
func - > common . arg_flags [ 2 ] = 0 ;
if ( func - > common . arg_info ) {
n = MIN ( func - > common . num_args , MAX_ARG_FLAG_NUM ) ;
i = 0 ;
while ( i < n ) {
2019-09-20 15:01:19 +00:00
ZEND_SET_ARG_FLAG ( func , i + 1 , ZEND_ARG_SEND_MODE ( & func - > common . arg_info [ i ] ) ) ;
2015-04-22 18:46:13 +00:00
i + + ;
}
2020-06-07 00:38:13 +00:00
if ( UNEXPECTED ( ( func - > common . fn_flags & ZEND_ACC_VARIADIC ) & & ZEND_ARG_SEND_MODE ( & func - > common . arg_info [ i ] ) ) ) {
2019-09-20 15:01:19 +00:00
uint32_t pass_by_reference = ZEND_ARG_SEND_MODE ( & func - > common . arg_info [ i ] ) ;
2015-04-22 18:46:13 +00:00
while ( i < MAX_ARG_FLAG_NUM ) {
2015-04-25 16:47:26 +00:00
ZEND_SET_ARG_FLAG ( func , i + 1 , pass_by_reference ) ;
2015-04-22 18:46:13 +00:00
i + + ;
}
}
}
}
/* }}} */
2019-09-25 11:21:13 +00:00
static zend_type zend_compile_single_typename ( zend_ast * ast )
2015-05-21 01:50:20 +00:00
{
2019-09-25 11:21:13 +00:00
ZEND_ASSERT ( ! ( ast - > attr & ZEND_TYPE_NULLABLE ) ) ;
2015-05-21 01:50:20 +00:00
if ( ast - > kind = = ZEND_AST_TYPE ) {
2020-01-07 14:06:36 +00:00
if ( ast - > attr = = IS_STATIC & & ! CG ( active_class_entry ) & & zend_is_scope_known ( ) ) {
zend_error_noreturn ( E_COMPILE_ERROR ,
" Cannot use \" static \" when no class scope is active " ) ;
}
2019-09-25 11:21:13 +00:00
return ( zend_type ) ZEND_TYPE_INIT_CODE ( ast - > attr , 0 , 0 ) ;
2015-05-21 01:50:20 +00:00
} else {
zend_string * class_name = zend_ast_get_str ( ast ) ;
2020-01-23 11:48:45 +00:00
zend_uchar type_code = zend_lookup_builtin_type_by_name ( class_name ) ;
2015-05-21 01:50:20 +00:00
2020-01-23 11:48:45 +00:00
if ( type_code ! = 0 ) {
2016-04-28 21:26:57 +00:00
if ( ( ast - > attr & ZEND_NAME_NOT_FQ ) ! = ZEND_NAME_NOT_FQ ) {
2015-11-26 15:56:08 +00:00
zend_error_noreturn ( E_COMPILE_ERROR ,
2018-04-08 18:19:14 +00:00
" Type declaration '%s' must be unqualified " ,
2015-11-26 15:56:08 +00:00
ZSTR_VAL ( zend_string_tolower ( class_name ) ) ) ;
2015-11-24 20:39:06 +00:00
}
2020-01-23 11:55:28 +00:00
return ( zend_type ) ZEND_TYPE_INIT_CODE ( type_code , 0 , 0 ) ;
2015-05-21 01:50:20 +00:00
} else {
2019-10-11 13:32:02 +00:00
const char * correct_name ;
zend_string * orig_name = zend_ast_get_str ( ast ) ;
2015-05-21 01:50:20 +00:00
uint32_t fetch_type = zend_get_class_fetch_type_ast ( ast ) ;
if ( fetch_type = = ZEND_FETCH_CLASS_DEFAULT ) {
class_name = zend_resolve_class_name_ast ( ast ) ;
zend_assert_valid_class_name ( class_name ) ;
} else {
zend_ensure_valid_class_fetch_type ( fetch_type ) ;
zend_string_addref ( class_name ) ;
}
2019-10-11 13:32:02 +00:00
if ( ast - > attr = = ZEND_NAME_NOT_FQ
& & zend_is_confusable_type ( orig_name , & correct_name )
& & zend_is_not_imported ( orig_name ) ) {
const char * extra =
FC ( current_namespace ) ? " or import the class with \" use \" " : " " ;
if ( correct_name ) {
zend_error ( E_COMPILE_WARNING ,
" \" %s \" will be interpreted as a class name. Did you mean \" %s \" ? "
" Write \" \\ %s \" %s to suppress this warning " ,
ZSTR_VAL ( orig_name ) , correct_name , ZSTR_VAL ( class_name ) , extra ) ;
} else {
zend_error ( E_COMPILE_WARNING ,
" \" %s \" is not a supported builtin type "
" and will be interpreted as a class name. "
" Write \" \\ %s \" %s to suppress this warning " ,
ZSTR_VAL ( orig_name ) , ZSTR_VAL ( class_name ) , extra ) ;
}
}
2019-09-25 11:21:13 +00:00
return ( zend_type ) ZEND_TYPE_INIT_CLASS ( class_name , 0 , 0 ) ;
2015-05-21 01:50:20 +00:00
}
}
}
2019-09-25 11:21:13 +00:00
static zend_bool zend_type_contains_traversable ( zend_type type ) {
2020-01-16 16:04:11 +00:00
zend_type * single_type ;
ZEND_TYPE_FOREACH ( type , single_type ) {
if ( ZEND_TYPE_HAS_NAME ( * single_type )
& & zend_string_equals_literal_ci ( ZEND_TYPE_NAME ( * single_type ) , " Traversable " ) ) {
return 1 ;
}
} ZEND_TYPE_FOREACH_END ( ) ;
2019-09-25 11:21:13 +00:00
return 0 ;
}
// TODO: Ideally we'd canonicalize "iterable" into "array|Traversable" and essentially
// treat it as a built-in type alias.
static zend_type zend_compile_typename (
zend_ast * ast , zend_bool force_allow_null , zend_bool use_arena ) /* {{{ */
{
zend_bool allow_null = force_allow_null ;
2020-01-23 11:55:28 +00:00
zend_ast_attr orig_ast_attr = ast - > attr ;
2019-09-25 11:21:13 +00:00
zend_type type = ZEND_TYPE_INIT_NONE ( 0 ) ;
if ( ast - > attr & ZEND_TYPE_NULLABLE ) {
allow_null = 1 ;
ast - > attr & = ~ ZEND_TYPE_NULLABLE ;
}
if ( ast - > kind = = ZEND_AST_TYPE_UNION ) {
zend_ast_list * list = zend_ast_get_list ( ast ) ;
for ( uint32_t i = 0 ; i < list - > children ; i + + ) {
zend_ast * type_ast = list - > child [ i ] ;
zend_type single_type = zend_compile_single_typename ( type_ast ) ;
2020-03-27 22:39:49 +00:00
uint32_t single_type_mask = ZEND_TYPE_PURE_MASK ( single_type ) ;
if ( single_type_mask = = MAY_BE_ANY ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Type mixed can only be used as a standalone type " ) ;
}
uint32_t type_mask_overlap = ZEND_TYPE_PURE_MASK ( type ) & single_type_mask ;
2019-09-25 11:21:13 +00:00
if ( type_mask_overlap ) {
zend_type overlap_type = ZEND_TYPE_INIT_MASK ( type_mask_overlap ) ;
zend_string * overlap_type_str = zend_type_to_string ( overlap_type ) ;
zend_error_noreturn ( E_COMPILE_ERROR ,
" Duplicate type %s is redundant " , ZSTR_VAL ( overlap_type_str ) ) ;
}
ZEND_TYPE_FULL_MASK ( type ) | = ZEND_TYPE_PURE_MASK ( single_type ) ;
2020-01-16 16:04:11 +00:00
ZEND_TYPE_FULL_MASK ( single_type ) & = ~ _ZEND_TYPE_MAY_BE_MASK ;
2019-09-25 11:21:13 +00:00
if ( ZEND_TYPE_HAS_CLASS ( single_type ) ) {
if ( ! ZEND_TYPE_HAS_CLASS ( type ) ) {
/* The first class type can be stored directly as the type ptr payload. */
ZEND_TYPE_SET_PTR ( type , ZEND_TYPE_NAME ( single_type ) ) ;
ZEND_TYPE_FULL_MASK ( type ) | = _ZEND_TYPE_NAME_BIT ;
} else {
zend_type_list * list ;
if ( ZEND_TYPE_HAS_LIST ( type ) ) {
/* Add name to existing name list. */
zend_type_list * old_list = ZEND_TYPE_LIST ( type ) ;
if ( use_arena ) {
// TODO: Add a zend_arena_realloc API?
list = zend_arena_alloc (
& CG ( arena ) , ZEND_TYPE_LIST_SIZE ( old_list - > num_types + 1 ) ) ;
memcpy ( list , old_list , ZEND_TYPE_LIST_SIZE ( old_list - > num_types ) ) ;
} else {
list = erealloc ( old_list , ZEND_TYPE_LIST_SIZE ( old_list - > num_types + 1 ) ) ;
}
} else {
/* Switch from single name to name list. */
size_t size = ZEND_TYPE_LIST_SIZE ( 2 ) ;
list = use_arena ? zend_arena_alloc ( & CG ( arena ) , size ) : emalloc ( size ) ;
2020-01-16 16:04:11 +00:00
list - > num_types = 1 ;
list - > types [ 0 ] = type ;
ZEND_TYPE_FULL_MASK ( list - > types [ 0 ] ) & = ~ _ZEND_TYPE_MAY_BE_MASK ;
2019-09-25 11:21:13 +00:00
}
2020-01-16 16:04:11 +00:00
list - > types [ list - > num_types + + ] = single_type ;
2019-09-25 11:21:13 +00:00
ZEND_TYPE_SET_LIST ( type , list ) ;
if ( use_arena ) {
ZEND_TYPE_FULL_MASK ( type ) | = _ZEND_TYPE_ARENA_BIT ;
}
/* Check for trivially redundant class types */
for ( size_t i = 0 ; i < list - > num_types - 1 ; i + + ) {
if ( zend_string_equals_ci (
2020-01-16 16:04:11 +00:00
ZEND_TYPE_NAME ( list - > types [ i ] ) , ZEND_TYPE_NAME ( single_type ) ) ) {
2019-09-25 11:21:13 +00:00
zend_string * single_type_str = zend_type_to_string ( single_type ) ;
zend_error_noreturn ( E_COMPILE_ERROR ,
" Duplicate type %s is redundant " , ZSTR_VAL ( single_type_str ) ) ;
}
}
}
}
}
} else {
type = zend_compile_single_typename ( ast ) ;
}
if ( allow_null ) {
ZEND_TYPE_FULL_MASK ( type ) | = MAY_BE_NULL ;
}
uint32_t type_mask = ZEND_TYPE_PURE_MASK ( type ) ;
if ( ( type_mask & ( MAY_BE_ARRAY | MAY_BE_ITERABLE ) ) = = ( MAY_BE_ARRAY | MAY_BE_ITERABLE ) ) {
zend_string * type_str = zend_type_to_string ( type ) ;
zend_error_noreturn ( E_COMPILE_ERROR ,
" Type %s contains both iterable and array, which is redundant " , ZSTR_VAL ( type_str ) ) ;
}
if ( ( type_mask & MAY_BE_ITERABLE ) & & zend_type_contains_traversable ( type ) ) {
zend_string * type_str = zend_type_to_string ( type ) ;
zend_error_noreturn ( E_COMPILE_ERROR ,
" Type %s contains both iterable and Traversable, which is redundant " ,
ZSTR_VAL ( type_str ) ) ;
}
2020-03-27 22:39:49 +00:00
if ( type_mask = = MAY_BE_ANY & & ( orig_ast_attr & ZEND_TYPE_NULLABLE ) ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Type mixed cannot be marked as nullable since mixed already includes null " ) ;
}
2020-01-07 14:06:36 +00:00
if ( ( type_mask & MAY_BE_OBJECT ) & & ( ZEND_TYPE_HAS_CLASS ( type ) | | ( type_mask & MAY_BE_STATIC ) ) ) {
2019-09-25 11:21:13 +00:00
zend_string * type_str = zend_type_to_string ( type ) ;
zend_error_noreturn ( E_COMPILE_ERROR ,
" Type %s contains both object and a class type, which is redundant " ,
ZSTR_VAL ( type_str ) ) ;
}
if ( ( type_mask & MAY_BE_VOID ) & & ( ZEND_TYPE_HAS_CLASS ( type ) | | type_mask ! = MAY_BE_VOID ) ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Void can only be used as a standalone type " ) ;
}
if ( ( type_mask & ( MAY_BE_NULL | MAY_BE_FALSE ) )
& & ! ZEND_TYPE_HAS_CLASS ( type ) & & ! ( type_mask & ~ ( MAY_BE_NULL | MAY_BE_FALSE ) ) ) {
if ( type_mask = = MAY_BE_NULL ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Null can not be used as a standalone type " ) ;
} else {
zend_error_noreturn ( E_COMPILE_ERROR , " False can not be used as a standalone type " ) ;
}
}
2020-01-23 11:48:45 +00:00
ast - > attr = orig_ast_attr ;
2019-09-25 11:21:13 +00:00
return type ;
}
2015-05-21 01:50:20 +00:00
/* }}} */
2019-10-08 13:52:18 +00:00
/* May convert value from int to float. */
2019-09-23 14:12:18 +00:00
static zend_bool zend_is_valid_default_value ( zend_type type , zval * value )
{
ZEND_ASSERT ( ZEND_TYPE_IS_SET ( type ) ) ;
if ( ZEND_TYPE_CONTAINS_CODE ( type , Z_TYPE_P ( value ) ) ) {
return 1 ;
}
2019-09-20 15:01:19 +00:00
if ( ( ZEND_TYPE_FULL_MASK ( type ) & MAY_BE_DOUBLE ) & & Z_TYPE_P ( value ) = = IS_LONG ) {
2019-09-23 14:12:18 +00:00
/* Integers are allowed as initializers for floating-point values. */
2019-10-08 13:52:18 +00:00
convert_to_double ( value ) ;
2019-09-23 14:12:18 +00:00
return 1 ;
}
2019-09-20 15:01:19 +00:00
if ( ( ZEND_TYPE_FULL_MASK ( type ) & MAY_BE_ITERABLE ) & & Z_TYPE_P ( value ) = = IS_ARRAY ) {
2019-09-23 14:12:18 +00:00
return 1 ;
}
return 0 ;
}
2020-06-28 17:16:33 +00:00
static void zend_compile_attributes ( HashTable * * attributes , zend_ast * ast , uint32_t offset , uint32_t target ) /* { { { */
2020-05-24 18:57:00 +00:00
{
2020-06-28 17:16:33 +00:00
zend_attribute * attr ;
zend_internal_attribute * config ;
2020-05-24 18:57:00 +00:00
zend_ast_list * list = zend_ast_get_list ( ast ) ;
2020-08-15 08:39:00 +00:00
uint32_t g , i , j ;
2020-05-24 18:57:00 +00:00
ZEND_ASSERT ( ast - > kind = = ZEND_AST_ATTRIBUTE_LIST ) ;
2020-08-15 08:39:00 +00:00
for ( g = 0 ; g < list - > children ; g + + ) {
zend_ast_list * group = zend_ast_get_list ( list - > child [ g ] ) ;
2020-06-28 17:16:33 +00:00
2020-08-15 08:39:00 +00:00
ZEND_ASSERT ( group - > kind = = ZEND_AST_ATTRIBUTE_GROUP ) ;
2020-05-24 18:57:00 +00:00
2020-08-15 08:39:00 +00:00
for ( i = 0 ; i < group - > children ; i + + ) {
ZEND_ASSERT ( group - > child [ i ] - > kind = = ZEND_AST_ATTRIBUTE ) ;
2020-05-24 18:57:00 +00:00
2020-08-15 08:39:00 +00:00
zend_ast * el = group - > child [ i ] ;
zend_string * name = zend_resolve_class_name_ast ( el - > child [ 0 ] ) ;
zend_ast_list * args = el - > child [ 1 ] ? zend_ast_get_list ( el - > child [ 1 ] ) : NULL ;
2020-05-24 18:57:00 +00:00
2020-08-15 08:39:00 +00:00
attr = zend_add_attribute ( attributes , 0 , offset , name , args ? args - > children : 0 ) ;
zend_string_release ( name ) ;
2020-04-06 10:46:52 +00:00
2020-08-15 08:39:00 +00:00
/* Populate arguments */
if ( args ) {
ZEND_ASSERT ( args - > kind = = ZEND_AST_ARG_LIST ) ;
zend_bool uses_named_args = 0 ;
for ( j = 0 ; j < args - > children ; j + + ) {
zend_ast * arg_ast = args - > child [ j ] ;
2020-07-02 13:27:45 +00:00
2020-08-15 08:39:00 +00:00
if ( arg_ast - > kind = = ZEND_AST_UNPACK ) {
zend_error_noreturn ( E_COMPILE_ERROR ,
" Cannot use unpacking in attribute argument list " ) ;
}
2020-04-06 10:46:52 +00:00
2020-08-15 08:39:00 +00:00
if ( arg_ast - > kind = = ZEND_AST_NAMED_ARG ) {
attr - > args [ j ] . name = zend_string_copy ( zend_ast_get_str ( arg_ast - > child [ 0 ] ) ) ;
arg_ast = arg_ast - > child [ 1 ] ;
uses_named_args = 1 ;
for ( uint32_t k = 0 ; k < j ; k + + ) {
if ( attr - > args [ k ] . name & &
zend_string_equals ( attr - > args [ k ] . name , attr - > args [ j ] . name ) ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Duplicate named parameter $%s " ,
ZSTR_VAL ( attr - > args [ j ] . name ) ) ;
}
2020-04-06 10:46:52 +00:00
}
2020-08-15 08:39:00 +00:00
} else if ( uses_named_args ) {
zend_error_noreturn ( E_COMPILE_ERROR ,
" Cannot use positional argument after named argument " ) ;
2020-04-06 10:46:52 +00:00
}
2020-08-15 08:39:00 +00:00
zend_const_expr_to_zval ( & attr - > args [ j ] . value , arg_ast ) ;
}
2020-05-24 18:57:00 +00:00
}
}
2020-06-28 17:16:33 +00:00
}
2020-05-24 18:57:00 +00:00
2020-06-28 17:16:33 +00:00
/* Validate attributes in a secondary loop (needed to detect repeated attributes). */
ZEND_HASH_FOREACH_PTR ( * attributes , attr ) {
if ( attr - > offset ! = offset | | NULL = = ( config = zend_internal_attribute_get ( attr - > lcname ) ) ) {
continue ;
}
if ( ! ( target & ( config - > flags & ZEND_ATTRIBUTE_TARGET_ALL ) ) ) {
zend_string * location = zend_get_attribute_target_names ( target ) ;
zend_string * allowed = zend_get_attribute_target_names ( config - > flags ) ;
2020-05-24 18:57:00 +00:00
2020-06-28 17:16:33 +00:00
zend_error_noreturn ( E_ERROR , " Attribute \" %s \" cannot target %s (allowed targets: %s) " ,
ZSTR_VAL ( attr - > name ) , ZSTR_VAL ( location ) , ZSTR_VAL ( allowed )
) ;
2020-05-24 18:57:00 +00:00
}
2020-06-28 17:16:33 +00:00
if ( ! ( config - > flags & ZEND_ATTRIBUTE_IS_REPEATABLE ) ) {
if ( zend_is_attribute_repeated ( * attributes , attr ) ) {
zend_error_noreturn ( E_ERROR , " Attribute \" %s \" must not be repeated " , ZSTR_VAL ( attr - > name ) ) ;
}
}
if ( config - > validator ! = NULL ) {
config - > validator ( attr , target , CG ( active_class_entry ) ) ;
}
} ZEND_HASH_FOREACH_END ( ) ;
2020-05-24 18:57:00 +00:00
}
/* }}} */
2020-01-13 16:06:26 +00:00
void zend_compile_params ( zend_ast * ast , zend_ast * return_type_ast , uint32_t fallback_return_type ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-27 20:26:06 +00:00
zend_ast_list * list = zend_ast_get_list ( ast ) ;
2014-08-25 19:21:16 +00:00
uint32_t i ;
2014-07-14 21:03:53 +00:00
zend_op_array * op_array = CG ( active_op_array ) ;
zend_arg_info * arg_infos ;
2020-01-09 11:21:02 +00:00
zend_string * optional_param = NULL ;
2017-12-31 04:35:25 +00:00
2020-01-13 16:06:26 +00:00
if ( return_type_ast | | fallback_return_type ) {
2015-10-20 16:50:13 +00:00
/* Use op_array->arg_info[-1] for return type */
2015-01-08 20:40:36 +00:00
arg_infos = safe_emalloc ( sizeof ( zend_arg_info ) , list - > children + 1 , 0 ) ;
arg_infos - > name = NULL ;
2020-01-13 16:06:26 +00:00
if ( return_type_ast ) {
arg_infos - > type = zend_compile_typename (
return_type_ast , /* force_allow_null */ 0 , /* use_arena */ 0 ) ;
ZEND_TYPE_FULL_MASK ( arg_infos - > type ) | = _ZEND_ARG_INFO_FLAGS (
( op_array - > fn_flags & ZEND_ACC_RETURN_REFERENCE ) ! = 0 , /* is_variadic */ 0 ) ;
} else {
arg_infos - > type = ( zend_type ) ZEND_TYPE_INIT_CODE ( fallback_return_type , 0 , 0 ) ;
}
2015-01-08 20:40:36 +00:00
arg_infos + + ;
op_array - > fn_flags | = ZEND_ACC_HAS_RETURN_TYPE ;
} else {
if ( list - > children = = 0 ) {
return ;
}
arg_infos = safe_emalloc ( sizeof ( zend_arg_info ) , list - > children , 0 ) ;
2011-12-19 10:05:48 +00:00
}
2015-01-03 09:22:58 +00:00
2014-07-27 20:26:06 +00:00
for ( i = 0 ; i < list - > children ; + + i ) {
zend_ast * param_ast = list - > child [ i ] ;
2014-07-14 21:03:53 +00:00
zend_ast * type_ast = param_ast - > child [ 0 ] ;
zend_ast * var_ast = param_ast - > child [ 1 ] ;
zend_ast * default_ast = param_ast - > child [ 2 ] ;
2020-05-24 18:57:00 +00:00
zend_ast * attributes_ast = param_ast - > child [ 3 ] ;
2020-03-24 12:18:28 +00:00
zend_ast * doc_comment_ast = param_ast - > child [ 4 ] ;
2017-10-31 22:10:21 +00:00
zend_string * name = zval_make_interned_string ( zend_ast_get_zval ( var_ast ) ) ;
2014-07-14 21:03:53 +00:00
zend_bool is_ref = ( param_ast - > attr & ZEND_PARAM_REF ) ! = 0 ;
zend_bool is_variadic = ( param_ast - > attr & ZEND_PARAM_VARIADIC ) ! = 0 ;
2020-03-24 12:18:28 +00:00
uint32_t visibility =
param_ast - > attr & ( ZEND_ACC_PUBLIC | ZEND_ACC_PROTECTED | ZEND_ACC_PRIVATE ) ;
2014-07-14 21:03:53 +00:00
znode var_node , default_node ;
zend_uchar opcode ;
zend_op * opline ;
zend_arg_info * arg_info ;
2011-11-01 00:39:10 +00:00
2020-07-25 11:02:01 +00:00
zend_ast_ref * attributes_copy = NULL ;
if ( visibility & & attributes_ast ) {
attributes_copy = zend_ast_copy ( attributes_ast ) ;
}
2014-12-13 22:06:14 +00:00
if ( zend_is_auto_global ( name ) ) {
2014-07-14 21:03:53 +00:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot re-assign auto-global variable %s " ,
2015-06-30 10:59:27 +00:00
ZSTR_VAL ( name ) ) ;
2014-07-14 21:03:53 +00:00
}
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2014-07-14 21:03:53 +00:00
var_node . op_type = IS_CV ;
2018-12-07 14:47:56 +00:00
var_node . u . op . var = lookup_cv ( name ) ;
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2014-07-22 14:55:34 +00:00
if ( EX_VAR_TO_NUM ( var_node . u . op . var ) ! = i ) {
2014-08-25 19:21:16 +00:00
zend_error_noreturn ( E_COMPILE_ERROR , " Redefinition of parameter $%s " ,
2015-06-30 10:59:27 +00:00
ZSTR_VAL ( name ) ) ;
2014-08-25 20:40:58 +00:00
} else if ( zend_string_equals_literal ( name , " this " ) ) {
2016-06-15 23:30:23 +00:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use $this as parameter " ) ;
2014-07-14 21:03:53 +00:00
}
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2014-07-14 21:03:53 +00:00
if ( op_array - > fn_flags & ZEND_ACC_VARIADIC ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Only the last parameter can be variadic " ) ;
}
2006-05-09 23:53:23 +00:00
2014-07-14 21:03:53 +00:00
if ( is_variadic ) {
opcode = ZEND_RECV_VARIADIC ;
default_node . op_type = IS_UNUSED ;
op_array - > fn_flags | = ZEND_ACC_VARIADIC ;
1999-04-07 18:10:10 +00:00
2014-07-14 21:03:53 +00:00
if ( default_ast ) {
zend_error_noreturn ( E_COMPILE_ERROR ,
" Variadic parameter cannot have a default value " ) ;
}
} else if ( default_ast ) {
2015-02-10 21:17:43 +00:00
/* we cannot substitute constants here or it will break ReflectionParameter::getDefaultValueConstantName() and ReflectionParameter::isDefaultValueConstant() */
uint32_t cops = CG ( compiler_options ) ;
CG ( compiler_options ) | = ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION | ZEND_COMPILE_NO_PERSISTENT_CONSTANT_SUBSTITUTION ;
2014-07-14 21:03:53 +00:00
opcode = ZEND_RECV_INIT ;
default_node . op_type = IS_CONST ;
2014-12-13 22:06:14 +00:00
zend_const_expr_to_zval ( & default_node . u . constant , default_ast ) ;
2015-02-10 21:17:43 +00:00
CG ( compiler_options ) = cops ;
2020-01-09 11:21:02 +00:00
if ( ! optional_param ) {
/* Ignore parameters of the form "Type $param = null".
* This is the PHP 5 style way of writing " ?Type $param " , so allow it for now . */
zend_bool is_implicit_nullable =
type_ast & & Z_TYPE ( default_node . u . constant ) = = IS_NULL ;
if ( ! is_implicit_nullable ) {
optional_param = name ;
}
}
2014-07-14 21:03:53 +00:00
} else {
opcode = ZEND_RECV ;
default_node . op_type = IS_UNUSED ;
op_array - > required_num_args = i + 1 ;
2020-01-09 11:21:02 +00:00
if ( optional_param ) {
zend_error ( E_DEPRECATED , " Required parameter $%s follows optional parameter $%s " ,
ZSTR_VAL ( name ) , ZSTR_VAL ( optional_param ) ) ;
}
2014-07-14 21:03:53 +00:00
}
arg_info = & arg_infos [ i ] ;
2014-12-03 13:56:09 +00:00
arg_info - > name = zend_string_copy ( name ) ;
2019-09-20 15:01:19 +00:00
arg_info - > type = ( zend_type ) ZEND_TYPE_INIT_NONE ( 0 ) ;
2014-07-14 21:03:53 +00:00
2020-05-24 18:57:00 +00:00
if ( attributes_ast ) {
zend_compile_attributes ( & op_array - > attributes , attributes_ast , i + 1 , ZEND_ATTRIBUTE_TARGET_PARAMETER ) ;
}
2014-07-14 21:03:53 +00:00
if ( type_ast ) {
2019-04-18 07:48:04 +00:00
uint32_t default_type = default_ast ? Z_TYPE ( default_node . u . constant ) : IS_UNDEF ;
2020-03-24 12:18:28 +00:00
zend_bool force_nullable = default_type = = IS_NULL & & ! visibility ;
2019-03-06 09:42:02 +00:00
2014-07-14 21:03:53 +00:00
op_array - > fn_flags | = ZEND_ACC_HAS_TYPE_HINTS ;
2020-03-24 12:18:28 +00:00
arg_info - > type = zend_compile_typename ( type_ast , force_nullable , /* use_arena */ 0 ) ;
2015-05-21 01:50:20 +00:00
2019-09-25 11:21:13 +00:00
if ( ZEND_TYPE_FULL_MASK ( arg_info - > type ) & MAY_BE_VOID ) {
2015-10-14 18:15:32 +00:00
zend_error_noreturn ( E_COMPILE_ERROR , " void cannot be used as a parameter type " ) ;
}
2020-03-24 12:18:28 +00:00
if ( default_type ! = IS_UNDEF & & default_type ! = IS_CONSTANT_AST & & ! force_nullable
2019-09-23 14:12:18 +00:00
& & ! zend_is_valid_default_value ( arg_info - > type , & default_node . u . constant ) ) {
zend_string * type_str = zend_type_to_string ( arg_info - > type ) ;
zend_error_noreturn ( E_COMPILE_ERROR ,
" Cannot use %s as default value for parameter $%s of type %s " ,
zend_get_type_by_const ( default_type ) ,
ZSTR_VAL ( name ) , ZSTR_VAL ( type_str ) ) ;
2014-07-14 21:03:53 +00:00
}
2019-10-08 15:29:41 +00:00
}
2015-06-17 09:07:43 +00:00
2019-10-08 15:29:41 +00:00
opline = zend_emit_op ( NULL , opcode , NULL , & default_node ) ;
SET_NODE ( opline - > result , & var_node ) ;
opline - > op1 . num = i + 1 ;
if ( type_ast ) {
2015-06-17 09:07:43 +00:00
/* Allocate cache slot to speed-up run-time class resolution */
2019-09-25 11:21:13 +00:00
opline - > extended_value =
zend_alloc_cache_slots ( zend_type_get_num_classes ( arg_info - > type ) ) ;
2017-12-31 04:35:25 +00:00
}
2019-09-20 15:01:19 +00:00
2020-03-24 12:18:28 +00:00
uint32_t arg_info_flags = _ZEND_ARG_INFO_FLAGS ( is_ref , is_variadic )
| ( visibility ? _ZEND_IS_PROMOTED_BIT : 0 ) ;
ZEND_TYPE_FULL_MASK ( arg_info - > type ) | = arg_info_flags ;
2019-12-20 03:46:25 +00:00
if ( opcode = = ZEND_RECV ) {
opline - > op2 . num = type_ast ?
ZEND_TYPE_FULL_MASK ( arg_info - > type ) : MAY_BE_ANY ;
}
2020-03-24 12:18:28 +00:00
if ( visibility ) {
zend_op_array * op_array = CG ( active_op_array ) ;
zend_class_entry * scope = op_array - > scope ;
zend_bool is_ctor =
2020-06-17 14:04:52 +00:00
scope & & zend_is_constructor ( op_array - > function_name ) ;
2020-03-24 12:18:28 +00:00
if ( ! is_ctor ) {
zend_error_noreturn ( E_COMPILE_ERROR ,
" Cannot declare promoted property outside a constructor " ) ;
}
if ( ( op_array - > fn_flags & ZEND_ACC_ABSTRACT )
| | ( scope - > ce_flags & ZEND_ACC_INTERFACE ) ) {
zend_error_noreturn ( E_COMPILE_ERROR ,
" Cannot declare promoted property in an abstract constructor " ) ;
}
if ( is_variadic ) {
zend_error_noreturn ( E_COMPILE_ERROR ,
" Cannot declare variadic promoted property " ) ;
}
if ( zend_hash_exists ( & scope - > properties_info , name ) ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot redeclare %s::$%s " ,
ZSTR_VAL ( scope - > name ) , ZSTR_VAL ( name ) ) ;
}
if ( ZEND_TYPE_FULL_MASK ( arg_info - > type ) & MAY_BE_CALLABLE ) {
zend_string * str = zend_type_to_string ( arg_info - > type ) ;
zend_error_noreturn ( E_COMPILE_ERROR ,
" Property %s::$%s cannot have type %s " ,
ZSTR_VAL ( scope - > name ) , ZSTR_VAL ( name ) , ZSTR_VAL ( str ) ) ;
}
/* Recompile the type, as it has different memory management requirements. */
zend_type type = ZEND_TYPE_INIT_NONE ( 0 ) ;
if ( type_ast ) {
type = zend_compile_typename ( type_ast , /* force_allow_null */ 0 , /* use_arena */ 1 ) ;
}
2020-07-17 13:09:29 +00:00
/* Don't give the property an explicit default value. For typed properties this means
* uninitialized , for untyped properties it means an implicit null default value . */
zval default_value ;
if ( ZEND_TYPE_IS_SET ( type ) ) {
ZVAL_UNDEF ( & default_value ) ;
} else {
ZVAL_NULL ( & default_value ) ;
}
2020-03-24 12:18:28 +00:00
zend_string * doc_comment =
doc_comment_ast ? zend_string_copy ( zend_ast_get_str ( doc_comment_ast ) ) : NULL ;
zend_property_info * prop = zend_declare_typed_property (
scope , name , & default_value , visibility | ZEND_ACC_PROMOTED , doc_comment , type ) ;
if ( attributes_ast ) {
zend_compile_attributes (
2020-07-25 11:02:01 +00:00
& prop - > attributes , GC_AST ( attributes_copy ) , 0 , ZEND_ATTRIBUTE_TARGET_PROPERTY ) ;
zend_ast_ref_destroy ( attributes_copy ) ;
2020-03-24 12:18:28 +00:00
}
}
2003-06-08 18:53:58 +00:00
}
2018-02-05 00:16:50 +00:00
/* These are assigned at the end to avoid uninitialized memory in case of an error */
2014-07-27 20:26:06 +00:00
op_array - > num_args = list - > children ;
2014-07-14 21:03:53 +00:00
op_array - > arg_info = arg_infos ;
2014-12-22 13:44:39 +00:00
/* Don't count the variadic argument */
if ( op_array - > fn_flags & ZEND_ACC_VARIADIC ) {
op_array - > num_args - - ;
2015-01-03 09:22:58 +00:00
}
2015-04-22 18:46:13 +00:00
zend_set_function_arg_flags ( ( zend_function * ) op_array ) ;
2020-03-24 12:18:28 +00:00
for ( i = 0 ; i < list - > children ; i + + ) {
zend_ast * param_ast = list - > child [ i ] ;
zend_bool is_ref = ( param_ast - > attr & ZEND_PARAM_REF ) ! = 0 ;
uint32_t visibility =
param_ast - > attr & ( ZEND_ACC_PUBLIC | ZEND_ACC_PROTECTED | ZEND_ACC_PRIVATE ) ;
if ( ! visibility ) {
continue ;
}
/* Emit $this->prop = $prop for promoted properties. */
zend_string * name = zend_ast_get_str ( param_ast - > child [ 1 ] ) ;
znode name_node , value_node ;
name_node . op_type = IS_CONST ;
ZVAL_STR_COPY ( & name_node . u . constant , name ) ;
value_node . op_type = IS_CV ;
value_node . u . op . var = lookup_cv ( name ) ;
zend_op * opline = zend_emit_op ( NULL ,
is_ref ? ZEND_ASSIGN_OBJ_REF : ZEND_ASSIGN_OBJ , NULL , & name_node ) ;
opline - > extended_value = zend_alloc_cache_slots ( 3 ) ;
zend_emit_op_data ( & value_node ) ;
}
2014-07-14 21:03:53 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-07-14 21:03:53 +00:00
2018-08-20 13:10:09 +00:00
static void zend_compile_closure_binding ( znode * closure , zend_op_array * op_array , zend_ast * uses_ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2015-12-29 10:16:08 +00:00
zend_ast_list * list = zend_ast_get_list ( uses_ast ) ;
2014-08-25 19:21:16 +00:00
uint32_t i ;
2014-07-18 10:30:39 +00:00
2018-08-20 13:10:09 +00:00
if ( ! list - > children ) {
return ;
}
if ( ! op_array - > static_variables ) {
op_array - > static_variables = zend_new_array ( 8 ) ;
}
2014-07-27 20:26:06 +00:00
for ( i = 0 ; i < list - > children ; + + i ) {
2015-12-29 10:16:08 +00:00
zend_ast * var_name_ast = list - > child [ i ] ;
2017-10-31 22:10:21 +00:00
zend_string * var_name = zval_make_interned_string ( zend_ast_get_zval ( var_name_ast ) ) ;
2019-05-02 12:57:16 +00:00
uint32_t mode = var_name_ast - > attr ;
2015-12-29 10:16:08 +00:00
zend_op * opline ;
2018-08-20 13:10:09 +00:00
zval * value ;
2014-07-18 10:30:39 +00:00
2015-12-29 10:16:08 +00:00
if ( zend_string_equals_literal ( var_name , " this " ) ) {
2014-07-18 10:30:39 +00:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use $this as lexical variable " ) ;
2013-01-14 08:23:22 +00:00
}
2014-07-18 10:30:39 +00:00
2015-12-29 10:16:08 +00:00
if ( zend_is_auto_global ( var_name ) ) {
2015-12-29 10:20:44 +00:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use auto-global as lexical variable " ) ;
}
2018-08-20 13:10:09 +00:00
value = zend_hash_add ( op_array - > static_variables , var_name , & EG ( uninitialized_zval ) ) ;
if ( ! value ) {
zend_error_noreturn ( E_COMPILE_ERROR ,
" Cannot use variable $%s twice " , ZSTR_VAL ( var_name ) ) ;
}
2019-06-10 12:19:39 +00:00
CG ( zend_lineno ) = zend_ast_get_lineno ( var_name_ast ) ;
2015-12-29 10:16:08 +00:00
opline = zend_emit_op ( NULL , ZEND_BIND_LEXICAL , closure , NULL ) ;
opline - > op2_type = IS_CV ;
2018-12-07 14:47:56 +00:00
opline - > op2 . var = lookup_cv ( var_name ) ;
2019-05-02 12:57:16 +00:00
opline - > extended_value =
( uint32_t ) ( ( char * ) value - ( char * ) op_array - > static_variables - > arData ) | mode ;
2015-12-29 10:16:08 +00:00
}
}
/* }}} */
2014-07-18 10:30:39 +00:00
2019-05-02 12:57:16 +00:00
typedef struct {
HashTable uses ;
zend_bool varvars_used ;
} closure_info ;
static void find_implicit_binds_recursively ( closure_info * info , zend_ast * ast ) {
if ( ! ast ) {
return ;
}
if ( ast - > kind = = ZEND_AST_VAR ) {
zend_ast * name_ast = ast - > child [ 0 ] ;
if ( name_ast - > kind = = ZEND_AST_ZVAL & & Z_TYPE_P ( zend_ast_get_zval ( name_ast ) ) = = IS_STRING ) {
zend_string * name = zend_ast_get_str ( name_ast ) ;
if ( zend_is_auto_global ( name ) ) {
/* These is no need to explicitly import auto-globals. */
return ;
}
if ( zend_string_equals_literal ( name , " this " ) ) {
/* $this does not need to be explicitly imported. */
return ;
}
zend_hash_add_empty_element ( & info - > uses , name ) ;
} else {
info - > varvars_used = 1 ;
find_implicit_binds_recursively ( info , name_ast ) ;
}
} else if ( zend_ast_is_list ( ast ) ) {
zend_ast_list * list = zend_ast_get_list ( ast ) ;
uint32_t i ;
for ( i = 0 ; i < list - > children ; i + + ) {
find_implicit_binds_recursively ( info , list - > child [ i ] ) ;
}
} else if ( ast - > kind = = ZEND_AST_CLOSURE ) {
/* For normal closures add the use() list. */
zend_ast_decl * closure_ast = ( zend_ast_decl * ) ast ;
zend_ast * uses_ast = closure_ast - > child [ 1 ] ;
if ( uses_ast ) {
zend_ast_list * uses_list = zend_ast_get_list ( uses_ast ) ;
uint32_t i ;
for ( i = 0 ; i < uses_list - > children ; i + + ) {
zend_hash_add_empty_element ( & info - > uses , zend_ast_get_str ( uses_list - > child [ i ] ) ) ;
}
}
} else if ( ast - > kind = = ZEND_AST_ARROW_FUNC ) {
/* For arrow functions recursively check the expression. */
zend_ast_decl * closure_ast = ( zend_ast_decl * ) ast ;
find_implicit_binds_recursively ( info , closure_ast - > child [ 2 ] ) ;
} else if ( ! zend_ast_is_special ( ast ) ) {
uint32_t i , children = zend_ast_get_num_children ( ast ) ;
for ( i = 0 ; i < children ; i + + ) {
find_implicit_binds_recursively ( info , ast - > child [ i ] ) ;
}
}
}
static void find_implicit_binds ( closure_info * info , zend_ast * params_ast , zend_ast * stmt_ast )
{
zend_ast_list * param_list = zend_ast_get_list ( params_ast ) ;
uint32_t i ;
2019-11-12 07:51:55 +00:00
zend_hash_init ( & info - > uses , param_list - > children , NULL , NULL , 0 ) ;
2019-05-02 12:57:16 +00:00
find_implicit_binds_recursively ( info , stmt_ast ) ;
/* Remove variables that are parameters */
for ( i = 0 ; i < param_list - > children ; i + + ) {
zend_ast * param_ast = param_list - > child [ i ] ;
zend_hash_del ( & info - > uses , zend_ast_get_str ( param_ast - > child [ 1 ] ) ) ;
}
}
static void compile_implicit_lexical_binds (
closure_info * info , znode * closure , zend_op_array * op_array )
{
zend_string * var_name ;
zend_op * opline ;
/* TODO We might want to use a special binding mode if varvars_used is set. */
if ( zend_hash_num_elements ( & info - > uses ) = = 0 ) {
return ;
}
if ( ! op_array - > static_variables ) {
op_array - > static_variables = zend_new_array ( 8 ) ;
}
ZEND_HASH_FOREACH_STR_KEY ( & info - > uses , var_name )
zval * value = zend_hash_add (
op_array - > static_variables , var_name , & EG ( uninitialized_zval ) ) ;
uint32_t offset = ( uint32_t ) ( ( char * ) value - ( char * ) op_array - > static_variables - > arData ) ;
opline = zend_emit_op ( NULL , ZEND_BIND_LEXICAL , closure , NULL ) ;
opline - > op2_type = IS_CV ;
opline - > op2 . var = lookup_cv ( var_name ) ;
opline - > extended_value = offset | ZEND_BIND_IMPLICIT ;
ZEND_HASH_FOREACH_END ( ) ;
}
static void zend_compile_closure_uses ( zend_ast * ast ) /* { { { */
2015-12-29 10:16:08 +00:00
{
2016-01-12 14:18:10 +00:00
zend_op_array * op_array = CG ( active_op_array ) ;
2015-12-29 10:16:08 +00:00
zend_ast_list * list = zend_ast_get_list ( ast ) ;
uint32_t i ;
for ( i = 0 ; i < list - > children ; + + i ) {
zend_ast * var_ast = list - > child [ i ] ;
2016-01-12 14:18:10 +00:00
zend_string * var_name = zend_ast_get_str ( var_ast ) ;
2015-12-29 10:16:08 +00:00
zval zv ;
ZVAL_NULL ( & zv ) ;
2016-01-12 14:18:10 +00:00
{
int i ;
for ( i = 0 ; i < op_array - > last_var ; i + + ) {
if ( zend_string_equals ( op_array - > vars [ i ] , var_name ) ) {
zend_error_noreturn ( E_COMPILE_ERROR ,
" Cannot use lexical variable $%s as a parameter name " , ZSTR_VAL ( var_name ) ) ;
}
}
}
2019-06-08 19:47:07 +00:00
CG ( zend_lineno ) = zend_ast_get_lineno ( var_ast ) ;
2019-05-27 15:11:44 +00:00
zend_compile_static_var_common ( var_name , & zv , var_ast - > attr ? ZEND_BIND_REF : 0 ) ;
2013-01-14 08:23:22 +00:00
}
2003-06-08 18:53:58 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2003-06-08 18:53:58 +00:00
2019-05-02 12:57:16 +00:00
static void zend_compile_implicit_closure_uses ( closure_info * info )
{
zend_string * var_name ;
ZEND_HASH_FOREACH_STR_KEY ( & info - > uses , var_name )
zval zv ;
ZVAL_NULL ( & zv ) ;
2019-05-27 15:11:44 +00:00
zend_compile_static_var_common ( var_name , & zv , ZEND_BIND_IMPLICIT ) ;
2019-05-02 12:57:16 +00:00
ZEND_HASH_FOREACH_END ( ) ;
}
2020-02-06 09:27:30 +00:00
static void add_stringable_interface ( zend_class_entry * ce ) {
for ( uint32_t i = 0 ; i < ce - > num_interfaces ; i + + ) {
if ( zend_string_equals_literal ( ce - > interface_names [ i ] . lc_name , " stringable " ) ) {
/* Interface already explicitly implemented */
return ;
}
}
ce - > num_interfaces + + ;
ce - > interface_names =
erealloc ( ce - > interface_names , sizeof ( zend_class_name ) * ce - > num_interfaces ) ;
// TODO: Add known interned strings instead?
ce - > interface_names [ ce - > num_interfaces - 1 ] . name =
zend_string_init ( " Stringable " , sizeof ( " Stringable " ) - 1 , 0 ) ;
ce - > interface_names [ ce - > num_interfaces - 1 ] . lc_name =
zend_string_init ( " stringable " , sizeof ( " stringable " ) - 1 , 0 ) ;
}
2020-04-27 10:33:29 +00:00
zend_string * zend_begin_method_decl ( zend_op_array * op_array , zend_string * name , zend_bool has_body ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-19 10:52:44 +00:00
zend_class_entry * ce = CG ( active_class_entry ) ;
zend_bool in_interface = ( ce - > ce_flags & ZEND_ACC_INTERFACE ) ! = 0 ;
2019-03-06 09:42:02 +00:00
uint32_t fn_flags = op_array - > fn_flags ;
1999-12-26 21:21:33 +00:00
2014-07-19 10:52:44 +00:00
zend_string * lcname ;
2003-03-05 11:14:44 +00:00
2020-04-16 17:53:13 +00:00
if ( ( fn_flags & ZEND_ACC_PRIVATE ) & & ( fn_flags & ZEND_ACC_FINAL ) & & ! zend_is_constructor ( name ) ) {
zend_error ( E_COMPILE_WARNING , " Private methods cannot be final as they are never overridden by other classes " ) ;
}
2014-07-19 10:52:44 +00:00
if ( in_interface ) {
2019-03-06 09:42:02 +00:00
if ( ! ( fn_flags & ZEND_ACC_PUBLIC ) | | ( fn_flags & ( ZEND_ACC_FINAL | ZEND_ACC_ABSTRACT ) ) ) {
2014-07-19 10:52:44 +00:00
zend_error_noreturn ( E_COMPILE_ERROR , " Access type for interface method "
2015-06-30 10:59:27 +00:00
" %s::%s() must be omitted " , ZSTR_VAL ( ce - > name ) , ZSTR_VAL ( name ) ) ;
2014-07-19 10:52:44 +00:00
}
op_array - > fn_flags | = ZEND_ACC_ABSTRACT ;
2003-02-11 09:48:37 +00:00
}
2014-07-19 10:52:44 +00:00
if ( op_array - > fn_flags & ZEND_ACC_ABSTRACT ) {
2020-01-09 14:04:33 +00:00
if ( ( op_array - > fn_flags & ZEND_ACC_PRIVATE ) & & ! ( ce - > ce_flags & ZEND_ACC_TRAIT ) ) {
2014-07-19 10:52:44 +00:00
zend_error_noreturn ( E_COMPILE_ERROR , " %s function %s::%s() cannot be declared private " ,
2015-06-30 10:59:27 +00:00
in_interface ? " Interface " : " Abstract " , ZSTR_VAL ( ce - > name ) , ZSTR_VAL ( name ) ) ;
2014-07-19 10:52:44 +00:00
}
1999-04-07 18:10:10 +00:00
2014-07-19 10:52:44 +00:00
if ( has_body ) {
zend_error_noreturn ( E_COMPILE_ERROR , " %s function %s::%s() cannot contain body " ,
2015-06-30 10:59:27 +00:00
in_interface ? " Interface " : " Abstract " , ZSTR_VAL ( ce - > name ) , ZSTR_VAL ( name ) ) ;
2014-07-19 10:52:44 +00:00
}
2002-02-14 04:01:53 +00:00
2014-07-19 10:52:44 +00:00
ce - > ce_flags | = ZEND_ACC_IMPLICIT_ABSTRACT_CLASS ;
} else if ( ! has_body ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Non-abstract method %s::%s() must contain body " ,
2015-06-30 10:59:27 +00:00
ZSTR_VAL ( ce - > name ) , ZSTR_VAL ( name ) ) ;
2014-04-03 11:26:23 +00:00
}
1999-04-07 18:10:10 +00:00
2014-07-19 10:52:44 +00:00
op_array - > scope = ce ;
2014-08-25 19:21:16 +00:00
op_array - > function_name = zend_string_copy ( name ) ;
2006-05-09 23:53:23 +00:00
2014-12-24 12:04:51 +00:00
lcname = zend_string_tolower ( name ) ;
2014-12-13 22:06:14 +00:00
lcname = zend_new_interned_string ( lcname ) ;
2013-01-28 02:02:51 +00:00
2014-07-19 10:52:44 +00:00
if ( zend_hash_add_ptr ( & ce - > function_table , lcname , op_array ) = = NULL ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot redeclare %s::%s() " ,
2015-06-30 10:59:27 +00:00
ZSTR_VAL ( ce - > name ) , ZSTR_VAL ( name ) ) ;
2009-11-14 19:17:22 +00:00
}
2002-12-06 17:09:44 +00:00
2020-07-20 12:56:48 +00:00
zend_add_magic_method ( ce , ( zend_function * ) op_array , lcname ) ;
if ( zend_string_equals_literal ( lcname , ZEND_TOSTRING_FUNC_NAME ) ) {
2020-02-06 09:27:30 +00:00
add_stringable_interface ( ce ) ;
2002-01-05 15:18:30 +00:00
}
1999-04-07 18:10:10 +00:00
2020-04-27 10:33:29 +00:00
return lcname ;
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2019-12-11 13:38:48 +00:00
static void zend_begin_func_decl ( znode * result , zend_op_array * op_array , zend_ast_decl * decl , zend_bool toplevel ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2016-05-04 16:43:55 +00:00
zend_string * unqualified_name , * name , * lcname , * key ;
2014-07-21 13:22:13 +00:00
zend_op * opline ;
2013-01-28 02:02:51 +00:00
2016-05-04 16:42:16 +00:00
unqualified_name = decl - > name ;
op_array - > function_name = name = zend_prefix_with_ns ( unqualified_name ) ;
2014-12-24 12:04:51 +00:00
lcname = zend_string_tolower ( name ) ;
2013-01-28 02:02:51 +00:00
2015-04-20 18:16:58 +00:00
if ( FC ( imports_function ) ) {
2020-04-24 21:00:13 +00:00
zend_string * import_name =
zend_hash_find_ptr_lc ( FC ( imports_function ) , unqualified_name ) ;
2015-02-11 08:03:48 +00:00
if ( import_name & & ! zend_string_equals_ci ( lcname , import_name ) ) {
2015-04-01 10:32:23 +00:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot declare function %s "
2015-06-30 10:59:27 +00:00
" because the name is already in use " , ZSTR_VAL ( name ) ) ;
2014-07-21 13:22:13 +00:00
}
2011-05-19 23:20:47 +00:00
}
2003-06-09 13:51:53 +00:00
2019-01-30 12:35:36 +00:00
if ( zend_string_equals_literal ( lcname , " __autoload " ) ) {
zend_error_noreturn ( E_COMPILE_ERROR ,
" __autoload() is no longer supported, use spl_autoload_register() instead " ) ;
2014-07-21 13:22:13 +00:00
}
1999-04-07 18:10:10 +00:00
2018-07-04 21:20:29 +00:00
if ( zend_string_equals_literal_ci ( unqualified_name , " assert " ) ) {
2019-01-29 10:04:20 +00:00
zend_error ( E_COMPILE_ERROR ,
" Defining a custom assert() function is not allowed, "
2018-07-04 21:20:29 +00:00
" as the function has special semantics " ) ;
}
2018-08-24 12:18:38 +00:00
zend_register_seen_symbol ( lcname , ZEND_SYMBOL_FUNCTION ) ;
if ( toplevel ) {
if ( UNEXPECTED ( zend_hash_add_ptr ( CG ( function_table ) , lcname , op_array ) = = NULL ) ) {
do_bind_function_error ( lcname , op_array , 1 ) ;
}
zend_string_release_ex ( lcname , 0 ) ;
2019-12-11 13:38:48 +00:00
return ;
2018-08-24 12:18:38 +00:00
}
2020-05-19 08:13:25 +00:00
/* Generate RTD keys until we find one that isn't in use yet. */
key = NULL ;
do {
zend_tmp_string_release ( key ) ;
key = zend_build_runtime_definition_key ( lcname , decl - > start_lineno ) ;
} while ( ! zend_hash_add_ptr ( CG ( function_table ) , key , op_array ) ) ;
2019-12-11 13:38:48 +00:00
2014-07-21 13:22:13 +00:00
if ( op_array - > fn_flags & ZEND_ACC_CLOSURE ) {
2014-12-13 22:06:14 +00:00
opline = zend_emit_op_tmp ( result , ZEND_DECLARE_LAMBDA_FUNCTION , NULL , NULL ) ;
2019-07-19 07:43:49 +00:00
opline - > extended_value = zend_alloc_cache_slot ( ) ;
2015-12-20 12:42:26 +00:00
opline - > op1_type = IS_CONST ;
LITERAL_STR ( opline - > op1 , key ) ;
2014-07-21 13:22:13 +00:00
} else {
2018-12-07 14:47:56 +00:00
opline = get_next_op ( ) ;
2014-07-21 13:22:13 +00:00
opline - > opcode = ZEND_DECLARE_FUNCTION ;
opline - > op1_type = IS_CONST ;
2015-12-20 12:42:26 +00:00
LITERAL_STR ( opline - > op1 , zend_string_copy ( lcname ) ) ;
/* RTD key is placed after lcname literal in op1 */
2018-12-07 14:47:56 +00:00
zend_add_literal_string ( & key ) ;
2014-07-21 13:22:13 +00:00
}
2018-05-28 13:27:12 +00:00
zend_string_release_ex ( lcname , 0 ) ;
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2018-08-24 12:18:38 +00:00
void zend_compile_func_decl ( znode * result , zend_ast * ast , zend_bool toplevel ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-21 13:38:21 +00:00
zend_ast_decl * decl = ( zend_ast_decl * ) ast ;
zend_ast * params_ast = decl - > child [ 0 ] ;
zend_ast * uses_ast = decl - > child [ 1 ] ;
zend_ast * stmt_ast = decl - > child [ 2 ] ;
2015-01-08 20:40:36 +00:00
zend_ast * return_type_ast = decl - > child [ 3 ] ;
2014-07-21 13:38:21 +00:00
zend_bool is_method = decl - > kind = = ZEND_AST_METHOD ;
2020-04-27 10:33:29 +00:00
zend_string * method_lcname ;
1999-04-07 18:10:10 +00:00
2019-02-12 16:34:55 +00:00
zend_class_entry * orig_class_entry = CG ( active_class_entry ) ;
2014-07-18 12:57:00 +00:00
zend_op_array * orig_op_array = CG ( active_op_array ) ;
2014-07-22 14:55:34 +00:00
zend_op_array * op_array = zend_arena_alloc ( & CG ( arena ) , sizeof ( zend_op_array ) ) ;
2015-04-20 15:39:32 +00:00
zend_oparray_context orig_oparray_context ;
2019-06-12 08:50:58 +00:00
closure_info info ;
memset ( & info , 0 , sizeof ( closure_info ) ) ;
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
init_op_array ( op_array , ZEND_USER_FUNCTION , INITIAL_OP_ARRAY_SIZE ) ;
1999-04-07 18:10:10 +00:00
2019-06-24 17:32:27 +00:00
if ( CG ( compiler_options ) & ZEND_COMPILE_PRELOAD ) {
op_array - > fn_flags | = ZEND_ACC_PRELOADED ;
ZEND_MAP_PTR_NEW ( op_array - > run_time_cache ) ;
ZEND_MAP_PTR_NEW ( op_array - > static_variables_ptr ) ;
} else {
ZEND_MAP_PTR_INIT ( op_array - > run_time_cache , zend_arena_alloc ( & CG ( arena ) , sizeof ( void * ) ) ) ;
ZEND_MAP_PTR_SET ( op_array - > run_time_cache , NULL ) ;
}
2018-10-17 12:52:50 +00:00
2015-03-19 17:30:11 +00:00
op_array - > fn_flags | = ( orig_op_array - > fn_flags & ZEND_ACC_STRICT_TYPES ) ;
2014-07-21 13:38:21 +00:00
op_array - > fn_flags | = decl - > flags ;
op_array - > line_start = decl - > start_lineno ;
op_array - > line_end = decl - > end_lineno ;
if ( decl - > doc_comment ) {
2014-08-25 19:21:16 +00:00
op_array - > doc_comment = zend_string_copy ( decl - > doc_comment ) ;
2014-07-18 13:23:16 +00:00
}
2020-05-24 18:57:00 +00:00
2019-05-02 12:57:16 +00:00
if ( decl - > kind = = ZEND_AST_CLOSURE | | decl - > kind = = ZEND_AST_ARROW_FUNC ) {
2015-10-06 20:59:36 +00:00
op_array - > fn_flags | = ZEND_ACC_CLOSURE ;
2014-07-18 11:15:58 +00:00
}
2006-03-15 09:04:36 +00:00
2014-07-19 10:52:44 +00:00
if ( is_method ) {
2014-07-21 13:38:21 +00:00
zend_bool has_body = stmt_ast ! = NULL ;
2020-04-27 10:33:29 +00:00
method_lcname = zend_begin_method_decl ( op_array , decl - > name , has_body ) ;
2014-07-19 10:52:44 +00:00
} else {
2019-12-11 13:38:48 +00:00
zend_begin_func_decl ( result , op_array , decl , toplevel ) ;
2019-05-02 12:57:16 +00:00
if ( decl - > kind = = ZEND_AST_ARROW_FUNC ) {
find_implicit_binds ( & info , params_ast , stmt_ast ) ;
compile_implicit_lexical_binds ( & info , result , op_array ) ;
} else if ( uses_ast ) {
2018-08-20 13:10:09 +00:00
zend_compile_closure_binding ( result , op_array , uses_ast ) ;
2015-12-29 10:16:08 +00:00
}
2006-03-15 09:04:36 +00:00
}
2014-07-15 22:06:41 +00:00
CG ( active_op_array ) = op_array ;
2015-07-14 00:37:35 +00:00
2020-05-24 18:57:00 +00:00
if ( decl - > child [ 4 ] ) {
int target = ZEND_ATTRIBUTE_TARGET_FUNCTION ;
if ( is_method ) {
target = ZEND_ATTRIBUTE_TARGET_METHOD ;
}
zend_compile_attributes ( & op_array - > attributes , decl - > child [ 4 ] , 0 , target ) ;
}
2019-02-12 16:34:55 +00:00
/* Do not leak the class scope into free standing functions, even if they are dynamically
* defined inside a class method . This is necessary for correct handling of magic constants .
* For example __CLASS__ should always be " " inside a free standing function . */
if ( decl - > kind = = ZEND_AST_FUNC_DECL ) {
CG ( active_class_entry ) = NULL ;
}
2018-10-19 10:22:29 +00:00
if ( toplevel ) {
op_array - > fn_flags | = ZEND_ACC_TOP_LEVEL ;
}
2015-04-20 15:39:32 +00:00
zend_oparray_context_begin ( & orig_oparray_context ) ;
2014-07-15 22:06:41 +00:00
2019-02-19 08:08:38 +00:00
if ( CG ( compiler_options ) & ZEND_COMPILE_EXTENDED_STMT ) {
2014-12-13 22:06:14 +00:00
zend_op * opline_ext = zend_emit_op ( NULL , ZEND_EXT_NOP , NULL , NULL ) ;
2014-07-21 13:38:21 +00:00
opline_ext - > lineno = decl - > start_lineno ;
2007-09-28 19:52:53 +00:00
}
2014-07-15 22:06:41 +00:00
2015-07-10 00:31:52 +00:00
{
/* Push a separator to the loop variable stack */
2015-07-10 11:30:25 +00:00
zend_loop_var dummy_var ;
dummy_var . opcode = ZEND_RETURN ;
2015-07-10 00:31:52 +00:00
zend_stack_push ( & CG ( loop_var_stack ) , ( void * ) & dummy_var ) ;
}
2020-01-13 16:06:26 +00:00
zend_compile_params ( params_ast , return_type_ast ,
2020-06-18 12:24:27 +00:00
is_method & & zend_string_equals_literal ( method_lcname , ZEND_TOSTRING_FUNC_NAME ) ? IS_STRING : 0 ) ;
2016-05-12 22:40:15 +00:00
if ( CG ( active_op_array ) - > fn_flags & ZEND_ACC_GENERATOR ) {
zend_mark_function_as_generator ( ) ;
zend_emit_op ( NULL , ZEND_GENERATOR_CREATE , NULL , NULL ) ;
}
2019-05-02 12:57:16 +00:00
if ( decl - > kind = = ZEND_AST_ARROW_FUNC ) {
zend_compile_implicit_closure_uses ( & info ) ;
zend_hash_destroy ( & info . uses ) ;
} else if ( uses_ast ) {
2014-12-13 22:06:14 +00:00
zend_compile_closure_uses ( uses_ast ) ;
2008-11-04 15:58:55 +00:00
}
2014-12-13 22:06:14 +00:00
zend_compile_stmt ( stmt_ast ) ;
2008-11-04 15:58:55 +00:00
2014-07-19 10:52:44 +00:00
if ( is_method ) {
2020-07-20 09:05:33 +00:00
CG ( zend_lineno ) = decl - > start_lineno ;
2014-07-19 10:52:44 +00:00
zend_check_magic_method_implementation (
2020-04-27 10:33:29 +00:00
CG ( active_class_entry ) , ( zend_function * ) op_array , method_lcname , E_COMPILE_ERROR ) ;
zend_string_release_ex ( method_lcname , 0 ) ;
2014-07-19 10:52:44 +00:00
}
2008-11-11 19:45:29 +00:00
2015-07-31 00:44:42 +00:00
/* put the implicit return on the really last line */
CG ( zend_lineno ) = decl - > end_lineno ;
2019-02-19 08:08:38 +00:00
zend_do_extended_stmt ( ) ;
2015-11-12 13:59:44 +00:00
zend_emit_final_return ( 0 ) ;
2008-11-11 19:45:29 +00:00
2014-12-13 22:06:14 +00:00
pass_two ( CG ( active_op_array ) ) ;
2015-04-20 15:39:32 +00:00
zend_oparray_context_end ( & orig_oparray_context ) ;
2008-11-11 19:45:29 +00:00
2015-07-10 00:31:52 +00:00
/* Pop the loop variable stack separator */
zend_stack_del_top ( & CG ( loop_var_stack ) ) ;
2014-07-18 10:58:24 +00:00
CG ( active_op_array ) = orig_op_array ;
2019-02-12 16:34:55 +00:00
CG ( active_class_entry ) = orig_class_entry ;
2014-07-18 10:58:24 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2013-01-28 02:02:51 +00:00
2020-05-24 18:57:00 +00:00
void zend_compile_prop_decl ( zend_ast * ast , zend_ast * type_ast , uint32_t flags , zend_ast * attr_ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-27 20:26:06 +00:00
zend_ast_list * list = zend_ast_get_list ( ast ) ;
2014-07-19 12:54:56 +00:00
zend_class_entry * ce = CG ( active_class_entry ) ;
2014-08-25 19:21:16 +00:00
uint32_t i , children = list - > children ;
2008-11-04 15:58:55 +00:00
2014-07-19 12:54:56 +00:00
if ( ce - > ce_flags & ZEND_ACC_INTERFACE ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Interfaces may not include member variables " ) ;
1999-04-07 18:10:10 +00:00
}
2014-07-19 12:54:56 +00:00
if ( flags & ZEND_ACC_ABSTRACT ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Properties cannot be declared abstract " ) ;
}
2014-06-30 11:43:45 +00:00
2014-07-30 17:12:48 +00:00
for ( i = 0 ; i < children ; + + i ) {
2020-05-24 18:57:00 +00:00
zend_property_info * info ;
2014-07-27 20:26:06 +00:00
zend_ast * prop_ast = list - > child [ i ] ;
2014-07-19 12:54:56 +00:00
zend_ast * name_ast = prop_ast - > child [ 0 ] ;
zend_ast * value_ast = prop_ast - > child [ 1 ] ;
2015-10-06 20:32:23 +00:00
zend_ast * doc_comment_ast = prop_ast - > child [ 2 ] ;
2017-10-31 22:10:21 +00:00
zend_string * name = zval_make_interned_string ( zend_ast_get_zval ( name_ast ) ) ;
2015-10-06 20:32:23 +00:00
zend_string * doc_comment = NULL ;
2014-07-19 12:54:56 +00:00
zval value_zv ;
2019-09-20 15:01:19 +00:00
zend_type type = ZEND_TYPE_INIT_NONE ( 0 ) ;
2019-01-07 11:28:51 +00:00
if ( type_ast ) {
2019-09-25 11:21:13 +00:00
type = zend_compile_typename ( type_ast , /* force_allow_null */ 0 , /* use_arena */ 1 ) ;
2019-01-07 11:28:51 +00:00
2019-09-20 15:01:19 +00:00
if ( ZEND_TYPE_FULL_MASK ( type ) & ( MAY_BE_VOID | MAY_BE_CALLABLE ) ) {
2019-09-19 10:11:29 +00:00
zend_string * str = zend_type_to_string ( type ) ;
2019-01-07 11:28:51 +00:00
zend_error_noreturn ( E_COMPILE_ERROR ,
" Property %s::$%s cannot have type %s " ,
2019-09-19 10:11:29 +00:00
ZSTR_VAL ( ce - > name ) , ZSTR_VAL ( name ) , ZSTR_VAL ( str ) ) ;
2019-01-07 11:28:51 +00:00
}
}
1999-04-07 18:10:10 +00:00
2015-10-06 20:32:23 +00:00
/* Doc comment has been appended as last element in ZEND_AST_PROP_ELEM ast */
if ( doc_comment_ast ) {
doc_comment = zend_string_copy ( zend_ast_get_str ( doc_comment_ast ) ) ;
}
2014-07-19 12:54:56 +00:00
if ( flags & ZEND_ACC_FINAL ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot declare property %s::$%s final, "
" the final modifier is allowed only for methods and classes " ,
2015-06-30 10:59:27 +00:00
ZSTR_VAL ( ce - > name ) , ZSTR_VAL ( name ) ) ;
2014-07-19 12:54:56 +00:00
}
1999-04-07 18:10:10 +00:00
2014-07-19 12:54:56 +00:00
if ( zend_hash_exists ( & ce - > properties_info , name ) ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot redeclare %s::$%s " ,
2015-06-30 10:59:27 +00:00
ZSTR_VAL ( ce - > name ) , ZSTR_VAL ( name ) ) ;
2014-07-19 12:54:56 +00:00
}
2014-04-22 15:54:34 +00:00
2014-07-19 12:54:56 +00:00
if ( value_ast ) {
2014-12-13 22:06:14 +00:00
zend_const_expr_to_zval ( & value_zv , value_ast ) ;
2019-01-07 11:28:51 +00:00
2019-09-23 14:12:18 +00:00
if ( ZEND_TYPE_IS_SET ( type ) & & ! Z_CONSTANT ( value_zv )
& & ! zend_is_valid_default_value ( type , & value_zv ) ) {
zend_string * str = zend_type_to_string ( type ) ;
2019-01-07 11:28:51 +00:00
if ( Z_TYPE ( value_zv ) = = IS_NULL ) {
zend_error_noreturn ( E_COMPILE_ERROR ,
2019-09-23 14:12:18 +00:00
" Default value for property of type %s may not be null. "
" Use the nullable type ?%s to allow null default value " ,
ZSTR_VAL ( str ) , ZSTR_VAL ( str ) ) ;
} else {
2019-01-07 11:28:51 +00:00
zend_error_noreturn ( E_COMPILE_ERROR ,
2019-09-23 14:12:18 +00:00
" Cannot use %s as default value for property %s::$%s of type %s " ,
2020-05-13 12:55:08 +00:00
zend_zval_type_name ( & value_zv ) ,
2019-09-23 14:12:18 +00:00
ZSTR_VAL ( ce - > name ) , ZSTR_VAL ( name ) , ZSTR_VAL ( str ) ) ;
2019-01-07 11:28:51 +00:00
}
}
} else if ( ! ZEND_TYPE_IS_SET ( type ) ) {
2014-07-19 12:54:56 +00:00
ZVAL_NULL ( & value_zv ) ;
2019-01-07 11:28:51 +00:00
} else {
ZVAL_UNDEF ( & value_zv ) ;
1999-04-07 18:10:10 +00:00
}
2020-05-24 18:57:00 +00:00
info = zend_declare_typed_property ( ce , name , & value_zv , flags , doc_comment , type ) ;
if ( attr_ast ) {
zend_compile_attributes ( & info - > attributes , attr_ast , 0 , ZEND_ATTRIBUTE_TARGET_PROPERTY ) ;
}
1999-04-07 18:10:10 +00:00
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2020-07-06 16:23:27 +00:00
void zend_compile_prop_group ( zend_ast * ast ) /* { { { */
2019-01-07 11:28:51 +00:00
{
2020-07-06 16:23:27 +00:00
zend_ast * type_ast = ast - > child [ 0 ] ;
zend_ast * prop_ast = ast - > child [ 1 ] ;
zend_ast * attr_ast = ast - > child [ 2 ] ;
2019-01-07 11:28:51 +00:00
2020-05-24 18:57:00 +00:00
if ( attr_ast & & zend_ast_get_list ( prop_ast ) - > children > 1 ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot apply attributes to a group of properties " ) ;
return ;
}
2020-07-06 16:23:27 +00:00
zend_compile_prop_decl ( prop_ast , type_ast , ast - > attr , attr_ast ) ;
2019-01-07 11:28:51 +00:00
}
/* }}} */
2019-03-06 09:42:02 +00:00
static void zend_check_const_and_trait_alias_attr ( uint32_t attr , const char * entity ) /* { { { */
{
if ( attr & ZEND_ACC_STATIC ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use 'static' as %s modifier " , entity ) ;
} else if ( attr & ZEND_ACC_ABSTRACT ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use 'abstract' as %s modifier " , entity ) ;
} else if ( attr & ZEND_ACC_FINAL ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use 'final' as %s modifier " , entity ) ;
}
}
/* }}} */
2020-07-06 16:23:27 +00:00
void zend_compile_class_const_decl ( zend_ast * ast , uint32_t flags , zend_ast * attr_ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-27 20:26:06 +00:00
zend_ast_list * list = zend_ast_get_list ( ast ) ;
2014-07-19 13:13:50 +00:00
zend_class_entry * ce = CG ( active_class_entry ) ;
2020-07-06 16:23:27 +00:00
uint32_t i , children = list - > children ;
2014-05-29 14:21:56 +00:00
2015-03-03 13:28:09 +00:00
if ( ( ce - > ce_flags & ZEND_ACC_TRAIT ) ! = 0 ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Traits cannot have constants " ) ;
return ;
}
2020-07-06 16:23:27 +00:00
for ( i = 0 ; i < children ; + + i ) {
2020-05-24 18:57:00 +00:00
zend_class_constant * c ;
2014-07-27 20:26:06 +00:00
zend_ast * const_ast = list - > child [ i ] ;
2014-07-19 13:13:50 +00:00
zend_ast * name_ast = const_ast - > child [ 0 ] ;
zend_ast * value_ast = const_ast - > child [ 1 ] ;
2015-12-08 09:40:42 +00:00
zend_ast * doc_comment_ast = const_ast - > child [ 2 ] ;
2017-10-31 22:10:21 +00:00
zend_string * name = zval_make_interned_string ( zend_ast_get_zval ( name_ast ) ) ;
2015-12-08 09:40:42 +00:00
zend_string * doc_comment = doc_comment_ast ? zend_string_copy ( zend_ast_get_str ( doc_comment_ast ) ) : NULL ;
2014-07-19 13:13:50 +00:00
zval value_zv ;
2014-05-29 14:21:56 +00:00
2020-07-06 16:23:27 +00:00
if ( UNEXPECTED ( flags & ( ZEND_ACC_STATIC | ZEND_ACC_ABSTRACT | ZEND_ACC_FINAL ) ) ) {
zend_check_const_and_trait_alias_attr ( flags , " constant " ) ;
2015-05-25 20:58:30 +00:00
}
2014-12-13 22:06:14 +00:00
zend_const_expr_to_zval ( & value_zv , value_ast ) ;
2020-07-06 16:23:27 +00:00
c = zend_declare_class_constant_ex ( ce , name , & value_zv , flags , doc_comment ) ;
2020-05-24 18:57:00 +00:00
if ( attr_ast ) {
zend_compile_attributes ( & c - > attributes , attr_ast , 0 , ZEND_ATTRIBUTE_TARGET_CLASS_CONST ) ;
}
2014-05-29 14:21:56 +00:00
}
2014-04-22 15:54:34 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-04-22 15:54:34 +00:00
2020-07-06 16:23:27 +00:00
void zend_compile_class_const_group ( zend_ast * ast ) /* { { { */
{
zend_ast * const_ast = ast - > child [ 0 ] ;
zend_ast * attr_ast = ast - > child [ 1 ] ;
if ( attr_ast & & zend_ast_get_list ( const_ast ) - > children > 1 ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot apply attributes to a group of constants " ) ;
return ;
}
zend_compile_class_const_decl ( const_ast , ast - > attr , attr_ast ) ;
}
/* }}} */
2018-07-11 15:56:10 +00:00
static void zend_compile_method_ref ( zend_ast * ast , zend_trait_method_reference * method_ref ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-19 20:39:01 +00:00
zend_ast * class_ast = ast - > child [ 0 ] ;
zend_ast * method_ast = ast - > child [ 1 ] ;
1999-04-07 18:10:10 +00:00
2014-08-25 19:21:16 +00:00
method_ref - > method_name = zend_string_copy ( zend_ast_get_str ( method_ast ) ) ;
2002-03-17 19:13:46 +00:00
2014-07-19 20:39:01 +00:00
if ( class_ast ) {
2020-01-13 10:34:04 +00:00
method_ref - > class_name = zend_resolve_const_class_name_reference ( class_ast , " trait name " ) ;
2014-07-19 20:39:01 +00:00
} else {
method_ref - > class_name = NULL ;
1999-04-07 18:10:10 +00:00
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
static void zend_compile_trait_precedence ( zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-19 20:39:01 +00:00
zend_ast * method_ref_ast = ast - > child [ 0 ] ;
zend_ast * insteadof_ast = ast - > child [ 1 ] ;
2018-07-11 15:56:10 +00:00
zend_ast_list * insteadof_list = zend_ast_get_list ( insteadof_ast ) ;
uint32_t i ;
zend_trait_precedence * precedence = emalloc ( sizeof ( zend_trait_precedence ) + ( insteadof_list - > children - 1 ) * sizeof ( zend_string * ) ) ;
zend_compile_method_ref ( method_ref_ast , & precedence - > trait_method ) ;
precedence - > num_excludes = insteadof_list - > children ;
2015-01-03 09:22:58 +00:00
2018-07-11 15:56:10 +00:00
for ( i = 0 ; i < insteadof_list - > children ; + + i ) {
zend_ast * name_ast = insteadof_list - > child [ i ] ;
2020-01-13 10:34:04 +00:00
precedence - > exclude_class_names [ i ] =
zend_resolve_const_class_name_reference ( name_ast , " trait name " ) ;
2018-07-11 15:56:10 +00:00
}
2014-07-19 20:39:01 +00:00
2014-12-13 22:06:14 +00:00
zend_add_to_list ( & CG ( active_class_entry ) - > trait_precedences , precedence ) ;
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
static void zend_compile_trait_alias ( zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-19 20:39:01 +00:00
zend_ast * method_ref_ast = ast - > child [ 0 ] ;
zend_ast * alias_ast = ast - > child [ 1 ] ;
2014-08-25 19:21:16 +00:00
uint32_t modifiers = ast - > attr ;
2014-07-19 20:39:01 +00:00
zend_trait_alias * alias ;
2019-03-06 09:42:02 +00:00
zend_check_const_and_trait_alias_attr ( modifiers , " method " ) ;
2014-07-19 20:39:01 +00:00
alias = emalloc ( sizeof ( zend_trait_alias ) ) ;
2018-07-11 15:56:10 +00:00
zend_compile_method_ref ( method_ref_ast , & alias - > trait_method ) ;
2014-07-19 20:39:01 +00:00
alias - > modifiers = modifiers ;
if ( alias_ast ) {
2014-08-25 19:21:16 +00:00
alias - > alias = zend_string_copy ( zend_ast_get_str ( alias_ast ) ) ;
2014-07-19 20:39:01 +00:00
} else {
alias - > alias = NULL ;
}
2014-12-13 22:06:14 +00:00
zend_add_to_list ( & CG ( active_class_entry ) - > trait_aliases , alias ) ;
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_use_trait ( zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-27 20:26:06 +00:00
zend_ast_list * traits = zend_ast_get_list ( ast - > child [ 0 ] ) ;
zend_ast_list * adaptations = ast - > child [ 1 ] ? zend_ast_get_list ( ast - > child [ 1 ] ) : NULL ;
2014-07-19 20:39:01 +00:00
zend_class_entry * ce = CG ( active_class_entry ) ;
2014-08-25 19:21:16 +00:00
uint32_t i ;
1999-04-07 18:10:10 +00:00
2018-08-22 23:02:26 +00:00
ce - > trait_names = erealloc ( ce - > trait_names , sizeof ( zend_class_name ) * ( ce - > num_traits + traits - > children ) ) ;
2014-07-27 20:26:06 +00:00
for ( i = 0 ; i < traits - > children ; + + i ) {
zend_ast * trait_ast = traits - > child [ i ] ;
2014-07-19 20:39:01 +00:00
if ( ce - > ce_flags & ZEND_ACC_INTERFACE ) {
2020-01-13 11:44:16 +00:00
zend_string * name = zend_ast_get_str ( trait_ast ) ;
2014-07-19 20:39:01 +00:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use traits inside of interfaces. "
2015-06-30 10:59:27 +00:00
" %s is used in %s " , ZSTR_VAL ( name ) , ZSTR_VAL ( ce - > name ) ) ;
1999-04-07 18:10:10 +00:00
}
2014-07-19 20:39:01 +00:00
2020-01-13 11:44:16 +00:00
ce - > trait_names [ ce - > num_traits ] . name =
zend_resolve_const_class_name_reference ( trait_ast , " trait name " ) ;
2018-08-22 23:02:26 +00:00
ce - > trait_names [ ce - > num_traits ] . lc_name = zend_string_tolower ( ce - > trait_names [ ce - > num_traits ] . name ) ;
2014-07-19 20:39:01 +00:00
ce - > num_traits + + ;
1999-04-07 18:10:10 +00:00
}
2001-07-16 15:48:31 +00:00
2014-07-27 20:26:06 +00:00
if ( ! adaptations ) {
2014-07-19 20:39:01 +00:00
return ;
}
2014-07-27 20:26:06 +00:00
for ( i = 0 ; i < adaptations - > children ; + + i ) {
zend_ast * adaptation_ast = adaptations - > child [ i ] ;
2014-07-19 20:39:01 +00:00
switch ( adaptation_ast - > kind ) {
case ZEND_AST_TRAIT_PRECEDENCE :
2014-12-13 22:06:14 +00:00
zend_compile_trait_precedence ( adaptation_ast ) ;
2014-07-19 20:39:01 +00:00
break ;
case ZEND_AST_TRAIT_ALIAS :
2014-12-13 22:06:14 +00:00
zend_compile_trait_alias ( adaptation_ast ) ;
2014-07-19 20:39:01 +00:00
break ;
EMPTY_SWITCH_DEFAULT_CASE ( )
}
2001-07-16 15:48:31 +00:00
}
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2018-08-24 12:40:53 +00:00
void zend_compile_implements ( zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-27 20:26:06 +00:00
zend_ast_list * list = zend_ast_get_list ( ast ) ;
2018-08-23 14:16:28 +00:00
zend_class_entry * ce = CG ( active_class_entry ) ;
zend_class_name * interface_names ;
2014-08-25 19:21:16 +00:00
uint32_t i ;
2018-08-23 14:16:28 +00:00
interface_names = emalloc ( sizeof ( zend_class_name ) * list - > children ) ;
2014-07-27 20:26:06 +00:00
for ( i = 0 ; i < list - > children ; + + i ) {
zend_ast * class_ast = list - > child [ i ] ;
2020-01-13 10:34:04 +00:00
interface_names [ i ] . name =
zend_resolve_const_class_name_reference ( class_ast , " interface name " ) ;
2018-08-23 14:16:28 +00:00
interface_names [ i ] . lc_name = zend_string_tolower ( interface_names [ i ] . name ) ;
2014-07-21 15:14:01 +00:00
}
2018-08-23 14:16:28 +00:00
ce - > num_interfaces = list - > children ;
ce - > interface_names = interface_names ;
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2020-02-06 10:13:13 +00:00
static zend_string * zend_generate_anon_class_name ( zend_ast_decl * decl )
2015-04-26 13:24:13 +00:00
{
2015-05-24 19:50:46 +00:00
zend_string * filename = CG ( active_op_array ) - > filename ;
2020-02-06 10:13:13 +00:00
uint32_t start_lineno = decl - > start_lineno ;
/* Use parent or first interface as prefix. */
zend_string * prefix = ZSTR_KNOWN ( ZEND_STR_CLASS ) ;
if ( decl - > child [ 0 ] ) {
prefix = zend_resolve_const_class_name_reference ( decl - > child [ 0 ] , " class name " ) ;
} else if ( decl - > child [ 1 ] ) {
zend_ast_list * list = zend_ast_get_list ( decl - > child [ 1 ] ) ;
prefix = zend_resolve_const_class_name_reference ( list - > child [ 0 ] , " interface name " ) ;
}
zend_string * result = zend_strpprintf ( 0 , " %s@anonymous%c%s:% " PRIu32 " $% " PRIx32 ,
ZSTR_VAL ( prefix ) , ' \0 ' , ZSTR_VAL ( filename ) , start_lineno , CG ( rtd_key_counter ) + + ) ;
zend_string_release ( prefix ) ;
2015-04-27 10:08:22 +00:00
return zend_new_interned_string ( result ) ;
2015-04-26 13:24:13 +00:00
}
2020-04-24 10:04:54 +00:00
void zend_compile_class_decl ( znode * result , zend_ast * ast , zend_bool toplevel ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-21 14:34:45 +00:00
zend_ast_decl * decl = ( zend_ast_decl * ) ast ;
zend_ast * extends_ast = decl - > child [ 0 ] ;
zend_ast * implements_ast = decl - > child [ 1 ] ;
zend_ast * stmt_ast = decl - > child [ 2 ] ;
2016-05-04 16:42:16 +00:00
zend_string * name , * lcname ;
2014-07-22 14:55:34 +00:00
zend_class_entry * ce = zend_arena_alloc ( & CG ( arena ) , sizeof ( zend_class_entry ) ) ;
2014-07-21 14:34:45 +00:00
zend_op * opline ;
2015-04-26 14:03:58 +00:00
zend_class_entry * original_ce = CG ( active_class_entry ) ;
2015-04-26 13:28:55 +00:00
2015-06-13 02:56:30 +00:00
if ( EXPECTED ( ( decl - > flags & ZEND_ACC_ANON_CLASS ) = = 0 ) ) {
2016-05-04 16:42:16 +00:00
zend_string * unqualified_name = decl - > name ;
2015-06-13 02:49:07 +00:00
if ( CG ( active_class_entry ) ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Class declarations may not be nested " ) ;
}
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2016-05-04 16:42:16 +00:00
zend_assert_valid_class_name ( unqualified_name ) ;
name = zend_prefix_with_ns ( unqualified_name ) ;
name = zend_new_interned_string ( name ) ;
lcname = zend_string_tolower ( name ) ;
Implemented Traits for PHP as proposed in the RFC [TRAITS]
# RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior
# Ok, here we go, I guess that will result in more discussion, which is fine
# by me. But now, the patch is here, and properly archived.
#
# See below a list of notes to the patch, it also includes a list of
# points which should be fixed
#
# Internals of the Traits Patch
# -----------------------------
#
# Open TODOs
# """"""""""
#
# - Reflection API
# - support for traits for internal classes
# - currently destroy_zend_class does not handle that case
#
# Introduced Structures
# """""""""""""""""""""
#
# Data structures to encode the composition information specified in the
# source:
# - zend_trait_method_reference
# - zend_trait_precedence
# - zend_trait_alias
#
# Changes
# """""""
#
# zend_class_entry
# - uses NULL terminated lists of pointers for
# - trait_aliases
# - trait_precedences
# - do you prefer an explicit counter?
# - the information is only necessary during class composition
# but might be interesting for reflection
# - did not want to blow up class further with not really necessary length counters
#
# added keywords
# - trait
# - insteadof
#
# Added opcodes
# ZEND_ADD_TRAIT
# - similar to ZEND_ADD_INTERFACE
# - adds the trait to the list of traits of a class, no actual composition done
# ZEND_BIND_TRAITS
# - emitted in zend_do_end_class_declaration
# - concludes the class definition and will initiate the trait composition
# when the class definition is encountered during runtime
#
# Added Flags
# ZEND_ACC_TRAIT = 0x120
# ZEND_ACC_IMPLEMENT_TRAITS = 0x400000
# ZEND_FETCH_CLASS_TRAIT = 14
#
# zend_vm_execute.h
# - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER,
# ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective
#
# zend_compile.c
# - refactored do_inherit_method_check
# split into do_inherit_method_check and do_inheritance_check_on_method
# - added helper functions use a '_' as prefix and are not mentioned in the
# headers
# - _copy_functions
# prepare hash-maps of functions which should be merged into a class
# here the aliases are handled
# - _merge_functions
# builds a hash-table of the methods which need to be added to a class
# does the conflict detection
# - reused php_runkit_function_copy_ctor
# - it is not identical with the original code anymore, needed to update it
# think I fixed some bugs, not sure whether all have been reported back to runkit
# - has to be renamed, left the name for the moment, to make its origin obvious
# - here might be optimization potential
# - not sure whether everything needs to be copied
# - copying the literals might be broken
# - added it since the literals array is freed by efree and gave problems
# with doubled frees
# - all immutable parts of the zend_op array should not be copied
# - am not sure which parts are immutable
# - and not sure how to avoid doubled frees on the same arrays on shutdown
# - _merge_functions_to_class
# does the final merging with the target class to handle inherited
# and overridden methods
# - small helper for NULL terminated lists
# zend_init_list, zend_add_to_list
#
# zend_language_parser.y
# - reused class definition for traits
# - there should be something with regard to properties
# - if they get explicitly defined, it might be worthwhile to
# check that there are no collisions with other traits in a composition
# (however, I would not introduce elaborate language features to control that
# but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2015-06-13 02:49:07 +00:00
if ( FC ( imports ) ) {
2020-04-24 21:00:13 +00:00
zend_string * import_name =
zend_hash_find_ptr_lc ( FC ( imports ) , unqualified_name ) ;
2016-05-04 16:42:16 +00:00
if ( import_name & & ! zend_string_equals_ci ( lcname , import_name ) ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot declare class %s "
" because the name is already in use " , ZSTR_VAL ( name ) ) ;
}
2015-06-13 02:49:07 +00:00
}
2016-10-06 21:09:41 +00:00
zend_register_seen_symbol ( lcname , ZEND_SYMBOL_CLASS ) ;
2002-11-10 17:50:27 +00:00
} else {
2020-05-19 08:13:25 +00:00
/* Find an anon class name that is not in use yet. */
name = NULL ;
lcname = NULL ;
do {
zend_tmp_string_release ( name ) ;
zend_tmp_string_release ( lcname ) ;
2020-05-20 09:24:37 +00:00
name = zend_generate_anon_class_name ( decl ) ;
2020-05-19 08:13:25 +00:00
lcname = zend_string_tolower ( name ) ;
} while ( zend_hash_exists ( CG ( class_table ) , lcname ) ) ;
2014-07-21 14:34:45 +00:00
}
2015-07-21 18:34:06 +00:00
lcname = zend_new_interned_string ( lcname ) ;
2014-07-21 14:34:45 +00:00
ce - > type = ZEND_USER_CLASS ;
2014-07-24 19:07:37 +00:00
ce - > name = name ;
2015-04-26 13:12:10 +00:00
zend_initialize_class_data ( ce , 1 ) ;
2014-07-21 14:34:45 +00:00
2019-06-24 17:32:27 +00:00
if ( CG ( compiler_options ) & ZEND_COMPILE_PRELOAD ) {
ce - > ce_flags | = ZEND_ACC_PRELOADED ;
ZEND_MAP_PTR_NEW ( ce - > static_members_table ) ;
}
2014-07-21 14:34:45 +00:00
ce - > ce_flags | = decl - > flags ;
2020-09-03 09:56:55 +00:00
ce - > info . user . filename = zend_string_copy ( zend_get_compiled_filename ( ) ) ;
2014-07-21 14:34:45 +00:00
ce - > info . user . line_start = decl - > start_lineno ;
ce - > info . user . line_end = decl - > end_lineno ;
2015-06-13 02:49:07 +00:00
2014-07-21 14:34:45 +00:00
if ( decl - > doc_comment ) {
2014-08-25 19:21:16 +00:00
ce - > info . user . doc_comment = zend_string_copy ( decl - > doc_comment ) ;
1999-04-07 18:10:10 +00:00
}
2003-01-19 17:25:39 +00:00
2015-06-13 02:56:30 +00:00
if ( UNEXPECTED ( ( decl - > flags & ZEND_ACC_ANON_CLASS ) ) ) {
2015-06-13 02:49:07 +00:00
/* Serialization is not supported for anonymous classes */
ce - > serialize = zend_class_serialize_deny ;
ce - > unserialize = zend_class_unserialize_deny ;
}
2014-07-21 14:34:45 +00:00
if ( extends_ast ) {
2020-01-13 10:34:04 +00:00
ce - > parent_name =
zend_resolve_const_class_name_reference ( extends_ast , " class name " ) ;
2008-01-23 17:55:55 +00:00
}
2014-07-21 14:34:45 +00:00
CG ( active_class_entry ) = ce ;
2008-07-14 09:49:03 +00:00
2020-05-24 18:57:00 +00:00
if ( decl - > child [ 4 ] ) {
zend_compile_attributes ( & ce - > attributes , decl - > child [ 4 ] , 0 , ZEND_ATTRIBUTE_TARGET_CLASS ) ;
}
2020-02-06 09:27:30 +00:00
if ( implements_ast ) {
zend_compile_implements ( implements_ast ) ;
}
2015-04-26 13:12:10 +00:00
zend_compile_stmt ( stmt_ast ) ;
2014-07-21 14:34:45 +00:00
2015-07-27 22:56:18 +00:00
/* Reset lineno for final opcodes and errors */
CG ( zend_lineno ) = ast - > lineno ;
2018-08-27 13:40:25 +00:00
if ( ( ce - > ce_flags & ( ZEND_ACC_IMPLICIT_ABSTRACT_CLASS | ZEND_ACC_INTERFACE | ZEND_ACC_TRAIT | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS ) ) = = ZEND_ACC_IMPLICIT_ABSTRACT_CLASS ) {
zend_verify_abstract_class ( ce ) ;
2014-06-06 11:04:30 +00:00
}
1999-04-07 18:10:10 +00:00
2015-04-26 14:03:58 +00:00
CG ( active_class_entry ) = original_ce ;
2018-08-24 12:18:38 +00:00
2018-10-17 13:12:46 +00:00
if ( toplevel ) {
ce - > ce_flags | = ZEND_ACC_TOP_LEVEL ;
}
2018-08-24 12:18:38 +00:00
if ( toplevel
/* We currently don't early-bind classes that implement interfaces or use traits */
2020-02-06 09:51:45 +00:00
& & ! ce - > num_interfaces & & ! ce - > num_traits
2019-12-09 14:14:39 +00:00
& & ! ( CG ( compiler_options ) & ZEND_COMPILE_PRELOAD ) ) {
2018-08-24 12:18:38 +00:00
if ( extends_ast ) {
2019-05-24 12:41:38 +00:00
zend_class_entry * parent_ce = zend_lookup_class_ex (
ce - > parent_name , NULL , ZEND_FETCH_CLASS_NO_AUTOLOAD ) ;
2018-08-24 12:18:38 +00:00
if ( parent_ce
2018-09-03 11:50:35 +00:00
& & ( ( parent_ce - > type ! = ZEND_INTERNAL_CLASS ) | | ! ( CG ( compiler_options ) & ZEND_COMPILE_IGNORE_INTERNAL_CLASSES ) )
2019-06-26 23:13:06 +00:00
& & ( ( parent_ce - > type ! = ZEND_USER_CLASS ) | | ! ( CG ( compiler_options ) & ZEND_COMPILE_IGNORE_OTHER_FILES ) | | ( parent_ce - > info . user . filename = = ce - > info . user . filename ) ) ) {
CG ( zend_lineno ) = decl - > end_lineno ;
if ( zend_try_early_bind ( ce , parent_ce , lcname , NULL ) ) {
2018-08-24 12:18:38 +00:00
CG ( zend_lineno ) = ast - > lineno ;
zend_string_release ( lcname ) ;
2020-04-24 10:04:54 +00:00
return ;
2018-08-24 12:18:38 +00:00
}
2019-06-26 23:13:06 +00:00
CG ( zend_lineno ) = ast - > lineno ;
2018-08-24 12:18:38 +00:00
}
2019-03-06 09:42:02 +00:00
} else if ( EXPECTED ( zend_hash_add_ptr ( CG ( class_table ) , lcname , ce ) ! = NULL ) ) {
zend_string_release ( lcname ) ;
zend_build_properties_info_table ( ce ) ;
ce - > ce_flags | = ZEND_ACC_LINKED ;
2020-04-24 10:04:54 +00:00
return ;
2018-08-24 12:18:38 +00:00
}
}
2018-12-07 14:47:56 +00:00
opline = get_next_op ( ) ;
2018-08-24 12:18:38 +00:00
2019-06-25 08:26:29 +00:00
if ( ce - > parent_name ) {
/* Lowercased parent name */
zend_string * lc_parent_name = zend_string_tolower ( ce - > parent_name ) ;
opline - > op2_type = IS_CONST ;
LITERAL_STR ( opline - > op2 , lc_parent_name ) ;
}
2018-08-24 12:18:38 +00:00
opline - > op1_type = IS_CONST ;
LITERAL_STR ( opline - > op1 , lcname ) ;
if ( decl - > flags & ZEND_ACC_ANON_CLASS ) {
2019-05-24 12:28:44 +00:00
opline - > opcode = ZEND_DECLARE_ANON_CLASS ;
2019-07-19 07:43:49 +00:00
opline - > extended_value = zend_alloc_cache_slot ( ) ;
2020-04-24 10:04:54 +00:00
zend_make_var_result ( result , opline ) ;
2018-09-19 09:22:58 +00:00
if ( ! zend_hash_add_ptr ( CG ( class_table ) , lcname , ce ) ) {
2020-05-19 08:13:25 +00:00
/* We checked above that the class name is not used. This really shouldn't happen. */
2019-12-11 16:11:30 +00:00
zend_error_noreturn ( E_ERROR ,
" Runtime definition key collision for %s. This is a bug " , ZSTR_VAL ( name ) ) ;
2018-08-24 12:18:38 +00:00
}
} else {
2020-05-19 08:13:25 +00:00
/* Generate RTD keys until we find one that isn't in use yet. */
zend_string * key = NULL ;
do {
zend_tmp_string_release ( key ) ;
key = zend_build_runtime_definition_key ( lcname , decl - > start_lineno ) ;
} while ( ! zend_hash_add_ptr ( CG ( class_table ) , key , ce ) ) ;
2018-08-24 12:18:38 +00:00
/* RTD key is placed after lcname literal in op1 */
2018-12-07 14:47:56 +00:00
zend_add_literal_string ( & key ) ;
2018-08-24 12:18:38 +00:00
2019-05-24 12:28:44 +00:00
opline - > opcode = ZEND_DECLARE_CLASS ;
if ( extends_ast & & toplevel
2018-08-24 12:18:38 +00:00
& & ( CG ( compiler_options ) & ZEND_COMPILE_DELAYED_BINDING )
/* We currently don't early-bind classes that implement interfaces or use traits */
2020-02-06 09:51:45 +00:00
& & ! ce - > num_interfaces & & ! ce - > num_traits
2019-05-24 12:28:44 +00:00
) {
CG ( active_op_array ) - > fn_flags | = ZEND_ACC_EARLY_BINDING ;
opline - > opcode = ZEND_DECLARE_CLASS_DELAYED ;
2019-07-19 08:46:03 +00:00
opline - > extended_value = zend_alloc_cache_slot ( ) ;
2019-05-24 12:28:44 +00:00
opline - > result_type = IS_UNUSED ;
opline - > result . opline_num = - 1 ;
2018-08-24 12:18:38 +00:00
}
}
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
static HashTable * zend_get_import_ht ( uint32_t type ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-21 21:41:11 +00:00
switch ( type ) {
2016-10-06 21:09:41 +00:00
case ZEND_SYMBOL_CLASS :
2015-04-20 18:16:58 +00:00
if ( ! FC ( imports ) ) {
FC ( imports ) = emalloc ( sizeof ( HashTable ) ) ;
zend_hash_init ( FC ( imports ) , 8 , NULL , str_dtor , 0 ) ;
2014-07-21 21:41:11 +00:00
}
2015-04-20 18:16:58 +00:00
return FC ( imports ) ;
2016-10-06 21:09:41 +00:00
case ZEND_SYMBOL_FUNCTION :
2015-04-20 18:16:58 +00:00
if ( ! FC ( imports_function ) ) {
FC ( imports_function ) = emalloc ( sizeof ( HashTable ) ) ;
zend_hash_init ( FC ( imports_function ) , 8 , NULL , str_dtor , 0 ) ;
2014-07-21 21:41:11 +00:00
}
2015-04-20 18:16:58 +00:00
return FC ( imports_function ) ;
2016-10-06 21:09:41 +00:00
case ZEND_SYMBOL_CONST :
2015-04-20 18:16:58 +00:00
if ( ! FC ( imports_const ) ) {
FC ( imports_const ) = emalloc ( sizeof ( HashTable ) ) ;
zend_hash_init ( FC ( imports_const ) , 8 , NULL , str_dtor , 0 ) ;
2014-07-21 21:41:11 +00:00
}
2015-04-20 18:16:58 +00:00
return FC ( imports_const ) ;
2014-07-21 21:41:11 +00:00
EMPTY_SWITCH_DEFAULT_CASE ( )
1999-12-23 15:03:25 +00:00
}
2014-10-31 17:49:29 +00:00
return NULL ;
1999-12-23 15:03:25 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-08-29 05:05:58 +00:00
static char * zend_get_use_type_str ( uint32_t type ) /* { { { */
{
2014-07-21 21:41:11 +00:00
switch ( type ) {
2016-10-06 21:09:41 +00:00
case ZEND_SYMBOL_CLASS :
2014-07-21 21:41:11 +00:00
return " " ;
2016-10-06 21:09:41 +00:00
case ZEND_SYMBOL_FUNCTION :
2014-07-21 21:41:11 +00:00
return " function " ;
2016-10-06 21:09:41 +00:00
case ZEND_SYMBOL_CONST :
2014-07-21 21:41:11 +00:00
return " const " ;
EMPTY_SWITCH_DEFAULT_CASE ( )
1999-04-07 18:10:10 +00:00
}
2014-10-31 17:49:29 +00:00
return " unknown " ;
2014-07-21 21:41:11 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-07-21 21:41:11 +00:00
2014-08-29 05:05:58 +00:00
static void zend_check_already_in_use ( uint32_t type , zend_string * old_name , zend_string * new_name , zend_string * check_name ) /* { { { */
{
2015-02-11 08:03:48 +00:00
if ( zend_string_equals_ci ( old_name , check_name ) ) {
2014-07-28 20:16:24 +00:00
return ;
2010-12-01 13:33:49 +00:00
}
2014-07-21 21:41:11 +00:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use%s %s as %s because the name "
2015-06-30 10:59:27 +00:00
" is already in use " , zend_get_use_type_str ( type ) , ZSTR_VAL ( old_name ) , ZSTR_VAL ( new_name ) ) ;
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_use ( zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-27 20:26:06 +00:00
zend_ast_list * list = zend_ast_get_list ( ast ) ;
2014-08-25 19:21:16 +00:00
uint32_t i ;
2015-04-20 18:16:58 +00:00
zend_string * current_ns = FC ( current_namespace ) ;
2014-08-25 19:21:16 +00:00
uint32_t type = ast - > attr ;
2014-12-13 22:06:14 +00:00
HashTable * current_import = zend_get_import_ht ( type ) ;
2016-10-06 21:09:41 +00:00
zend_bool case_sensitive = type = = ZEND_SYMBOL_CONST ;
2014-07-21 20:49:31 +00:00
2014-07-27 20:26:06 +00:00
for ( i = 0 ; i < list - > children ; + + i ) {
zend_ast * use_ast = list - > child [ i ] ;
2014-07-21 20:49:31 +00:00
zend_ast * old_name_ast = use_ast - > child [ 0 ] ;
zend_ast * new_name_ast = use_ast - > child [ 1 ] ;
2014-07-28 13:16:35 +00:00
zend_string * old_name = zend_ast_get_str ( old_name_ast ) ;
2014-07-21 21:41:11 +00:00
zend_string * new_name , * lookup_name ;
2014-07-21 20:49:31 +00:00
if ( new_name_ast ) {
2014-08-25 19:21:16 +00:00
new_name = zend_string_copy ( zend_ast_get_str ( new_name_ast ) ) ;
2014-07-21 20:49:31 +00:00
} else {
2014-09-28 21:17:29 +00:00
const char * unqualified_name ;
size_t unqualified_name_len ;
if ( zend_get_unqualified_name ( old_name , & unqualified_name , & unqualified_name_len ) ) {
2015-01-18 14:46:32 +00:00
/* The form "use A\B" is equivalent to "use A\B as B" */
2014-09-28 21:17:29 +00:00
new_name = zend_string_init ( unqualified_name , unqualified_name_len , 0 ) ;
2014-07-21 20:49:31 +00:00
} else {
2014-08-25 19:21:16 +00:00
new_name = zend_string_copy ( old_name ) ;
1999-04-07 18:10:10 +00:00
2014-07-21 20:49:31 +00:00
if ( ! current_ns ) {
zend_error ( E_WARNING , " The use statement with non-compound name '%s' "
2015-06-30 10:59:27 +00:00
" has no effect " , ZSTR_VAL ( new_name ) ) ;
2014-07-21 20:49:31 +00:00
}
}
}
1999-04-07 18:10:10 +00:00
2014-07-21 21:41:11 +00:00
if ( case_sensitive ) {
2014-08-25 19:21:16 +00:00
lookup_name = zend_string_copy ( new_name ) ;
2014-07-21 21:41:11 +00:00
} else {
2014-12-24 12:04:51 +00:00
lookup_name = zend_string_tolower ( new_name ) ;
2014-07-21 21:41:11 +00:00
}
1999-04-07 18:10:10 +00:00
2016-10-06 21:09:41 +00:00
if ( type = = ZEND_SYMBOL_CLASS & & zend_is_reserved_class_name ( new_name ) ) {
2014-07-21 20:49:31 +00:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use %s as %s because '%s' "
2015-06-30 10:59:27 +00:00
" is a special class name " , ZSTR_VAL ( old_name ) , ZSTR_VAL ( new_name ) , ZSTR_VAL ( new_name ) ) ;
2004-10-04 19:54:35 +00:00
}
1999-04-07 18:10:10 +00:00
2014-07-21 20:49:31 +00:00
if ( current_ns ) {
2015-06-30 10:59:27 +00:00
zend_string * ns_name = zend_string_alloc ( ZSTR_LEN ( current_ns ) + 1 + ZSTR_LEN ( new_name ) , 0 ) ;
zend_str_tolower_copy ( ZSTR_VAL ( ns_name ) , ZSTR_VAL ( current_ns ) , ZSTR_LEN ( current_ns ) ) ;
ZSTR_VAL ( ns_name ) [ ZSTR_LEN ( current_ns ) ] = ' \\ ' ;
2017-12-01 14:00:11 +00:00
memcpy ( ZSTR_VAL ( ns_name ) + ZSTR_LEN ( current_ns ) + 1 , ZSTR_VAL ( lookup_name ) , ZSTR_LEN ( lookup_name ) + 1 ) ;
1999-04-07 18:10:10 +00:00
2016-10-06 21:09:41 +00:00
if ( zend_have_seen_symbol ( ns_name , type ) ) {
2014-07-21 21:41:11 +00:00
zend_check_already_in_use ( type , old_name , new_name , ns_name ) ;
2014-07-21 20:49:31 +00:00
}
2001-12-26 14:46:18 +00:00
2018-05-08 14:30:15 +00:00
zend_string_efree ( ns_name ) ;
2019-03-06 09:42:02 +00:00
} else if ( zend_have_seen_symbol ( lookup_name , type ) ) {
zend_check_already_in_use ( type , old_name , new_name , lookup_name ) ;
2012-04-12 09:54:52 +00:00
}
2014-08-25 19:21:16 +00:00
zend_string_addref ( old_name ) ;
2019-08-12 14:58:52 +00:00
old_name = zend_new_interned_string ( old_name ) ;
2014-07-21 21:41:11 +00:00
if ( ! zend_hash_add_ptr ( current_import , lookup_name , old_name ) ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use%s %s as %s because the name "
2015-06-30 10:59:27 +00:00
" is already in use " , zend_get_use_type_str ( type ) , ZSTR_VAL ( old_name ) , ZSTR_VAL ( new_name ) ) ;
2014-07-21 20:49:31 +00:00
}
2018-05-28 13:27:12 +00:00
zend_string_release_ex ( lookup_name , 0 ) ;
zend_string_release_ex ( new_name , 0 ) ;
2012-04-12 09:54:52 +00:00
}
2014-07-21 20:49:31 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2006-05-09 23:53:23 +00:00
2015-03-07 20:59:20 +00:00
void zend_compile_group_use ( zend_ast * ast ) /* { { { */
{
2015-03-08 16:01:55 +00:00
uint32_t i ;
2015-03-07 20:59:20 +00:00
zend_string * ns = zend_ast_get_str ( ast - > child [ 0 ] ) ;
zend_ast_list * list = zend_ast_get_list ( ast - > child [ 1 ] ) ;
for ( i = 0 ; i < list - > children ; i + + ) {
2015-03-08 16:01:55 +00:00
zend_ast * inline_use , * use = list - > child [ i ] ;
2015-03-07 20:59:20 +00:00
zval * name_zval = zend_ast_get_zval ( use - > child [ 0 ] ) ;
zend_string * name = Z_STR_P ( name_zval ) ;
2015-06-30 10:59:27 +00:00
zend_string * compound_ns = zend_concat_names ( ZSTR_VAL ( ns ) , ZSTR_LEN ( ns ) , ZSTR_VAL ( name ) , ZSTR_LEN ( name ) ) ;
2018-05-28 13:27:12 +00:00
zend_string_release_ex ( name , 0 ) ;
2015-03-07 20:59:20 +00:00
ZVAL_STR ( name_zval , compound_ns ) ;
2019-03-28 08:29:08 +00:00
inline_use = zend_ast_create_list ( 1 , ZEND_AST_USE , use ) ;
2015-03-07 20:59:20 +00:00
inline_use - > attr = ast - > attr ? ast - > attr : use - > attr ;
zend_compile_use ( inline_use ) ;
}
}
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_const_decl ( zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-27 20:26:06 +00:00
zend_ast_list * list = zend_ast_get_list ( ast ) ;
2014-08-25 19:21:16 +00:00
uint32_t i ;
2014-07-27 20:26:06 +00:00
for ( i = 0 ; i < list - > children ; + + i ) {
zend_ast * const_ast = list - > child [ i ] ;
2014-07-22 09:55:07 +00:00
zend_ast * name_ast = const_ast - > child [ 0 ] ;
zend_ast * value_ast = const_ast - > child [ 1 ] ;
2016-05-04 16:42:16 +00:00
zend_string * unqualified_name = zend_ast_get_str ( name_ast ) ;
2006-05-09 23:53:23 +00:00
2016-05-04 16:42:16 +00:00
zend_string * name ;
2014-07-22 09:55:07 +00:00
znode name_node , value_node ;
zval * value_zv = & value_node . u . constant ;
value_node . op_type = IS_CONST ;
2014-12-13 22:06:14 +00:00
zend_const_expr_to_zval ( value_zv , value_ast ) ;
2014-07-22 09:55:07 +00:00
2019-01-30 16:16:09 +00:00
if ( zend_get_special_const ( ZSTR_VAL ( unqualified_name ) , ZSTR_LEN ( unqualified_name ) ) ) {
2016-05-04 16:42:16 +00:00
zend_error_noreturn ( E_COMPILE_ERROR ,
" Cannot redeclare constant '%s' " , ZSTR_VAL ( unqualified_name ) ) ;
2004-10-04 19:54:35 +00:00
}
2002-02-04 19:29:56 +00:00
2016-05-04 16:42:16 +00:00
name = zend_prefix_with_ns ( unqualified_name ) ;
2014-12-13 22:06:14 +00:00
name = zend_new_interned_string ( name ) ;
2014-07-22 09:55:07 +00:00
2016-05-04 16:42:16 +00:00
if ( FC ( imports_const ) ) {
zend_string * import_name = zend_hash_find_ptr ( FC ( imports_const ) , unqualified_name ) ;
if ( import_name & & ! zend_string_equals ( import_name , name ) ) {
2015-04-01 10:32:23 +00:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot declare const %s because "
2015-06-30 10:59:27 +00:00
" the name is already in use " , ZSTR_VAL ( name ) ) ;
2014-07-22 09:55:07 +00:00
}
}
name_node . op_type = IS_CONST ;
ZVAL_STR ( & name_node . u . constant , name ) ;
2014-12-13 22:06:14 +00:00
zend_emit_op ( NULL , ZEND_DECLARE_CONST , & name_node , & value_node ) ;
2014-07-22 09:55:07 +00:00
2016-10-06 21:09:41 +00:00
zend_register_seen_symbol ( name , ZEND_SYMBOL_CONST ) ;
2014-07-22 09:55:07 +00:00
}
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}}*/
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_namespace ( zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-22 10:45:44 +00:00
zend_ast * name_ast = ast - > child [ 0 ] ;
zend_ast * stmt_ast = ast - > child [ 1 ] ;
zend_string * name ;
2014-07-22 12:08:52 +00:00
zend_bool with_bracket = stmt_ast ! = NULL ;
2002-07-30 04:07:15 +00:00
2014-07-22 12:08:52 +00:00
/* handle mixed syntax declaration or nested namespaces */
2015-04-20 18:16:58 +00:00
if ( ! FC ( has_bracketed_namespaces ) ) {
if ( FC ( current_namespace ) ) {
2014-07-22 12:08:52 +00:00
/* previous namespace declarations were unbracketed */
if ( with_bracket ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot mix bracketed namespace declarations "
" with unbracketed namespace declarations " ) ;
}
}
} else {
/* previous namespace declarations were bracketed */
if ( ! with_bracket ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot mix bracketed namespace declarations "
" with unbracketed namespace declarations " ) ;
2015-04-20 18:16:58 +00:00
} else if ( FC ( current_namespace ) | | FC ( in_namespace ) ) {
2014-07-22 12:08:52 +00:00
zend_error_noreturn ( E_COMPILE_ERROR , " Namespace declarations cannot be nested " ) ;
2005-09-09 06:48:49 +00:00
}
}
2015-04-20 18:16:58 +00:00
if ( ( ( ! with_bracket & & ! FC ( current_namespace ) )
| | ( with_bracket & & ! FC ( has_bracketed_namespaces ) ) ) & & CG ( active_op_array ) - > last > 0
2014-07-22 12:08:52 +00:00
) {
/* ignore ZEND_EXT_STMT and ZEND_TICKS */
2014-08-25 19:21:16 +00:00
uint32_t num = CG ( active_op_array ) - > last ;
2014-07-22 12:08:52 +00:00
while ( num > 0 & &
( CG ( active_op_array ) - > opcodes [ num - 1 ] . opcode = = ZEND_EXT_STMT | |
CG ( active_op_array ) - > opcodes [ num - 1 ] . opcode = = ZEND_TICKS ) ) {
- - num ;
}
if ( num > 0 ) {
2014-07-28 20:03:16 +00:00
zend_error_noreturn ( E_COMPILE_ERROR , " Namespace declaration statement has to be "
2015-11-29 07:43:41 +00:00
" the very first statement or after any declare call in the script " ) ;
2014-07-22 12:08:52 +00:00
}
2006-12-12 23:25:23 +00:00
}
2015-04-20 18:16:58 +00:00
if ( FC ( current_namespace ) ) {
2018-05-28 13:27:12 +00:00
zend_string_release_ex ( FC ( current_namespace ) , 0 ) ;
2014-07-22 10:45:44 +00:00
}
2002-07-30 04:07:15 +00:00
2014-07-22 10:45:44 +00:00
if ( name_ast ) {
2014-07-28 13:16:35 +00:00
name = zend_ast_get_str ( name_ast ) ;
2001-08-08 15:07:11 +00:00
2020-06-15 09:50:55 +00:00
if ( zend_string_equals_literal_ci ( name , " namespace " ) ) {
2015-06-30 10:59:27 +00:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use '%s' as namespace name " , ZSTR_VAL ( name ) ) ;
2001-08-08 15:07:11 +00:00
}
2014-07-22 10:45:44 +00:00
2015-04-20 18:16:58 +00:00
FC ( current_namespace ) = zend_string_copy ( name ) ;
2001-08-08 15:07:11 +00:00
} else {
2015-04-20 18:16:58 +00:00
FC ( current_namespace ) = NULL ;
2001-08-08 15:07:11 +00:00
}
2014-12-13 22:06:14 +00:00
zend_reset_import_tables ( ) ;
2005-02-11 22:26:45 +00:00
2015-04-20 18:16:58 +00:00
FC ( in_namespace ) = 1 ;
2014-07-22 12:08:52 +00:00
if ( with_bracket ) {
2015-04-20 18:16:58 +00:00
FC ( has_bracketed_namespaces ) = 1 ;
2014-07-22 12:08:52 +00:00
}
1999-04-07 18:10:10 +00:00
2014-07-22 10:45:44 +00:00
if ( stmt_ast ) {
2014-12-13 22:06:14 +00:00
zend_compile_top_stmt ( stmt_ast ) ;
zend_end_namespace ( ) ;
2014-07-22 10:45:44 +00:00
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_halt_compiler ( zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-22 12:22:59 +00:00
zend_ast * offset_ast = ast - > child [ 0 ] ;
2014-08-25 19:21:16 +00:00
zend_long offset = Z_LVAL_P ( zend_ast_get_zval ( offset_ast ) ) ;
2006-05-09 23:53:23 +00:00
2014-07-22 12:22:59 +00:00
zend_string * filename , * name ;
const char const_name [ ] = " __COMPILER_HALT_OFFSET__ " ;
2005-02-07 15:22:38 +00:00
2015-04-20 18:16:58 +00:00
if ( FC ( has_bracketed_namespaces ) & & FC ( in_namespace ) ) {
2014-07-28 20:03:16 +00:00
zend_error_noreturn ( E_COMPILE_ERROR ,
" __HALT_COMPILER() can only be used from the outermost scope " ) ;
2014-07-22 12:22:59 +00:00
}
2005-02-07 16:09:54 +00:00
2014-12-13 22:06:14 +00:00
filename = zend_get_compiled_filename ( ) ;
2014-07-22 12:22:59 +00:00
name = zend_mangle_property_name ( const_name , sizeof ( const_name ) - 1 ,
2015-06-30 10:59:27 +00:00
ZSTR_VAL ( filename ) , ZSTR_LEN ( filename ) , 0 ) ;
2014-07-22 12:22:59 +00:00
2015-06-30 10:59:27 +00:00
zend_register_long_constant ( ZSTR_VAL ( name ) , ZSTR_LEN ( name ) , offset , CONST_CS , 0 ) ;
2018-05-28 13:27:12 +00:00
zend_string_release_ex ( name , 0 ) ;
2014-07-22 12:22:59 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-07-22 12:22:59 +00:00
2014-12-13 22:06:14 +00:00
static zend_bool zend_try_ct_eval_magic_const ( zval * zv , zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-29 21:22:23 +00:00
zend_op_array * op_array = CG ( active_op_array ) ;
zend_class_entry * ce = CG ( active_class_entry ) ;
switch ( ast - > attr ) {
2014-08-26 20:47:11 +00:00
case T_LINE :
2014-10-12 18:54:45 +00:00
ZVAL_LONG ( zv , ast - > lineno ) ;
2014-08-26 20:47:11 +00:00
break ;
case T_FILE :
2014-09-19 13:32:50 +00:00
ZVAL_STR_COPY ( zv , CG ( compiled_filename ) ) ;
2014-08-26 20:47:11 +00:00
break ;
case T_DIR :
{
zend_string * filename = CG ( compiled_filename ) ;
2015-06-30 10:59:27 +00:00
zend_string * dirname = zend_string_init ( ZSTR_VAL ( filename ) , ZSTR_LEN ( filename ) , 0 ) ;
2017-05-15 14:35:22 +00:00
# ifdef ZEND_WIN32
2017-05-16 10:49:19 +00:00
ZSTR_LEN ( dirname ) = php_win32_ioutil_dirname ( ZSTR_VAL ( dirname ) , ZSTR_LEN ( dirname ) ) ;
2017-05-15 14:35:22 +00:00
# else
2017-05-16 10:49:19 +00:00
ZSTR_LEN ( dirname ) = zend_dirname ( ZSTR_VAL ( dirname ) , ZSTR_LEN ( dirname ) ) ;
2017-05-15 14:35:22 +00:00
# endif
2014-08-26 20:47:11 +00:00
2015-06-30 10:59:27 +00:00
if ( strcmp ( ZSTR_VAL ( dirname ) , " . " ) = = 0 ) {
2015-03-19 23:02:42 +00:00
dirname = zend_string_extend ( dirname , MAXPATHLEN , 0 ) ;
2014-08-26 20:47:11 +00:00
# if HAVE_GETCWD
2015-07-16 20:48:56 +00:00
ZEND_IGNORE_VALUE ( VCWD_GETCWD ( ZSTR_VAL ( dirname ) , MAXPATHLEN ) ) ;
2014-08-26 20:47:11 +00:00
# elif HAVE_GETWD
2015-07-16 20:48:56 +00:00
ZEND_IGNORE_VALUE ( VCWD_GETWD ( ZSTR_VAL ( dirname ) ) ) ;
2014-08-26 20:47:11 +00:00
# endif
2017-05-16 10:49:19 +00:00
ZSTR_LEN ( dirname ) = strlen ( ZSTR_VAL ( dirname ) ) ;
2014-08-26 20:47:11 +00:00
}
ZVAL_STR ( zv , dirname ) ;
break ;
}
2014-07-29 21:22:23 +00:00
case T_FUNC_C :
if ( op_array & & op_array - > function_name ) {
2014-09-19 13:32:50 +00:00
ZVAL_STR_COPY ( zv , op_array - > function_name ) ;
2014-07-29 21:22:23 +00:00
} else {
ZVAL_EMPTY_STRING ( zv ) ;
}
break ;
case T_METHOD_C :
2019-02-12 16:34:55 +00:00
/* Detect whether we are directly inside a class (e.g. a class constant) and treat
* this as not being inside a function . */
if ( op_array & & ce & & ! op_array - > scope & & ! ( op_array - > fn_flags & ZEND_ACC_CLOSURE ) ) {
op_array = NULL ;
}
if ( op_array & & op_array - > function_name ) {
if ( op_array - > scope ) {
2020-04-14 14:52:13 +00:00
ZVAL_NEW_STR ( zv ,
zend_create_member_string ( op_array - > scope - > name , op_array - > function_name ) ) ;
2014-07-29 21:22:23 +00:00
} else {
2019-02-12 16:34:55 +00:00
ZVAL_STR_COPY ( zv , op_array - > function_name ) ;
2014-07-29 21:22:23 +00:00
}
} else {
ZVAL_EMPTY_STRING ( zv ) ;
}
break ;
case T_CLASS_C :
if ( ce ) {
2015-02-12 22:19:14 +00:00
if ( ( ce - > ce_flags & ZEND_ACC_TRAIT ) ! = 0 ) {
2014-07-29 21:22:23 +00:00
return 0 ;
} else {
2014-09-19 13:32:50 +00:00
ZVAL_STR_COPY ( zv , ce - > name ) ;
2014-07-29 21:22:23 +00:00
}
} else {
ZVAL_EMPTY_STRING ( zv ) ;
}
break ;
case T_TRAIT_C :
2015-02-12 22:19:14 +00:00
if ( ce & & ( ce - > ce_flags & ZEND_ACC_TRAIT ) ! = 0 ) {
2014-09-19 13:32:50 +00:00
ZVAL_STR_COPY ( zv , ce - > name ) ;
2014-07-29 21:22:23 +00:00
} else {
ZVAL_EMPTY_STRING ( zv ) ;
}
break ;
case T_NS_C :
2015-04-20 18:16:58 +00:00
if ( FC ( current_namespace ) ) {
ZVAL_STR_COPY ( zv , FC ( current_namespace ) ) ;
2014-07-29 21:22:23 +00:00
} else {
ZVAL_EMPTY_STRING ( zv ) ;
}
break ;
EMPTY_SWITCH_DEFAULT_CASE ( )
2014-03-13 13:01:28 +00:00
}
2014-07-29 21:22:23 +00:00
return 1 ;
2005-02-07 15:22:38 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2005-02-07 15:22:38 +00:00
2020-04-01 11:02:58 +00:00
ZEND_API zend_bool zend_binary_op_produces_error ( uint32_t opcode , zval * op1 , zval * op2 ) /* { { { */
2016-03-30 00:44:27 +00:00
{
2020-04-01 11:02:58 +00:00
if ( ( opcode = = ZEND_CONCAT | | opcode = = ZEND_FAST_CONCAT ) ) {
/* Array to string warning. */
return Z_TYPE_P ( op1 ) = = IS_ARRAY | | Z_TYPE_P ( op2 ) = = IS_ARRAY ;
}
2016-03-30 00:44:27 +00:00
if ( ! ( opcode = = ZEND_ADD | | opcode = = ZEND_SUB | | opcode = = ZEND_MUL | | opcode = = ZEND_DIV
2020-04-01 11:02:58 +00:00
| | opcode = = ZEND_POW | | opcode = = ZEND_MOD | | opcode = = ZEND_SL | | opcode = = ZEND_SR
| | opcode = = ZEND_BW_OR | | opcode = = ZEND_BW_AND | | opcode = = ZEND_BW_XOR ) ) {
/* Only the numeric operations throw errors. */
2016-03-30 00:44:27 +00:00
return 0 ;
}
2020-04-01 11:02:58 +00:00
if ( Z_TYPE_P ( op1 ) = = IS_ARRAY | | Z_TYPE_P ( op2 ) = = IS_ARRAY ) {
if ( opcode = = ZEND_ADD & & Z_TYPE_P ( op1 ) = = IS_ARRAY & & Z_TYPE_P ( op2 ) = = IS_ARRAY ) {
/* Adding two arrays is allowed. */
return 0 ;
}
2020-04-01 08:25:22 +00:00
/* Numeric operators throw when one of the operands is an array. */
return 1 ;
2020-04-01 11:02:58 +00:00
}
2016-03-30 00:44:27 +00:00
/* While basic arithmetic operators always produce numeric string errors,
* bitwise operators don ' t produce errors if both operands are strings */
if ( ( opcode = = ZEND_BW_OR | | opcode = = ZEND_BW_AND | | opcode = = ZEND_BW_XOR )
& & Z_TYPE_P ( op1 ) = = IS_STRING & & Z_TYPE_P ( op2 ) = = IS_STRING ) {
return 0 ;
}
if ( Z_TYPE_P ( op1 ) = = IS_STRING
& & ! is_numeric_string ( Z_STRVAL_P ( op1 ) , Z_STRLEN_P ( op1 ) , NULL , NULL , 0 ) ) {
return 1 ;
}
if ( Z_TYPE_P ( op2 ) = = IS_STRING
& & ! is_numeric_string ( Z_STRVAL_P ( op2 ) , Z_STRLEN_P ( op2 ) , NULL , NULL , 0 ) ) {
return 1 ;
}
2020-04-01 12:47:21 +00:00
if ( ( opcode = = ZEND_MOD & & zval_get_long ( op2 ) = = 0 )
| | ( opcode = = ZEND_DIV & & zval_get_double ( op2 ) = = 0.0 ) ) {
2020-04-01 11:02:58 +00:00
/* Division by zero throws an error. */
return 1 ;
}
if ( ( opcode = = ZEND_SL | | opcode = = ZEND_SR ) & & zval_get_long ( op2 ) < 0 ) {
/* Shift by negative number throws an error. */
2019-02-27 17:46:31 +00:00
return 1 ;
}
return 0 ;
}
/* }}} */
2015-06-16 16:09:59 +00:00
static inline zend_bool zend_try_ct_eval_binary_op ( zval * result , uint32_t opcode , zval * op1 , zval * op2 ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2020-04-01 11:02:58 +00:00
if ( zend_binary_op_produces_error ( opcode , op1 , op2 ) ) {
2019-02-27 17:46:31 +00:00
return 0 ;
}
2016-03-30 00:44:27 +00:00
2020-04-01 11:02:58 +00:00
binary_op_type fn = get_binary_op ( opcode ) ;
2014-12-13 22:06:14 +00:00
fn ( result , op1 , op2 ) ;
2015-06-16 16:09:59 +00:00
return 1 ;
2014-07-29 21:22:23 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2015-06-10 22:57:37 +00:00
static inline void zend_ct_eval_unary_op ( zval * result , uint32_t opcode , zval * op ) /* { { { */
{
unary_op_type fn = get_unary_op ( opcode ) ;
fn ( result , op ) ;
}
/* }}} */
2016-03-30 00:44:27 +00:00
static inline zend_bool zend_try_ct_eval_unary_pm ( zval * result , zend_ast_kind kind , zval * op ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-29 21:22:23 +00:00
zval left ;
2015-12-19 02:25:44 +00:00
ZVAL_LONG ( & left , ( kind = = ZEND_AST_UNARY_PLUS ) ? 1 : - 1 ) ;
2016-03-30 00:44:27 +00:00
return zend_try_ct_eval_binary_op ( result , ZEND_MUL , & left , op ) ;
2014-07-29 21:22:23 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2004-08-12 05:41:01 +00:00
2014-12-13 22:06:14 +00:00
static inline void zend_ct_eval_greater ( zval * result , zend_ast_kind kind , zval * op1 , zval * op2 ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-29 21:22:23 +00:00
binary_op_type fn = kind = = ZEND_AST_GREATER
? is_smaller_function : is_smaller_or_equal_function ;
2014-12-13 22:06:14 +00:00
fn ( result , op2 , op1 ) ;
2014-07-29 21:22:23 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
static zend_bool zend_try_ct_eval_array ( zval * result , zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-29 21:22:23 +00:00
zend_ast_list * list = zend_ast_get_list ( ast ) ;
2019-01-02 10:32:48 +00:00
zend_ast * last_elem_ast = NULL ;
2014-08-25 19:21:16 +00:00
uint32_t i ;
2015-06-15 15:41:47 +00:00
zend_bool is_constant = 1 ;
2005-02-07 16:09:54 +00:00
2016-07-06 19:15:05 +00:00
if ( ast - > attr = = ZEND_ARRAY_SYNTAX_LIST ) {
2016-04-04 22:34:42 +00:00
zend_error ( E_COMPILE_ERROR , " Cannot use list() as standalone expression " ) ;
}
2014-07-29 21:22:23 +00:00
/* First ensure that *all* child nodes are constant and by-val */
for ( i = 0 ; i < list - > children ; + + i ) {
zend_ast * elem_ast = list - > child [ i ] ;
2016-04-04 22:34:42 +00:00
if ( elem_ast = = NULL ) {
2019-01-02 10:32:48 +00:00
/* Report error at line of last non-empty element */
if ( last_elem_ast ) {
CG ( zend_lineno ) = zend_ast_get_lineno ( last_elem_ast ) ;
}
2016-04-04 22:34:42 +00:00
zend_error ( E_COMPILE_ERROR , " Cannot use empty array elements in arrays " ) ;
}
2018-10-06 14:04:41 +00:00
if ( elem_ast - > kind ! = ZEND_AST_UNPACK ) {
zend_eval_const_expr ( & elem_ast - > child [ 0 ] ) ;
zend_eval_const_expr ( & elem_ast - > child [ 1 ] ) ;
2019-11-12 07:51:55 +00:00
2018-10-06 14:04:41 +00:00
if ( elem_ast - > attr /* by_ref */ | | elem_ast - > child [ 0 ] - > kind ! = ZEND_AST_ZVAL
| | ( elem_ast - > child [ 1 ] & & elem_ast - > child [ 1 ] - > kind ! = ZEND_AST_ZVAL )
) {
is_constant = 0 ;
}
} else {
zend_eval_const_expr ( & elem_ast - > child [ 0 ] ) ;
2019-11-12 07:51:55 +00:00
2018-10-06 14:04:41 +00:00
if ( elem_ast - > child [ 0 ] - > kind ! = ZEND_AST_ZVAL ) {
is_constant = 0 ;
}
2007-01-10 15:58:08 +00:00
}
2019-01-02 10:32:48 +00:00
last_elem_ast = elem_ast ;
1999-04-07 18:10:10 +00:00
}
2015-06-15 15:41:47 +00:00
if ( ! is_constant ) {
return 0 ;
}
2017-10-24 14:27:31 +00:00
if ( ! list - > children ) {
ZVAL_EMPTY_ARRAY ( result ) ;
return 1 ;
}
2014-07-29 21:22:23 +00:00
array_init_size ( result , list - > children ) ;
for ( i = 0 ; i < list - > children ; + + i ) {
zend_ast * elem_ast = list - > child [ i ] ;
zend_ast * value_ast = elem_ast - > child [ 0 ] ;
2019-06-28 08:24:56 +00:00
zend_ast * key_ast ;
2006-05-11 21:07:39 +00:00
2014-07-29 21:22:23 +00:00
zval * value = zend_ast_get_zval ( value_ast ) ;
2018-10-06 14:04:41 +00:00
if ( elem_ast - > kind = = ZEND_AST_UNPACK ) {
if ( Z_TYPE_P ( value ) = = IS_ARRAY ) {
HashTable * ht = Z_ARRVAL_P ( value ) ;
zval * val ;
zend_string * key ;
ZEND_HASH_FOREACH_STR_KEY_VAL ( ht , key , val ) {
if ( key ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot unpack array with string keys " ) ;
}
if ( ! zend_hash_next_index_insert ( Z_ARRVAL_P ( result ) , val ) ) {
zval_ptr_dtor ( result ) ;
return 0 ;
}
Z_TRY_ADDREF_P ( val ) ;
} ZEND_HASH_FOREACH_END ( ) ;
2019-11-12 07:51:55 +00:00
2018-10-06 14:04:41 +00:00
continue ;
} else {
zend_error_noreturn ( E_COMPILE_ERROR , " Only arrays and Traversables can be unpacked " ) ;
}
2019-11-12 07:51:55 +00:00
}
2017-11-01 02:25:10 +00:00
Z_TRY_ADDREF_P ( value ) ;
2014-07-29 21:22:23 +00:00
2019-06-28 08:24:56 +00:00
key_ast = elem_ast - > child [ 1 ] ;
2014-07-29 21:22:23 +00:00
if ( key_ast ) {
zval * key = zend_ast_get_zval ( key_ast ) ;
switch ( Z_TYPE_P ( key ) ) {
case IS_LONG :
zend_hash_index_update ( Z_ARRVAL_P ( result ) , Z_LVAL_P ( key ) , value ) ;
break ;
case IS_STRING :
zend_symtable_update ( Z_ARRVAL_P ( result ) , Z_STR_P ( key ) , value ) ;
break ;
case IS_DOUBLE :
zend_hash_index_update ( Z_ARRVAL_P ( result ) ,
zend_dval_to_lval ( Z_DVAL_P ( key ) ) , value ) ;
break ;
case IS_FALSE :
zend_hash_index_update ( Z_ARRVAL_P ( result ) , 0 , value ) ;
break ;
case IS_TRUE :
zend_hash_index_update ( Z_ARRVAL_P ( result ) , 1 , value ) ;
break ;
case IS_NULL :
2015-06-29 13:44:54 +00:00
zend_hash_update ( Z_ARRVAL_P ( result ) , ZSTR_EMPTY_ALLOC ( ) , value ) ;
2014-07-29 21:22:23 +00:00
break ;
default :
2015-04-01 10:32:23 +00:00
zend_error_noreturn ( E_COMPILE_ERROR , " Illegal offset type " ) ;
2014-07-29 21:22:23 +00:00
break ;
}
2019-03-06 09:42:02 +00:00
} else if ( ! zend_hash_next_index_insert ( Z_ARRVAL_P ( result ) , value ) ) {
zval_ptr_dtor_nogc ( value ) ;
zval_ptr_dtor ( result ) ;
return 0 ;
2012-08-25 14:23:14 +00:00
}
2003-07-24 12:38:33 +00:00
}
2005-02-07 16:09:54 +00:00
2014-07-29 21:22:23 +00:00
return 1 ;
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-07-29 21:22:23 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_binary_op ( znode * result , zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-14 16:30:18 +00:00
zend_ast * left_ast = ast - > child [ 0 ] ;
zend_ast * right_ast = ast - > child [ 1 ] ;
2014-08-25 19:21:16 +00:00
uint32_t opcode = ast - > attr ;
2005-02-20 10:19:11 +00:00
2014-06-14 16:30:18 +00:00
znode left_node , right_node ;
2020-05-24 10:42:48 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & left_node , left_ast ) ;
zend_compile_expr ( & right_node , right_ast ) ;
2005-02-07 16:09:54 +00:00
2014-07-29 21:22:23 +00:00
if ( left_node . op_type = = IS_CONST & & right_node . op_type = = IS_CONST ) {
2015-06-16 16:09:59 +00:00
if ( zend_try_ct_eval_binary_op ( & result - > u . constant , opcode ,
& left_node . u . constant , & right_node . u . constant )
) {
2015-04-06 11:30:05 +00:00
result - > op_type = IS_CONST ;
zval_ptr_dtor ( & left_node . u . constant ) ;
zval_ptr_dtor ( & right_node . u . constant ) ;
return ;
2015-06-16 16:09:59 +00:00
}
1999-04-07 18:10:10 +00:00
}
2015-01-19 14:02:17 +00:00
do {
if ( opcode = = ZEND_IS_EQUAL | | opcode = = ZEND_IS_NOT_EQUAL ) {
if ( left_node . op_type = = IS_CONST ) {
if ( Z_TYPE ( left_node . u . constant ) = = IS_FALSE ) {
opcode = ( opcode = = ZEND_IS_NOT_EQUAL ) ? ZEND_BOOL : ZEND_BOOL_NOT ;
zend_emit_op_tmp ( result , opcode , & right_node , NULL ) ;
break ;
} else if ( Z_TYPE ( left_node . u . constant ) = = IS_TRUE ) {
opcode = ( opcode = = ZEND_IS_EQUAL ) ? ZEND_BOOL : ZEND_BOOL_NOT ;
zend_emit_op_tmp ( result , opcode , & right_node , NULL ) ;
break ;
}
} else if ( right_node . op_type = = IS_CONST ) {
if ( Z_TYPE ( right_node . u . constant ) = = IS_FALSE ) {
opcode = ( opcode = = ZEND_IS_NOT_EQUAL ) ? ZEND_BOOL : ZEND_BOOL_NOT ;
zend_emit_op_tmp ( result , opcode , & left_node , NULL ) ;
break ;
} else if ( Z_TYPE ( right_node . u . constant ) = = IS_TRUE ) {
opcode = ( opcode = = ZEND_IS_EQUAL ) ? ZEND_BOOL : ZEND_BOOL_NOT ;
zend_emit_op_tmp ( result , opcode , & left_node , NULL ) ;
break ;
}
}
2019-11-12 10:49:55 +00:00
} else if ( opcode = = ZEND_IS_IDENTICAL | | opcode = = ZEND_IS_NOT_IDENTICAL ) {
/* convert $x === null to is_null($x) (i.e. ZEND_TYPE_CHECK opcode). Do the same thing for false/true. (covers IS_NULL, IS_FALSE, and IS_TRUE) */
if ( left_node . op_type = = IS_CONST ) {
if ( Z_TYPE ( left_node . u . constant ) < = IS_TRUE & & Z_TYPE ( left_node . u . constant ) > = IS_NULL ) {
zend_op * opline = zend_emit_op_tmp ( result , ZEND_TYPE_CHECK , & right_node , NULL ) ;
opline - > extended_value =
( opcode = = ZEND_IS_IDENTICAL ) ?
( 1 < < Z_TYPE ( left_node . u . constant ) ) :
( MAY_BE_ANY - ( 1 < < Z_TYPE ( left_node . u . constant ) ) ) ;
return ;
}
} else if ( right_node . op_type = = IS_CONST ) {
if ( Z_TYPE ( right_node . u . constant ) < = IS_TRUE & & Z_TYPE ( right_node . u . constant ) > = IS_NULL ) {
zend_op * opline = zend_emit_op_tmp ( result , ZEND_TYPE_CHECK , & left_node , NULL ) ;
opline - > extended_value =
( opcode = = ZEND_IS_IDENTICAL ) ?
( 1 < < Z_TYPE ( right_node . u . constant ) ) :
( MAY_BE_ANY - ( 1 < < Z_TYPE ( right_node . u . constant ) ) ) ;
return ;
}
}
} else if ( opcode = = ZEND_CONCAT ) {
2015-06-04 06:38:22 +00:00
/* convert constant operands to strings at compile-time */
if ( left_node . op_type = = IS_CONST ) {
2019-02-27 17:46:31 +00:00
if ( Z_TYPE ( left_node . u . constant ) = = IS_ARRAY ) {
zend_emit_op_tmp ( & left_node , ZEND_CAST , & left_node , NULL ) - > extended_value = IS_STRING ;
} else {
convert_to_string ( & left_node . u . constant ) ;
}
2015-06-04 06:38:22 +00:00
}
if ( right_node . op_type = = IS_CONST ) {
2019-02-27 17:46:31 +00:00
if ( Z_TYPE ( right_node . u . constant ) = = IS_ARRAY ) {
zend_emit_op_tmp ( & right_node , ZEND_CAST , & right_node , NULL ) - > extended_value = IS_STRING ;
} else {
convert_to_string ( & right_node . u . constant ) ;
}
2015-06-04 06:38:22 +00:00
}
2017-12-29 10:54:18 +00:00
if ( left_node . op_type = = IS_CONST & & right_node . op_type = = IS_CONST ) {
opcode = ZEND_FAST_CONCAT ;
}
2015-06-04 06:38:22 +00:00
}
2015-01-19 14:02:17 +00:00
zend_emit_op_tmp ( result , opcode , & left_node , & right_node ) ;
} while ( 0 ) ;
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-06-14 16:30:18 +00:00
/* We do not use zend_compile_binary_op for this because we want to retain the left-to-right
* evaluation order . */
2014-12-13 22:06:14 +00:00
void zend_compile_greater ( znode * result , zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-14 16:30:18 +00:00
zend_ast * left_ast = ast - > child [ 0 ] ;
zend_ast * right_ast = ast - > child [ 1 ] ;
znode left_node , right_node ;
1999-04-07 18:10:10 +00:00
2014-06-14 16:30:18 +00:00
ZEND_ASSERT ( ast - > kind = = ZEND_AST_GREATER | | ast - > kind = = ZEND_AST_GREATER_EQUAL ) ;
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & left_node , left_ast ) ;
zend_compile_expr ( & right_node , right_ast ) ;
1999-04-07 18:10:10 +00:00
2014-07-29 21:22:23 +00:00
if ( left_node . op_type = = IS_CONST & & right_node . op_type = = IS_CONST ) {
result - > op_type = IS_CONST ;
zend_ct_eval_greater ( & result - > u . constant , ast - > kind ,
2014-12-13 22:06:14 +00:00
& left_node . u . constant , & right_node . u . constant ) ;
2014-07-29 21:22:23 +00:00
zval_ptr_dtor ( & left_node . u . constant ) ;
zval_ptr_dtor ( & right_node . u . constant ) ;
return ;
}
1999-04-07 18:10:10 +00:00
2014-07-28 20:03:16 +00:00
zend_emit_op_tmp ( result ,
ast - > kind = = ZEND_AST_GREATER ? ZEND_IS_SMALLER : ZEND_IS_SMALLER_OR_EQUAL ,
2014-12-13 22:06:14 +00:00
& right_node , & left_node ) ;
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_unary_op ( znode * result , zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-14 16:30:18 +00:00
zend_ast * expr_ast = ast - > child [ 0 ] ;
2014-08-25 19:21:16 +00:00
uint32_t opcode = ast - > attr ;
2000-01-24 19:00:30 +00:00
2014-06-14 16:30:18 +00:00
znode expr_node ;
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & expr_node , expr_ast ) ;
2008-07-24 22:21:41 +00:00
2015-06-10 22:57:37 +00:00
if ( expr_node . op_type = = IS_CONST ) {
result - > op_type = IS_CONST ;
zend_ct_eval_unary_op ( & result - > u . constant , opcode ,
& expr_node . u . constant ) ;
zval_ptr_dtor ( & expr_node . u . constant ) ;
return ;
}
2014-12-13 22:06:14 +00:00
zend_emit_op_tmp ( result , opcode , & expr_node , NULL ) ;
2014-06-14 16:30:18 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2008-06-29 08:21:35 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_unary_pm ( znode * result , zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-14 16:30:18 +00:00
zend_ast * expr_ast = ast - > child [ 0 ] ;
2015-12-17 22:36:14 +00:00
znode expr_node ;
2015-12-19 02:25:44 +00:00
znode lefthand_node ;
2010-11-24 05:41:23 +00:00
2014-06-26 10:43:20 +00:00
ZEND_ASSERT ( ast - > kind = = ZEND_AST_UNARY_PLUS | | ast - > kind = = ZEND_AST_UNARY_MINUS ) ;
2010-11-24 05:41:23 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & expr_node , expr_ast ) ;
2000-01-24 19:00:30 +00:00
2019-03-06 09:42:02 +00:00
if ( expr_node . op_type = = IS_CONST
& & zend_try_ct_eval_unary_pm ( & result - > u . constant , ast - > kind , & expr_node . u . constant ) ) {
result - > op_type = IS_CONST ;
zval_ptr_dtor ( & expr_node . u . constant ) ;
return ;
2002-07-30 22:19:50 +00:00
}
2000-01-24 19:00:30 +00:00
2015-12-19 02:25:44 +00:00
lefthand_node . op_type = IS_CONST ;
ZVAL_LONG ( & lefthand_node . u . constant , ( ast - > kind = = ZEND_AST_UNARY_PLUS ) ? 1 : - 1 ) ;
zend_emit_op_tmp ( result , ZEND_MUL , & lefthand_node , & expr_node ) ;
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_short_circuiting ( znode * result , zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-14 16:30:18 +00:00
zend_ast * left_ast = ast - > child [ 0 ] ;
zend_ast * right_ast = ast - > child [ 1 ] ;
1999-04-07 18:10:10 +00:00
2014-06-14 16:30:18 +00:00
znode left_node , right_node ;
zend_op * opline_jmpz , * opline_bool ;
2014-08-25 19:21:16 +00:00
uint32_t opnum_jmpz ;
1999-04-07 18:10:10 +00:00
2014-06-14 16:30:18 +00:00
ZEND_ASSERT ( ast - > kind = = ZEND_AST_AND | | ast - > kind = = ZEND_AST_OR ) ;
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & left_node , left_ast ) ;
1999-04-07 18:10:10 +00:00
2015-06-14 13:46:11 +00:00
if ( left_node . op_type = = IS_CONST ) {
2015-06-14 14:56:06 +00:00
if ( ( ast - > kind = = ZEND_AST_AND & & ! zend_is_true ( & left_node . u . constant ) )
2015-06-14 15:08:39 +00:00
| | ( ast - > kind = = ZEND_AST_OR & & zend_is_true ( & left_node . u . constant ) ) ) {
2015-06-14 13:46:11 +00:00
result - > op_type = IS_CONST ;
ZVAL_BOOL ( & result - > u . constant , zend_is_true ( & left_node . u . constant ) ) ;
} else {
zend_compile_expr ( & right_node , right_ast ) ;
if ( right_node . op_type = = IS_CONST ) {
result - > op_type = IS_CONST ;
ZVAL_BOOL ( & result - > u . constant , zend_is_true ( & right_node . u . constant ) ) ;
zval_ptr_dtor ( & right_node . u . constant ) ;
} else {
2016-03-17 14:45:19 +00:00
zend_emit_op_tmp ( result , ZEND_BOOL , & right_node , NULL ) ;
2015-06-14 13:46:11 +00:00
}
}
zval_ptr_dtor ( & left_node . u . constant ) ;
return ;
}
2018-12-07 14:47:56 +00:00
opnum_jmpz = get_next_op_number ( ) ;
2014-07-28 20:03:16 +00:00
opline_jmpz = zend_emit_op ( NULL , ast - > kind = = ZEND_AST_AND ? ZEND_JMPZ_EX : ZEND_JMPNZ_EX ,
2014-12-13 22:06:14 +00:00
& left_node , NULL ) ;
2007-11-21 09:41:35 +00:00
2014-06-14 16:30:18 +00:00
if ( left_node . op_type = = IS_TMP_VAR ) {
SET_NODE ( opline_jmpz - > result , & left_node ) ;
2020-04-24 10:10:06 +00:00
GET_NODE ( result , opline_jmpz - > result ) ;
2015-06-14 14:56:06 +00:00
} else {
2020-04-24 10:10:06 +00:00
zend_make_tmp_result ( result , opline_jmpz ) ;
2011-10-18 19:42:42 +00:00
}
2013-01-28 02:02:51 +00:00
2015-06-19 15:05:35 +00:00
zend_compile_expr ( & right_node , right_ast ) ;
2015-06-14 13:46:11 +00:00
opline_bool = zend_emit_op ( NULL , ZEND_BOOL , & right_node , NULL ) ;
SET_NODE ( opline_bool - > result , result ) ;
2014-12-13 22:06:14 +00:00
zend_update_jump_target_to_next ( opnum_jmpz ) ;
2007-11-21 09:41:35 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2007-11-21 09:41:35 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_post_incdec ( znode * result , zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-14 16:30:18 +00:00
zend_ast * var_ast = ast - > child [ 0 ] ;
2014-07-27 20:26:06 +00:00
ZEND_ASSERT ( ast - > kind = = ZEND_AST_POST_INC | | ast - > kind = = ZEND_AST_POST_DEC ) ;
2007-11-21 09:41:35 +00:00
2015-03-27 15:40:04 +00:00
zend_ensure_writable_variable ( var_ast ) ;
2020-05-24 10:42:48 +00:00
if ( var_ast - > kind = = ZEND_AST_PROP | | var_ast - > kind = = ZEND_AST_NULLSAFE_PROP ) {
2019-01-07 11:28:51 +00:00
zend_op * opline = zend_compile_prop ( NULL , var_ast , BP_VAR_RW , 0 ) ;
2014-07-27 20:26:06 +00:00
opline - > opcode = ast - > kind = = ZEND_AST_POST_INC ? ZEND_POST_INC_OBJ : ZEND_POST_DEC_OBJ ;
2014-12-13 22:06:14 +00:00
zend_make_tmp_result ( result , opline ) ;
2019-01-07 11:28:51 +00:00
} else if ( var_ast - > kind = = ZEND_AST_STATIC_PROP ) {
zend_op * opline = zend_compile_static_prop ( NULL , var_ast , BP_VAR_RW , 0 , 0 ) ;
opline - > opcode = ast - > kind = = ZEND_AST_POST_INC ? ZEND_POST_INC_STATIC_PROP : ZEND_POST_DEC_STATIC_PROP ;
zend_make_tmp_result ( result , opline ) ;
2011-10-18 19:42:42 +00:00
} else {
2014-07-29 19:00:19 +00:00
znode var_node ;
2019-01-07 11:28:51 +00:00
zend_compile_var ( & var_node , var_ast , BP_VAR_RW , 0 ) ;
2014-07-28 20:03:16 +00:00
zend_emit_op_tmp ( result , ast - > kind = = ZEND_AST_POST_INC ? ZEND_POST_INC : ZEND_POST_DEC ,
2014-12-13 22:06:14 +00:00
& var_node , NULL ) ;
2011-10-18 19:42:42 +00:00
}
2014-06-14 16:30:18 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2007-11-21 09:41:35 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_pre_incdec ( znode * result , zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-14 16:30:18 +00:00
zend_ast * var_ast = ast - > child [ 0 ] ;
2014-07-27 20:26:06 +00:00
ZEND_ASSERT ( ast - > kind = = ZEND_AST_PRE_INC | | ast - > kind = = ZEND_AST_PRE_DEC ) ;
2013-01-28 02:02:51 +00:00
2015-03-27 15:40:04 +00:00
zend_ensure_writable_variable ( var_ast ) ;
2020-05-24 10:42:48 +00:00
if ( var_ast - > kind = = ZEND_AST_PROP | | var_ast - > kind = = ZEND_AST_NULLSAFE_PROP ) {
2019-01-07 11:28:51 +00:00
zend_op * opline = zend_compile_prop ( result , var_ast , BP_VAR_RW , 0 ) ;
2014-07-27 20:26:06 +00:00
opline - > opcode = ast - > kind = = ZEND_AST_PRE_INC ? ZEND_PRE_INC_OBJ : ZEND_PRE_DEC_OBJ ;
2020-02-07 10:36:52 +00:00
opline - > result_type = IS_TMP_VAR ;
result - > op_type = IS_TMP_VAR ;
2019-01-07 11:28:51 +00:00
} else if ( var_ast - > kind = = ZEND_AST_STATIC_PROP ) {
zend_op * opline = zend_compile_static_prop ( result , var_ast , BP_VAR_RW , 0 , 0 ) ;
opline - > opcode = ast - > kind = = ZEND_AST_PRE_INC ? ZEND_PRE_INC_STATIC_PROP : ZEND_PRE_DEC_STATIC_PROP ;
2020-02-07 10:36:52 +00:00
opline - > result_type = IS_TMP_VAR ;
result - > op_type = IS_TMP_VAR ;
2014-06-14 16:30:18 +00:00
} else {
2014-07-29 19:00:19 +00:00
znode var_node ;
2019-01-07 11:28:51 +00:00
zend_compile_var ( & var_node , var_ast , BP_VAR_RW , 0 ) ;
2020-02-07 10:36:52 +00:00
zend_emit_op_tmp ( result , ast - > kind = = ZEND_AST_PRE_INC ? ZEND_PRE_INC : ZEND_PRE_DEC ,
2014-12-13 22:06:14 +00:00
& var_node , NULL ) ;
2014-06-14 16:30:18 +00:00
}
2007-11-21 09:41:35 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2007-11-21 09:41:35 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_cast ( znode * result , zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-14 16:30:18 +00:00
zend_ast * expr_ast = ast - > child [ 0 ] ;
znode expr_node ;
1999-04-07 18:10:10 +00:00
zend_op * opline ;
2006-05-09 23:53:23 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & expr_node , expr_ast ) ;
1999-04-07 18:10:10 +00:00
2019-10-03 11:57:20 +00:00
if ( ast - > attr = = _IS_BOOL ) {
opline = zend_emit_op_tmp ( result , ZEND_BOOL , & expr_node , NULL ) ;
} else if ( ast - > attr = = IS_NULL ) {
2019-01-29 09:46:21 +00:00
zend_error ( E_COMPILE_ERROR , " The (unset) cast is no longer supported " ) ;
2019-10-03 11:57:20 +00:00
} else {
opline = zend_emit_op_tmp ( result , ZEND_CAST , & expr_node , NULL ) ;
opline - > extended_value = ast - > attr ;
2017-02-01 23:23:11 +00:00
}
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
static void zend_compile_shorthand_conditional ( znode * result , zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-14 16:30:18 +00:00
zend_ast * cond_ast = ast - > child [ 0 ] ;
zend_ast * false_ast = ast - > child [ 2 ] ;
1999-04-07 18:10:10 +00:00
2014-06-14 16:30:18 +00:00
znode cond_node , false_node ;
2015-07-06 15:41:29 +00:00
zend_op * opline_qm_assign ;
2014-08-25 19:21:16 +00:00
uint32_t opnum_jmp_set ;
1999-04-07 18:10:10 +00:00
2014-06-14 16:30:18 +00:00
ZEND_ASSERT ( ast - > child [ 1 ] = = NULL ) ;
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & cond_node , cond_ast ) ;
1999-04-07 18:10:10 +00:00
2018-12-07 14:47:56 +00:00
opnum_jmp_set = get_next_op_number ( ) ;
2014-12-13 22:06:14 +00:00
zend_emit_op_tmp ( result , ZEND_JMP_SET , & cond_node , NULL ) ;
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & false_node , false_ast ) ;
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
opline_qm_assign = zend_emit_op_tmp ( NULL , ZEND_QM_ASSIGN , & false_node , NULL ) ;
2014-06-14 16:30:18 +00:00
SET_NODE ( opline_qm_assign - > result , result ) ;
2015-07-06 15:41:29 +00:00
zend_update_jump_target_to_next ( opnum_jmp_set ) ;
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_conditional ( znode * result , zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-14 16:30:18 +00:00
zend_ast * cond_ast = ast - > child [ 0 ] ;
zend_ast * true_ast = ast - > child [ 1 ] ;
zend_ast * false_ast = ast - > child [ 2 ] ;
2006-05-09 23:53:23 +00:00
2014-06-14 16:30:18 +00:00
znode cond_node , true_node , false_node ;
2015-07-06 15:41:29 +00:00
zend_op * opline_qm_assign2 ;
uint32_t opnum_jmpz , opnum_jmp ;
2014-06-14 16:30:18 +00:00
2019-04-09 09:04:13 +00:00
if ( cond_ast - > kind = = ZEND_AST_CONDITIONAL
& & cond_ast - > attr ! = ZEND_PARENTHESIZED_CONDITIONAL ) {
if ( cond_ast - > child [ 1 ] ) {
if ( true_ast ) {
2020-07-24 08:35:03 +00:00
zend_error ( E_COMPILE_ERROR ,
" Unparenthesized `a ? b : c ? d : e` is not supported. "
2019-04-09 09:04:13 +00:00
" Use either `(a ? b : c) ? d : e` or `a ? b : (c ? d : e)` " ) ;
} else {
2020-07-24 08:35:03 +00:00
zend_error ( E_COMPILE_ERROR ,
" Unparenthesized `a ? b : c ?: d` is not supported. "
2019-04-09 09:04:13 +00:00
" Use either `(a ? b : c) ?: d` or `a ? b : (c ?: d)` " ) ;
}
} else {
if ( true_ast ) {
2020-07-24 08:35:03 +00:00
zend_error ( E_COMPILE_ERROR ,
" Unparenthesized `a ?: b ? c : d` is not supported. "
2019-04-09 09:04:13 +00:00
" Use either `(a ?: b) ? c : d` or `a ?: (b ? c : d)` " ) ;
} else {
/* This case is harmless: (a ?: b) ?: c always produces the same result
* as a ? : ( b ? : c ) . */
}
}
}
2014-06-14 16:30:18 +00:00
if ( ! true_ast ) {
2014-12-13 22:06:14 +00:00
zend_compile_shorthand_conditional ( result , ast ) ;
1999-04-07 18:10:10 +00:00
return ;
}
2015-01-03 09:22:58 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & cond_node , cond_ast ) ;
2006-05-09 23:53:23 +00:00
2014-12-13 22:06:14 +00:00
opnum_jmpz = zend_emit_cond_jump ( ZEND_JMPZ , & cond_node , 0 ) ;
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & true_node , true_ast ) ;
2006-05-09 23:53:23 +00:00
2014-12-13 22:06:14 +00:00
zend_emit_op_tmp ( result , ZEND_QM_ASSIGN , & true_node , NULL ) ;
2006-05-09 23:53:23 +00:00
2014-12-13 22:06:14 +00:00
opnum_jmp = zend_emit_jump ( 0 ) ;
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
zend_update_jump_target_to_next ( opnum_jmpz ) ;
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & false_node , false_ast ) ;
2006-05-09 23:53:23 +00:00
2015-07-06 15:41:29 +00:00
opline_qm_assign2 = zend_emit_op ( NULL , ZEND_QM_ASSIGN , & false_node , NULL ) ;
2014-06-14 16:30:18 +00:00
SET_NODE ( opline_qm_assign2 - > result , result ) ;
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
zend_update_jump_target_to_next ( opnum_jmp ) ;
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_coalesce ( znode * result , zend_ast * ast ) /* { { { */
2014-09-16 18:14:46 +00:00
{
zend_ast * expr_ast = ast - > child [ 0 ] ;
zend_ast * default_ast = ast - > child [ 1 ] ;
znode expr_node , default_node ;
zend_op * opline ;
uint32_t opnum ;
2019-01-07 11:28:51 +00:00
zend_compile_var ( & expr_node , expr_ast , BP_VAR_IS , 0 ) ;
2014-09-16 18:14:46 +00:00
2018-12-07 14:47:56 +00:00
opnum = get_next_op_number ( ) ;
2014-12-13 22:06:14 +00:00
zend_emit_op_tmp ( result , ZEND_COALESCE , & expr_node , NULL ) ;
2014-09-16 18:14:46 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & default_node , default_ast ) ;
2014-09-16 18:14:46 +00:00
2014-12-13 22:06:14 +00:00
opline = zend_emit_op_tmp ( NULL , ZEND_QM_ASSIGN , & default_node , NULL ) ;
2014-09-16 18:14:46 +00:00
SET_NODE ( opline - > result , result ) ;
opline = & CG ( active_op_array ) - > opcodes [ opnum ] ;
2018-12-07 14:47:56 +00:00
opline - > op2 . opline_num = get_next_op_number ( ) ;
2014-09-16 18:14:46 +00:00
}
/* }}} */
2019-01-15 16:04:24 +00:00
static void znode_dtor ( zval * zv ) {
2019-10-04 08:38:11 +00:00
znode * node = Z_PTR_P ( zv ) ;
if ( node - > op_type = = IS_CONST ) {
zval_ptr_dtor_nogc ( & node - > u . constant ) ;
}
efree ( node ) ;
2019-01-15 16:04:24 +00:00
}
void zend_compile_assign_coalesce ( znode * result , zend_ast * ast ) /* { { { */
{
zend_ast * var_ast = ast - > child [ 0 ] ;
zend_ast * default_ast = ast - > child [ 1 ] ;
znode var_node_is , var_node_w , default_node , assign_node , * node ;
zend_op * opline ;
uint32_t coalesce_opnum ;
zend_bool need_frees = 0 ;
/* Remember expressions compiled during the initial BP_VAR_IS lookup,
* to avoid double - evaluation when we compile again with BP_VAR_W . */
HashTable * orig_memoized_exprs = CG ( memoized_exprs ) ;
int orig_memoize_mode = CG ( memoize_mode ) ;
zend_ensure_writable_variable ( var_ast ) ;
if ( is_this_fetch ( var_ast ) ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot re-assign $this " ) ;
}
ALLOC_HASHTABLE ( CG ( memoized_exprs ) ) ;
zend_hash_init ( CG ( memoized_exprs ) , 0 , NULL , znode_dtor , 0 ) ;
CG ( memoize_mode ) = ZEND_MEMOIZE_COMPILE ;
zend_compile_var ( & var_node_is , var_ast , BP_VAR_IS , 0 ) ;
coalesce_opnum = get_next_op_number ( ) ;
zend_emit_op_tmp ( result , ZEND_COALESCE , & var_node_is , NULL ) ;
CG ( memoize_mode ) = ZEND_MEMOIZE_NONE ;
zend_compile_expr ( & default_node , default_ast ) ;
CG ( memoize_mode ) = ZEND_MEMOIZE_FETCH ;
zend_compile_var ( & var_node_w , var_ast , BP_VAR_W , 0 ) ;
/* Reproduce some of the zend_compile_assign() opcode fixup logic here. */
opline = & CG ( active_op_array ) - > opcodes [ CG ( active_op_array ) - > last - 1 ] ;
switch ( var_ast - > kind ) {
case ZEND_AST_VAR :
2020-02-07 10:36:52 +00:00
zend_emit_op_tmp ( & assign_node , ZEND_ASSIGN , & var_node_w , & default_node ) ;
2019-01-15 16:04:24 +00:00
break ;
case ZEND_AST_STATIC_PROP :
opline - > opcode = ZEND_ASSIGN_STATIC_PROP ;
2020-02-07 10:36:52 +00:00
opline - > result_type = IS_TMP_VAR ;
var_node_w . op_type = IS_TMP_VAR ;
2019-01-15 16:04:24 +00:00
zend_emit_op_data ( & default_node ) ;
assign_node = var_node_w ;
break ;
case ZEND_AST_DIM :
opline - > opcode = ZEND_ASSIGN_DIM ;
2020-02-07 10:36:52 +00:00
opline - > result_type = IS_TMP_VAR ;
var_node_w . op_type = IS_TMP_VAR ;
2019-01-15 16:04:24 +00:00
zend_emit_op_data ( & default_node ) ;
assign_node = var_node_w ;
break ;
case ZEND_AST_PROP :
2020-05-24 10:42:48 +00:00
case ZEND_AST_NULLSAFE_PROP :
2019-01-15 16:04:24 +00:00
opline - > opcode = ZEND_ASSIGN_OBJ ;
2020-02-07 10:36:52 +00:00
opline - > result_type = IS_TMP_VAR ;
var_node_w . op_type = IS_TMP_VAR ;
2019-01-15 16:04:24 +00:00
zend_emit_op_data ( & default_node ) ;
assign_node = var_node_w ;
break ;
EMPTY_SWITCH_DEFAULT_CASE ( ) ;
}
opline = zend_emit_op_tmp ( NULL , ZEND_QM_ASSIGN , & assign_node , NULL ) ;
SET_NODE ( opline - > result , result ) ;
ZEND_HASH_FOREACH_PTR ( CG ( memoized_exprs ) , node ) {
if ( node - > op_type = = IS_TMP_VAR | | node - > op_type = = IS_VAR ) {
need_frees = 1 ;
break ;
}
} ZEND_HASH_FOREACH_END ( ) ;
/* Free DUPed expressions if there are any */
if ( need_frees ) {
uint32_t jump_opnum = zend_emit_jump ( 0 ) ;
zend_update_jump_target_to_next ( coalesce_opnum ) ;
ZEND_HASH_FOREACH_PTR ( CG ( memoized_exprs ) , node ) {
if ( node - > op_type = = IS_TMP_VAR | | node - > op_type = = IS_VAR ) {
zend_emit_op ( NULL , ZEND_FREE , node , NULL ) ;
}
} ZEND_HASH_FOREACH_END ( ) ;
zend_update_jump_target_to_next ( jump_opnum ) ;
} else {
zend_update_jump_target_to_next ( coalesce_opnum ) ;
}
zend_hash_destroy ( CG ( memoized_exprs ) ) ;
FREE_HASHTABLE ( CG ( memoized_exprs ) ) ;
CG ( memoized_exprs ) = orig_memoized_exprs ;
CG ( memoize_mode ) = orig_memoize_mode ;
}
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_print ( znode * result , zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2015-09-29 13:49:22 +00:00
zend_op * opline ;
2014-06-14 16:30:18 +00:00
zend_ast * expr_ast = ast - > child [ 0 ] ;
2000-01-24 19:00:30 +00:00
2014-06-14 16:30:18 +00:00
znode expr_node ;
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & expr_node , expr_ast ) ;
2014-06-14 16:30:18 +00:00
2015-09-29 13:49:22 +00:00
opline = zend_emit_op ( NULL , ZEND_ECHO , & expr_node , NULL ) ;
2015-09-30 02:41:27 +00:00
opline - > extended_value = 1 ;
2014-12-06 11:57:20 +00:00
result - > op_type = IS_CONST ;
ZVAL_LONG ( & result - > u . constant , 1 ) ;
2000-01-24 19:00:30 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2000-01-24 19:00:30 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_exit ( znode * result , zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-14 16:30:18 +00:00
zend_ast * expr_ast = ast - > child [ 0 ] ;
2003-03-02 13:33:31 +00:00
2014-06-14 16:30:18 +00:00
if ( expr_ast ) {
znode expr_node ;
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & expr_node , expr_ast ) ;
zend_emit_op ( NULL , ZEND_EXIT , & expr_node , NULL ) ;
2014-06-14 16:30:18 +00:00
} else {
2014-12-13 22:06:14 +00:00
zend_emit_op ( NULL , ZEND_EXIT , NULL , NULL ) ;
2003-03-02 13:33:31 +00:00
}
2014-06-14 16:30:18 +00:00
result - > op_type = IS_CONST ;
ZVAL_BOOL ( & result - > u . constant , 1 ) ;
2003-03-02 13:33:31 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2003-03-02 13:33:31 +00:00
2015-02-20 11:59:56 +00:00
void zend_compile_yield ( znode * result , zend_ast * ast ) /* { { { */
{
zend_ast * value_ast = ast - > child [ 0 ] ;
zend_ast * key_ast = ast - > child [ 1 ] ;
znode value_node , key_node ;
znode * value_node_ptr = NULL , * key_node_ptr = NULL ;
zend_op * opline ;
zend_bool returns_by_ref = ( CG ( active_op_array ) - > fn_flags & ZEND_ACC_RETURN_REFERENCE ) ! = 0 ;
zend_mark_function_as_generator ( ) ;
2001-08-08 17:18:16 +00:00
2014-06-14 16:30:18 +00:00
if ( key_ast ) {
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & key_node , key_ast ) ;
2014-06-14 16:30:18 +00:00
key_node_ptr = & key_node ;
}
2014-06-16 17:11:52 +00:00
2014-06-14 16:30:18 +00:00
if ( value_ast ) {
2019-01-26 11:10:03 +00:00
if ( returns_by_ref & & zend_is_variable ( value_ast ) ) {
2019-01-07 11:28:51 +00:00
zend_compile_var ( & value_node , value_ast , BP_VAR_W , 1 ) ;
2014-06-16 17:11:52 +00:00
} else {
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & value_node , value_ast ) ;
2014-06-16 17:11:52 +00:00
}
2014-06-14 16:30:18 +00:00
value_node_ptr = & value_node ;
}
2014-12-13 22:06:14 +00:00
opline = zend_emit_op ( result , ZEND_YIELD , value_node_ptr , key_node_ptr ) ;
2014-06-14 16:30:18 +00:00
if ( value_ast & & returns_by_ref & & zend_is_call ( value_ast ) ) {
opline - > extended_value = ZEND_RETURNS_FUNCTION ;
}
2010-07-08 14:05:11 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2010-07-08 14:05:11 +00:00
2015-02-20 11:59:56 +00:00
void zend_compile_yield_from ( znode * result , zend_ast * ast ) /* { { { */
{
zend_ast * expr_ast = ast - > child [ 0 ] ;
znode expr_node ;
zend_mark_function_as_generator ( ) ;
2016-02-12 16:55:29 +00:00
if ( CG ( active_op_array ) - > fn_flags & ZEND_ACC_RETURN_REFERENCE ) {
zend_error_noreturn ( E_COMPILE_ERROR ,
" Cannot use \" yield from \" inside a by-reference generator " ) ;
}
2015-02-20 11:59:56 +00:00
zend_compile_expr ( & expr_node , expr_ast ) ;
zend_emit_op_tmp ( result , ZEND_YIELD_FROM , & expr_node , NULL ) ;
}
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_instanceof ( znode * result , zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-14 16:30:18 +00:00
zend_ast * obj_ast = ast - > child [ 0 ] ;
zend_ast * class_ast = ast - > child [ 1 ] ;
1999-04-07 18:10:10 +00:00
2014-06-14 16:30:18 +00:00
znode obj_node , class_node ;
zend_op * opline ;
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & obj_node , obj_ast ) ;
2014-06-14 16:30:18 +00:00
if ( obj_node . op_type = = IS_CONST ) {
2017-12-19 21:16:45 +00:00
zend_do_free ( & obj_node ) ;
result - > op_type = IS_CONST ;
ZVAL_FALSE ( & result - > u . constant ) ;
return ;
2001-08-06 14:36:46 +00:00
}
2019-01-02 08:48:29 +00:00
zend_compile_class_ref ( & class_node , class_ast ,
2015-12-14 16:50:20 +00:00
ZEND_FETCH_CLASS_NO_AUTOLOAD | ZEND_FETCH_CLASS_EXCEPTION ) ;
2014-10-22 13:23:43 +00:00
2014-12-13 22:06:14 +00:00
opline = zend_emit_op_tmp ( result , ZEND_INSTANCEOF , & obj_node , NULL ) ;
2003-05-29 09:01:55 +00:00
2014-10-22 13:23:43 +00:00
if ( class_node . op_type = = IS_CONST ) {
opline - > op2_type = IS_CONST ;
opline - > op2 . constant = zend_add_class_name_literal (
2018-12-07 14:47:56 +00:00
Z_STR ( class_node . u . constant ) ) ;
2018-02-05 16:41:47 +00:00
opline - > extended_value = zend_alloc_cache_slot ( ) ;
2014-10-22 13:23:43 +00:00
} else {
SET_NODE ( opline - > op2 , & class_node ) ;
}
2014-06-14 16:30:18 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-06-14 16:30:18 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_include_or_eval ( znode * result , zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-19 11:57:29 +00:00
zend_ast * expr_ast = ast - > child [ 0 ] ;
znode expr_node ;
zend_op * opline ;
2014-12-13 22:06:14 +00:00
zend_do_extended_fcall_begin ( ) ;
zend_compile_expr ( & expr_node , expr_ast ) ;
2014-06-19 11:57:29 +00:00
2014-12-13 22:06:14 +00:00
opline = zend_emit_op ( result , ZEND_INCLUDE_OR_EVAL , & expr_node , NULL ) ;
2014-06-19 11:57:29 +00:00
opline - > extended_value = ast - > attr ;
2014-12-13 22:06:14 +00:00
zend_do_extended_fcall_end ( ) ;
2014-06-19 11:57:29 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-06-19 11:57:29 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_isset_or_empty ( znode * result , zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-19 11:57:29 +00:00
zend_ast * var_ast = ast - > child [ 0 ] ;
znode var_node ;
2014-11-10 16:31:31 +00:00
zend_op * opline = NULL ;
2014-06-19 11:57:29 +00:00
ZEND_ASSERT ( ast - > kind = = ZEND_AST_ISSET | | ast - > kind = = ZEND_AST_EMPTY ) ;
2019-01-26 11:10:03 +00:00
if ( ! zend_is_variable ( var_ast ) ) {
2014-06-19 11:57:29 +00:00
if ( ast - > kind = = ZEND_AST_EMPTY ) {
/* empty(expr) can be transformed to !expr */
2019-03-28 08:29:08 +00:00
zend_ast * not_ast = zend_ast_create_ex ( ZEND_AST_UNARY_OP , ZEND_BOOL_NOT , var_ast ) ;
2014-12-13 22:06:14 +00:00
zend_compile_expr ( result , not_ast ) ;
2014-06-19 11:57:29 +00:00
return ;
} else {
zend_error_noreturn ( E_COMPILE_ERROR ,
" Cannot use isset() on the result of an expression "
" (you can use \" null !== expression \" instead) " ) ;
}
}
2020-08-03 08:16:04 +00:00
zend_short_circuiting_mark_inner ( var_ast ) ;
2014-06-19 11:57:29 +00:00
switch ( var_ast - > kind ) {
case ZEND_AST_VAR :
2016-06-15 23:30:23 +00:00
if ( is_this_fetch ( var_ast ) ) {
opline = zend_emit_op ( result , ZEND_ISSET_ISEMPTY_THIS , NULL , NULL ) ;
2019-08-16 10:55:28 +00:00
CG ( active_op_array ) - > fn_flags | = ZEND_ACC_USES_THIS ;
2016-06-15 23:30:23 +00:00
} else if ( zend_try_compile_cv ( & var_node , var_ast ) = = SUCCESS ) {
2017-07-17 11:11:50 +00:00
opline = zend_emit_op ( result , ZEND_ISSET_ISEMPTY_CV , & var_node , NULL ) ;
2014-06-19 11:57:29 +00:00
} else {
2015-02-02 17:44:16 +00:00
opline = zend_compile_simple_var_no_cv ( result , var_ast , BP_VAR_IS , 0 ) ;
2014-06-19 11:57:29 +00:00
opline - > opcode = ZEND_ISSET_ISEMPTY_VAR ;
2008-11-25 09:56:32 +00:00
}
1999-04-07 18:10:10 +00:00
break ;
2014-06-19 11:57:29 +00:00
case ZEND_AST_DIM :
2017-11-16 21:28:29 +00:00
opline = zend_compile_dim ( result , var_ast , BP_VAR_IS ) ;
2014-06-19 11:57:29 +00:00
opline - > opcode = ZEND_ISSET_ISEMPTY_DIM_OBJ ;
break ;
case ZEND_AST_PROP :
2020-05-24 10:42:48 +00:00
case ZEND_AST_NULLSAFE_PROP :
2019-01-07 11:28:51 +00:00
opline = zend_compile_prop ( result , var_ast , BP_VAR_IS , 0 ) ;
2014-06-19 11:57:29 +00:00
opline - > opcode = ZEND_ISSET_ISEMPTY_PROP_OBJ ;
1999-04-07 18:10:10 +00:00
break ;
2014-06-19 11:57:29 +00:00
case ZEND_AST_STATIC_PROP :
2019-01-07 11:28:51 +00:00
opline = zend_compile_static_prop ( result , var_ast , BP_VAR_IS , 0 , 0 ) ;
2015-10-27 12:47:58 +00:00
opline - > opcode = ZEND_ISSET_ISEMPTY_STATIC_PROP ;
2014-06-19 11:57:29 +00:00
break ;
EMPTY_SWITCH_DEFAULT_CASE ( )
1999-04-07 18:10:10 +00:00
}
2006-05-09 23:53:23 +00:00
2014-08-26 10:22:03 +00:00
result - > op_type = opline - > result_type = IS_TMP_VAR ;
2018-05-31 16:02:51 +00:00
if ( ! ( ast - > kind = = ZEND_AST_ISSET ) ) {
opline - > extended_value | = ZEND_ISEMPTY ;
2018-02-05 16:41:47 +00:00
}
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2003-03-31 20:42:01 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_silence ( znode * result , zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-19 11:57:29 +00:00
zend_ast * expr_ast = ast - > child [ 0 ] ;
znode silence_node ;
2003-02-10 16:11:24 +00:00
2014-12-13 22:06:14 +00:00
zend_emit_op_tmp ( & silence_node , ZEND_BEGIN_SILENCE , NULL , NULL ) ;
2005-12-01 11:48:17 +00:00
2014-06-19 11:57:29 +00:00
if ( expr_ast - > kind = = ZEND_AST_VAR ) {
/* For @$var we need to force a FETCH instruction, otherwise the CV access will
* happen outside the silenced section . */
2015-02-02 17:44:16 +00:00
zend_compile_simple_var_no_cv ( result , expr_ast , BP_VAR_R , 0 ) ;
2005-12-01 11:48:17 +00:00
} else {
2014-12-13 22:06:14 +00:00
zend_compile_expr ( result , expr_ast ) ;
2005-12-01 11:48:17 +00:00
}
2005-09-01 10:05:32 +00:00
2015-11-11 08:12:44 +00:00
zend_emit_op ( NULL , ZEND_END_SILENCE , & silence_node , NULL ) ;
2003-02-10 16:11:24 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2003-02-10 16:11:24 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_shell_exec ( znode * result , zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-19 11:57:29 +00:00
zend_ast * expr_ast = ast - > child [ 0 ] ;
2003-08-03 08:21:08 +00:00
2014-06-19 11:57:29 +00:00
zval fn_name ;
2014-07-13 11:11:55 +00:00
zend_ast * name_ast , * args_ast , * call_ast ;
2014-06-19 11:57:29 +00:00
ZVAL_STRING ( & fn_name , " shell_exec " ) ;
2019-03-28 08:29:08 +00:00
name_ast = zend_ast_create_zval ( & fn_name ) ;
args_ast = zend_ast_create_list ( 1 , ZEND_AST_ARG_LIST , expr_ast ) ;
call_ast = zend_ast_create ( ZEND_AST_CALL , name_ast , args_ast ) ;
2014-06-19 11:57:29 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr ( result , call_ast ) ;
2014-06-19 11:57:29 +00:00
2014-07-25 18:24:15 +00:00
zval_ptr_dtor ( & fn_name ) ;
2005-01-22 02:29:18 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2005-01-22 02:29:18 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_array ( znode * result , zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-27 20:26:06 +00:00
zend_ast_list * list = zend_ast_get_list ( ast ) ;
2014-06-19 11:57:29 +00:00
zend_op * opline ;
2014-10-02 09:37:44 +00:00
uint32_t i , opnum_init = - 1 ;
2014-06-19 11:57:29 +00:00
zend_bool packed = 1 ;
2014-12-13 22:06:14 +00:00
if ( zend_try_ct_eval_array ( & result - > u . constant , ast ) ) {
2007-09-28 19:52:53 +00:00
result - > op_type = IS_CONST ;
2014-07-29 21:22:23 +00:00
return ;
2007-09-28 19:52:53 +00:00
}
2017-05-18 10:18:08 +00:00
/* Empty arrays are handled at compile-time */
ZEND_ASSERT ( list - > children > 0 ) ;
2014-07-27 20:26:06 +00:00
for ( i = 0 ; i < list - > children ; + + i ) {
zend_ast * elem_ast = list - > child [ i ] ;
2016-04-04 22:34:42 +00:00
zend_ast * value_ast , * key_ast ;
zend_bool by_ref ;
2016-06-14 10:17:49 +00:00
znode value_node , key_node , * key_node_ptr = NULL ;
2016-04-04 22:34:42 +00:00
if ( elem_ast = = NULL ) {
zend_error ( E_COMPILE_ERROR , " Cannot use empty array elements in arrays " ) ;
}
value_ast = elem_ast - > child [ 0 ] ;
2008-11-25 09:56:32 +00:00
2018-10-06 14:04:41 +00:00
if ( elem_ast - > kind = = ZEND_AST_UNPACK ) {
zend_compile_expr ( & value_node , value_ast ) ;
if ( i = = 0 ) {
2019-10-04 08:11:30 +00:00
opnum_init = get_next_op_number ( ) ;
2018-10-06 14:04:41 +00:00
opline = zend_emit_op_tmp ( result , ZEND_INIT_ARRAY , NULL , NULL ) ;
}
opline = zend_emit_op ( NULL , ZEND_ADD_ARRAY_UNPACK , & value_node , NULL ) ;
SET_NODE ( opline - > result , result ) ;
continue ;
}
2019-06-28 08:24:56 +00:00
key_ast = elem_ast - > child [ 1 ] ;
by_ref = elem_ast - > attr ;
2014-06-19 11:57:29 +00:00
if ( key_ast ) {
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & key_node , key_ast ) ;
zend_handle_numeric_op ( & key_node ) ;
2014-06-19 11:57:29 +00:00
key_node_ptr = & key_node ;
}
2007-09-28 19:52:53 +00:00
2014-06-19 11:57:29 +00:00
if ( by_ref ) {
zend_ensure_writable_variable ( value_ast ) ;
2019-01-07 11:28:51 +00:00
zend_compile_var ( & value_node , value_ast , BP_VAR_W , 1 ) ;
2014-06-19 11:57:29 +00:00
} else {
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & value_node , value_ast ) ;
2008-11-25 09:56:32 +00:00
}
2014-06-19 11:57:29 +00:00
if ( i = = 0 ) {
2018-12-07 14:47:56 +00:00
opnum_init = get_next_op_number ( ) ;
2014-12-13 22:06:14 +00:00
opline = zend_emit_op_tmp ( result , ZEND_INIT_ARRAY , & value_node , key_node_ptr ) ;
2014-07-27 20:26:06 +00:00
opline - > extended_value = list - > children < < ZEND_ARRAY_SIZE_SHIFT ;
2014-06-19 11:57:29 +00:00
} else {
2014-07-28 20:03:16 +00:00
opline = zend_emit_op ( NULL , ZEND_ADD_ARRAY_ELEMENT ,
2014-12-13 22:06:14 +00:00
& value_node , key_node_ptr ) ;
2014-06-19 11:57:29 +00:00
SET_NODE ( opline - > result , result ) ;
2008-11-25 09:56:32 +00:00
}
2014-06-19 11:57:29 +00:00
opline - > extended_value | = by_ref ;
2014-08-15 15:10:06 +00:00
if ( key_ast & & key_node . op_type = = IS_CONST & & Z_TYPE ( key_node . u . constant ) = = IS_STRING ) {
packed = 0 ;
2008-11-25 09:56:32 +00:00
}
2007-12-13 08:57:52 +00:00
}
2008-11-25 09:56:32 +00:00
2014-06-19 11:57:29 +00:00
/* Add a flag to INIT_ARRAY if we know this array cannot be packed */
if ( ! packed ) {
2016-04-29 11:44:56 +00:00
ZEND_ASSERT ( opnum_init ! = ( uint32_t ) - 1 ) ;
2014-06-19 11:57:29 +00:00
opline = & CG ( active_op_array ) - > opcodes [ opnum_init ] ;
opline - > extended_value | = ZEND_ARRAY_NOT_PACKED ;
2013-07-16 18:39:33 +00:00
}
2014-06-19 11:57:29 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2013-07-16 18:39:33 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_const ( znode * result , zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-19 11:57:29 +00:00
zend_ast * name_ast = ast - > child [ 0 ] ;
zend_op * opline ;
2014-09-23 18:21:28 +00:00
zend_bool is_fully_qualified ;
zend_string * orig_name = zend_ast_get_str ( name_ast ) ;
2015-07-29 17:18:13 +00:00
zend_string * resolved_name = zend_resolve_const_name ( orig_name , name_ast - > attr , & is_fully_qualified ) ;
2014-06-19 11:57:29 +00:00
2015-07-29 17:18:13 +00:00
if ( zend_string_equals_literal ( resolved_name , " __COMPILER_HALT_OFFSET__ " ) | | ( name_ast - > attr ! = ZEND_NAME_RELATIVE & & zend_string_equals_literal ( orig_name , " __COMPILER_HALT_OFFSET__ " ) ) ) {
2015-03-18 12:31:29 +00:00
zend_ast * last = CG ( ast ) ;
2019-03-14 08:46:04 +00:00
while ( last & & last - > kind = = ZEND_AST_STMT_LIST ) {
2015-03-18 12:31:29 +00:00
zend_ast_list * list = zend_ast_get_list ( last ) ;
2019-10-02 10:06:00 +00:00
if ( list - > children = = 0 ) {
break ;
}
2015-03-18 12:31:29 +00:00
last = list - > child [ list - > children - 1 ] ;
}
2019-03-14 08:46:04 +00:00
if ( last & & last - > kind = = ZEND_AST_HALT_COMPILER ) {
2015-03-18 12:31:29 +00:00
result - > op_type = IS_CONST ;
2015-07-29 17:18:13 +00:00
ZVAL_LONG ( & result - > u . constant , Z_LVAL_P ( zend_ast_get_zval ( last - > child [ 0 ] ) ) ) ;
2018-05-28 13:27:12 +00:00
zend_string_release_ex ( resolved_name , 0 ) ;
2015-03-18 12:31:29 +00:00
return ;
}
}
2015-07-29 17:18:13 +00:00
if ( zend_try_ct_eval_const ( & result - > u . constant , resolved_name , is_fully_qualified ) ) {
result - > op_type = IS_CONST ;
2018-05-28 13:27:12 +00:00
zend_string_release_ex ( resolved_name , 0 ) ;
2015-07-29 17:18:13 +00:00
return ;
}
2014-12-13 22:06:14 +00:00
opline = zend_emit_op_tmp ( result , ZEND_FETCH_CONSTANT , NULL , NULL ) ;
2014-06-19 11:57:29 +00:00
opline - > op2_type = IS_CONST ;
2019-01-31 11:25:51 +00:00
if ( is_fully_qualified | | ! FC ( current_namespace ) ) {
2014-06-19 11:57:29 +00:00
opline - > op2 . constant = zend_add_const_name_literal (
2018-12-07 14:47:56 +00:00
resolved_name , 0 ) ;
2014-06-19 11:57:29 +00:00
} else {
2019-01-31 11:25:51 +00:00
opline - > op1 . num = IS_CONSTANT_UNQUALIFIED_IN_NAMESPACE ;
opline - > op2 . constant = zend_add_const_name_literal (
resolved_name , 1 ) ;
2011-07-07 23:07:14 +00:00
}
2018-02-05 16:41:47 +00:00
opline - > extended_value = zend_alloc_cache_slot ( ) ;
2007-09-28 19:52:53 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2007-09-28 19:52:53 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_class_const ( znode * result , zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-19 11:57:29 +00:00
zend_ast * class_ast = ast - > child [ 0 ] ;
zend_ast * const_ast = ast - > child [ 1 ] ;
2007-09-28 19:52:53 +00:00
2014-06-19 11:57:29 +00:00
znode class_node , const_node ;
2015-02-13 14:33:50 +00:00
zend_op * opline ;
2015-02-10 14:43:23 +00:00
2017-05-08 03:32:08 +00:00
zend_eval_const_expr ( & ast - > child [ 0 ] ) ;
zend_eval_const_expr ( & ast - > child [ 1 ] ) ;
class_ast = ast - > child [ 0 ] ;
const_ast = ast - > child [ 1 ] ;
2015-02-10 14:43:23 +00:00
if ( class_ast - > kind = = ZEND_AST_ZVAL ) {
2015-10-27 12:47:58 +00:00
zend_string * resolved_name ;
2015-02-10 14:43:23 +00:00
resolved_name = zend_resolve_class_name_ast ( class_ast ) ;
if ( const_ast - > kind = = ZEND_AST_ZVAL & & zend_try_ct_eval_class_const ( & result - > u . constant , resolved_name , zend_ast_get_str ( const_ast ) ) ) {
result - > op_type = IS_CONST ;
2018-05-28 13:27:12 +00:00
zend_string_release_ex ( resolved_name , 0 ) ;
2015-02-10 14:43:23 +00:00
return ;
}
2018-05-28 13:27:12 +00:00
zend_string_release_ex ( resolved_name , 0 ) ;
2015-02-10 14:43:23 +00:00
}
2014-06-19 11:57:29 +00:00
2019-01-02 08:48:29 +00:00
zend_compile_class_ref ( & class_node , class_ast , ZEND_FETCH_CLASS_EXCEPTION ) ;
2007-09-28 19:52:53 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & const_node , const_ast ) ;
2014-06-19 11:57:29 +00:00
2015-10-27 12:47:58 +00:00
opline = zend_emit_op_tmp ( result , ZEND_FETCH_CLASS_CONSTANT , NULL , & const_node ) ;
2014-06-19 11:57:29 +00:00
2014-12-13 22:06:14 +00:00
zend_set_class_name_op1 ( opline , & class_node ) ;
2014-06-19 11:57:29 +00:00
2019-01-07 11:28:51 +00:00
opline - > extended_value = zend_alloc_cache_slots ( 2 ) ;
2014-06-19 11:57:29 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-06-19 11:57:29 +00:00
2019-01-04 09:49:23 +00:00
void zend_compile_class_name ( znode * result , zend_ast * ast ) /* { { { */
{
zend_ast * class_ast = ast - > child [ 0 ] ;
2019-01-04 10:16:59 +00:00
if ( zend_try_compile_const_expr_resolve_class_name ( & result - > u . constant , class_ast ) ) {
2019-01-04 09:49:23 +00:00
result - > op_type = IS_CONST ;
return ;
}
2020-01-08 14:57:13 +00:00
if ( class_ast - > kind = = ZEND_AST_ZVAL ) {
zend_op * opline = zend_emit_op_tmp ( result , ZEND_FETCH_CLASS_NAME , NULL , NULL ) ;
opline - > op1 . num = zend_get_class_fetch_type ( zend_ast_get_str ( class_ast ) ) ;
} else {
znode expr_node ;
zend_compile_expr ( & expr_node , class_ast ) ;
if ( expr_node . op_type = = IS_CONST ) {
/* Unlikely case that happen if class_ast is constant folded.
* Handle it here , to avoid needing a CONST specialization in the VM . */
2020-05-26 12:10:57 +00:00
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use \" ::class \" on value of type %s " ,
2020-05-13 12:55:08 +00:00
zend_zval_type_name ( & expr_node . u . constant ) ) ;
2020-01-08 14:57:13 +00:00
}
zend_emit_op_tmp ( result , ZEND_FETCH_CLASS_NAME , & expr_node , NULL ) ;
}
2019-01-04 09:49:23 +00:00
}
/* }}} */
2019-01-21 20:34:09 +00:00
static zend_op * zend_compile_rope_add_ex ( zend_op * opline , znode * result , uint32_t num , znode * elem_node ) /* { { { */
{
if ( num = = 0 ) {
result - > op_type = IS_TMP_VAR ;
result - > u . op . var = - 1 ;
opline - > opcode = ZEND_ROPE_INIT ;
} else {
opline - > opcode = ZEND_ROPE_ADD ;
SET_NODE ( opline - > op1 , result ) ;
}
SET_NODE ( opline - > op2 , elem_node ) ;
SET_NODE ( opline - > result , result ) ;
opline - > extended_value = num ;
return opline ;
}
/* }}} */
2015-03-24 19:47:21 +00:00
static zend_op * zend_compile_rope_add ( znode * result , uint32_t num , znode * elem_node ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2018-12-07 14:47:56 +00:00
zend_op * opline = get_next_op ( ) ;
2014-06-21 18:03:29 +00:00
2015-03-24 19:47:21 +00:00
if ( num = = 0 ) {
result - > op_type = IS_TMP_VAR ;
result - > u . op . var = - 1 ;
opline - > opcode = ZEND_ROPE_INIT ;
} else {
opline - > opcode = ZEND_ROPE_ADD ;
SET_NODE ( opline - > op1 , result ) ;
}
SET_NODE ( opline - > op2 , elem_node ) ;
SET_NODE ( opline - > result , result ) ;
opline - > extended_value = num ;
return opline ;
}
/* }}} */
2007-09-28 19:52:53 +00:00
2015-03-24 19:47:21 +00:00
static void zend_compile_encaps_list ( znode * result , zend_ast * ast ) /* { { { */
{
uint32_t i , j ;
uint32_t rope_init_lineno = - 1 ;
zend_op * opline = NULL , * init_opline ;
znode elem_node , last_const_node ;
zend_ast_list * list = zend_ast_get_list ( ast ) ;
2019-01-21 20:34:09 +00:00
uint32_t reserved_op_number = - 1 ;
2014-06-21 18:03:29 +00:00
2015-03-24 19:47:21 +00:00
ZEND_ASSERT ( list - > children > 0 ) ;
2014-06-21 18:03:29 +00:00
2015-03-24 19:47:21 +00:00
j = 0 ;
last_const_node . op_type = IS_UNUSED ;
for ( i = 0 ; i < list - > children ; i + + ) {
zend_compile_expr ( & elem_node , list - > child [ i ] ) ;
2007-10-17 10:01:22 +00:00
2015-03-24 19:47:21 +00:00
if ( elem_node . op_type = = IS_CONST ) {
convert_to_string ( & elem_node . u . constant ) ;
2007-11-12 15:52:22 +00:00
2015-03-24 19:47:21 +00:00
if ( Z_STRLEN ( elem_node . u . constant ) = = 0 ) {
zval_ptr_dtor ( & elem_node . u . constant ) ;
} else if ( last_const_node . op_type = = IS_CONST ) {
concat_function ( & last_const_node . u . constant , & last_const_node . u . constant , & elem_node . u . constant ) ;
zval_ptr_dtor ( & elem_node . u . constant ) ;
2014-06-21 18:03:29 +00:00
} else {
2015-03-24 19:47:21 +00:00
last_const_node . op_type = IS_CONST ;
ZVAL_COPY_VALUE ( & last_const_node . u . constant , & elem_node . u . constant ) ;
2019-01-21 20:34:09 +00:00
/* Reserve place for ZEND_ROPE_ADD instruction */
reserved_op_number = get_next_op_number ( ) ;
opline = get_next_op ( ) ;
opline - > opcode = ZEND_NOP ;
2007-11-12 15:52:22 +00:00
}
2015-03-24 19:47:21 +00:00
continue ;
2014-06-21 18:03:29 +00:00
} else {
2015-03-24 19:47:21 +00:00
if ( j = = 0 ) {
2019-01-21 20:34:09 +00:00
if ( last_const_node . op_type = = IS_CONST ) {
rope_init_lineno = reserved_op_number ;
} else {
rope_init_lineno = get_next_op_number ( ) ;
}
2015-03-24 19:47:21 +00:00
}
if ( last_const_node . op_type = = IS_CONST ) {
2019-01-21 20:34:09 +00:00
opline = & CG ( active_op_array ) - > opcodes [ reserved_op_number ] ;
zend_compile_rope_add_ex ( opline , result , j + + , & last_const_node ) ;
2015-03-24 19:47:21 +00:00
last_const_node . op_type = IS_UNUSED ;
}
opline = zend_compile_rope_add ( result , j + + , & elem_node ) ;
2007-10-17 10:01:22 +00:00
}
2015-03-24 19:47:21 +00:00
}
2007-11-12 15:52:22 +00:00
2015-03-24 19:47:21 +00:00
if ( j = = 0 ) {
result - > op_type = IS_CONST ;
if ( last_const_node . op_type = = IS_CONST ) {
ZVAL_COPY_VALUE ( & result - > u . constant , & last_const_node . u . constant ) ;
} else {
ZVAL_EMPTY_STRING ( & result - > u . constant ) ;
/* empty string */
}
2019-01-21 20:34:09 +00:00
CG ( active_op_array ) - > last = reserved_op_number - 1 ;
2015-03-24 19:47:21 +00:00
return ;
} else if ( last_const_node . op_type = = IS_CONST ) {
2019-01-21 20:34:09 +00:00
opline = & CG ( active_op_array ) - > opcodes [ reserved_op_number ] ;
opline = zend_compile_rope_add_ex ( opline , result , j + + , & last_const_node ) ;
2015-03-24 19:47:21 +00:00
}
init_opline = CG ( active_op_array ) - > opcodes + rope_init_lineno ;
if ( j = = 1 ) {
if ( opline - > op2_type = = IS_CONST ) {
GET_NODE ( result , opline - > op2 ) ;
MAKE_NOP ( opline ) ;
2014-06-21 18:03:29 +00:00
} else {
2015-03-24 19:47:21 +00:00
opline - > opcode = ZEND_CAST ;
opline - > extended_value = IS_STRING ;
opline - > op1_type = opline - > op2_type ;
opline - > op1 = opline - > op2 ;
SET_UNUSED ( opline - > op2 ) ;
2020-04-24 10:10:06 +00:00
zend_make_tmp_result ( result , opline ) ;
2015-03-24 19:47:21 +00:00
}
} else if ( j = = 2 ) {
opline - > opcode = ZEND_FAST_CONCAT ;
opline - > extended_value = 0 ;
opline - > op1_type = init_opline - > op2_type ;
opline - > op1 = init_opline - > op2 ;
2020-04-24 10:10:06 +00:00
zend_make_tmp_result ( result , opline ) ;
2015-03-24 19:47:21 +00:00
MAKE_NOP ( init_opline ) ;
} else {
uint32_t var ;
init_opline - > extended_value = j ;
opline - > opcode = ZEND_ROPE_END ;
2020-04-24 10:10:06 +00:00
zend_make_tmp_result ( result , opline ) ;
2018-12-07 14:47:56 +00:00
var = opline - > op1 . var = get_temporary_variable ( ) ;
2015-03-24 19:47:21 +00:00
/* Allocates the necessary number of zval slots to keep the rope */
i = ( ( j * sizeof ( zend_string * ) ) + ( sizeof ( zval ) - 1 ) ) / sizeof ( zval ) ;
while ( i > 1 ) {
2018-12-07 14:47:56 +00:00
get_temporary_variable ( ) ;
2017-12-31 04:35:25 +00:00
i - - ;
2015-03-24 19:47:21 +00:00
}
2015-11-10 18:48:03 +00:00
2015-03-24 19:47:21 +00:00
/* Update all the previous opcodes to use the same variable */
while ( opline ! = init_opline ) {
opline - - ;
if ( opline - > opcode = = ZEND_ROPE_ADD & &
2016-04-29 11:44:56 +00:00
opline - > result . var = = ( uint32_t ) - 1 ) {
2015-03-24 19:47:21 +00:00
opline - > op1 . var = var ;
opline - > result . var = var ;
} else if ( opline - > opcode = = ZEND_ROPE_INIT & &
2016-04-29 11:44:56 +00:00
opline - > result . var = = ( uint32_t ) - 1 ) {
2015-03-24 19:47:21 +00:00
opline - > result . var = var ;
}
2007-11-12 15:52:22 +00:00
}
2007-09-28 19:52:53 +00:00
}
2014-06-21 18:03:29 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-06-21 18:03:29 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_magic_const ( znode * result , zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2015-05-05 16:22:20 +00:00
zend_op * opline ;
2014-12-13 22:06:14 +00:00
if ( zend_try_ct_eval_magic_const ( & result - > u . constant , ast ) ) {
2014-07-21 16:02:31 +00:00
result - > op_type = IS_CONST ;
return ;
2007-09-28 19:52:53 +00:00
}
2014-07-21 16:02:31 +00:00
2014-11-27 09:52:31 +00:00
ZEND_ASSERT ( ast - > attr = = T_CLASS_C & &
CG ( active_class_entry ) & &
2015-02-12 22:19:14 +00:00
( CG ( active_class_entry ) - > ce_flags & ZEND_ACC_TRAIT ) ! = 0 ) ;
2014-07-21 16:02:31 +00:00
2015-05-05 16:22:20 +00:00
opline = zend_emit_op_tmp ( result , ZEND_FETCH_CLASS_NAME , NULL , NULL ) ;
2018-01-31 15:14:43 +00:00
opline - > op1 . num = ZEND_FETCH_CLASS_SELF ;
2014-07-16 21:10:16 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-07-16 21:10:16 +00:00
2014-08-29 05:05:58 +00:00
zend_bool zend_is_allowed_in_const_expr ( zend_ast_kind kind ) /* { { { */
{
2014-06-28 16:03:26 +00:00
return kind = = ZEND_AST_ZVAL | | kind = = ZEND_AST_BINARY_OP
2014-06-26 20:02:54 +00:00
| | kind = = ZEND_AST_GREATER | | kind = = ZEND_AST_GREATER_EQUAL
2014-06-26 14:03:15 +00:00
| | kind = = ZEND_AST_AND | | kind = = ZEND_AST_OR
2014-07-27 20:26:06 +00:00
| | kind = = ZEND_AST_UNARY_OP
2014-06-26 14:03:15 +00:00
| | kind = = ZEND_AST_UNARY_PLUS | | kind = = ZEND_AST_UNARY_MINUS
2014-08-16 20:08:02 +00:00
| | kind = = ZEND_AST_CONDITIONAL | | kind = = ZEND_AST_DIM
2014-06-26 14:35:30 +00:00
| | kind = = ZEND_AST_ARRAY | | kind = = ZEND_AST_ARRAY_ELEM
2018-10-06 14:04:41 +00:00
| | kind = = ZEND_AST_UNPACK
2014-06-26 19:44:46 +00:00
| | kind = = ZEND_AST_CONST | | kind = = ZEND_AST_CLASS_CONST
2019-01-04 09:49:23 +00:00
| | kind = = ZEND_AST_CLASS_NAME
2016-04-17 08:27:15 +00:00
| | kind = = ZEND_AST_MAGIC_CONST | | kind = = ZEND_AST_COALESCE ;
2014-06-26 14:35:30 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-06-26 14:35:30 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_const_expr_class_const ( zend_ast * * ast_ptr ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-26 14:35:30 +00:00
zend_ast * ast = * ast_ptr ;
zend_ast * class_ast = ast - > child [ 0 ] ;
zend_ast * const_ast = ast - > child [ 1 ] ;
2014-09-22 22:40:17 +00:00
zend_string * class_name ;
2014-07-28 13:16:35 +00:00
zend_string * const_name = zend_ast_get_str ( const_ast ) ;
2017-10-10 07:11:05 +00:00
zend_string * name ;
2014-06-26 14:35:30 +00:00
int fetch_type ;
2014-06-28 16:03:26 +00:00
if ( class_ast - > kind ! = ZEND_AST_ZVAL ) {
2014-06-26 14:35:30 +00:00
zend_error_noreturn ( E_COMPILE_ERROR ,
" Dynamic class names are not allowed in compile-time class constant references " ) ;
2007-09-28 19:52:53 +00:00
}
2014-09-22 22:40:17 +00:00
class_name = zend_ast_get_str ( class_ast ) ;
2014-07-28 13:39:43 +00:00
fetch_type = zend_get_class_fetch_type ( class_name ) ;
2013-07-16 18:39:33 +00:00
2014-06-26 14:35:30 +00:00
if ( ZEND_FETCH_CLASS_STATIC = = fetch_type ) {
zend_error_noreturn ( E_COMPILE_ERROR ,
" \" static:: \" is not allowed in compile-time constants " ) ;
2014-07-19 21:30:07 +00:00
}
2015-01-03 09:22:58 +00:00
2014-07-19 21:30:07 +00:00
if ( ZEND_FETCH_CLASS_DEFAULT = = fetch_type ) {
2014-12-13 22:06:14 +00:00
class_name = zend_resolve_class_name_ast ( class_ast ) ;
2013-07-16 18:39:33 +00:00
} else {
2014-08-25 19:21:16 +00:00
zend_string_addref ( class_name ) ;
2013-07-16 18:39:33 +00:00
}
2020-04-14 14:52:13 +00:00
name = zend_create_member_string ( class_name , const_name ) ;
2014-06-26 14:35:30 +00:00
zend_ast_destroy ( ast ) ;
2018-05-28 13:27:12 +00:00
zend_string_release_ex ( class_name , 0 ) ;
2013-08-24 21:53:43 +00:00
2019-03-28 08:29:08 +00:00
* ast_ptr = zend_ast_create_constant ( name , fetch_type | ZEND_FETCH_CLASS_EXCEPTION ) ;
2014-06-26 14:03:15 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2013-08-24 21:53:43 +00:00
2019-01-04 09:49:23 +00:00
void zend_compile_const_expr_class_name ( zend_ast * * ast_ptr ) /* { { { */
{
2019-01-04 10:28:07 +00:00
zend_ast * ast = * ast_ptr ;
zend_ast * class_ast = ast - > child [ 0 ] ;
2020-01-08 14:57:13 +00:00
if ( class_ast - > kind ! = ZEND_AST_ZVAL ) {
zend_error_noreturn ( E_COMPILE_ERROR ,
" (expression)::class cannot be used in constant expressions " ) ;
}
2019-01-04 10:28:07 +00:00
zend_string * class_name = zend_ast_get_str ( class_ast ) ;
uint32_t fetch_type = zend_get_class_fetch_type ( class_name ) ;
2019-01-04 09:49:23 +00:00
2019-01-04 10:38:35 +00:00
switch ( fetch_type ) {
case ZEND_FETCH_CLASS_SELF :
case ZEND_FETCH_CLASS_PARENT :
/* For the const-eval representation store the fetch type instead of the name. */
zend_string_release ( class_name ) ;
ast - > child [ 0 ] = NULL ;
ast - > attr = fetch_type ;
return ;
case ZEND_FETCH_CLASS_STATIC :
zend_error_noreturn ( E_COMPILE_ERROR ,
" static::class cannot be used for compile-time class name resolution " ) ;
return ;
EMPTY_SWITCH_DEFAULT_CASE ( )
2019-01-04 10:16:59 +00:00
}
2019-01-04 09:49:23 +00:00
}
2014-12-13 22:06:14 +00:00
void zend_compile_const_expr_const ( zend_ast * * ast_ptr ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-26 14:56:50 +00:00
zend_ast * ast = * ast_ptr ;
2014-06-28 20:27:06 +00:00
zend_ast * name_ast = ast - > child [ 0 ] ;
2014-09-23 18:21:28 +00:00
zend_string * orig_name = zend_ast_get_str ( name_ast ) ;
2014-07-22 11:25:47 +00:00
zend_bool is_fully_qualified ;
2017-10-10 07:11:05 +00:00
zval result ;
zend_string * resolved_name ;
2014-06-26 14:56:50 +00:00
2017-10-10 07:11:05 +00:00
resolved_name = zend_resolve_const_name (
orig_name , name_ast - > attr , & is_fully_qualified ) ;
2014-06-26 14:56:50 +00:00
2017-10-10 07:11:05 +00:00
if ( zend_try_ct_eval_const ( & result , resolved_name , is_fully_qualified ) ) {
2018-05-28 13:27:12 +00:00
zend_string_release_ex ( resolved_name , 0 ) ;
2014-06-26 14:56:50 +00:00
zend_ast_destroy ( ast ) ;
2019-03-28 08:29:08 +00:00
* ast_ptr = zend_ast_create_zval ( & result ) ;
2014-06-26 14:56:50 +00:00
return ;
}
zend_ast_destroy ( ast ) ;
2019-03-28 08:31:18 +00:00
* ast_ptr = zend_ast_create_constant ( resolved_name ,
2019-01-31 11:25:51 +00:00
! is_fully_qualified & & FC ( current_namespace ) ? IS_CONSTANT_UNQUALIFIED_IN_NAMESPACE : 0 ) ;
2014-06-26 14:56:50 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2013-08-24 21:53:43 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_const_expr_magic_const ( zend_ast * * ast_ptr ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-21 16:21:13 +00:00
zend_ast * ast = * ast_ptr ;
2013-11-09 02:37:38 +00:00
2014-07-21 16:21:13 +00:00
/* Other cases already resolved by constant folding */
2019-01-04 08:52:04 +00:00
ZEND_ASSERT ( ast - > attr = = T_CLASS_C ) ;
2013-11-09 02:37:38 +00:00
2017-10-10 07:11:05 +00:00
zend_ast_destroy ( ast ) ;
2019-03-28 08:29:08 +00:00
* ast_ptr = zend_ast_create ( ZEND_AST_CONSTANT_CLASS ) ;
2013-07-16 18:39:33 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2013-07-16 18:39:33 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_const_expr ( zend_ast * * ast_ptr ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-06-26 14:03:15 +00:00
zend_ast * ast = * ast_ptr ;
2014-06-28 16:03:26 +00:00
if ( ast = = NULL | | ast - > kind = = ZEND_AST_ZVAL ) {
2014-06-26 14:03:15 +00:00
return ;
2013-07-23 18:21:48 +00:00
}
2014-06-26 14:03:15 +00:00
if ( ! zend_is_allowed_in_const_expr ( ast - > kind ) ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Constant expression contains invalid operations " ) ;
2013-07-23 18:21:48 +00:00
}
2014-06-26 14:35:30 +00:00
switch ( ast - > kind ) {
case ZEND_AST_CLASS_CONST :
2014-12-13 22:06:14 +00:00
zend_compile_const_expr_class_const ( ast_ptr ) ;
2014-06-26 14:35:30 +00:00
break ;
2019-01-04 09:49:23 +00:00
case ZEND_AST_CLASS_NAME :
zend_compile_const_expr_class_name ( ast_ptr ) ;
break ;
2014-06-26 14:56:50 +00:00
case ZEND_AST_CONST :
2014-12-13 22:06:14 +00:00
zend_compile_const_expr_const ( ast_ptr ) ;
2014-06-26 14:56:50 +00:00
break ;
2014-07-21 16:21:13 +00:00
case ZEND_AST_MAGIC_CONST :
2014-12-13 22:06:14 +00:00
zend_compile_const_expr_magic_const ( ast_ptr ) ;
2014-07-21 16:21:13 +00:00
break ;
2014-07-30 15:29:59 +00:00
default :
2014-12-13 22:06:14 +00:00
zend_ast_apply ( ast , zend_compile_const_expr ) ;
2014-07-30 15:29:59 +00:00
break ;
2014-06-26 14:35:30 +00:00
}
2013-07-23 18:21:48 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2013-07-23 18:21:48 +00:00
2014-12-13 22:06:14 +00:00
void zend_const_expr_to_zval ( zval * result , zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-30 15:44:26 +00:00
zend_ast * orig_ast = ast ;
2014-12-13 22:06:14 +00:00
zend_eval_const_expr ( & ast ) ;
zend_compile_const_expr ( & ast ) ;
2014-07-30 15:44:26 +00:00
if ( ast - > kind = = ZEND_AST_ZVAL ) {
ZVAL_COPY_VALUE ( result , zend_ast_get_zval ( ast ) ) ;
} else {
2017-10-09 13:57:51 +00:00
ZVAL_AST ( result , zend_ast_copy ( ast ) ) ;
2016-04-21 00:45:09 +00:00
/* destroy the ast here, it might have been replaced */
zend_ast_destroy ( ast ) ;
2007-09-28 19:52:53 +00:00
}
2016-04-21 00:45:09 +00:00
/* Kill this branch of the original AST, as it was already destroyed.
* It would be nice to find a better solution to this problem in the
* future . */
orig_ast - > kind = 0 ;
2014-07-30 15:44:26 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2007-09-28 19:52:53 +00:00
2014-07-22 11:02:51 +00:00
/* Same as compile_stmt, but with early binding */
2014-12-13 22:06:14 +00:00
void zend_compile_top_stmt ( zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-22 11:02:51 +00:00
if ( ! ast ) {
return ;
2007-09-28 19:52:53 +00:00
}
2014-07-22 11:02:51 +00:00
if ( ast - > kind = = ZEND_AST_STMT_LIST ) {
2014-07-27 20:26:06 +00:00
zend_ast_list * list = zend_ast_get_list ( ast ) ;
2014-08-25 19:21:16 +00:00
uint32_t i ;
2014-07-27 20:26:06 +00:00
for ( i = 0 ; i < list - > children ; + + i ) {
2014-12-13 22:06:14 +00:00
zend_compile_top_stmt ( list - > child [ i ] ) ;
2013-08-24 22:05:55 +00:00
}
2014-07-22 11:02:51 +00:00
return ;
2013-08-24 22:05:55 +00:00
}
2018-08-24 12:18:38 +00:00
if ( ast - > kind = = ZEND_AST_FUNC_DECL ) {
CG ( zend_lineno ) = ast - > lineno ;
zend_compile_func_decl ( NULL , ast , 1 ) ;
CG ( zend_lineno ) = ( ( zend_ast_decl * ) ast ) - > end_lineno ;
} else if ( ast - > kind = = ZEND_AST_CLASS ) {
CG ( zend_lineno ) = ast - > lineno ;
2020-04-24 10:04:54 +00:00
zend_compile_class_decl ( NULL , ast , 1 ) ;
2018-08-24 12:18:38 +00:00
CG ( zend_lineno ) = ( ( zend_ast_decl * ) ast ) - > end_lineno ;
} else {
zend_compile_stmt ( ast ) ;
}
2014-07-22 13:50:23 +00:00
if ( ast - > kind ! = ZEND_AST_NAMESPACE & & ast - > kind ! = ZEND_AST_HALT_COMPILER ) {
2014-12-13 22:06:14 +00:00
zend_verify_namespace ( ) ;
2014-07-22 12:08:52 +00:00
}
2008-11-25 09:56:32 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2008-11-25 09:56:32 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_stmt ( zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-09 21:39:21 +00:00
if ( ! ast ) {
return ;
2007-09-28 19:52:53 +00:00
}
2014-07-09 21:39:21 +00:00
2014-07-12 15:10:10 +00:00
CG ( zend_lineno ) = ast - > lineno ;
2014-07-12 12:03:42 +00:00
2019-02-19 08:08:38 +00:00
if ( ( CG ( compiler_options ) & ZEND_COMPILE_EXTENDED_STMT ) & & ! zend_is_unticked_stmt ( ast ) ) {
zend_do_extended_stmt ( ) ;
2015-07-22 11:12:54 +00:00
}
2014-06-07 11:06:53 +00:00
switch ( ast - > kind ) {
2014-07-09 21:39:21 +00:00
case ZEND_AST_STMT_LIST :
2014-12-13 22:06:14 +00:00
zend_compile_stmt_list ( ast ) ;
2014-07-09 22:00:48 +00:00
break ;
2014-06-07 11:06:53 +00:00
case ZEND_AST_GLOBAL :
2014-12-13 22:06:14 +00:00
zend_compile_global_var ( ast ) ;
2014-07-09 22:00:48 +00:00
break ;
2014-07-12 15:00:53 +00:00
case ZEND_AST_STATIC :
2014-12-13 22:06:14 +00:00
zend_compile_static_var ( ast ) ;
2014-07-12 15:00:53 +00:00
break ;
2014-06-07 11:06:53 +00:00
case ZEND_AST_UNSET :
2014-12-13 22:06:14 +00:00
zend_compile_unset ( ast ) ;
2014-07-09 22:00:48 +00:00
break ;
2014-07-07 19:06:02 +00:00
case ZEND_AST_RETURN :
2014-12-13 22:06:14 +00:00
zend_compile_return ( ast ) ;
2014-07-09 22:00:48 +00:00
break ;
2014-07-27 20:26:06 +00:00
case ZEND_AST_ECHO :
2014-12-13 22:06:14 +00:00
zend_compile_echo ( ast ) ;
2014-07-09 22:00:48 +00:00
break ;
2014-07-27 20:26:06 +00:00
case ZEND_AST_BREAK :
case ZEND_AST_CONTINUE :
2014-12-13 22:06:14 +00:00
zend_compile_break_continue ( ast ) ;
2014-07-09 22:00:48 +00:00
break ;
2014-07-27 20:26:06 +00:00
case ZEND_AST_GOTO :
2014-12-13 22:06:14 +00:00
zend_compile_goto ( ast ) ;
2014-07-09 22:00:48 +00:00
break ;
2014-07-09 21:46:22 +00:00
case ZEND_AST_LABEL :
2014-12-13 22:06:14 +00:00
zend_compile_label ( ast ) ;
2014-07-09 22:00:48 +00:00
break ;
2014-07-10 12:35:59 +00:00
case ZEND_AST_WHILE :
2014-12-13 22:06:14 +00:00
zend_compile_while ( ast ) ;
2014-07-10 12:35:59 +00:00
break ;
2014-07-10 12:46:22 +00:00
case ZEND_AST_DO_WHILE :
2014-12-13 22:06:14 +00:00
zend_compile_do_while ( ast ) ;
2014-07-10 12:46:22 +00:00
break ;
2014-07-10 13:51:47 +00:00
case ZEND_AST_FOR :
2014-12-13 22:06:14 +00:00
zend_compile_for ( ast ) ;
2014-07-10 13:51:47 +00:00
break ;
2014-07-11 10:16:21 +00:00
case ZEND_AST_FOREACH :
2014-12-13 22:06:14 +00:00
zend_compile_foreach ( ast ) ;
2014-07-11 10:16:21 +00:00
break ;
2014-07-10 14:38:04 +00:00
case ZEND_AST_IF :
2014-12-13 22:06:14 +00:00
zend_compile_if ( ast ) ;
2014-07-10 14:38:04 +00:00
break ;
2014-07-11 13:31:47 +00:00
case ZEND_AST_SWITCH :
2014-12-13 22:06:14 +00:00
zend_compile_switch ( ast ) ;
2014-07-11 13:31:47 +00:00
break ;
2014-07-12 11:50:58 +00:00
case ZEND_AST_TRY :
2014-12-13 22:06:14 +00:00
zend_compile_try ( ast ) ;
2014-07-12 11:50:58 +00:00
break ;
2014-07-22 14:11:19 +00:00
case ZEND_AST_DECLARE :
2014-12-13 22:06:14 +00:00
zend_compile_declare ( ast ) ;
2014-07-22 14:11:19 +00:00
break ;
2014-07-15 22:06:41 +00:00
case ZEND_AST_FUNC_DECL :
2014-07-19 10:52:44 +00:00
case ZEND_AST_METHOD :
2018-08-24 12:18:38 +00:00
zend_compile_func_decl ( NULL , ast , 0 ) ;
2014-07-15 22:06:41 +00:00
break ;
2019-01-07 11:28:51 +00:00
case ZEND_AST_PROP_GROUP :
zend_compile_prop_group ( ast ) ;
2014-07-19 12:54:56 +00:00
break ;
2020-05-24 18:57:00 +00:00
case ZEND_AST_CLASS_CONST_GROUP :
2020-07-06 16:23:27 +00:00
zend_compile_class_const_group ( ast ) ;
2014-07-19 13:13:50 +00:00
break ;
2014-07-19 20:39:01 +00:00
case ZEND_AST_USE_TRAIT :
2014-12-13 22:06:14 +00:00
zend_compile_use_trait ( ast ) ;
2014-07-19 20:39:01 +00:00
break ;
2014-07-21 14:34:45 +00:00
case ZEND_AST_CLASS :
2020-04-24 10:04:54 +00:00
zend_compile_class_decl ( NULL , ast , 0 ) ;
2014-07-21 14:34:45 +00:00
break ;
2015-03-07 20:59:20 +00:00
case ZEND_AST_GROUP_USE :
zend_compile_group_use ( ast ) ;
2015-01-19 05:22:23 +00:00
break ;
2014-07-21 20:49:31 +00:00
case ZEND_AST_USE :
2014-12-13 22:06:14 +00:00
zend_compile_use ( ast ) ;
2014-07-21 20:49:31 +00:00
break ;
2014-07-22 09:55:07 +00:00
case ZEND_AST_CONST_DECL :
2014-12-13 22:06:14 +00:00
zend_compile_const_decl ( ast ) ;
2014-07-22 09:55:07 +00:00
break ;
2014-07-22 10:45:44 +00:00
case ZEND_AST_NAMESPACE :
2014-12-13 22:06:14 +00:00
zend_compile_namespace ( ast ) ;
2014-07-22 10:45:44 +00:00
break ;
2014-07-22 12:22:59 +00:00
case ZEND_AST_HALT_COMPILER :
2014-12-13 22:06:14 +00:00
zend_compile_halt_compiler ( ast ) ;
2014-07-22 12:22:59 +00:00
break ;
2020-04-24 14:12:06 +00:00
case ZEND_AST_THROW :
2020-05-24 10:42:48 +00:00
zend_compile_expr ( NULL , ast ) ;
2020-04-24 14:12:06 +00:00
break ;
2014-07-09 22:04:27 +00:00
default :
{
znode result ;
2014-12-13 22:06:14 +00:00
zend_compile_expr ( & result , ast ) ;
zend_do_free ( & result ) ;
2014-07-09 22:04:27 +00:00
}
2013-07-16 18:39:33 +00:00
}
2014-07-09 22:00:48 +00:00
2015-04-20 18:16:58 +00:00
if ( FC ( declarables ) . ticks & & ! zend_is_unticked_stmt ( ast ) ) {
2014-12-13 22:06:14 +00:00
zend_emit_tick ( ) ;
2013-07-23 18:21:48 +00:00
}
2007-09-28 19:52:53 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2007-09-28 19:52:53 +00:00
2020-05-24 10:42:48 +00:00
static void zend_compile_expr_inner ( znode * result , zend_ast * ast ) /* { { { */
2014-08-29 05:05:58 +00:00
{
/* CG(zend_lineno) = ast->lineno; */
2014-07-27 11:25:32 +00:00
CG ( zend_lineno ) = zend_ast_get_lineno ( ast ) ;
2008-11-25 09:56:32 +00:00
2019-01-15 16:04:24 +00:00
if ( CG ( memoize_mode ) ! = ZEND_MEMOIZE_NONE ) {
zend_compile_memoized_expr ( result , ast ) ;
return ;
}
2014-06-07 11:06:53 +00:00
switch ( ast - > kind ) {
2014-06-28 16:03:26 +00:00
case ZEND_AST_ZVAL :
2014-06-07 11:06:53 +00:00
ZVAL_COPY ( & result - > u . constant , zend_ast_get_zval ( ast ) ) ;
result - > op_type = IS_CONST ;
return ;
case ZEND_AST_ZNODE :
* result = * zend_ast_get_znode ( ast ) ;
return ;
case ZEND_AST_VAR :
case ZEND_AST_DIM :
case ZEND_AST_PROP :
2020-05-24 10:42:48 +00:00
case ZEND_AST_NULLSAFE_PROP :
2014-06-07 11:06:53 +00:00
case ZEND_AST_STATIC_PROP :
case ZEND_AST_CALL :
case ZEND_AST_METHOD_CALL :
2020-05-24 10:42:48 +00:00
case ZEND_AST_NULLSAFE_METHOD_CALL :
2014-06-07 11:06:53 +00:00
case ZEND_AST_STATIC_CALL :
2019-01-07 11:28:51 +00:00
zend_compile_var ( result , ast , BP_VAR_R , 0 ) ;
2014-06-07 11:06:53 +00:00
return ;
case ZEND_AST_ASSIGN :
2014-12-13 22:06:14 +00:00
zend_compile_assign ( result , ast ) ;
2014-06-07 11:06:53 +00:00
return ;
case ZEND_AST_ASSIGN_REF :
2014-12-13 22:06:14 +00:00
zend_compile_assign_ref ( result , ast ) ;
2014-06-07 11:06:53 +00:00
return ;
2014-07-27 20:26:06 +00:00
case ZEND_AST_NEW :
2014-12-13 22:06:14 +00:00
zend_compile_new ( result , ast ) ;
2014-06-14 16:30:18 +00:00
return ;
2014-07-27 20:26:06 +00:00
case ZEND_AST_CLONE :
2014-12-13 22:06:14 +00:00
zend_compile_clone ( result , ast ) ;
2014-06-14 16:30:18 +00:00
return ;
2014-06-19 11:57:29 +00:00
case ZEND_AST_ASSIGN_OP :
2014-12-13 22:06:14 +00:00
zend_compile_compound_assign ( result , ast ) ;
2014-06-07 11:06:53 +00:00
return ;
2014-06-19 11:57:29 +00:00
case ZEND_AST_BINARY_OP :
2014-12-13 22:06:14 +00:00
zend_compile_binary_op ( result , ast ) ;
2014-06-14 16:30:18 +00:00
return ;
case ZEND_AST_GREATER :
case ZEND_AST_GREATER_EQUAL :
2014-12-13 22:06:14 +00:00
zend_compile_greater ( result , ast ) ;
2014-06-14 16:30:18 +00:00
return ;
2014-07-27 20:26:06 +00:00
case ZEND_AST_UNARY_OP :
2014-12-13 22:06:14 +00:00
zend_compile_unary_op ( result , ast ) ;
2014-06-14 16:30:18 +00:00
return ;
2014-06-26 10:43:20 +00:00
case ZEND_AST_UNARY_PLUS :
case ZEND_AST_UNARY_MINUS :
2014-12-13 22:06:14 +00:00
zend_compile_unary_pm ( result , ast ) ;
2014-06-14 16:30:18 +00:00
return ;
case ZEND_AST_AND :
case ZEND_AST_OR :
2014-12-13 22:06:14 +00:00
zend_compile_short_circuiting ( result , ast ) ;
2014-06-14 16:30:18 +00:00
return ;
2014-07-27 20:26:06 +00:00
case ZEND_AST_POST_INC :
case ZEND_AST_POST_DEC :
2014-12-13 22:06:14 +00:00
zend_compile_post_incdec ( result , ast ) ;
2014-06-14 16:30:18 +00:00
return ;
2014-07-27 20:26:06 +00:00
case ZEND_AST_PRE_INC :
case ZEND_AST_PRE_DEC :
2014-12-13 22:06:14 +00:00
zend_compile_pre_incdec ( result , ast ) ;
2014-06-14 16:30:18 +00:00
return ;
2014-06-19 11:57:29 +00:00
case ZEND_AST_CAST :
2014-12-13 22:06:14 +00:00
zend_compile_cast ( result , ast ) ;
2014-06-14 16:30:18 +00:00
return ;
case ZEND_AST_CONDITIONAL :
2014-12-13 22:06:14 +00:00
zend_compile_conditional ( result , ast ) ;
2014-06-14 16:30:18 +00:00
return ;
2014-09-16 18:14:46 +00:00
case ZEND_AST_COALESCE :
2014-12-13 22:06:14 +00:00
zend_compile_coalesce ( result , ast ) ;
2014-09-16 18:14:46 +00:00
return ;
2019-01-15 16:04:24 +00:00
case ZEND_AST_ASSIGN_COALESCE :
zend_compile_assign_coalesce ( result , ast ) ;
return ;
2014-07-27 20:26:06 +00:00
case ZEND_AST_PRINT :
2014-12-13 22:06:14 +00:00
zend_compile_print ( result , ast ) ;
2014-06-14 16:30:18 +00:00
return ;
2014-07-27 20:26:06 +00:00
case ZEND_AST_EXIT :
2014-12-13 22:06:14 +00:00
zend_compile_exit ( result , ast ) ;
2014-06-14 16:30:18 +00:00
return ;
2014-07-27 20:26:06 +00:00
case ZEND_AST_YIELD :
2014-12-13 22:06:14 +00:00
zend_compile_yield ( result , ast ) ;
2014-06-14 16:30:18 +00:00
return ;
2015-02-20 11:59:56 +00:00
case ZEND_AST_YIELD_FROM :
zend_compile_yield_from ( result , ast ) ;
return ;
2014-07-27 20:26:06 +00:00
case ZEND_AST_INSTANCEOF :
2014-12-13 22:06:14 +00:00
zend_compile_instanceof ( result , ast ) ;
2014-06-14 16:30:18 +00:00
return ;
2014-07-27 20:26:06 +00:00
case ZEND_AST_INCLUDE_OR_EVAL :
2014-12-13 22:06:14 +00:00
zend_compile_include_or_eval ( result , ast ) ;
2014-06-19 11:57:29 +00:00
return ;
case ZEND_AST_ISSET :
case ZEND_AST_EMPTY :
2014-12-13 22:06:14 +00:00
zend_compile_isset_or_empty ( result , ast ) ;
2014-06-19 11:57:29 +00:00
return ;
case ZEND_AST_SILENCE :
2014-12-13 22:06:14 +00:00
zend_compile_silence ( result , ast ) ;
2014-06-19 11:57:29 +00:00
return ;
case ZEND_AST_SHELL_EXEC :
2014-12-13 22:06:14 +00:00
zend_compile_shell_exec ( result , ast ) ;
2014-06-19 11:57:29 +00:00
return ;
case ZEND_AST_ARRAY :
2014-12-13 22:06:14 +00:00
zend_compile_array ( result , ast ) ;
2014-06-19 11:57:29 +00:00
return ;
case ZEND_AST_CONST :
2014-12-13 22:06:14 +00:00
zend_compile_const ( result , ast ) ;
2014-06-19 11:57:29 +00:00
return ;
case ZEND_AST_CLASS_CONST :
2014-12-13 22:06:14 +00:00
zend_compile_class_const ( result , ast ) ;
2014-06-19 11:57:29 +00:00
return ;
2019-01-04 09:49:23 +00:00
case ZEND_AST_CLASS_NAME :
zend_compile_class_name ( result , ast ) ;
return ;
2014-06-21 18:03:29 +00:00
case ZEND_AST_ENCAPS_LIST :
2014-12-13 22:06:14 +00:00
zend_compile_encaps_list ( result , ast ) ;
2014-06-21 18:03:29 +00:00
return ;
2014-07-16 21:10:16 +00:00
case ZEND_AST_MAGIC_CONST :
2014-12-13 22:06:14 +00:00
zend_compile_magic_const ( result , ast ) ;
2014-07-16 21:10:16 +00:00
return ;
2014-07-18 10:58:24 +00:00
case ZEND_AST_CLOSURE :
2019-05-02 12:57:16 +00:00
case ZEND_AST_ARROW_FUNC :
2018-08-24 12:18:38 +00:00
zend_compile_func_decl ( result , ast , 0 ) ;
2014-07-18 10:58:24 +00:00
return ;
2020-03-18 23:51:51 +00:00
case ZEND_AST_THROW :
zend_compile_throw ( result , ast ) ;
2020-04-23 18:26:08 +00:00
return ;
2020-04-09 20:36:37 +00:00
case ZEND_AST_MATCH :
zend_compile_match ( result , ast ) ;
return ;
2014-06-07 11:06:53 +00:00
default :
ZEND_ASSERT ( 0 /* not supported */ ) ;
2013-11-06 18:21:07 +00:00
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
2013-11-06 18:21:07 +00:00
2020-05-24 10:42:48 +00:00
void zend_compile_expr ( znode * result , zend_ast * ast )
{
uint32_t checkpoint = zend_short_circuiting_checkpoint ( ) ;
zend_compile_expr_inner ( result , ast ) ;
zend_short_circuiting_commit ( checkpoint , result , ast ) ;
}
2020-08-28 13:41:27 +00:00
static zend_op * zend_compile_var_inner ( znode * result , zend_ast * ast , uint32_t type , bool by_ref )
2014-08-29 05:05:58 +00:00
{
2017-04-15 16:06:42 +00:00
CG ( zend_lineno ) = zend_ast_get_lineno ( ast ) ;
2014-06-07 11:06:53 +00:00
switch ( ast - > kind ) {
case ZEND_AST_VAR :
2019-01-07 11:28:51 +00:00
return zend_compile_simple_var ( result , ast , type , 0 ) ;
2014-06-07 11:06:53 +00:00
case ZEND_AST_DIM :
2019-01-07 11:28:51 +00:00
return zend_compile_dim ( result , ast , type ) ;
2014-06-07 11:06:53 +00:00
case ZEND_AST_PROP :
2020-05-24 10:42:48 +00:00
case ZEND_AST_NULLSAFE_PROP :
2019-01-07 11:28:51 +00:00
return zend_compile_prop ( result , ast , type , by_ref ) ;
2014-06-07 11:06:53 +00:00
case ZEND_AST_STATIC_PROP :
2019-01-07 11:28:51 +00:00
return zend_compile_static_prop ( result , ast , type , by_ref , 0 ) ;
2014-06-07 11:06:53 +00:00
case ZEND_AST_CALL :
2014-12-13 22:06:14 +00:00
zend_compile_call ( result , ast , type ) ;
2019-01-07 11:28:51 +00:00
return NULL ;
2014-06-07 11:06:53 +00:00
case ZEND_AST_METHOD_CALL :
2020-05-24 10:42:48 +00:00
case ZEND_AST_NULLSAFE_METHOD_CALL :
2014-12-13 22:06:14 +00:00
zend_compile_method_call ( result , ast , type ) ;
2019-01-07 11:28:51 +00:00
return NULL ;
2014-06-07 11:06:53 +00:00
case ZEND_AST_STATIC_CALL :
2014-12-13 22:06:14 +00:00
zend_compile_static_call ( result , ast , type ) ;
2019-01-07 11:28:51 +00:00
return NULL ;
2014-08-15 15:10:06 +00:00
case ZEND_AST_ZNODE :
* result = * zend_ast_get_znode ( ast ) ;
2019-01-07 11:28:51 +00:00
return NULL ;
2014-06-07 11:06:53 +00:00
default :
2015-12-11 14:56:52 +00:00
if ( type = = BP_VAR_W | | type = = BP_VAR_RW | | type = = BP_VAR_UNSET ) {
2014-09-10 13:55:26 +00:00
zend_error_noreturn ( E_COMPILE_ERROR ,
" Cannot use temporary expression in write context " ) ;
2014-06-19 11:57:29 +00:00
}
2008-02-12 00:21:15 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr ( result , ast ) ;
2019-01-07 11:28:51 +00:00
return NULL ;
2011-01-19 17:17:52 +00:00
}
2014-06-07 11:06:53 +00:00
}
2020-05-24 10:42:48 +00:00
2020-08-28 13:41:27 +00:00
zend_op * zend_compile_var ( znode * result , zend_ast * ast , uint32_t type , bool by_ref ) /* { { { */
2020-05-24 10:42:48 +00:00
{
uint32_t checkpoint = zend_short_circuiting_checkpoint ( ) ;
zend_op * opcode = zend_compile_var_inner ( result , ast , type , by_ref ) ;
zend_short_circuiting_commit ( checkpoint , result , ast ) ;
return opcode ;
}
2008-02-12 00:21:15 +00:00
2019-01-07 11:28:51 +00:00
zend_op * zend_delayed_compile_var ( znode * result , zend_ast * ast , uint32_t type , zend_bool by_ref ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-08-15 15:10:06 +00:00
switch ( ast - > kind ) {
2015-02-02 17:44:16 +00:00
case ZEND_AST_VAR :
2019-01-07 11:28:51 +00:00
return zend_compile_simple_var ( result , ast , type , 1 ) ;
2014-08-15 15:10:06 +00:00
case ZEND_AST_DIM :
2019-01-07 11:28:51 +00:00
return zend_delayed_compile_dim ( result , ast , type ) ;
2014-08-15 15:10:06 +00:00
case ZEND_AST_PROP :
2020-05-24 10:42:48 +00:00
case ZEND_AST_NULLSAFE_PROP :
2019-01-07 11:28:51 +00:00
{
zend_op * opline = zend_delayed_compile_prop ( result , ast , type ) ;
if ( by_ref ) {
opline - > extended_value | = ZEND_FETCH_REF ;
}
return opline ;
}
2015-02-02 17:44:16 +00:00
case ZEND_AST_STATIC_PROP :
2019-01-07 11:28:51 +00:00
return zend_compile_static_prop ( result , ast , type , by_ref , 1 ) ;
2014-08-15 15:10:06 +00:00
default :
2019-01-07 11:28:51 +00:00
return zend_compile_var ( result , ast , type , 0 ) ;
2008-02-12 00:21:15 +00:00
}
2014-08-15 15:10:06 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2008-02-12 00:21:15 +00:00
2014-12-13 22:06:14 +00:00
void zend_eval_const_expr ( zend_ast * * ast_ptr ) /* { { { */
2014-08-29 05:05:58 +00:00
{
2014-07-21 16:02:31 +00:00
zend_ast * ast = * ast_ptr ;
zval result ;
2008-02-12 00:21:15 +00:00
2014-07-30 15:29:59 +00:00
if ( ! ast ) {
2014-06-23 19:30:57 +00:00
return ;
2008-02-12 00:21:15 +00:00
}
2014-06-23 19:30:57 +00:00
switch ( ast - > kind ) {
case ZEND_AST_BINARY_OP :
2014-12-13 22:06:14 +00:00
zend_eval_const_expr ( & ast - > child [ 0 ] ) ;
zend_eval_const_expr ( & ast - > child [ 1 ] ) ;
2014-07-29 21:22:23 +00:00
if ( ast - > child [ 0 ] - > kind ! = ZEND_AST_ZVAL | | ast - > child [ 1 ] - > kind ! = ZEND_AST_ZVAL ) {
return ;
}
2015-06-16 16:09:59 +00:00
if ( ! zend_try_ct_eval_binary_op ( & result , ast - > attr ,
zend_ast_get_zval ( ast - > child [ 0 ] ) , zend_ast_get_zval ( ast - > child [ 1 ] ) )
) {
return ;
2015-04-06 11:30:05 +00:00
}
2014-06-23 19:30:57 +00:00
break ;
2014-06-26 10:43:20 +00:00
case ZEND_AST_GREATER :
case ZEND_AST_GREATER_EQUAL :
2014-12-13 22:06:14 +00:00
zend_eval_const_expr ( & ast - > child [ 0 ] ) ;
zend_eval_const_expr ( & ast - > child [ 1 ] ) ;
2014-07-29 21:22:23 +00:00
if ( ast - > child [ 0 ] - > kind ! = ZEND_AST_ZVAL | | ast - > child [ 1 ] - > kind ! = ZEND_AST_ZVAL ) {
return ;
}
zend_ct_eval_greater ( & result , ast - > kind ,
2014-12-13 22:06:14 +00:00
zend_ast_get_zval ( ast - > child [ 0 ] ) , zend_ast_get_zval ( ast - > child [ 1 ] ) ) ;
2014-06-26 10:43:20 +00:00
break ;
2015-06-16 14:53:17 +00:00
case ZEND_AST_AND :
case ZEND_AST_OR :
{
2019-12-06 10:07:57 +00:00
zend_bool child0_is_true , child1_is_true ;
zend_eval_const_expr ( & ast - > child [ 0 ] ) ;
zend_eval_const_expr ( & ast - > child [ 1 ] ) ;
if ( ast - > child [ 0 ] - > kind ! = ZEND_AST_ZVAL ) {
return ;
2015-06-16 14:53:17 +00:00
}
2019-12-06 10:07:57 +00:00
child0_is_true = zend_is_true ( zend_ast_get_zval ( ast - > child [ 0 ] ) ) ;
if ( child0_is_true = = ( ast - > kind = = ZEND_AST_OR ) ) {
ZVAL_BOOL ( & result , ast - > kind = = ZEND_AST_OR ) ;
break ;
}
if ( ast - > child [ 1 ] - > kind ! = ZEND_AST_ZVAL ) {
2015-06-16 14:53:17 +00:00
return ;
}
2019-12-06 10:07:57 +00:00
child1_is_true = zend_is_true ( zend_ast_get_zval ( ast - > child [ 1 ] ) ) ;
2015-06-16 14:53:17 +00:00
if ( ast - > kind = = ZEND_AST_OR ) {
2019-12-06 10:07:57 +00:00
ZVAL_BOOL ( & result , child0_is_true | | child1_is_true ) ;
2015-06-16 14:53:17 +00:00
} else {
2019-12-06 10:07:57 +00:00
ZVAL_BOOL ( & result , child0_is_true & & child1_is_true ) ;
2015-06-16 14:53:17 +00:00
}
break ;
}
case ZEND_AST_UNARY_OP :
zend_eval_const_expr ( & ast - > child [ 0 ] ) ;
if ( ast - > child [ 0 ] - > kind ! = ZEND_AST_ZVAL ) {
return ;
}
zend_ct_eval_unary_op ( & result , ast - > attr , zend_ast_get_zval ( ast - > child [ 0 ] ) ) ;
break ;
2014-06-26 10:43:20 +00:00
case ZEND_AST_UNARY_PLUS :
case ZEND_AST_UNARY_MINUS :
2014-12-13 22:06:14 +00:00
zend_eval_const_expr ( & ast - > child [ 0 ] ) ;
2014-07-29 21:22:23 +00:00
if ( ast - > child [ 0 ] - > kind ! = ZEND_AST_ZVAL ) {
return ;
}
2016-03-30 00:44:27 +00:00
if ( ! zend_try_ct_eval_unary_pm ( & result , ast - > kind , zend_ast_get_zval ( ast - > child [ 0 ] ) ) ) {
return ;
}
2015-06-16 14:53:17 +00:00
break ;
2016-04-21 00:45:09 +00:00
case ZEND_AST_COALESCE :
2016-04-21 19:51:00 +00:00
/* Set isset fetch indicator here, opcache disallows runtime altering of the AST */
if ( ast - > child [ 0 ] - > kind = = ZEND_AST_DIM ) {
2019-03-13 10:51:31 +00:00
ast - > child [ 0 ] - > attr | = ZEND_DIM_IS ;
2016-04-21 19:51:00 +00:00
}
2016-04-21 00:45:09 +00:00
zend_eval_const_expr ( & ast - > child [ 0 ] ) ;
if ( ast - > child [ 0 ] - > kind ! = ZEND_AST_ZVAL ) {
/* ensure everything was compile-time evaluated at least once */
zend_eval_const_expr ( & ast - > child [ 1 ] ) ;
return ;
}
if ( Z_TYPE_P ( zend_ast_get_zval ( ast - > child [ 0 ] ) ) = = IS_NULL ) {
zend_eval_const_expr ( & ast - > child [ 1 ] ) ;
* ast_ptr = ast - > child [ 1 ] ;
ast - > child [ 1 ] = NULL ;
zend_ast_destroy ( ast ) ;
} else {
* ast_ptr = ast - > child [ 0 ] ;
ast - > child [ 0 ] = NULL ;
zend_ast_destroy ( ast ) ;
}
return ;
2015-06-16 14:53:17 +00:00
case ZEND_AST_CONDITIONAL :
{
zend_ast * * child , * child_ast ;
zend_eval_const_expr ( & ast - > child [ 0 ] ) ;
if ( ast - > child [ 0 ] - > kind ! = ZEND_AST_ZVAL ) {
/* ensure everything was compile-time evaluated at least once */
if ( ast - > child [ 1 ] ) {
zend_eval_const_expr ( & ast - > child [ 1 ] ) ;
}
zend_eval_const_expr ( & ast - > child [ 2 ] ) ;
return ;
}
child = & ast - > child [ 2 - zend_is_true ( zend_ast_get_zval ( ast - > child [ 0 ] ) ) ] ;
if ( * child = = NULL ) {
child - - ;
}
child_ast = * child ;
* child = NULL ;
zend_ast_destroy ( ast ) ;
* ast_ptr = child_ast ;
zend_eval_const_expr ( ast_ptr ) ;
return ;
}
case ZEND_AST_DIM :
{
/* constant expression should be always read context ... */
zval * container , * dim ;
2015-11-13 13:01:11 +00:00
if ( ast - > child [ 1 ] = = NULL ) {
zend_error_noreturn ( E_COMPILE_ERROR , " Cannot use [] for reading " ) ;
}
2019-03-13 10:51:31 +00:00
if ( ast - > attr & ZEND_DIM_ALTERNATIVE_SYNTAX ) {
ast - > attr & = ~ ZEND_DIM_ALTERNATIVE_SYNTAX ; /* remove flag to avoid duplicate warning */
2020-05-22 14:52:17 +00:00
zend_error ( E_COMPILE_ERROR , " Array and string offset access syntax with curly braces is no longer supported " ) ;
2019-03-13 10:51:31 +00:00
}
2016-04-21 19:51:00 +00:00
/* Set isset fetch indicator here, opcache disallows runtime altering of the AST */
2020-06-07 00:38:13 +00:00
if ( ( ast - > attr & ZEND_DIM_IS ) & & ast - > child [ 0 ] - > kind = = ZEND_AST_DIM ) {
2019-03-13 10:51:31 +00:00
ast - > child [ 0 ] - > attr | = ZEND_DIM_IS ;
2016-04-21 19:51:00 +00:00
}
2015-06-16 14:53:17 +00:00
zend_eval_const_expr ( & ast - > child [ 0 ] ) ;
zend_eval_const_expr ( & ast - > child [ 1 ] ) ;
2015-11-13 13:01:11 +00:00
if ( ast - > child [ 0 ] - > kind ! = ZEND_AST_ZVAL | | ast - > child [ 1 ] - > kind ! = ZEND_AST_ZVAL ) {
2015-06-16 14:53:17 +00:00
return ;
}
container = zend_ast_get_zval ( ast - > child [ 0 ] ) ;
dim = zend_ast_get_zval ( ast - > child [ 1 ] ) ;
if ( Z_TYPE_P ( container ) = = IS_ARRAY ) {
zval * el ;
if ( Z_TYPE_P ( dim ) = = IS_LONG ) {
el = zend_hash_index_find ( Z_ARR_P ( container ) , Z_LVAL_P ( dim ) ) ;
if ( el ) {
ZVAL_COPY ( & result , el ) ;
} else {
return ;
}
} else if ( Z_TYPE_P ( dim ) = = IS_STRING ) {
el = zend_symtable_find ( Z_ARR_P ( container ) , Z_STR_P ( dim ) ) ;
if ( el ) {
ZVAL_COPY ( & result , el ) ;
} else {
return ;
}
} else {
return ; /* warning... handle at runtime */
}
} else if ( Z_TYPE_P ( container ) = = IS_STRING ) {
zend_long offset ;
zend_uchar c ;
if ( Z_TYPE_P ( dim ) = = IS_LONG ) {
offset = Z_LVAL_P ( dim ) ;
} else if ( Z_TYPE_P ( dim ) ! = IS_STRING | | is_numeric_string ( Z_STRVAL_P ( dim ) , Z_STRLEN_P ( dim ) , & offset , NULL , 1 ) ! = IS_LONG ) {
return ;
}
2015-09-23 20:19:05 +00:00
if ( offset < 0 | | ( size_t ) offset > = Z_STRLEN_P ( container ) ) {
2015-06-16 14:53:17 +00:00
return ;
}
c = ( zend_uchar ) Z_STRVAL_P ( container ) [ offset ] ;
2020-06-08 10:45:01 +00:00
ZVAL_CHAR ( & result , c ) ;
2015-06-16 14:53:17 +00:00
} else if ( Z_TYPE_P ( container ) < = IS_FALSE ) {
ZVAL_NULL ( & result ) ;
} else {
return ;
}
2014-06-26 10:43:20 +00:00
break ;
2015-06-16 14:53:17 +00:00
}
2014-06-23 19:30:57 +00:00
case ZEND_AST_ARRAY :
2014-12-13 22:06:14 +00:00
if ( ! zend_try_ct_eval_array ( & result , ast ) ) {
2014-07-29 21:22:23 +00:00
return ;
}
2014-06-23 19:30:57 +00:00
break ;
2014-07-21 16:02:31 +00:00
case ZEND_AST_MAGIC_CONST :
2014-12-13 22:06:14 +00:00
if ( ! zend_try_ct_eval_magic_const ( & result , ast ) ) {
2014-07-29 21:22:23 +00:00
return ;
}
2014-07-21 16:02:31 +00:00
break ;
2014-09-23 18:21:28 +00:00
case ZEND_AST_CONST :
2014-09-28 21:17:29 +00:00
{
zend_ast * name_ast = ast - > child [ 0 ] ;
zend_bool is_fully_qualified ;
zend_string * resolved_name = zend_resolve_const_name (
2014-12-13 22:06:14 +00:00
zend_ast_get_str ( name_ast ) , name_ast - > attr , & is_fully_qualified ) ;
2014-09-28 21:17:29 +00:00
2014-12-13 22:06:14 +00:00
if ( ! zend_try_ct_eval_const ( & result , resolved_name , is_fully_qualified ) ) {
2018-05-28 13:27:12 +00:00
zend_string_release_ex ( resolved_name , 0 ) ;
2014-08-26 09:06:19 +00:00
return ;
}
2014-09-28 21:17:29 +00:00
2018-05-28 13:27:12 +00:00
zend_string_release_ex ( resolved_name , 0 ) ;
2014-09-23 18:21:28 +00:00
break ;
2014-09-28 21:17:29 +00:00
}
2015-02-10 14:43:23 +00:00
case ZEND_AST_CLASS_CONST :
{
2019-01-04 09:49:23 +00:00
zend_ast * class_ast ;
zend_ast * name_ast ;
2015-02-10 14:43:23 +00:00
zend_string * resolved_name ;
2017-05-08 03:36:07 +00:00
zend_eval_const_expr ( & ast - > child [ 0 ] ) ;
zend_eval_const_expr ( & ast - > child [ 1 ] ) ;
class_ast = ast - > child [ 0 ] ;
name_ast = ast - > child [ 1 ] ;
2015-02-10 14:43:23 +00:00
if ( class_ast - > kind ! = ZEND_AST_ZVAL | | name_ast - > kind ! = ZEND_AST_ZVAL ) {
return ;
}
resolved_name = zend_resolve_class_name_ast ( class_ast ) ;
if ( ! zend_try_ct_eval_class_const ( & result , resolved_name , zend_ast_get_str ( name_ast ) ) ) {
2018-05-28 13:27:12 +00:00
zend_string_release_ex ( resolved_name , 0 ) ;
2015-02-10 14:43:23 +00:00
return ;
}
2018-05-28 13:27:12 +00:00
zend_string_release_ex ( resolved_name , 0 ) ;
2015-02-10 14:43:23 +00:00
break ;
}
2019-01-04 09:49:23 +00:00
case ZEND_AST_CLASS_NAME :
{
zend_ast * class_ast = ast - > child [ 0 ] ;
2019-01-04 10:16:59 +00:00
if ( ! zend_try_compile_const_expr_resolve_class_name ( & result , class_ast ) ) {
return ;
2019-01-04 09:49:23 +00:00
}
2019-01-04 10:16:59 +00:00
break ;
2019-01-04 09:49:23 +00:00
}
2014-07-29 21:22:23 +00:00
default :
return ;
2008-02-12 00:21:15 +00:00
}
2014-07-29 21:22:23 +00:00
zend_ast_destroy ( ast ) ;
2019-03-28 08:29:08 +00:00
* ast_ptr = zend_ast_create_zval ( & result ) ;
2008-02-12 00:21:15 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */