/Zend/zend_compile.c
C | 9277 lines | 8026 code | 924 blank | 327 comment | 1618 complexity | a142d13b4798cf62d9d1e736f262e637 MD5 | raw file
Possible License(s): BSD-2-Clause, BSD-3-Clause, MPL-2.0-no-copyleft-exception, LGPL-2.1
Large files files are truncated, but you can click here to view the full file
- /*
- +----------------------------------------------------------------------+
- | Zend Engine |
- +----------------------------------------------------------------------+
- | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
- +----------------------------------------------------------------------+
- | This source file is subject to version 2.00 of the Zend license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.zend.com/license/2_00.txt. |
- | 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. |
- +----------------------------------------------------------------------+
- | Authors: Andi Gutmans <andi@php.net> |
- | Zeev Suraski <zeev@php.net> |
- | Nikita Popov <nikic@php.net> |
- +----------------------------------------------------------------------+
- */
- #include <zend_language_parser.h>
- #include "zend.h"
- #include "zend_compile.h"
- #include "zend_constants.h"
- #include "zend_llist.h"
- #include "zend_API.h"
- #include "zend_exceptions.h"
- #include "zend_interfaces.h"
- #include "zend_virtual_cwd.h"
- #include "zend_multibyte.h"
- #include "zend_language_scanner.h"
- #include "zend_inheritance.h"
- #include "zend_vm.h"
- #define SET_NODE(target, src) do { \
- target ## _type = (src)->op_type; \
- if ((src)->op_type == IS_CONST) { \
- target.constant = zend_add_literal(&(src)->u.constant); \
- } else { \
- target = (src)->u.op; \
- } \
- } while (0)
- #define GET_NODE(target, src) do { \
- (target)->op_type = src ## _type; \
- if ((target)->op_type == IS_CONST) { \
- ZVAL_COPY_VALUE(&(target)->u.constant, CT_CONSTANT(src)); \
- } else { \
- (target)->u.op = src; \
- } \
- } while (0)
- #define FC(member) (CG(file_context).member)
- typedef struct _zend_loop_var {
- zend_uchar opcode;
- zend_uchar var_type;
- uint32_t var_num;
- uint32_t try_catch_offset;
- } zend_loop_var;
- static inline uint32_t zend_alloc_cache_slots(unsigned count) {
- if (count == 0) {
- return (uint32_t) -1;
- }
- zend_op_array *op_array = CG(active_op_array);
- uint32_t ret = op_array->cache_size;
- op_array->cache_size += count * sizeof(void*);
- return ret;
- }
- static inline uint32_t zend_alloc_cache_slot(void) {
- return zend_alloc_cache_slots(1);
- }
- ZEND_API zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle, int type);
- ZEND_API zend_op_array *(*zend_compile_string)(zval *source_string, const char *filename);
- #ifndef ZTS
- ZEND_API zend_compiler_globals compiler_globals;
- ZEND_API zend_executor_globals executor_globals;
- #endif
- static zend_op *zend_emit_op(znode *result, zend_uchar opcode, znode *op1, znode *op2);
- static zend_bool zend_try_ct_eval_array(zval *result, zend_ast *ast);
- static void init_op(zend_op *op)
- {
- MAKE_NOP(op);
- op->extended_value = 0;
- op->lineno = CG(zend_lineno);
- }
- static zend_always_inline uint32_t get_next_op_number(void)
- {
- return CG(active_op_array)->last;
- }
- static zend_op *get_next_op(void)
- {
- zend_op_array *op_array = CG(active_op_array);
- 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];
- }
- static void zend_destroy_property_info_internal(zval *zv) /* {{{ */
- {
- zend_property_info *property_info = Z_PTR_P(zv);
- zend_string_release(property_info->name);
- zend_type_release(property_info->type, /* persistent */ 1);
- free(property_info);
- }
- /* }}} */
- static zend_string *zend_build_runtime_definition_key(zend_string *name, uint32_t start_lineno) /* {{{ */
- {
- zend_string *filename = CG(active_op_array)->filename;
- zend_string *result = zend_strpprintf(0, "%c%s%s:%" PRIu32 "$%" PRIx32,
- '\0', ZSTR_VAL(name), ZSTR_VAL(filename), start_lineno, CG(rtd_key_counter)++);
- return zend_new_interned_string(result);
- }
- /* }}} */
- static zend_bool zend_get_unqualified_name(const zend_string *name, const char **result, size_t *result_len) /* {{{ */
- {
- const char *ns_separator = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
- if (ns_separator != NULL) {
- *result = ns_separator + 1;
- *result_len = ZSTR_VAL(name) + ZSTR_LEN(name) - *result;
- return 1;
- }
- return 0;
- }
- /* }}} */
- 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")},
- {ZEND_STRL("void")},
- {ZEND_STRL("iterable")},
- {ZEND_STRL("object")},
- {NULL, 0}
- };
- static zend_bool zend_is_reserved_class_name(const zend_string *name) /* {{{ */
- {
- const struct reserved_class_name *reserved = reserved_class_names;
- const char *uqname = ZSTR_VAL(name);
- size_t uqname_len = ZSTR_LEN(name);
- 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;
- }
- /* }}} */
- void zend_assert_valid_class_name(const zend_string *name) /* {{{ */
- {
- if (zend_is_reserved_class_name(name)) {
- zend_error_noreturn(E_COMPILE_ERROR,
- "Cannot use '%s' as class name as it is reserved", ZSTR_VAL(name));
- }
- }
- /* }}} */
- typedef struct _builtin_type_info {
- const char* name;
- const size_t name_len;
- const zend_uchar type;
- } builtin_type_info;
- static const builtin_type_info builtin_types[] = {
- {ZEND_STRL("null"), IS_NULL},
- {ZEND_STRL("false"), IS_FALSE},
- {ZEND_STRL("int"), IS_LONG},
- {ZEND_STRL("float"), IS_DOUBLE},
- {ZEND_STRL("string"), IS_STRING},
- {ZEND_STRL("bool"), _IS_BOOL},
- {ZEND_STRL("void"), IS_VOID},
- {ZEND_STRL("iterable"), IS_ITERABLE},
- {ZEND_STRL("object"), IS_OBJECT},
- {NULL, 0, IS_UNDEF}
- };
- 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},
- };
- static zend_always_inline zend_uchar zend_lookup_builtin_type_by_name(const zend_string *name) /* {{{ */
- {
- const builtin_type_info *info = &builtin_types[0];
- for (; info->name; ++info) {
- if (ZSTR_LEN(name) == info->name_len
- && zend_binary_strcasecmp(ZSTR_VAL(name), ZSTR_LEN(name), info->name, info->name_len) == 0
- ) {
- return info->type;
- }
- }
- return 0;
- }
- /* }}} */
- 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. */
- return !FC(imports) || zend_hash_find_ptr_lc(FC(imports), name) == NULL;
- }
- void zend_oparray_context_begin(zend_oparray_context *prev_context) /* {{{ */
- {
- *prev_context = CG(context);
- CG(context).opcodes_size = INITIAL_OP_ARRAY_SIZE;
- CG(context).vars_size = 0;
- CG(context).literals_size = 0;
- CG(context).fast_call_var = -1;
- CG(context).try_catch_offset = -1;
- CG(context).current_brk_cont = -1;
- CG(context).last_brk_cont = 0;
- CG(context).brk_cont_array = NULL;
- CG(context).labels = NULL;
- }
- /* }}} */
- void zend_oparray_context_end(zend_oparray_context *prev_context) /* {{{ */
- {
- if (CG(context).brk_cont_array) {
- efree(CG(context).brk_cont_array);
- CG(context).brk_cont_array = NULL;
- }
- 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) /* {{{ */
- {
- if (FC(imports)) {
- zend_hash_destroy(FC(imports));
- efree(FC(imports));
- FC(imports) = NULL;
- }
- if (FC(imports_function)) {
- zend_hash_destroy(FC(imports_function));
- efree(FC(imports_function));
- FC(imports_function) = NULL;
- }
- 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)) {
- zend_string_release_ex(FC(current_namespace), 0);
- FC(current_namespace) = NULL;
- }
- }
- /* }}} */
- void zend_file_context_begin(zend_file_context *prev_context) /* {{{ */
- {
- *prev_context = CG(file_context);
- 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;
- zend_hash_init(&FC(seen_symbols), 8, NULL, NULL, 0);
- }
- /* }}} */
- void zend_file_context_end(zend_file_context *prev_context) /* {{{ */
- {
- zend_end_namespace();
- zend_hash_destroy(&FC(seen_symbols));
- CG(file_context) = *prev_context;
- }
- /* }}} */
- void zend_init_compiler_data_structures(void) /* {{{ */
- {
- zend_stack_init(&CG(loop_var_stack), sizeof(zend_loop_var));
- zend_stack_init(&CG(delayed_oplines_stack), sizeof(zend_op));
- CG(active_class_entry) = NULL;
- CG(in_compilation) = 0;
- CG(skip_shebang) = 0;
- CG(encoding_declared) = 0;
- CG(memoized_exprs) = NULL;
- CG(memoize_mode) = 0;
- }
- /* }}} */
- 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;
- }
- ZEND_API void file_handle_dtor(zend_file_handle *fh) /* {{{ */
- {
- zend_file_handle_dtor(fh);
- }
- /* }}} */
- void init_compiler(void) /* {{{ */
- {
- CG(arena) = zend_arena_create(64 * 1024);
- CG(active_op_array) = NULL;
- memset(&CG(context), 0, sizeof(CG(context)));
- zend_init_compiler_data_structures();
- zend_init_rsrc_list();
- zend_hash_init(&CG(filenames_table), 8, NULL, ZVAL_PTR_DTOR, 0);
- zend_llist_init(&CG(open_files), sizeof(zend_file_handle), (void (*)(void *)) file_handle_dtor, 0);
- CG(unclean_shutdown) = 0;
- CG(delayed_variance_obligations) = NULL;
- CG(delayed_autoloads) = NULL;
- }
- /* }}} */
- void shutdown_compiler(void) /* {{{ */
- {
- zend_stack_destroy(&CG(loop_var_stack));
- zend_stack_destroy(&CG(delayed_oplines_stack));
- zend_hash_destroy(&CG(filenames_table));
- zend_arena_destroy(CG(arena));
- 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;
- }
- }
- /* }}} */
- ZEND_API zend_string *zend_set_compiled_filename(zend_string *new_compiled_filename) /* {{{ */
- {
- zval *p, rv;
- if ((p = zend_hash_find(&CG(filenames_table), new_compiled_filename))) {
- ZEND_ASSERT(Z_TYPE_P(p) == IS_STRING);
- CG(compiled_filename) = Z_STR_P(p);
- return Z_STR_P(p);
- }
- new_compiled_filename = zend_new_interned_string(zend_string_copy(new_compiled_filename));
- ZVAL_STR(&rv, new_compiled_filename);
- zend_hash_add_new(&CG(filenames_table), new_compiled_filename, &rv);
- CG(compiled_filename) = new_compiled_filename;
- return new_compiled_filename;
- }
- /* }}} */
- ZEND_API void zend_restore_compiled_filename(zend_string *original_compiled_filename) /* {{{ */
- {
- CG(compiled_filename) = original_compiled_filename;
- }
- /* }}} */
- ZEND_API zend_string *zend_get_compiled_filename(void) /* {{{ */
- {
- return CG(compiled_filename);
- }
- /* }}} */
- ZEND_API int zend_get_compiled_lineno(void) /* {{{ */
- {
- return CG(zend_lineno);
- }
- /* }}} */
- ZEND_API zend_bool zend_is_compiling(void) /* {{{ */
- {
- return CG(in_compilation);
- }
- /* }}} */
- static zend_always_inline uint32_t get_temporary_variable(void) /* {{{ */
- {
- return (uint32_t)CG(active_op_array)->T++;
- }
- /* }}} */
- static int lookup_cv(zend_string *name) /* {{{ */{
- zend_op_array *op_array = CG(active_op_array);
- int i = 0;
- zend_ulong hash_value = zend_string_hash_val(name);
- while (i < op_array->last_var) {
- if (ZSTR_H(op_array->vars[i]) == hash_value
- && zend_string_equals(op_array->vars[i], name)) {
- return EX_NUM_TO_VAR(i);
- }
- i++;
- }
- i = op_array->last_var;
- op_array->last_var++;
- if (op_array->last_var > CG(context).vars_size) {
- CG(context).vars_size += 16; /* FIXME */
- op_array->vars = erealloc(op_array->vars, CG(context).vars_size * sizeof(zend_string*));
- }
- op_array->vars[i] = zend_string_copy(name);
- return EX_NUM_TO_VAR(i);
- }
- /* }}} */
- static inline zend_string *zval_make_interned_string(zval *zv) /* {{{ */
- {
- 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))) {
- Z_TYPE_FLAGS_P(zv) = 0;
- }
- return Z_STR_P(zv);
- }
- /* Common part of zend_add_literal and zend_append_individual_literal */
- static inline void zend_insert_literal(zend_op_array *op_array, zval *zv, int literal_position) /* {{{ */
- {
- zval *lit = CT_CONSTANT_EX(op_array, literal_position);
- if (Z_TYPE_P(zv) == IS_STRING) {
- zval_make_interned_string(zv);
- }
- ZVAL_COPY_VALUE(lit, zv);
- Z_EXTRA_P(lit) = 0;
- }
- /* }}} */
- /* 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()). */
- static int zend_add_literal(zval *zv) /* {{{ */
- {
- zend_op_array *op_array = CG(active_op_array);
- int i = op_array->last_literal;
- op_array->last_literal++;
- if (i >= CG(context).literals_size) {
- while (i >= CG(context).literals_size) {
- CG(context).literals_size += 16; /* FIXME */
- }
- op_array->literals = (zval*)erealloc(op_array->literals, CG(context).literals_size * sizeof(zval));
- }
- zend_insert_literal(op_array, zv, i);
- return i;
- }
- /* }}} */
- static inline int zend_add_literal_string(zend_string **str) /* {{{ */
- {
- int ret;
- zval zv;
- ZVAL_STR(&zv, *str);
- ret = zend_add_literal(&zv);
- *str = Z_STR(zv);
- return ret;
- }
- /* }}} */
- static int zend_add_func_name_literal(zend_string *name) /* {{{ */
- {
- /* Original name */
- int ret = zend_add_literal_string(&name);
- /* Lowercased name */
- zend_string *lc_name = zend_string_tolower(name);
- zend_add_literal_string(&lc_name);
- return ret;
- }
- /* }}} */
- static int zend_add_ns_func_name_literal(zend_string *name) /* {{{ */
- {
- const char *unqualified_name;
- size_t unqualified_name_len;
- /* Original name */
- int ret = zend_add_literal_string(&name);
- /* Lowercased name */
- zend_string *lc_name = zend_string_tolower(name);
- zend_add_literal_string(&lc_name);
- /* Lowercased unqualfied name */
- if (zend_get_unqualified_name(name, &unqualified_name, &unqualified_name_len)) {
- lc_name = zend_string_alloc(unqualified_name_len, 0);
- zend_str_tolower_copy(ZSTR_VAL(lc_name), unqualified_name, unqualified_name_len);
- zend_add_literal_string(&lc_name);
- }
- return ret;
- }
- /* }}} */
- static int zend_add_class_name_literal(zend_string *name) /* {{{ */
- {
- /* Original name */
- int ret = zend_add_literal_string(&name);
- /* Lowercased name */
- zend_string *lc_name = zend_string_tolower(name);
- zend_add_literal_string(&lc_name);
- return ret;
- }
- /* }}} */
- static int zend_add_const_name_literal(zend_string *name, zend_bool unqualified) /* {{{ */
- {
- zend_string *tmp_name;
- int ret = zend_add_literal_string(&name);
- size_t ns_len = 0, after_ns_len = ZSTR_LEN(name);
- const char *after_ns = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
- if (after_ns) {
- after_ns += 1;
- ns_len = after_ns - ZSTR_VAL(name) - 1;
- after_ns_len = ZSTR_LEN(name) - ns_len - 1;
- /* lowercased namespace name & original constant name */
- tmp_name = zend_string_init(ZSTR_VAL(name), ZSTR_LEN(name), 0);
- zend_str_tolower(ZSTR_VAL(tmp_name), ns_len);
- zend_add_literal_string(&tmp_name);
- if (!unqualified) {
- return ret;
- }
- } else {
- after_ns = ZSTR_VAL(name);
- }
- /* original unqualified constant name */
- tmp_name = zend_string_init(after_ns, after_ns_len, 0);
- zend_add_literal_string(&tmp_name);
- return ret;
- }
- /* }}} */
- #define LITERAL_STR(op, str) do { \
- zval _c; \
- ZVAL_STR(&_c, str); \
- op.constant = zend_add_literal(&_c); \
- } while (0)
- void zend_stop_lexing(void)
- {
- if (LANG_SCNG(on_event)) {
- LANG_SCNG(on_event)(ON_STOP, END, 0, LANG_SCNG(on_event_context));
- }
- LANG_SCNG(yy_cursor) = LANG_SCNG(yy_limit);
- }
- static inline void zend_begin_loop(
- zend_uchar free_opcode, const znode *loop_var, zend_bool is_switch) /* {{{ */
- {
- zend_brk_cont_element *brk_cont_element;
- int parent = CG(context).current_brk_cont;
- zend_loop_var info = {0};
- CG(context).current_brk_cont = CG(context).last_brk_cont;
- brk_cont_element = get_next_brk_cont_element();
- brk_cont_element->parent = parent;
- brk_cont_element->is_switch = is_switch;
- if (loop_var && (loop_var->op_type & (IS_VAR|IS_TMP_VAR))) {
- uint32_t start = get_next_op_number();
- info.opcode = free_opcode;
- info.var_type = loop_var->op_type;
- info.var_num = loop_var->u.op.var;
- brk_cont_element->start = start;
- } else {
- info.opcode = ZEND_NOP;
- /* 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;
- }
- zend_stack_push(&CG(loop_var_stack), &info);
- }
- /* }}} */
- static inline void zend_end_loop(int cont_addr, const znode *var_node) /* {{{ */
- {
- uint32_t end = get_next_op_number();
- zend_brk_cont_element *brk_cont_element
- = &CG(context).brk_cont_array[CG(context).current_brk_cont];
- brk_cont_element->cont = cont_addr;
- brk_cont_element->brk = end;
- CG(context).current_brk_cont = brk_cont_element->parent;
- zend_stack_del_top(&CG(loop_var_stack));
- }
- /* }}} */
- void zend_do_free(znode *op1) /* {{{ */
- {
- if (op1->op_type == IS_TMP_VAR) {
- zend_op *opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1];
- while (opline->opcode == ZEND_END_SILENCE ||
- opline->opcode == ZEND_OP_DATA) {
- opline--;
- }
- if (opline->result_type == IS_TMP_VAR && opline->result.var == op1->u.op.var) {
- 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;
- 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;
- }
- }
- zend_emit_op(NULL, ZEND_FREE, op1, NULL);
- } else if (op1->op_type == IS_VAR) {
- zend_op *opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1];
- while (opline->opcode == ZEND_END_SILENCE ||
- opline->opcode == ZEND_EXT_FCALL_END ||
- opline->opcode == ZEND_OP_DATA) {
- opline--;
- }
- if (opline->result_type == IS_VAR
- && opline->result.var == op1->u.op.var) {
- if (opline->opcode == ZEND_FETCH_THIS) {
- opline->opcode = ZEND_NOP;
- opline->result_type = IS_UNUSED;
- } else {
- opline->result_type = IS_UNUSED;
- }
- } else {
- while (opline >= CG(active_op_array)->opcodes) {
- if ((opline->opcode == ZEND_FETCH_LIST_R ||
- opline->opcode == ZEND_FETCH_LIST_W) &&
- opline->op1_type == IS_VAR &&
- opline->op1.var == op1->u.op.var) {
- zend_emit_op(NULL, ZEND_FREE, op1, NULL);
- return;
- }
- if (opline->result_type == IS_VAR
- && opline->result.var == op1->u.op.var) {
- if (opline->opcode == ZEND_NEW) {
- zend_emit_op(NULL, ZEND_FREE, op1, NULL);
- }
- break;
- }
- opline--;
- }
- }
- } else if (op1->op_type == IS_CONST) {
- /* 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. */
- zval_ptr_dtor_nogc(&op1->u.constant);
- }
- }
- /* }}} */
- 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)) {
- zend_throw_exception(zend_ce_compile_error,
- "Multiple abstract modifiers are not allowed", 0);
- return 0;
- }
- if ((flags & ZEND_ACC_FINAL) && (new_flag & ZEND_ACC_FINAL)) {
- zend_throw_exception(zend_ce_compile_error, "Multiple final modifiers are not allowed", 0);
- return 0;
- }
- if ((new_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) && (new_flags & ZEND_ACC_FINAL)) {
- zend_throw_exception(zend_ce_compile_error,
- "Cannot use the final modifier on an abstract class", 0);
- return 0;
- }
- return new_flags;
- }
- /* }}} */
- uint32_t zend_add_member_modifier(uint32_t flags, uint32_t new_flag) /* {{{ */
- {
- uint32_t new_flags = flags | new_flag;
- if ((flags & ZEND_ACC_PPP_MASK) && (new_flag & ZEND_ACC_PPP_MASK)) {
- zend_throw_exception(zend_ce_compile_error,
- "Multiple access type modifiers are not allowed", 0);
- return 0;
- }
- if ((flags & ZEND_ACC_ABSTRACT) && (new_flag & ZEND_ACC_ABSTRACT)) {
- zend_throw_exception(zend_ce_compile_error, "Multiple abstract modifiers are not allowed", 0);
- return 0;
- }
- if ((flags & ZEND_ACC_STATIC) && (new_flag & ZEND_ACC_STATIC)) {
- zend_throw_exception(zend_ce_compile_error, "Multiple static modifiers are not allowed", 0);
- return 0;
- }
- if ((flags & ZEND_ACC_FINAL) && (new_flag & ZEND_ACC_FINAL)) {
- zend_throw_exception(zend_ce_compile_error, "Multiple final modifiers are not allowed", 0);
- return 0;
- }
- if ((new_flags & ZEND_ACC_ABSTRACT) && (new_flags & ZEND_ACC_FINAL)) {
- zend_throw_exception(zend_ce_compile_error,
- "Cannot use the final modifier on an abstract class member", 0);
- return 0;
- }
- return new_flags;
- }
- /* }}} */
- 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));
- }
- zend_string *zend_concat_names(char *name1, size_t name1_len, char *name2, size_t name2_len) {
- return zend_string_concat3(name1, name1_len, "\\", 1, name2, name2_len);
- }
- zend_string *zend_prefix_with_ns(zend_string *name) {
- if (FC(current_namespace)) {
- zend_string *ns = FC(current_namespace);
- return zend_concat_names(ZSTR_VAL(ns), ZSTR_LEN(ns), ZSTR_VAL(name), ZSTR_LEN(name));
- } else {
- return zend_string_copy(name);
- }
- }
- zend_string *zend_resolve_non_class_name(
- zend_string *name, uint32_t type, zend_bool *is_fully_qualified,
- zend_bool case_sensitive, HashTable *current_import_sub
- ) {
- char *compound;
- *is_fully_qualified = 0;
- if (ZSTR_VAL(name)[0] == '\\') {
- /* Remove \ prefix (only relevant if this is a string rather than a label) */
- *is_fully_qualified = 1;
- return zend_string_init(ZSTR_VAL(name) + 1, ZSTR_LEN(name) - 1, 0);
- }
- if (type == ZEND_NAME_FQ) {
- *is_fully_qualified = 1;
- return zend_string_copy(name);
- }
- if (type == ZEND_NAME_RELATIVE) {
- *is_fully_qualified = 1;
- return zend_prefix_with_ns(name);
- }
- if (current_import_sub) {
- /* If an unqualified name is a function/const alias, replace it. */
- zend_string *import_name;
- if (case_sensitive) {
- import_name = zend_hash_find_ptr(current_import_sub, name);
- } else {
- import_name = zend_hash_find_ptr_lc(current_import_sub, name);
- }
- if (import_name) {
- *is_fully_qualified = 1;
- return zend_string_copy(import_name);
- }
- }
- compound = memchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
- if (compound) {
- *is_fully_qualified = 1;
- }
- if (compound && FC(imports)) {
- /* If the first part of a qualified name is an alias, substitute it. */
- size_t len = compound - ZSTR_VAL(name);
- zend_string *import_name = zend_hash_str_find_ptr_lc(FC(imports), ZSTR_VAL(name), len);
- if (import_name) {
- return zend_concat_names(
- ZSTR_VAL(import_name), ZSTR_LEN(import_name), ZSTR_VAL(name) + len + 1, ZSTR_LEN(name) - len - 1);
- }
- }
- return zend_prefix_with_ns(name);
- }
- /* }}} */
- zend_string *zend_resolve_function_name(zend_string *name, uint32_t type, zend_bool *is_fully_qualified) /* {{{ */
- {
- return zend_resolve_non_class_name(
- name, type, is_fully_qualified, 0, FC(imports_function));
- }
- /* }}} */
- zend_string *zend_resolve_const_name(zend_string *name, uint32_t type, zend_bool *is_fully_qualified) /* {{{ */ {
- return zend_resolve_non_class_name(
- name, type, is_fully_qualified, 1, FC(imports_const));
- }
- /* }}} */
- zend_string *zend_resolve_class_name(zend_string *name, uint32_t type) /* {{{ */
- {
- char *compound;
- if (type == ZEND_NAME_RELATIVE) {
- return zend_prefix_with_ns(name);
- }
- if (type == ZEND_NAME_FQ || ZSTR_VAL(name)[0] == '\\') {
- /* Remove \ prefix (only relevant if this is a string rather than a label) */
- if (ZSTR_VAL(name)[0] == '\\') {
- name = zend_string_init(ZSTR_VAL(name) + 1, ZSTR_LEN(name) - 1, 0);
- } else {
- zend_string_addref(name);
- }
- /* Ensure that \self, \parent and \static are not used */
- if (ZEND_FETCH_CLASS_DEFAULT != zend_get_class_fetch_type(name)) {
- zend_error_noreturn(E_COMPILE_ERROR, "'\\%s' is an invalid class name", ZSTR_VAL(name));
- }
- return name;
- }
- if (FC(imports)) {
- compound = memchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
- if (compound) {
- /* If the first part of a qualified name is an alias, substitute it. */
- size_t len = compound - ZSTR_VAL(name);
- zend_string *import_name =
- zend_hash_str_find_ptr_lc(FC(imports), ZSTR_VAL(name), len);
- if (import_name) {
- return zend_concat_names(
- ZSTR_VAL(import_name), ZSTR_LEN(import_name), ZSTR_VAL(name) + len + 1, ZSTR_LEN(name) - len - 1);
- }
- } else {
- /* If an unqualified name is an alias, replace it. */
- zend_string *import_name
- = zend_hash_find_ptr_lc(FC(imports), name);
- if (import_name) {
- return zend_string_copy(import_name);
- }
- }
- }
- /* If not fully qualified and not an alias, prepend the current namespace */
- return zend_prefix_with_ns(name);
- }
- /* }}} */
- zend_string *zend_resolve_class_name_ast(zend_ast *ast) /* {{{ */
- {
- 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);
- }
- /* }}} */
- static void label_ptr_dtor(zval *zv) /* {{{ */
- {
- efree_size(Z_PTR_P(zv), sizeof(zend_label));
- }
- /* }}} */
- static void str_dtor(zval *zv) /* {{{ */ {
- zend_string_release_ex(Z_STR_P(zv), 0);
- }
- /* }}} */
- static zend_bool zend_is_call(zend_ast *ast);
- static uint32_t zend_add_try_element(uint32_t try_op) /* {{{ */
- {
- zend_op_array *op_array = CG(active_op_array);
- uint32_t try_catch_offset = op_array->last_try_catch++;
- zend_try_catch_element *elem;
- op_array->try_catch_array = safe_erealloc(
- op_array->try_catch_array, sizeof(zend_try_catch_element), op_array->last_try_catch, 0);
- 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;
- return try_catch_offset;
- }
- /* }}} */
- ZEND_API void function_add_ref(zend_function *function) /* {{{ */
- {
- if (function->type == ZEND_USER_FUNCTION) {
- zend_op_array *op_array = &function->op_array;
- if (op_array->refcount) {
- (*op_array->refcount)++;
- }
- if (op_array->static_variables
- && !(GC_FLAGS(op_array->static_variables) & IS_ARRAY_IMMUTABLE)) {
- GC_ADDREF(op_array->static_variables);
- }
- 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);
- }
- }
- if (function->common.function_name) {
- zend_string_addref(function->common.function_name);
- }
- }
- /* }}} */
- 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)",
- op_array ? ZSTR_VAL(op_array->function_name) : ZSTR_VAL(old_function->common.function_name),
- ZSTR_VAL(old_function->op_array.filename),
- old_function->op_array.opcodes[0].lineno);
- } else {
- zend_error_noreturn(error_level, "Cannot redeclare %s()",
- op_array ? ZSTR_VAL(op_array->function_name) : ZSTR_VAL(old_function->common.function_name));
- }
- }
- ZEND_API int do_bind_function(zval *lcname) /* {{{ */
- {
- zend_function *function;
- zval *rtd_key, *zv;
- rtd_key = lcname + 1;
- zv = zend_hash_find_ex(EG(function_table), Z_STR_P(rtd_key), 1);
- if (UNEXPECTED(!zv)) {
- do_bind_function_error(Z_STR_P(lcname), NULL, 0);
- return FAILURE;
- }
- 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);
- return FAILURE;
- }
- return SUCCESS;
- }
- /* }}} */
- ZEND_API int do_bind_class(zval *lcname, zend_string *lc_parent_name) /* {{{ */
- {
- zend_class_entry *ce;
- zval *rtd_key, *zv;
- rtd_key = lcname + 1;
- zv = zend_hash_find_ex(EG(class_table), Z_STR_P(rtd_key), 1);
- if (UNEXPECTED(!zv)) {
- ce = zend_hash_find_ptr(EG(class_table), Z_STR_P(lcname));
- 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));
- return FAILURE;
- } else {
- do {
- ZEND_ASSERT(EG(current_execute_data)->func->op_array.fn_flags & ZEND_ACC_PRELOADED);
- 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);
- }
- }
- /* Register the derived class */
- 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)) {
- 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));
- return FAILURE;
- }
- if (zend_do_link_class(ce, lc_parent_name) == FAILURE) {
- /* Reload bucket pointer, the hash table may have been reallocated */
- zv = zend_hash_find(EG(class_table), Z_STR_P(lcname));
- zend_hash_set_bucket_key(EG(class_table), (Bucket *) zv, Z_STR_P(rtd_key));
- return FAILURE;
- }
- return SUCCESS;
- }
- /* }}} */
- 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);
- }
- result = zend_string_concat3(
- ZSTR_VAL(type), ZSTR_LEN(type), "|", 1, ZSTR_VAL(new_type), ZSTR_LEN(new_type));
- 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;
- }
- zend_string *zend_type_to_string_resolved(zend_type type, zend_class_entry *scope) {
- zend_string *str = NULL;
- if (ZEND_TYPE_HAS_LIST(type)) {
- 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);
- } else {
- str = add_type_string(str, resolve_class_name(ZEND_TYPE_NAME(*list_type), scope));
- }
- } 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)) {
- str = zend_string_copy(ZEND_TYPE_CE(type)->name);
- }
- uint32_t type_mask = ZEND_TYPE_FULL_MASK(type);
- 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);
- }
- 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) {
- zend_string *nullable_str = zend_string_concat2("?", 1, ZSTR_VAL(str), ZSTR_LEN(str));
- zend_string_release(str);
- return nullable_str;
- }
- str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_NULL_LOWERCASE));
- }
- return str;
- }
- ZEND_API zend_string *zend_type_to_string(zend_type type) {
- return zend_type_to_string_resolved(type, NULL);
- }
- 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");
- }
- 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");
- }
- if (CG(active_op_array)->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
- zend_type return_type = CG(active_op_array)->arg_info[-1].type;
- zend_bool valid_type = (ZEND_TYPE_FULL_MASK(return_type) & MAY_BE_ITERABLE) != 0;
- 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();
- }
- if (!valid_type) {
- zend_string *str = zend_type_to_string(return_type);
- zend_error_noreturn(E_COMPILE_ERROR,
- "Generators may only declare a return type containing " \
- "Generator, Iterator, Traversable, or iterable, %s is not permitted",
- ZSTR_VAL(str));
- }
- }
- CG(active_op_array)->fn_flags |= ZEND_ACC_GENERATOR;
- }
- /* }}} */
- 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) {
- if (opline->opcode == ZEND_DECLARE_CLASS_DELAYED) {
- *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;
- }
- /* }}} */
- ZEND_API void zend_do_delayed_early_binding(zend_op_array *op_array, uint32_t first_early_binding_opline) /* {{{ */
- {
- if (first_early_binding_opline != (uint32_t)-1) {
- zend_bool orig_in_compilation = CG(in_compilation);
- uint32_t opline_num = first_early_binding_opline;
- 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);
- CG(in_compilation) = 1;
- while (opline_num != (uint32_t)-1) {
- const zend_op *opline = &op_array->opcodes[opline_num];
- zval *lcname = RT_CONSTANT(opline, opline->op1);
- 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);
- if (parent_ce) {
- 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;
- }
- }
- }
- opline_num = op_array->opcodes[opline_num].result.opline_num;
- }
- CG(in_compilation) = orig_in_compilation;
- }
- }
- /* }}} */
- ZEND_API zend_string *zend_mangle_property_name(const char *src1, size_t src1_length, const char *src2, size_t src2_length, int internal) /* {{{ */
- {
- size_t prop_name_length = 1 + src1_length + 1 + src2_length;
- zend_string *prop_name = zend_string_alloc(prop_name_length, internal);
- 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);
- return prop_name;
- }
- /* }}} */
- static zend_always_inline size_t zend_strnlen(const char* s, size_t maxlen) /* {{{ */
- {
- size_t len = 0;
- while (*s++ && maxlen--) len++;
- return len;
- }
- /* }}} */
- ZEND_API int zend_unmangle_property_name_ex(const zend_string *name, const char **class_name, const char **prop_name, size_t *prop_len) /* {{{ */
- {
- size_t class_name_len;
- size_t anonclass_src_len;
- *class_name = NULL;
- if (!ZSTR_LEN(name) || ZSTR_VAL(name)[0] != '\0') {
- *prop_name = ZSTR_VAL(name);
- if (prop_len) {
- *prop_len = ZSTR_LEN(name);
- }
- return SUCCESS;
- }
- if (ZSTR_LEN(name) < 3 || ZSTR_VAL(name)[1] == '\0') {
- zend_error(E_NOTICE, "Illegal member variable name");
- *prop_name = ZSTR_VAL(name);
- if (prop_len) {
- *prop_len = ZSTR_LEN(name);
- }
- return FAILURE;
- }
- 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') {
- zend_error(E_NOTICE, "Corrupt member variable name");
- *prop_name = ZSTR_VAL(name);
- if (prop_len) {
- *prop_len = ZSTR_LEN(name);
- }
- return FAILURE;
- }
- *class_name = ZSTR_VAL(name) + 1;
- 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;
- }
- *prop_name = ZSTR_VAL(name) + class_name_len + 2;
- if (prop_len) {
- *prop_len = ZSTR_LEN(name) - class_name_len - 2;
- }
- return SUCCESS;
- }
- /* }}} */
- 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;
- }
- static zend_bool zend_try_ct_eval_const(zval *zv, zend_string *name, zend_bool is_fully_qualified) /* {{{ */
- {
- zend_constant *c = zend_hash_find_ptr(EG(zend_constants), name);
- if (c && can_ct_eval_const(c)) {
- ZVAL_COPY_OR_DUP(zv, &c->value);
- return 1;
- }
- {
- /* Substitute true, false and null (including unqualified usage in namespaces) */
- const char *lookup_name = ZSTR_VAL(name);
- size_t lookup_len = ZSTR_LEN(name);
- if (!is_fully_qualified) {
- zend_get_unqualified_name(name, &lookup_name, &lookup_len);
- }
- if ((c = zend_get_special_const(lookup_name, lookup_len))) {
- ZVAL_COPY_VALUE(zv, &c->value);
- return 1;
- }
- return 0;
- }
- }
- /* }}} */
- 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)) {
- /* 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;
- }
- /* 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);
- }
- /* }}} */
- 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));
- }
- /* }}} */
- 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);
- }
- static void zend_ensure_valid_class_fetch_type(uint32_t fetch_type) /* {{{ */
- {
- 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) {
- zend_error_noreturn(E_COMPILE_ERROR,
- "Cannot use \"parent\" when current class scope has no parent");
- }
- }
- }
- /* }}} */
- static zend_bool zend_try_compile_const_expr_resolve_class_name(zval *zv, zend_ast *class_ast) /* {{{ */
- {
- uint32_t fetch_type;
- zval *class_name;
- if (class_ast->kind != ZEND_AST_ZVAL) {
- return 0;
- }
- 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));
- zend_ensure_valid_class_fetch_type(fetch_type);
- switch (fetch_type) {
- case ZEND_FETCH_CLASS_SELF:
- if (CG(active_class_entry) && zend_is_scope_known()) {
- ZVAL_STR_COPY(zv, CG(active_class_entry)->name);
- return 1;
- }
- return 0;
- case ZEND_FETCH_CLASS_PARENT:
- 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:
- return 0;
- case ZEND_FETCH_CLASS_DEFAULT:
- ZVAL_STR(zv, zend_resolve_class_name_ast(class_ast));
- return 1;
- EMPTY_SWITCH_DEFAULT_CASE()
- }
- }
- /* }}} */
- /* 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 {
- ce = zend_hash_find_ptr_lc(CG(class_table), ce->parent_name);
- if (!ce) {
- break;
- }
- }
- }
- /* Reverse case cannot be true during compilation */
- return 0;
- }
- }
- 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);
- zend_class_constant *cc;
- zval *c;
- if (class_name_refers_to_active_ce(class_name, fetch_type)) {
- cc = zend_hash_find_ptr(&CG(active_class_entry)->constants_table, name);
- } else if (fetch_type == ZEND_FETCH_CLASS_DEFAULT && !(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION)) {
- zend_class_entry *ce = zend_hash_find_ptr_lc(CG(class_table), class_name);
- if (ce) {
- cc = zend_hash_find_ptr(&ce->constants_table, name);
- } else {
- return 0;
- }
- } else {
- return 0;
- }
- if (CG(compiler_options) & ZEND_COMPILE_NO_PERSISTENT_CONSTANT_SUBSTITUTION) {
- return 0;
- }
- if (!cc || !zend_verify_ct_const_access(cc, CG(active_class_entry))) {
- return 0;
- }
- c = &cc->value;
- /* Substitute case-sensitive (or lowercase) persistent class constants */
- if (Z_TYPE_P(c) < IS_OBJECT) {
- ZVAL_COPY_OR_DUP(zv, c);
- return 1;
- }
- return 0;
- }
- /* }}} */
- static void zend_add_to_list(void *result, void *item) /* {{{ */
- {
- void** list = *(void**)result;
- size_t n = 0;
- if (list) {
- while (list[n]) {
- n++;
- }
- }
- list = erealloc(list, sizeof(void*) * (n+2));
- list[n] = item;
- list[n+1] = NULL;
- *(void**)result = list;
- }
- /* }}} */
- void zend_do_extended_stmt(void) /* {{{ */
- {
- zend_op *opline;
- if (!(CG(compiler_options) & ZEND_COMPILE_EXTENDED_STMT)) {
- return;
- }
- opline = get_next_op();
- opline->opcode = ZEND_EXT_STMT;
- }
- /* }}} */
- void zend_do_extended_fcall_begin(void) /* {{{ */
- {
- zend_op *opline;
- if (!(CG(compiler_options) & ZEND_COMPILE_EXTENDED_FCALL)) {
- return;
- }
- opline = get_next_op();
- opline->opcode = ZEND_EXT_FCALL_BEGIN;
- }
- /* }}} */
- void zend_do_extended_fcall_end(void) /* {{{ */
- {
- zend_op *opline;
- if (!(CG(compiler_options) & ZEND_COMPILE_EXTENDED_FCALL)) {
- return;
- }
- opline = get_next_op();
- opline->opcode = ZEND_EXT_FCALL_END;
- }
- /* }}} */
- zend_bool zend_is_auto_global_str(char *name, size_t len) /* {{{ */ {
- zend_auto_global *auto_global;
- 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);
- }
- return 1;
- }
- return 0;
- }
- /* }}} */
- zend_bool zend_is_auto_global(zend_string *name) /* {{{ */
- {
- zend_auto_global *auto_global;
- if ((auto_global = zend_hash_find_ptr(CG(auto_globals), name)) != NULL) {
- if (auto_global->armed) {
- auto_global->armed = auto_global->auto_global_callback(auto_global->name);
- }
- return 1;
- }
- return 0;
- }
- /* }}} */
- int zend_register_auto_global(zend_string *name, zend_bool jit, z…
Large files files are truncated, but you can click here to view the full file