/Zend/zend_compile.c
C | 5454 lines | 4294 code | 754 blank | 406 comment | 1094 complexity | 79b2bba80d4838380d8d3483804f6547 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-2.1, BSD-3-Clause
Large files files are truncated, but you can click here to view the full file
- /*
- +----------------------------------------------------------------------+
- | Zend Engine |
- +----------------------------------------------------------------------+
- | Copyright (c) 1998-2011 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@zend.com> |
- | Zeev Suraski <zeev@zend.com> |
- +----------------------------------------------------------------------+
- */
- /* $Id: zend_compile.c 308443 2011-02-17 23:24:50Z felipe $ */
- #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 "tsrm_virtual_cwd.h"
- #ifdef ZEND_MULTIBYTE
- #include "zend_multibyte.h"
- #endif /* ZEND_MULTIBYTE */
- ZEND_API zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);
- ZEND_API zend_op_array *(*zend_compile_string)(zval *source_string, char *filename TSRMLS_DC);
- #ifndef ZTS
- ZEND_API zend_compiler_globals compiler_globals;
- ZEND_API zend_executor_globals executor_globals;
- #endif
- static void zend_duplicate_property_info(zend_property_info *property_info) /* {{{ */
- {
- property_info->name = estrndup(property_info->name, property_info->name_length);
- if (property_info->doc_comment) {
- property_info->doc_comment = estrndup(property_info->doc_comment, property_info->doc_comment_len);
- }
- }
- /* }}} */
- static void zend_duplicate_property_info_internal(zend_property_info *property_info) /* {{{ */
- {
- property_info->name = zend_strndup(property_info->name, property_info->name_length);
- }
- /* }}} */
- static void zend_destroy_property_info(zend_property_info *property_info) /* {{{ */
- {
- efree(property_info->name);
- if (property_info->doc_comment) {
- efree(property_info->doc_comment);
- }
- }
- /* }}} */
- static void zend_destroy_property_info_internal(zend_property_info *property_info) /* {{{ */
- {
- free(property_info->name);
- }
- /* }}} */
- static void build_runtime_defined_function_key(zval *result, const char *name, int name_length TSRMLS_DC) /* {{{ */
- {
- char char_pos_buf[32];
- uint char_pos_len;
- char *filename;
- char_pos_len = zend_sprintf(char_pos_buf, "%p", LANG_SCNG(yy_text));
- if (CG(active_op_array)->filename) {
- filename = CG(active_op_array)->filename;
- } else {
- filename = "-";
- }
- /* NULL, name length, filename length, last accepting char position length */
- result->value.str.len = 1+name_length+strlen(filename)+char_pos_len;
- #ifdef ZEND_MULTIBYTE
- /* must be binary safe */
- result->value.str.val = (char *) safe_emalloc(result->value.str.len, 1, 1);
- result->value.str.val[0] = '\0';
- sprintf(result->value.str.val+1, "%s%s%s", name, filename, char_pos_buf);
- #else
- zend_spprintf(&result->value.str.val, 0, "%c%s%s%s", '\0', name, filename, char_pos_buf);
- #endif /* ZEND_MULTIBYTE */
- result->type = IS_STRING;
- Z_SET_REFCOUNT_P(result, 1);
- }
- /* }}} */
- int zend_auto_global_arm(zend_auto_global *auto_global TSRMLS_DC) /* {{{ */
- {
- auto_global->armed = (auto_global->auto_global_callback ? 1 : 0);
- return 0;
- }
- /* }}} */
- ZEND_API int zend_auto_global_disable_jit(const char *varname, zend_uint varname_length TSRMLS_DC) /* {{{ */
- {
- zend_auto_global *auto_global;
- if (zend_hash_find(CG(auto_globals), varname, varname_length+1, (void **) &auto_global)==FAILURE) {
- return FAILURE;
- }
- auto_global->armed = 0;
- return SUCCESS;
- }
- /* }}} */
- static void init_compiler_declarables(TSRMLS_D) /* {{{ */
- {
- Z_TYPE(CG(declarables).ticks) = IS_LONG;
- Z_LVAL(CG(declarables).ticks) = 0;
- }
- /* }}} */
- void zend_init_compiler_data_structures(TSRMLS_D) /* {{{ */
- {
- zend_stack_init(&CG(bp_stack));
- zend_stack_init(&CG(function_call_stack));
- zend_stack_init(&CG(switch_cond_stack));
- zend_stack_init(&CG(foreach_copy_stack));
- zend_stack_init(&CG(object_stack));
- zend_stack_init(&CG(declare_stack));
- CG(active_class_entry) = NULL;
- zend_llist_init(&CG(list_llist), sizeof(list_llist_element), NULL, 0);
- zend_llist_init(&CG(dimension_llist), sizeof(int), NULL, 0);
- zend_stack_init(&CG(list_stack));
- CG(in_compilation) = 0;
- CG(start_lineno) = 0;
- CG(current_namespace) = NULL;
- CG(in_namespace) = 0;
- CG(has_bracketed_namespaces) = 0;
- CG(current_import) = NULL;
- init_compiler_declarables(TSRMLS_C);
- zend_hash_apply(CG(auto_globals), (apply_func_t) zend_auto_global_arm TSRMLS_CC);
- zend_stack_init(&CG(labels_stack));
- CG(labels) = NULL;
- #ifdef ZEND_MULTIBYTE
- CG(script_encoding_list) = NULL;
- CG(script_encoding_list_size) = 0;
- CG(internal_encoding) = NULL;
- CG(encoding_detector) = NULL;
- CG(encoding_converter) = NULL;
- CG(encoding_oddlen) = NULL;
- CG(encoding_declared) = 0;
- #endif /* ZEND_MULTIBYTE */
- }
- /* }}} */
- ZEND_API void file_handle_dtor(zend_file_handle *fh) /* {{{ */
- {
- TSRMLS_FETCH();
- zend_file_handle_dtor(fh TSRMLS_CC);
- }
- /* }}} */
- void init_compiler(TSRMLS_D) /* {{{ */
- {
- CG(active_op_array) = NULL;
- zend_init_compiler_data_structures(TSRMLS_C);
- zend_init_rsrc_list(TSRMLS_C);
- zend_hash_init(&CG(filenames_table), 5, NULL, (dtor_func_t) free_estring, 0);
- zend_llist_init(&CG(open_files), sizeof(zend_file_handle), (void (*)(void *)) file_handle_dtor, 0);
- CG(unclean_shutdown) = 0;
- }
- /* }}} */
- void shutdown_compiler(TSRMLS_D) /* {{{ */
- {
- zend_stack_destroy(&CG(bp_stack));
- zend_stack_destroy(&CG(function_call_stack));
- zend_stack_destroy(&CG(switch_cond_stack));
- zend_stack_destroy(&CG(foreach_copy_stack));
- zend_stack_destroy(&CG(object_stack));
- zend_stack_destroy(&CG(declare_stack));
- zend_stack_destroy(&CG(list_stack));
- zend_hash_destroy(&CG(filenames_table));
- zend_llist_destroy(&CG(open_files));
- zend_stack_destroy(&CG(labels_stack));
- #ifdef ZEND_MULTIBYTE
- if (CG(script_encoding_list)) {
- efree(CG(script_encoding_list));
- }
- #endif /* ZEND_MULTIBYTE */
- }
- /* }}} */
- ZEND_API char *zend_set_compiled_filename(const char *new_compiled_filename TSRMLS_DC) /* {{{ */
- {
- char **pp, *p;
- int length = strlen(new_compiled_filename);
- if (zend_hash_find(&CG(filenames_table), new_compiled_filename, length+1, (void **) &pp) == SUCCESS) {
- CG(compiled_filename) = *pp;
- return *pp;
- }
- p = estrndup(new_compiled_filename, length);
- zend_hash_update(&CG(filenames_table), new_compiled_filename, length+1, &p, sizeof(char *), (void **) &pp);
- CG(compiled_filename) = p;
- return p;
- }
- /* }}} */
- ZEND_API void zend_restore_compiled_filename(char *original_compiled_filename TSRMLS_DC) /* {{{ */
- {
- CG(compiled_filename) = original_compiled_filename;
- }
- /* }}} */
- ZEND_API char *zend_get_compiled_filename(TSRMLS_D) /* {{{ */
- {
- return CG(compiled_filename);
- }
- /* }}} */
- ZEND_API int zend_get_compiled_lineno(TSRMLS_D) /* {{{ */
- {
- return CG(zend_lineno);
- }
- /* }}} */
- ZEND_API zend_bool zend_is_compiling(TSRMLS_D) /* {{{ */
- {
- return CG(in_compilation);
- }
- /* }}} */
- static zend_uint get_temporary_variable(zend_op_array *op_array) /* {{{ */
- {
- return (op_array->T)++ * ZEND_MM_ALIGNED_SIZE(sizeof(temp_variable));
- }
- /* }}} */
- static int lookup_cv(zend_op_array *op_array, char* name, int name_len) /* {{{ */
- {
- int i = 0;
- ulong hash_value = zend_inline_hash_func(name, name_len+1);
- while (i < op_array->last_var) {
- if (op_array->vars[i].hash_value == hash_value &&
- op_array->vars[i].name_len == name_len &&
- strcmp(op_array->vars[i].name, name) == 0) {
- efree(name);
- return i;
- }
- i++;
- }
- i = op_array->last_var;
- op_array->last_var++;
- if (op_array->last_var > op_array->size_var) {
- op_array->size_var += 16; /* FIXME */
- op_array->vars = erealloc(op_array->vars, op_array->size_var*sizeof(zend_compiled_variable));
- }
- op_array->vars[i].name = name; /* estrndup(name, name_len); */
- op_array->vars[i].name_len = name_len;
- op_array->vars[i].hash_value = hash_value;
- return i;
- }
- /* }}} */
- void zend_do_binary_op(zend_uchar op, znode *result, const znode *op1, const znode *op2 TSRMLS_DC) /* {{{ */
- {
- zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
- opline->opcode = op;
- opline->result.op_type = IS_TMP_VAR;
- opline->result.u.var = get_temporary_variable(CG(active_op_array));
- opline->op1 = *op1;
- opline->op2 = *op2;
- *result = opline->result;
- }
- /* }}} */
- void zend_do_unary_op(zend_uchar op, znode *result, const znode *op1 TSRMLS_DC) /* {{{ */
- {
- zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
- opline->opcode = op;
- opline->result.op_type = IS_TMP_VAR;
- opline->result.u.var = get_temporary_variable(CG(active_op_array));
- opline->op1 = *op1;
- *result = opline->result;
- SET_UNUSED(opline->op2);
- }
- /* }}} */
- #define MAKE_NOP(opline) { opline->opcode = ZEND_NOP; memset(&opline->result,0,sizeof(znode)); memset(&opline->op1,0,sizeof(znode)); memset(&opline->op2,0,sizeof(znode)); opline->result.op_type=opline->op1.op_type=opline->op2.op_type=IS_UNUSED; }
- static void zend_do_op_data(zend_op *data_op, const znode *value TSRMLS_DC) /* {{{ */
- {
- data_op->opcode = ZEND_OP_DATA;
- data_op->op1 = *value;
- SET_UNUSED(data_op->op2);
- }
- /* }}} */
- void zend_do_binary_assign_op(zend_uchar op, znode *result, const znode *op1, const znode *op2 TSRMLS_DC) /* {{{ */
- {
- int last_op_number = get_next_op_number(CG(active_op_array));
- zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
- if (last_op_number > 0) {
- zend_op *last_op = &CG(active_op_array)->opcodes[last_op_number-1];
- switch (last_op->opcode) {
- case ZEND_FETCH_OBJ_RW:
- last_op->opcode = op;
- last_op->extended_value = ZEND_ASSIGN_OBJ;
- zend_do_op_data(opline, op2 TSRMLS_CC);
- SET_UNUSED(opline->result);
- *result = last_op->result;
- return;
- case ZEND_FETCH_DIM_RW:
- last_op->opcode = op;
- last_op->extended_value = ZEND_ASSIGN_DIM;
- zend_do_op_data(opline, op2 TSRMLS_CC);
- opline->op2.u.var = get_temporary_variable(CG(active_op_array));
- opline->op2.u.EA.type = 0;
- opline->op2.op_type = IS_VAR;
- SET_UNUSED(opline->result);
- *result = last_op->result;
- return;
- default:
- break;
- }
- }
- opline->opcode = op;
- opline->op1 = *op1;
- opline->op2 = *op2;
- opline->result.op_type = IS_VAR;
- opline->result.u.EA.type = 0;
- opline->result.u.var = get_temporary_variable(CG(active_op_array));
- *result = opline->result;
- }
- /* }}} */
- void fetch_simple_variable_ex(znode *result, znode *varname, int bp, zend_uchar op TSRMLS_DC) /* {{{ */
- {
- zend_op opline;
- zend_op *opline_ptr;
- zend_llist *fetch_list_ptr;
- if (varname->op_type == IS_CONST) {
- if (Z_TYPE(varname->u.constant) != IS_STRING) {
- convert_to_string(&varname->u.constant);
- }
- if (!zend_is_auto_global(varname->u.constant.value.str.val, varname->u.constant.value.str.len TSRMLS_CC) &&
- !(varname->u.constant.value.str.len == (sizeof("this")-1) &&
- !memcmp(varname->u.constant.value.str.val, "this", sizeof("this"))) &&
- (CG(active_op_array)->last == 0 ||
- CG(active_op_array)->opcodes[CG(active_op_array)->last-1].opcode != ZEND_BEGIN_SILENCE)) {
- result->op_type = IS_CV;
- result->u.var = lookup_cv(CG(active_op_array), varname->u.constant.value.str.val, varname->u.constant.value.str.len);
- result->u.EA.type = 0;
- varname->u.constant.value.str.val = CG(active_op_array)->vars[result->u.var].name;
- return;
- }
- }
- if (bp) {
- opline_ptr = &opline;
- init_op(opline_ptr TSRMLS_CC);
- } else {
- opline_ptr = get_next_op(CG(active_op_array) TSRMLS_CC);
- }
- opline_ptr->opcode = op;
- opline_ptr->result.op_type = IS_VAR;
- opline_ptr->result.u.EA.type = 0;
- opline_ptr->result.u.var = get_temporary_variable(CG(active_op_array));
- opline_ptr->op1 = *varname;
- *result = opline_ptr->result;
- SET_UNUSED(opline_ptr->op2);
- opline_ptr->op2.u.EA.type = ZEND_FETCH_LOCAL;
- if (varname->op_type == IS_CONST && varname->u.constant.type == IS_STRING) {
- if (zend_is_auto_global(varname->u.constant.value.str.val, varname->u.constant.value.str.len TSRMLS_CC)) {
- opline_ptr->op2.u.EA.type = ZEND_FETCH_GLOBAL;
- }
- }
- if (bp) {
- zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr);
- zend_llist_add_element(fetch_list_ptr, opline_ptr);
- }
- }
- /* }}} */
- void fetch_simple_variable(znode *result, znode *varname, int bp TSRMLS_DC) /* {{{ */
- {
- /* the default mode must be Write, since fetch_simple_variable() is used to define function arguments */
- fetch_simple_variable_ex(result, varname, bp, ZEND_FETCH_W TSRMLS_CC);
- }
- /* }}} */
- void zend_do_fetch_static_member(znode *result, znode *class_name TSRMLS_DC) /* {{{ */
- {
- znode class_node;
- zend_llist *fetch_list_ptr;
- zend_llist_element *le;
- zend_op *opline_ptr;
- zend_op opline;
- zend_do_fetch_class(&class_node, class_name TSRMLS_CC);
- zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr);
- if (result->op_type == IS_CV) {
- init_op(&opline TSRMLS_CC);
- opline.opcode = ZEND_FETCH_W;
- opline.result.op_type = IS_VAR;
- opline.result.u.EA.type = 0;
- opline.result.u.var = get_temporary_variable(CG(active_op_array));
- opline.op1.op_type = IS_CONST;
- opline.op1.u.constant.type = IS_STRING;
- opline.op1.u.constant.value.str.val = estrdup(CG(active_op_array)->vars[result->u.var].name);
- opline.op1.u.constant.value.str.len = CG(active_op_array)->vars[result->u.var].name_len;
- SET_UNUSED(opline.op2);
- opline.op2 = class_node;
- opline.op2.u.EA.type = ZEND_FETCH_STATIC_MEMBER;
- *result = opline.result;
- zend_llist_add_element(fetch_list_ptr, &opline);
- } else {
- le = fetch_list_ptr->head;
- opline_ptr = (zend_op *)le->data;
- if (opline_ptr->opcode != ZEND_FETCH_W && opline_ptr->op1.op_type == IS_CV) {
- init_op(&opline TSRMLS_CC);
- opline.opcode = ZEND_FETCH_W;
- opline.result.op_type = IS_VAR;
- opline.result.u.EA.type = 0;
- opline.result.u.var = get_temporary_variable(CG(active_op_array));
- opline.op1.op_type = IS_CONST;
- opline.op1.u.constant.type = IS_STRING;
- opline.op1.u.constant.value.str.val = estrdup(CG(active_op_array)->vars[opline_ptr->op1.u.var].name);
- opline.op1.u.constant.value.str.len = CG(active_op_array)->vars[opline_ptr->op1.u.var].name_len;
- SET_UNUSED(opline.op2);
- opline.op2 = class_node;
- opline.op2.u.EA.type = ZEND_FETCH_STATIC_MEMBER;
- opline_ptr->op1 = opline.result;
- zend_llist_prepend_element(fetch_list_ptr, &opline);
- } else {
- opline_ptr->op2 = class_node;
- opline_ptr->op2.u.EA.type = ZEND_FETCH_STATIC_MEMBER;
- }
- }
- }
- /* }}} */
- void fetch_array_begin(znode *result, znode *varname, znode *first_dim TSRMLS_DC) /* {{{ */
- {
- fetch_simple_variable(result, varname, 1 TSRMLS_CC);
- fetch_array_dim(result, result, first_dim TSRMLS_CC);
- }
- /* }}} */
- void fetch_array_dim(znode *result, const znode *parent, const znode *dim TSRMLS_DC) /* {{{ */
- {
- zend_op opline;
- zend_llist *fetch_list_ptr;
- init_op(&opline TSRMLS_CC);
- opline.opcode = ZEND_FETCH_DIM_W; /* the backpatching routine assumes W */
- opline.result.op_type = IS_VAR;
- opline.result.u.EA.type = 0;
- opline.result.u.var = get_temporary_variable(CG(active_op_array));
- opline.op1 = *parent;
- opline.op2 = *dim;
- opline.extended_value = ZEND_FETCH_STANDARD;
- *result = opline.result;
- zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr);
- zend_llist_add_element(fetch_list_ptr, &opline);
- }
- /* }}} */
- void fetch_string_offset(znode *result, const znode *parent, const znode *offset TSRMLS_DC) /* {{{ */
- {
- fetch_array_dim(result, parent, offset TSRMLS_CC);
- }
- /* }}} */
- void zend_do_print(znode *result, const znode *arg TSRMLS_DC) /* {{{ */
- {
- zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
- opline->result.op_type = IS_TMP_VAR;
- opline->result.u.var = get_temporary_variable(CG(active_op_array));
- opline->opcode = ZEND_PRINT;
- opline->op1 = *arg;
- SET_UNUSED(opline->op2);
- *result = opline->result;
- }
- /* }}} */
- void zend_do_echo(const znode *arg TSRMLS_DC) /* {{{ */
- {
- zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
- opline->opcode = ZEND_ECHO;
- opline->op1 = *arg;
- SET_UNUSED(opline->op2);
- }
- /* }}} */
- void zend_do_abstract_method(const znode *function_name, znode *modifiers, const znode *body TSRMLS_DC) /* {{{ */
- {
- char *method_type;
- if (CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE) {
- Z_LVAL(modifiers->u.constant) |= ZEND_ACC_ABSTRACT;
- method_type = "Interface";
- } else {
- method_type = "Abstract";
- }
- if (modifiers->u.constant.value.lval & ZEND_ACC_ABSTRACT) {
- if(modifiers->u.constant.value.lval & ZEND_ACC_PRIVATE) {
- zend_error(E_COMPILE_ERROR, "%s function %s::%s() cannot be declared private", method_type, CG(active_class_entry)->name, function_name->u.constant.value.str.val);
- }
- if (Z_LVAL(body->u.constant) == ZEND_ACC_ABSTRACT) {
- zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
- opline->opcode = ZEND_RAISE_ABSTRACT_ERROR;
- SET_UNUSED(opline->op1);
- SET_UNUSED(opline->op2);
- } else {
- /* we had code in the function body */
- zend_error(E_COMPILE_ERROR, "%s function %s::%s() cannot contain body", method_type, CG(active_class_entry)->name, function_name->u.constant.value.str.val);
- }
- } else {
- if (body->u.constant.value.lval == ZEND_ACC_ABSTRACT) {
- zend_error(E_COMPILE_ERROR, "Non-abstract method %s::%s() must contain body", CG(active_class_entry)->name, function_name->u.constant.value.str.val);
- }
- }
- }
- /* }}} */
- static zend_bool opline_is_fetch_this(const zend_op *opline TSRMLS_DC) /* {{{ */
- {
- if ((opline->opcode == ZEND_FETCH_W) && (opline->op1.op_type == IS_CONST)
- && (opline->op1.u.constant.type == IS_STRING)
- && (opline->op1.u.constant.value.str.len == (sizeof("this")-1))
- && !memcmp(opline->op1.u.constant.value.str.val, "this", sizeof("this"))) {
- return 1;
- } else {
- return 0;
- }
- }
- /* }}} */
- void zend_do_assign(znode *result, znode *variable, const znode *value TSRMLS_DC) /* {{{ */
- {
- int last_op_number;
- zend_op *opline;
- if (value->op_type == IS_CV) {
- zend_llist *fetch_list_ptr;
- zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr);
- if (fetch_list_ptr && fetch_list_ptr->head) {
- opline = (zend_op *)fetch_list_ptr->head->data;
- if (opline->opcode == ZEND_FETCH_DIM_W &&
- opline->op1.op_type == IS_CV &&
- opline->op1.u.var == value->u.var) {
- opline = get_next_op(CG(active_op_array) TSRMLS_CC);
- opline->opcode = ZEND_FETCH_R;
- opline->result.op_type = IS_VAR;
- opline->result.u.EA.type = 0;
- opline->result.u.var = get_temporary_variable(CG(active_op_array));
- opline->op1.op_type = IS_CONST;
- ZVAL_STRINGL(&opline->op1.u.constant,
- CG(active_op_array)->vars[value->u.var].name,
- CG(active_op_array)->vars[value->u.var].name_len, 1);
- SET_UNUSED(opline->op2);
- opline->op2.u.EA.type = ZEND_FETCH_LOCAL;
- value = &opline->result;
- }
- }
- }
- zend_do_end_variable_parse(variable, BP_VAR_W, 0 TSRMLS_CC);
- last_op_number = get_next_op_number(CG(active_op_array));
- opline = get_next_op(CG(active_op_array) TSRMLS_CC);
- if (variable->op_type == IS_CV) {
- if (variable->u.var == CG(active_op_array)->this_var) {
- zend_error(E_COMPILE_ERROR, "Cannot re-assign $this");
- }
- } else if (variable->op_type == IS_VAR) {
- int n = 0;
- while (last_op_number - n > 0) {
- zend_op *last_op;
- last_op = &CG(active_op_array)->opcodes[last_op_number-n-1];
- if (last_op->result.op_type == IS_VAR &&
- last_op->result.u.var == variable->u.var) {
- if (last_op->opcode == ZEND_FETCH_OBJ_W) {
- if (n > 0) {
- int opline_no = (opline-CG(active_op_array)->opcodes)/sizeof(*opline);
- *opline = *last_op;
- MAKE_NOP(last_op);
- /* last_op = opline; */
- opline = get_next_op(CG(active_op_array) TSRMLS_CC);
- /* get_next_op can realloc, we need to move last_op */
- last_op = &CG(active_op_array)->opcodes[opline_no];
- }
- last_op->opcode = ZEND_ASSIGN_OBJ;
- zend_do_op_data(opline, value TSRMLS_CC);
- SET_UNUSED(opline->result);
- *result = last_op->result;
- return;
- } else if (last_op->opcode == ZEND_FETCH_DIM_W) {
- if (n > 0) {
- int opline_no = (opline-CG(active_op_array)->opcodes)/sizeof(*opline);
- *opline = *last_op;
- MAKE_NOP(last_op);
- /* last_op = opline; */
- /* TBFixed: this can realloc opcodes, leaving last_op pointing wrong */
- opline = get_next_op(CG(active_op_array) TSRMLS_CC);
- /* get_next_op can realloc, we need to move last_op */
- last_op = &CG(active_op_array)->opcodes[opline_no];
- }
- last_op->opcode = ZEND_ASSIGN_DIM;
- zend_do_op_data(opline, value TSRMLS_CC);
- opline->op2.u.var = get_temporary_variable(CG(active_op_array));
- opline->op2.u.EA.type = 0;
- opline->op2.op_type = IS_VAR;
- SET_UNUSED(opline->result);
- *result = last_op->result;
- return;
- } else if (opline_is_fetch_this(last_op TSRMLS_CC)) {
- zend_error(E_COMPILE_ERROR, "Cannot re-assign $this");
- } else {
- break;
- }
- }
- n++;
- }
- }
- opline->opcode = ZEND_ASSIGN;
- opline->op1 = *variable;
- opline->op2 = *value;
- opline->result.op_type = IS_VAR;
- opline->result.u.EA.type = 0;
- opline->result.u.var = get_temporary_variable(CG(active_op_array));
- *result = opline->result;
- }
- /* }}} */
- static inline zend_bool zend_is_function_or_method_call(const znode *variable) /* {{{ */
- {
- zend_uint type = variable->u.EA.type;
- return ((type & ZEND_PARSED_METHOD_CALL) || (type == ZEND_PARSED_FUNCTION_CALL));
- }
- /* }}} */
- void zend_do_assign_ref(znode *result, const znode *lvar, const znode *rvar TSRMLS_DC) /* {{{ */
- {
- zend_op *opline;
- if (lvar->op_type == IS_CV) {
- if (lvar->u.var == CG(active_op_array)->this_var) {
- zend_error(E_COMPILE_ERROR, "Cannot re-assign $this");
- }
- } else if (lvar->op_type == IS_VAR) {
- int last_op_number = get_next_op_number(CG(active_op_array));
- if (last_op_number > 0) {
- opline = &CG(active_op_array)->opcodes[last_op_number-1];
- if (opline_is_fetch_this(opline TSRMLS_CC)) {
- zend_error(E_COMPILE_ERROR, "Cannot re-assign $this");
- }
- }
- }
- opline = get_next_op(CG(active_op_array) TSRMLS_CC);
- opline->opcode = ZEND_ASSIGN_REF;
- if (zend_is_function_or_method_call(rvar)) {
- opline->extended_value = ZEND_RETURNS_FUNCTION;
- } else if (rvar->u.EA.type & ZEND_PARSED_NEW) {
- opline->extended_value = ZEND_RETURNS_NEW;
- } else {
- opline->extended_value = 0;
- }
- if (result) {
- opline->result.op_type = IS_VAR;
- opline->result.u.EA.type = 0;
- opline->result.u.var = get_temporary_variable(CG(active_op_array));
- *result = opline->result;
- } else {
- /* SET_UNUSED(opline->result); */
- opline->result.u.EA.type |= EXT_TYPE_UNUSED;
- }
- opline->op1 = *lvar;
- opline->op2 = *rvar;
- }
- /* }}} */
- static inline void do_begin_loop(TSRMLS_D) /* {{{ */
- {
- zend_brk_cont_element *brk_cont_element;
- int parent;
- parent = CG(active_op_array)->current_brk_cont;
- CG(active_op_array)->current_brk_cont = CG(active_op_array)->last_brk_cont;
- brk_cont_element = get_next_brk_cont_element(CG(active_op_array));
- brk_cont_element->start = get_next_op_number(CG(active_op_array));
- brk_cont_element->parent = parent;
- }
- /* }}} */
- static inline void do_end_loop(int cont_addr, int has_loop_var TSRMLS_DC) /* {{{ */
- {
- if (!has_loop_var) {
- /* The start fileld is used to free temporary variables in case of exceptions.
- * We won't try to free something of we don't have loop variable.
- */
- CG(active_op_array)->brk_cont_array[CG(active_op_array)->current_brk_cont].start = -1;
- }
- CG(active_op_array)->brk_cont_array[CG(active_op_array)->current_brk_cont].cont = cont_addr;
- CG(active_op_array)->brk_cont_array[CG(active_op_array)->current_brk_cont].brk = get_next_op_number(CG(active_op_array));
- CG(active_op_array)->current_brk_cont = CG(active_op_array)->brk_cont_array[CG(active_op_array)->current_brk_cont].parent;
- }
- /* }}} */
- void zend_do_while_cond(const znode *expr, znode *close_bracket_token TSRMLS_DC) /* {{{ */
- {
- int while_cond_op_number = get_next_op_number(CG(active_op_array));
- zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
- opline->opcode = ZEND_JMPZ;
- opline->op1 = *expr;
- close_bracket_token->u.opline_num = while_cond_op_number;
- SET_UNUSED(opline->op2);
- do_begin_loop(TSRMLS_C);
- INC_BPC(CG(active_op_array));
- }
- /* }}} */
- void zend_do_while_end(const znode *while_token, const znode *close_bracket_token TSRMLS_DC) /* {{{ */
- {
- zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
- /* add unconditional jump */
- opline->opcode = ZEND_JMP;
- opline->op1.u.opline_num = while_token->u.opline_num;
- SET_UNUSED(opline->op1);
- SET_UNUSED(opline->op2);
- /* update while's conditional jmp */
- CG(active_op_array)->opcodes[close_bracket_token->u.opline_num].op2.u.opline_num = get_next_op_number(CG(active_op_array));
- do_end_loop(while_token->u.opline_num, 0 TSRMLS_CC);
- DEC_BPC(CG(active_op_array));
- }
- /* }}} */
- void zend_do_for_cond(const znode *expr, znode *second_semicolon_token TSRMLS_DC) /* {{{ */
- {
- int for_cond_op_number = get_next_op_number(CG(active_op_array));
- zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
- opline->opcode = ZEND_JMPZNZ;
- opline->op1 = *expr; /* the conditional expression */
- second_semicolon_token->u.opline_num = for_cond_op_number;
- SET_UNUSED(opline->op2);
- }
- /* }}} */
- void zend_do_for_before_statement(const znode *cond_start, const znode *second_semicolon_token TSRMLS_DC) /* {{{ */
- {
- zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
- opline->opcode = ZEND_JMP;
- opline->op1.u.opline_num = cond_start->u.opline_num;
- CG(active_op_array)->opcodes[second_semicolon_token->u.opline_num].extended_value = get_next_op_number(CG(active_op_array));
- SET_UNUSED(opline->op1);
- SET_UNUSED(opline->op2);
- do_begin_loop(TSRMLS_C);
- INC_BPC(CG(active_op_array));
- }
- /* }}} */
- void zend_do_for_end(const znode *second_semicolon_token TSRMLS_DC) /* {{{ */
- {
- zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
- opline->opcode = ZEND_JMP;
- opline->op1.u.opline_num = second_semicolon_token->u.opline_num+1;
- CG(active_op_array)->opcodes[second_semicolon_token->u.opline_num].op2.u.opline_num = get_next_op_number(CG(active_op_array));
- SET_UNUSED(opline->op1);
- SET_UNUSED(opline->op2);
- do_end_loop(second_semicolon_token->u.opline_num+1, 0 TSRMLS_CC);
- DEC_BPC(CG(active_op_array));
- }
- /* }}} */
- void zend_do_pre_incdec(znode *result, const znode *op1, zend_uchar op TSRMLS_DC) /* {{{ */
- {
- int last_op_number = get_next_op_number(CG(active_op_array));
- zend_op *opline;
- if (last_op_number > 0) {
- zend_op *last_op = &CG(active_op_array)->opcodes[last_op_number-1];
- if (last_op->opcode == ZEND_FETCH_OBJ_RW) {
- last_op->opcode = (op==ZEND_PRE_INC)?ZEND_PRE_INC_OBJ:ZEND_PRE_DEC_OBJ;
- last_op->result.op_type = IS_VAR;
- last_op->result.u.EA.type = 0;
- last_op->result.u.var = get_temporary_variable(CG(active_op_array));
- *result = last_op->result;
- return;
- }
- }
- opline = get_next_op(CG(active_op_array) TSRMLS_CC);
- opline->opcode = op;
- opline->op1 = *op1;
- SET_UNUSED(opline->op2);
- opline->result.op_type = IS_VAR;
- opline->result.u.EA.type = 0;
- opline->result.u.var = get_temporary_variable(CG(active_op_array));
- *result = opline->result;
- }
- /* }}} */
- void zend_do_post_incdec(znode *result, const znode *op1, zend_uchar op TSRMLS_DC) /* {{{ */
- {
- int last_op_number = get_next_op_number(CG(active_op_array));
- zend_op *opline;
- if (last_op_number > 0) {
- zend_op *last_op = &CG(active_op_array)->opcodes[last_op_number-1];
- if (last_op->opcode == ZEND_FETCH_OBJ_RW) {
- last_op->opcode = (op==ZEND_POST_INC)?ZEND_POST_INC_OBJ:ZEND_POST_DEC_OBJ;
- last_op->result.op_type = IS_TMP_VAR;
- last_op->result.u.var = get_temporary_variable(CG(active_op_array));
- *result = last_op->result;
- return;
- }
- }
- opline = get_next_op(CG(active_op_array) TSRMLS_CC);
- opline->opcode = op;
- opline->op1 = *op1;
- SET_UNUSED(opline->op2);
- opline->result.op_type = IS_TMP_VAR;
- opline->result.u.var = get_temporary_variable(CG(active_op_array));
- *result = opline->result;
- }
- /* }}} */
- void zend_do_if_cond(const znode *cond, znode *closing_bracket_token TSRMLS_DC) /* {{{ */
- {
- int if_cond_op_number = get_next_op_number(CG(active_op_array));
- zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
- opline->opcode = ZEND_JMPZ;
- opline->op1 = *cond;
- closing_bracket_token->u.opline_num = if_cond_op_number;
- SET_UNUSED(opline->op2);
- INC_BPC(CG(active_op_array));
- }
- /* }}} */
- void zend_do_if_after_statement(const znode *closing_bracket_token, unsigned char initialize TSRMLS_DC) /* {{{ */
- {
- int if_end_op_number = get_next_op_number(CG(active_op_array));
- zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
- zend_llist *jmp_list_ptr;
- opline->opcode = ZEND_JMP;
- /* save for backpatching */
- if (initialize) {
- zend_llist jmp_list;
- zend_llist_init(&jmp_list, sizeof(int), NULL, 0);
- zend_stack_push(&CG(bp_stack), (void *) &jmp_list, sizeof(zend_llist));
- }
- zend_stack_top(&CG(bp_stack), (void **) &jmp_list_ptr);
- zend_llist_add_element(jmp_list_ptr, &if_end_op_number);
- CG(active_op_array)->opcodes[closing_bracket_token->u.opline_num].op2.u.opline_num = if_end_op_number+1;
- SET_UNUSED(opline->op1);
- SET_UNUSED(opline->op2);
- }
- /* }}} */
- void zend_do_if_end(TSRMLS_D) /* {{{ */
- {
- int next_op_number = get_next_op_number(CG(active_op_array));
- zend_llist *jmp_list_ptr;
- zend_llist_element *le;
- zend_stack_top(&CG(bp_stack), (void **) &jmp_list_ptr);
- for (le=jmp_list_ptr->head; le; le = le->next) {
- CG(active_op_array)->opcodes[*((int *) le->data)].op1.u.opline_num = next_op_number;
- }
- zend_llist_destroy(jmp_list_ptr);
- zend_stack_del_top(&CG(bp_stack));
- DEC_BPC(CG(active_op_array));
- }
- /* }}} */
- void zend_check_writable_variable(const znode *variable) /* {{{ */
- {
- zend_uint type = variable->u.EA.type;
- if (type & ZEND_PARSED_METHOD_CALL) {
- zend_error(E_COMPILE_ERROR, "Can't use method return value in write context");
- }
- if (type == ZEND_PARSED_FUNCTION_CALL) {
- zend_error(E_COMPILE_ERROR, "Can't use function return value in write context");
- }
- }
- /* }}} */
- void zend_do_begin_variable_parse(TSRMLS_D) /* {{{ */
- {
- zend_llist fetch_list;
- zend_llist_init(&fetch_list, sizeof(zend_op), NULL, 0);
- zend_stack_push(&CG(bp_stack), (void *) &fetch_list, sizeof(zend_llist));
- }
- /* }}} */
- void zend_do_end_variable_parse(znode *variable, int type, int arg_offset TSRMLS_DC) /* {{{ */
- {
- zend_llist *fetch_list_ptr;
- zend_llist_element *le;
- zend_op *opline = NULL;
- zend_op *opline_ptr;
- zend_uint this_var = -1;
- zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr);
- le = fetch_list_ptr->head;
- /* TODO: $foo->x->y->z = 1 should fetch "x" and "y" for R or RW, not just W */
- if (le) {
- opline_ptr = (zend_op *)le->data;
- if (opline_is_fetch_this(opline_ptr TSRMLS_CC)) {
- /* convert to FETCH_?(this) into IS_CV */
- if (CG(active_op_array)->last == 0 ||
- CG(active_op_array)->opcodes[CG(active_op_array)->last-1].opcode != ZEND_BEGIN_SILENCE) {
- this_var = opline_ptr->result.u.var;
- if (CG(active_op_array)->this_var == -1) {
- CG(active_op_array)->this_var = lookup_cv(CG(active_op_array), Z_STRVAL(opline_ptr->op1.u.constant), Z_STRLEN(opline_ptr->op1.u.constant));
- } else {
- efree(Z_STRVAL(opline_ptr->op1.u.constant));
- }
- le = le->next;
- if (variable->op_type == IS_VAR &&
- variable->u.var == this_var) {
- variable->op_type = IS_CV;
- variable->u.var = CG(active_op_array)->this_var;
- }
- } else if (CG(active_op_array)->this_var == -1) {
- CG(active_op_array)->this_var = lookup_cv(CG(active_op_array), estrndup("this", sizeof("this")-1), sizeof("this")-1);
- }
- }
- while (le) {
- opline_ptr = (zend_op *)le->data;
- opline = get_next_op(CG(active_op_array) TSRMLS_CC);
- memcpy(opline, opline_ptr, sizeof(zend_op));
- if (opline->op1.op_type == IS_VAR &&
- opline->op1.u.var == this_var) {
- opline->op1.op_type = IS_CV;
- opline->op1.u.var = CG(active_op_array)->this_var;
- }
- switch (type) {
- case BP_VAR_R:
- if (opline->opcode == ZEND_FETCH_DIM_W && opline->op2.op_type == IS_UNUSED) {
- zend_error(E_COMPILE_ERROR, "Cannot use [] for reading");
- }
- opline->opcode -= 3;
- break;
- case BP_VAR_W:
- break;
- case BP_VAR_RW:
- opline->opcode += 3;
- break;
- case BP_VAR_IS:
- if (opline->opcode == ZEND_FETCH_DIM_W && opline->op2.op_type == IS_UNUSED) {
- zend_error(E_COMPILE_ERROR, "Cannot use [] for reading");
- }
- opline->opcode += 6; /* 3+3 */
- break;
- case BP_VAR_FUNC_ARG:
- opline->opcode += 9; /* 3+3+3 */
- opline->extended_value = arg_offset;
- break;
- case BP_VAR_UNSET:
- if (opline->opcode == ZEND_FETCH_DIM_W && opline->op2.op_type == IS_UNUSED) {
- zend_error(E_COMPILE_ERROR, "Cannot use [] for unsetting");
- }
- opline->opcode += 12; /* 3+3+3+3 */
- break;
- }
- le = le->next;
- }
- if (opline && type == BP_VAR_W && arg_offset) {
- opline->extended_value = ZEND_FETCH_MAKE_REF;
- }
- }
- zend_llist_destroy(fetch_list_ptr);
- zend_stack_del_top(&CG(bp_stack));
- }
- /* }}} */
- void zend_do_add_string(znode *result, const znode *op1, znode *op2 TSRMLS_DC) /* {{{ */
- {
- zend_op *opline;
- if (Z_STRLEN(op2->u.constant) > 1) {
- opline = get_next_op(CG(active_op_array) TSRMLS_CC);
- opline->opcode = ZEND_ADD_STRING;
- } else if (Z_STRLEN(op2->u.constant) == 1) {
- int ch = *Z_STRVAL(op2->u.constant);
- /* Free memory and use ZEND_ADD_CHAR in case of 1 character strings */
- efree(Z_STRVAL(op2->u.constant));
- ZVAL_LONG(&op2->u.constant, ch);
- opline = get_next_op(CG(active_op_array) TSRMLS_CC);
- opline->opcode = ZEND_ADD_CHAR;
- } else { /* String can be empty after a variable at the end of a heredoc */
- efree(Z_STRVAL(op2->u.constant));
- return;
- }
- if (op1) {
- opline->op1 = *op1;
- opline->result = *op1;
- } else {
- SET_UNUSED(opline->op1);
- opline->result.op_type = IS_TMP_VAR;
- opline->result.u.var = get_temporary_variable(CG(active_op_array));
- }
- opline->op2 = *op2;
- *result = opline->result;
- }
- /* }}} */
- void zend_do_add_variable(znode *result, const znode *op1, const znode *op2 TSRMLS_DC) /* {{{ */
- {
- zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
- opline->opcode = ZEND_ADD_VAR;
- if (op1) {
- opline->op1 = *op1;
- opline->result = *op1;
- } else {
- SET_UNUSED(opline->op1);
- opline->result.op_type = IS_TMP_VAR;
- opline->result.u.var = get_temporary_variable(CG(active_op_array));
- }
- opline->op2 = *op2;
- *result = opline->result;
- }
- /* }}} */
- void zend_do_free(znode *op1 TSRMLS_DC) /* {{{ */
- {
- if (op1->op_type==IS_TMP_VAR) {
- zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
- opline->opcode = ZEND_FREE;
- opline->op1 = *op1;
- SET_UNUSED(opline->op2);
- } 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.op_type == IS_VAR
- && opline->result.u.var == op1->u.var) {
- opline->result.u.EA.type |= EXT_TYPE_UNUSED;
- } else {
- while (opline>CG(active_op_array)->opcodes) {
- if (opline->opcode == ZEND_FETCH_DIM_R
- && opline->op1.op_type == IS_VAR
- && opline->op1.u.var == op1->u.var) {
- /* This should the end of a list() construct
- * Mark its result as unused
- */
- opline->extended_value = ZEND_FETCH_STANDARD;
- break;
- } else if (opline->result.op_type==IS_VAR
- && opline->result.u.var == op1->u.var) {
- if (opline->opcode == ZEND_NEW) {
- opline->result.u.EA.type |= EXT_TYPE_UNUSED;
- }
- break;
- }
- opline--;
- }
- }
- } else if (op1->op_type == IS_CONST) {
- zval_dtor(&op1->u.constant);
- }
- }
- /* }}} */
- int zend_do_verify_access_types(const znode *current_access_type, const znode *new_modifier) /* {{{ */
- {
- if ((Z_LVAL(current_access_type->u.constant) & ZEND_ACC_PPP_MASK)
- && (Z_LVAL(new_modifier->u.constant) & ZEND_ACC_PPP_MASK)) {
- zend_error(E_COMPILE_ERROR, "Multiple access type modifiers are not allowed");
- }
- if ((Z_LVAL(current_access_type->u.constant) & ZEND_ACC_ABSTRACT)
- && (Z_LVAL(new_modifier->u.constant) & ZEND_ACC_ABSTRACT)) {
- zend_error(E_COMPILE_ERROR, "Multiple abstract modifiers are not allowed");
- }
- if ((Z_LVAL(current_access_type->u.constant) & ZEND_ACC_STATIC)
- && (Z_LVAL(new_modifier->u.constant) & ZEND_ACC_STATIC)) {
- zend_error(E_COMPILE_ERROR, "Multiple static modifiers are not allowed");
- }
- if ((Z_LVAL(current_access_type->u.constant) & ZEND_ACC_FINAL)
- && (Z_LVAL(new_modifier->u.constant) & ZEND_ACC_FINAL)) {
- zend_error(E_COMPILE_ERROR, "Multiple final modifiers are not allowed");
- }
- if (((Z_LVAL(current_access_type->u.constant) | Z_LVAL(new_modifier->u.constant)) & (ZEND_ACC_ABSTRACT | ZEND_ACC_FINAL)) == (ZEND_ACC_ABSTRACT | ZEND_ACC_FINAL)) {
- zend_error(E_COMPILE_ERROR, "Cannot use the final modifier on an abstract class member");
- }
- return (Z_LVAL(current_access_type->u.constant) | Z_LVAL(new_modifier->u.constant));
- }
- /* }}} */
- void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, znode *fn_flags_znode TSRMLS_DC) /* {{{ */
- {
- zend_op_array op_array;
- char *name = function_name->u.constant.value.str.val;
- int name_len = function_name->u.constant.value.str.len;
- int function_begin_line = function_token->u.opline_num;
- zend_uint fn_flags;
- char *lcname;
- zend_bool orig_interactive;
- ALLOCA_FLAG(use_heap)
- if (is_method) {
- if (CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE) {
- if ((Z_LVAL(fn_flags_znode->u.constant) & ~(ZEND_ACC_STATIC|ZEND_ACC_PUBLIC))) {
- zend_error(E_COMPILE_ERROR, "Access type for interface method %s::%s() must be omitted", CG(active_class_entry)->name, function_name->u.constant.value.str.val);
- }
- Z_LVAL(fn_flags_znode->u.constant) |= ZEND_ACC_ABSTRACT; /* propagates to the rest of the parser */
- }
- fn_flags = Z_LVAL(fn_flags_znode->u.constant); /* must be done *after* the above check */
- } else {
- fn_flags = 0;
- }
- if ((fn_flags & ZEND_ACC_STATIC) && (fn_flags & ZEND_ACC_ABSTRACT) && !(CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE)) {
- zend_error(E_STRICT, "Static function %s%s%s() should not be abstract", is_method ? CG(active_class_entry)->name : "", is_method ? "::" : "", Z_STRVAL(function_name->u.constant));
- }
- function_token->u.op_array = CG(active_op_array);
- lcname = zend_str_tolower_dup(name, name_len);
- orig_interactive = CG(interactive);
- CG(interactive) = 0;
- init_op_array(&op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC);
- CG(interactive) = orig_interactive;
- op_array.function_name = name;
- op_array.return_reference = return_reference;
- op_array.fn_flags |= fn_flags;
- op_array.pass_rest_by_reference = 0;
- op_array.scope = is_method?CG(active_class_entry):NULL;
- op_array.prototype = NULL;
- op_array.line_start = zend_get_compiled_lineno(TSRMLS_C);
- if (is_method) {
- if (zend_hash_add(&CG(active_class_entry)->function_table, lcname, name_len+1, &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array)) == FAILURE) {
- zend_error(E_COMPILE_ERROR, "Cannot redeclare %s::%s()", CG(active_class_entry)->name, name);
- }
- if (fn_flags & ZEND_ACC_ABSTRACT) {
- CG(active_class_entry)->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
- }
- if (!(fn_flags & ZEND_ACC_PPP_MASK)) {
- fn_flags |= ZEND_ACC_PUBLIC;
- }
- if (CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE) {
- if ((name_len == sizeof(ZEND_CALL_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)-1))) {
- if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
- zend_error(E_WARNING, "The magic method __call() must have public visibility and cannot be static");
- }
- } else if ((name_len == sizeof(ZEND_CALLSTATIC_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CALLSTATIC_FUNC_NAME, sizeof(ZEND_CALLSTATIC_FUNC_NAME)-1))) {
- if ((fn_flags & (ZEND_ACC_PPP_MASK ^ ZEND_ACC_PUBLIC)) || (fn_flags & ZEND_ACC_STATIC) == 0) {
- zend_error(E_WARNING, "The magic method __callStatic() must have public visibility and be static");
- }
- } else if ((name_len == sizeof(ZEND_GET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_GET_FUNC_NAME, sizeof(ZEND_GET_FUNC_NAME)-1))) {
- if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
- zend_error(E_WARNING, "The magic method __get() must have public visibility and cannot be static");
- }
- } else if ((name_len == sizeof(ZEND_SET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_SET_FUNC_NAME, sizeof(ZEND_SET_FUNC_NAME)-1))) {
- if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
- zend_error(E_WARNING, "The magic method __set() must have public visibility and cannot be static");
- }
- } else if ((name_len == sizeof(ZEND_UNSET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_UNSET_FUNC_NAME, sizeof(ZEND_UNSET_FUNC_NAME)-1))) {
- if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
- zend_error(E_WARNING, "The magic method __unset() must have public visibility and cannot be static");
- }
- } else if ((name_len == sizeof(ZEND_ISSET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_ISSET_FUNC_NAME, sizeof(ZEND_ISSET_FUNC_NAME)-1))) {
- if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
- zend_error(E_WARNING, "The magic method __isset() must have public visibility and cannot be static");
- }
- } else if ((name_len == sizeof(ZEND_TOSTRING_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_TOSTRING_FUNC_NAME, sizeof(ZEND_TOSTRING_FUNC_NAME)-1))) {
- if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
- zend_error(E_WARNING, "The magic method __toString() must have public visibility and cannot be static");
- }
- }
- } else {
- char *class_lcname;
-
- class_lcname = do_alloca(CG(active_class_entry)->name_length + 1, use_heap);
- zend_str_tolower_copy(class_lcname, CG(active_class_entry)->name, CG(active_class_entry)->name_length);
- /* Improve after RC: cache the lowercase class name */
- if ((CG(active_class_entry)->name_length == name_len) && (!memcmp(class_lcname, lcname, name_len))) {
- if (!CG(active_class_entry)->constructor) {
- CG(active_class_entry)->constructor = (zend_function *) CG(active_op_array);
- }
- } else if ((name_len == sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)))) {
- if (CG(active_class_entry)->constructor) {
- zend_error(E_STRICT, "Redefining already defined constructor for class %s", CG(active_class_entry)->name);
- }
- CG(active_class_entry)->constructor = (zend_function *) CG(active_op_array);
- } else if ((name_len == sizeof(ZEND_DESTRUCTOR_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_DESTRUCTOR_FUNC_NAME, sizeof(ZEND_DESTRUCTOR_FUNC_NAME)-1))) {
- CG(active_class_entry)->destructor = (zend_function *) CG(active_op_array);
- } else if ((name_len == sizeof(ZEND_CLONE_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CLONE_FUNC_NAME, sizeof(ZEND_CLONE_FUNC_NAME)-1))) {
- CG(active_class_entry)->clone = (zend_function *) CG(active_op_array);
- } else if ((name_len == sizeof(ZEND_CALL_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)-1))) {
- if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
- zend_error(E_WARNING, "The magic method __call() must have public visibility and cannot be static");
- }
- CG(active_class_entry)->__call = (zend_function *) CG(active_op_array);
- } else if ((name_len == sizeof(ZEND_CALLSTATIC_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CALLSTATIC_FUNC_NAME, sizeof(ZEND_CALLSTATIC_FUNC_NAME)-1))) {
- if ((fn_flags & (ZEND_ACC_PPP_MASK ^ ZEND_ACC_PUBLIC)) || (fn_flags & ZEND_ACC_STATIC) == 0) {
- zend_error(E_WARNING, "The magic method __callStatic() must have public visibility and be static");
- }
- CG(active_class_entry)->__callstatic = (zend_function *) CG(active_op_array);
- } else if ((name_len == sizeof(ZEND_GET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_GET_FUNC_NAME, sizeof(ZEND_GET_FUNC_NAME)-1))) {
- if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
- zend_error(E_WARNING, "The magic method __get() must have public visibility and cannot be static");
- }
- CG(active_class_entry)->__get = (zend_function *) CG(active_op_array);
- } else if ((name_len == sizeof(ZEND_SET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_SET_FUNC_NAME, sizeof(ZEND_SET_FUNC_NAME)-1))) {
- if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
- zend_error(E_WARNING, "The magic method __set() must have public visibility and cannot be static");
- }
- CG(active_class_entry)->__set = (zend_function *) CG(active_op_array);
- } else if ((name_len == sizeof(ZEND_UNSET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_UNSET_FUNC_NAME, sizeof(ZEND_UNSET_FUNC_NAME)-1))) {
- if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
- zend_error(E_WARNING, "The magic method __unset() must have public visibility and cannot be static");
- }
- CG(active_class_entry)->__unset = (zend_function *) CG(active_op_array);
- } else if ((name_len == sizeof(ZEND_ISSET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_ISSET_FUNC_NAME, sizeof(ZEND_ISSET_FUNC_NAME)-1))) {
- if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
- zend_error(E_WARNING, "The magic method __isset() must have public visibility and cannot be static");
- }
- CG(active_class_entry)->__isset = (zend_function *) CG(active_op_array);
- } else if ((name_len == sizeof(ZEND_TOSTRING_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_TOSTRING_FUNC_NAME, sizeof(ZEND_TOSTRING_FUNC_NAME)-1))) {
- if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
- zend_error(E_WARNING, "The magic method __toString() must have public visibility and cannot be static");
- }
- CG(active_class_entry)->__tostring = (zend_function *) CG(active_op_array);
- } else if (!(fn_flags & ZEND_ACC_STATIC)) {
- CG(active_op_array)->fn_flags |= ZEND_ACC_ALLOW_STATIC;
- }
- free_alloca(class_lcname, use_heap);
- }
- efree(lcname);
- } else {
- zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
- if (CG(current_namespace)) {
- /* Prefix function name with current namespcae name */
- znode tmp;
- tmp.u.constant = *CG(current_namespace);
- zval_copy_ctor(&tmp.u.constant);
- zend_do_build_namespace_name(&tmp, &tmp, function_name TSRMLS_CC);
- op_array.function_name = Z_STRVAL(tmp.u.constant);
- efree(lcname);
- name_len = Z_STRLEN(tmp.u.constant);
- lcname = zend_str_tolower_dup(Z_STRVAL(tmp.u.constant), name_len);
- }
- opline->opcode = ZEND_DECLARE_FUNCTION;
- opline->op1.op_type = IS_CONST;
- build_runtime_defined_function_key(&opline->op1.u.constant, lcname, name_len TSRMLS_CC);
- opline->op2.op_type = IS_CONST;
- opline->op2.u.constant.type = IS_STRING;
- opline->op2.u.constant.value.str.val = lcname;
- opline->op2.u.constant.value.str.len = name_len;
- Z_SET_REFCOUNT(opline->op2.u.constant, 1);
- opline->extended_value = ZEND_DECLARE_FUNCTION;
- zend_hash_update(CG(function_table), opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array));
- }
- if (CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO) {
- zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
- opline->opcode = ZEND_EXT_NOP;
- opline->lineno = function_begin_line;
- SET_UNUSED(opline->op1);
- SET_UNUSED(opline->op2);
- }
- {
- /* Push a seperator to the switch and foreach stacks */
- zend_switch_entry switch_entry;
- switch_entry.cond.op_type = IS_UNUSED;
- switch_entry.default_case = 0;
- switch_entry.control_var = 0;
- zend_stack_push(&CG(switch_cond_stack), (void *) &switch_entry, sizeof(switch_entry));
- {
- /* Foreach stack separator */
- zend_op dummy_opline;
- dummy_opline.result.op_type = IS_UNUSED;
- dummy_opline.op1.op_type = IS_UNUSED;
- zend_stack_push(&CG(foreach_copy_stack), (void *) &dummy_opline, sizeof(zend_op));
- }
- }
- if (CG(doc_comment)) {
- CG(active_op_array)->doc_comment = CG(doc_comment);
- CG(active_op_array)->doc_comment_len = CG(doc_comment_len);
- CG(doc_comment) = NULL;
- CG(doc_comment_len) = 0;
- }
- zend_stack_push(&CG(labels_stack), (void *) &CG(labels), sizeof(HashTable*));
- CG(labels) = NULL;
- }
- /* }}} */
- void zend_do_begin_lambda_function_declaration(znode *result, znode *function_token, int return_reference TSRMLS_DC) /* {{{ */
- {
- znode function_name;
- zend_op_array *current_op_array = CG(active_op_array);
- int current_op_number = get_next_op_number(CG(active_op_array));
- zend_op *current_op;
- function_name.op_type = IS_CONST;
- ZVAL_STRINGL(&function_name.u.constant, "{closure}", sizeof("{closure}")-1, 1);
- zend_do_begin_function_declaration(function_token, &function_name, 0, return_reference, NULL TSRMLS_CC);
- result->op_type = IS_TMP_VAR;
- result->u.var = get_temporary_variable(current_op_array);
- current_op = ¤t_op_array->opcodes[current_op_number];
- current_op->opcode = ZEND_DECLARE_LAMBDA_FUNCTION;
- zval_dtor(¤t_op->op2.u.constant);
- ZVAL_LONG(¤t_op->op2.u.constant, zend_hash_func(Z_STRVAL(current_op->op1.u.constant), Z_STRLEN(current_op->op1.u.constant)));
- current_op->result = *result;
- CG(active_op_array)->fn_flags |= ZEND_ACC_CLOSURE;
- }
- /* }}} */
- void zend_d…
Large files files are truncated, but you can click here to view the full file