diff options
Diffstat (limited to 'Zend/zend_opcode.c')
| -rw-r--r-- | Zend/zend_opcode.c | 227 |
1 files changed, 102 insertions, 125 deletions
diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index ea8fa0917d..6bed3c7b59 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -18,8 +18,6 @@ +----------------------------------------------------------------------+ */ -/* $Id$ */ - #include <stdio.h> #include "zend.h" @@ -27,6 +25,7 @@ #include "zend_compile.h" #include "zend_extensions.h" #include "zend_API.h" +#include "zend_sort.h" #include "zend_vm.h" @@ -44,11 +43,6 @@ static void zend_extension_op_array_dtor_handler(zend_extension *extension, zend } } -static void op_array_alloc_ops(zend_op_array *op_array, uint32_t size) -{ - op_array->opcodes = erealloc(op_array->opcodes, size * sizeof(zend_op)); -} - void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_size) { op_array->type = type; @@ -59,8 +53,7 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz op_array->refcount = (uint32_t *) emalloc(sizeof(uint32_t)); *op_array->refcount = 1; op_array->last = 0; - op_array->opcodes = NULL; - op_array_alloc_ops(op_array, initial_ops_size); + op_array->opcodes = emalloc(initial_ops_size * sizeof(zend_op)); op_array->last_var = 0; op_array->vars = NULL; @@ -87,8 +80,6 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz op_array->fn_flags = 0; - op_array->early_binding = -1; - op_array->last_literal = 0; op_array->literals = NULL; @@ -104,30 +95,10 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz ZEND_API void destroy_zend_function(zend_function *function) { - if (function->type == ZEND_USER_FUNCTION) { - destroy_op_array(&function->op_array); - } else { - ZEND_ASSERT(function->type == ZEND_INTERNAL_FUNCTION); - ZEND_ASSERT(function->common.function_name); - zend_string_release(function->common.function_name); + zval tmp; - if (function->common.arg_info && - (function->common.fn_flags & (ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_HAS_TYPE_HINTS))) { - uint32_t i; - uint32_t num_args = function->common.num_args + 1; - zend_arg_info *arg_info = function->common.arg_info - 1; - - if (function->common.fn_flags & ZEND_ACC_VARIADIC) { - num_args++; - } - for (i = 0 ; i < num_args; i++) { - if (ZEND_TYPE_IS_CLASS(arg_info[i].type)) { - zend_string_release(ZEND_TYPE_NAME(arg_info[i].type)); - } - } - free(arg_info); - } - } + ZVAL_PTR(&tmp, function); + zend_function_dtor(&tmp); } ZEND_API void zend_function_dtor(zval *zv) @@ -141,8 +112,8 @@ ZEND_API void zend_function_dtor(zval *zv) } else { ZEND_ASSERT(function->type == ZEND_INTERNAL_FUNCTION); ZEND_ASSERT(function->common.function_name); - zend_string_release(function->common.function_name); -#ifndef ZTS + zend_string_release_ex(function->common.function_name, 1); + if ((function->common.fn_flags & (ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_HAS_TYPE_HINTS)) && !function->common.scope && function->common.arg_info) { @@ -155,12 +126,12 @@ ZEND_API void zend_function_dtor(zval *zv) } for (i = 0 ; i < num_args; i++) { if (ZEND_TYPE_IS_CLASS(arg_info[i].type)) { - zend_string_release(ZEND_TYPE_NAME(arg_info[i].type)); + zend_string_release_ex(ZEND_TYPE_NAME(arg_info[i].type), 1); } } free(arg_info); } -#endif + if (!(function->common.fn_flags & ZEND_ACC_ARENA_ALLOCATED)) { pefree(function, 1); } @@ -179,7 +150,6 @@ ZEND_API void zend_cleanup_internal_class_data(zend_class_entry *ce) #else ce->static_members_table = NULL; #endif - ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED; while (p != end) { i_zval_ptr_dtor(p ZEND_FILE_LINE_CC); p++; @@ -197,18 +167,15 @@ void _destroy_zend_class_traits_info(zend_class_entry *ce) if (ce->trait_aliases) { size_t i = 0; while (ce->trait_aliases[i]) { - if (ce->trait_aliases[i]->trait_method) { - if (ce->trait_aliases[i]->trait_method->method_name) { - zend_string_release(ce->trait_aliases[i]->trait_method->method_name); - } - if (ce->trait_aliases[i]->trait_method->class_name) { - zend_string_release(ce->trait_aliases[i]->trait_method->class_name); - } - efree(ce->trait_aliases[i]->trait_method); + if (ce->trait_aliases[i]->trait_method.method_name) { + zend_string_release_ex(ce->trait_aliases[i]->trait_method.method_name, 0); + } + if (ce->trait_aliases[i]->trait_method.class_name) { + zend_string_release_ex(ce->trait_aliases[i]->trait_method.class_name, 0); } if (ce->trait_aliases[i]->alias) { - zend_string_release(ce->trait_aliases[i]->alias); + zend_string_release_ex(ce->trait_aliases[i]->alias, 0); } efree(ce->trait_aliases[i]); @@ -219,21 +186,15 @@ void _destroy_zend_class_traits_info(zend_class_entry *ce) } if (ce->trait_precedences) { - size_t i = 0; + int i = 0; + int j; while (ce->trait_precedences[i]) { - zend_string_release(ce->trait_precedences[i]->trait_method->method_name); - zend_string_release(ce->trait_precedences[i]->trait_method->class_name); - efree(ce->trait_precedences[i]->trait_method); - - if (ce->trait_precedences[i]->exclude_from_classes) { - size_t j = 0; - zend_trait_precedence *cur_precedence = ce->trait_precedences[i]; - while (cur_precedence->exclude_from_classes[j].class_name) { - zend_string_release(cur_precedence->exclude_from_classes[j].class_name); - j++; - } - efree(ce->trait_precedences[i]->exclude_from_classes); + zend_string_release_ex(ce->trait_precedences[i]->trait_method.method_name, 0); + zend_string_release_ex(ce->trait_precedences[i]->trait_method.class_name, 0); + + for (j = 0; j < ce->trait_precedences[i]->num_excludes; j++) { + zend_string_release_ex(ce->trait_precedences[i]->exclude_class_names[j], 0); } efree(ce->trait_precedences[i]); i++; @@ -246,9 +207,7 @@ ZEND_API void destroy_zend_class(zval *zv) { zend_property_info *prop_info; zend_class_entry *ce = Z_PTR_P(zv); -#ifndef ZTS zend_function *fn; -#endif if (--ce->refcount > 0) { return; @@ -277,23 +236,23 @@ ZEND_API void destroy_zend_class(zval *zv) } ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop_info) { if (prop_info->ce == ce || (prop_info->flags & ZEND_ACC_SHADOW)) { - zend_string_release(prop_info->name); + zend_string_release_ex(prop_info->name, 0); if (prop_info->doc_comment) { - zend_string_release(prop_info->doc_comment); + zend_string_release_ex(prop_info->doc_comment, 0); } } } ZEND_HASH_FOREACH_END(); zend_hash_destroy(&ce->properties_info); - zend_string_release(ce->name); + zend_string_release_ex(ce->name, 0); zend_hash_destroy(&ce->function_table); if (zend_hash_num_elements(&ce->constants_table)) { zend_class_constant *c; ZEND_HASH_FOREACH_PTR(&ce->constants_table, c) { if (c->ce == ce) { - zval_ptr_dtor(&c->value); + zval_ptr_dtor_nogc(&c->value); if (c->doc_comment) { - zend_string_release(c->doc_comment); + zend_string_release_ex(c->doc_comment, 0); } } } ZEND_HASH_FOREACH_END(); @@ -303,7 +262,7 @@ ZEND_API void destroy_zend_class(zval *zv) efree(ce->interfaces); } if (ce->info.user.doc_comment) { - zend_string_release(ce->info.user.doc_comment); + zend_string_release_ex(ce->info.user.doc_comment, 0); } _destroy_zend_class_traits_info(ce); @@ -331,8 +290,9 @@ ZEND_API void destroy_zend_class(zval *zv) free(ce->default_static_members_table); } zend_hash_destroy(&ce->properties_info); - zend_string_release(ce->name); -#ifndef ZTS + zend_string_release_ex(ce->name, 1); + + /* TODO: eliminate this loop for classes without functions with arg_info */ ZEND_HASH_FOREACH_PTR(&ce->function_table, fn) { if ((fn->common.fn_flags & (ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_HAS_TYPE_HINTS)) && fn->common.scope == ce) { @@ -340,19 +300,25 @@ ZEND_API void destroy_zend_class(zval *zv) fn->common.scope = NULL; } } ZEND_HASH_FOREACH_END(); -#endif + zend_hash_destroy(&ce->function_table); if (zend_hash_num_elements(&ce->constants_table)) { zend_class_constant *c; ZEND_HASH_FOREACH_PTR(&ce->constants_table, c) { - zval_internal_ptr_dtor(&c->value); - if (c->doc_comment && c->ce == ce) { - zend_string_release(c->doc_comment); + if (c->ce == ce) { + zval_internal_ptr_dtor(&c->value); + if (c->doc_comment) { + zend_string_release_ex(c->doc_comment, 1); + } } + free(c); } ZEND_HASH_FOREACH_END(); zend_hash_destroy(&ce->constants_table); } + if (ce->iterator_funcs_ptr) { + free(ce->iterator_funcs_ptr); + } if (ce->num_interfaces > 0) { free(ce->interfaces); } @@ -370,13 +336,11 @@ void zend_class_add_ref(zval *zv) ZEND_API void destroy_op_array(zend_op_array *op_array) { - zval *literal = op_array->literals; - zval *end; uint32_t i; if (op_array->static_variables && !(GC_FLAGS(op_array->static_variables) & IS_ARRAY_IMMUTABLE)) { - if (--GC_REFCOUNT(op_array->static_variables) == 0) { + if (GC_DELREF(op_array->static_variables) == 0) { zend_array_destroy(op_array->static_variables); } } @@ -396,26 +360,30 @@ ZEND_API void destroy_op_array(zend_op_array *op_array) i = op_array->last_var; while (i > 0) { i--; - zend_string_release(op_array->vars[i]); + zend_string_release_ex(op_array->vars[i], 0); } efree(op_array->vars); } - if (literal) { - end = literal + op_array->last_literal; + if (op_array->literals) { + zval *literal = op_array->literals; + zval *end = literal + op_array->last_literal; while (literal < end) { zval_ptr_dtor_nogc(literal); literal++; } - efree(op_array->literals); + if (ZEND_USE_ABS_CONST_ADDR + || !(op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO)) { + efree(op_array->literals); + } } efree(op_array->opcodes); if (op_array->function_name) { - zend_string_release(op_array->function_name); + zend_string_release_ex(op_array->function_name, 0); } if (op_array->doc_comment) { - zend_string_release(op_array->doc_comment); + zend_string_release_ex(op_array->doc_comment, 0); } if (op_array->live_range) { efree(op_array->live_range); @@ -441,52 +409,16 @@ ZEND_API void destroy_op_array(zend_op_array *op_array) } for (i = 0 ; i < num_args; i++) { if (arg_info[i].name) { - zend_string_release(arg_info[i].name); + zend_string_release_ex(arg_info[i].name, 0); } if (ZEND_TYPE_IS_CLASS(arg_info[i].type)) { - zend_string_release(ZEND_TYPE_NAME(arg_info[i].type)); + zend_string_release_ex(ZEND_TYPE_NAME(arg_info[i].type), 0); } } efree(arg_info); } } -void init_op(zend_op *op) -{ - memset(op, 0, sizeof(zend_op)); - op->lineno = CG(zend_lineno); - SET_UNUSED(op->result); -} - -zend_op *get_next_op(zend_op_array *op_array) -{ - uint32_t next_op_num = op_array->last++; - zend_op *next_op; - - if (next_op_num >= CG(context).opcodes_size) { - CG(context).opcodes_size *= 4; - op_array_alloc_ops(op_array, CG(context).opcodes_size); - } - - next_op = &(op_array->opcodes[next_op_num]); - - init_op(next_op); - - return next_op; -} - -uint32_t get_next_op_number(zend_op_array *op_array) -{ - return op_array->last; -} - -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_update_extended_info(zend_op_array *op_array) { zend_op *opline = op_array->opcodes, *end=opline+op_array->last; @@ -556,6 +488,20 @@ static uint32_t zend_get_brk_cont_target(const zend_op_array *op_array, const ze return opline->opcode == ZEND_BRK ? jmp_to->brk : jmp_to->cont; } +/* Live ranges must be sorted by increasing start opline */ +static int cmp_live_range(const zend_live_range *a, const zend_live_range *b) { + return a->start - b->start; +} +static void swap_live_range(zend_live_range *a, zend_live_range *b) { + zend_live_range tmp = *a; + *a = *b; + *b = tmp; +} +static void zend_sort_live_ranges(zend_op_array *op_array) { + zend_sort(op_array->live_range, op_array->last_live_range, sizeof(zend_live_range), + (compare_func_t) cmp_live_range, (swap_func_t) swap_live_range); +} + ZEND_API int pass_two(zend_op_array *op_array) { zend_op *opline, *end; @@ -576,6 +522,8 @@ ZEND_API int pass_two(zend_op_array *op_array) op_array->vars = (zend_string**) erealloc(op_array->vars, sizeof(zend_string*)*op_array->last_var); CG(context).vars_size = op_array->last_var; } + +#if ZEND_USE_ABS_CONST_ADDR if (CG(context).opcodes_size != op_array->last) { op_array->opcodes = (zend_op *) erealloc(op_array->opcodes, sizeof(zend_op)*op_array->last); CG(context).opcodes_size = op_array->last; @@ -584,10 +532,34 @@ ZEND_API int pass_two(zend_op_array *op_array) op_array->literals = (zval*)erealloc(op_array->literals, sizeof(zval) * op_array->last_literal); CG(context).literals_size = op_array->last_literal; } +#else + op_array->opcodes = (zend_op *) erealloc(op_array->opcodes, + ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_op) * op_array->last, 16) + + sizeof(zval) * op_array->last_literal); + if (op_array->literals) { + memcpy(((char*)op_array->opcodes) + ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_op) * op_array->last, 16), + op_array->literals, sizeof(zval) * op_array->last_literal); + efree(op_array->literals); + op_array->literals = (zval*)(((char*)op_array->opcodes) + ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_op) * op_array->last, 16)); + } + CG(context).opcodes_size = op_array->last; + CG(context).literals_size = op_array->last_literal; +#endif + opline = op_array->opcodes; end = opline + op_array->last; while (opline < end) { switch (opline->opcode) { + case ZEND_RECV_INIT: + { + zval *val = CT_CONSTANT(opline->op2); + if (Z_TYPE_P(val) == IS_CONSTANT_AST) { + uint32_t slot = ZEND_MM_ALIGNED_SIZE_EX(op_array->cache_size, 8); + Z_CACHE_SLOT_P(val) = slot; + op_array->cache_size += sizeof(zval); + } + } + break; case ZEND_FAST_CALL: opline->op1.opline_num = op_array->try_catch_array[opline->op1.num].finally_op; ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op1); @@ -644,12 +616,16 @@ ZEND_API int pass_two(zend_op_array *op_array) } case ZEND_DECLARE_ANON_CLASS: case ZEND_DECLARE_ANON_INHERITED_CLASS: - case ZEND_CATCH: case ZEND_FE_FETCH_R: case ZEND_FE_FETCH_RW: /* absolute index to relative offset */ opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, opline->extended_value); break; + case ZEND_CATCH: + if (!(opline->extended_value & ZEND_LAST_CATCH)) { + ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op2); + } + break; case ZEND_RETURN: case ZEND_RETURN_BY_REF: if (op_array->fn_flags & ZEND_ACC_GENERATOR) { @@ -671,12 +647,12 @@ ZEND_API int pass_two(zend_op_array *op_array) } } if (opline->op1_type == IS_CONST) { - ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline->op1); + ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline, opline->op1); } else if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) { opline->op1.var = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + opline->op1.var); } if (opline->op2_type == IS_CONST) { - ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline->op2); + ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline, opline->op2); } else if (opline->op2_type & (IS_VAR|IS_TMP_VAR)) { opline->op2.var = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + opline->op2.var); } @@ -690,6 +666,7 @@ ZEND_API int pass_two(zend_op_array *op_array) if (op_array->live_range) { int i; + zend_sort_live_ranges(op_array); for (i = 0; i < op_array->last_live_range; i++) { op_array->live_range[i].var = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + (op_array->live_range[i].var / sizeof(zval))) | |
