diff options
Diffstat (limited to 'Zend/zend_opcode.c')
-rw-r--r-- | Zend/zend_opcode.c | 393 |
1 files changed, 210 insertions, 183 deletions
diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 41b4bd2571..5902abd4c5 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | Zend Engine | +----------------------------------------------------------------------+ - | Copyright (c) 1998-2013 Zend Technologies Ltd. (http://www.zend.com) | + | Copyright (c) 1998-2014 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 | @@ -43,7 +43,7 @@ static void zend_extension_op_array_dtor_handler(zend_extension *extension, zend } } -static void op_array_alloc_ops(zend_op_array *op_array, zend_uint size) +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)); } @@ -52,14 +52,7 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz { op_array->type = type; - if (CG(interactive)) { - /* We must avoid a realloc() on the op_array in interactive mode, since pointers to constants - * will become invalid - */ - initial_ops_size = INITIAL_INTERACTIVE_OP_ARRAY_SIZE; - } - - op_array->refcount = (zend_uint *) emalloc(sizeof(zend_uint)); + op_array->refcount = (uint32_t *) emalloc(sizeof(uint32_t)); *op_array->refcount = 1; op_array->last = 0; op_array->opcodes = NULL; @@ -70,19 +63,16 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz op_array->T = 0; - op_array->nested_calls = 0; - op_array->used_stack = 0; - op_array->function_name = NULL; op_array->filename = zend_get_compiled_filename(TSRMLS_C); op_array->doc_comment = NULL; - op_array->doc_comment_len = 0; op_array->arg_info = NULL; op_array->num_args = 0; op_array->required_num_args = 0; op_array->scope = NULL; + op_array->prototype = NULL; op_array->brk_cont_array = NULL; op_array->try_catch_array = NULL; @@ -90,11 +80,10 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz op_array->static_variables = NULL; op_array->last_try_catch = 0; - op_array->has_finally_block = 0; op_array->this_var = -1; - op_array->fn_flags = CG(interactive)?ZEND_ACC_INTERACTIVE:0; + op_array->fn_flags = 0; op_array->early_binding = -1; @@ -111,71 +100,73 @@ 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 TSRMLS_DC) { - switch (function->type) { - case ZEND_USER_FUNCTION: - destroy_op_array((zend_op_array *) function TSRMLS_CC); - break; - case ZEND_INTERNAL_FUNCTION: - /* do nothing */ - break; + if (function->type == ZEND_USER_FUNCTION) { + destroy_op_array(&function->op_array TSRMLS_CC); + } else { + ZEND_ASSERT(function->type == ZEND_INTERNAL_FUNCTION); + ZEND_ASSERT(function->common.function_name); + zend_string_release(function->common.function_name); } } -ZEND_API void zend_function_dtor(zend_function *function) +ZEND_API void zend_function_dtor(zval *zv) { + zend_function *function = Z_PTR_P(zv); TSRMLS_FETCH(); - destroy_zend_function(function TSRMLS_CC); -} - -static void zend_cleanup_op_array_data(zend_op_array *op_array) -{ - if (op_array->static_variables) { - zend_hash_clean(op_array->static_variables); - } -} - -ZEND_API int zend_cleanup_function_data(zend_function *function TSRMLS_DC) -{ if (function->type == ZEND_USER_FUNCTION) { - zend_cleanup_op_array_data((zend_op_array *) function); - return ZEND_HASH_APPLY_KEEP; + ZEND_ASSERT(function->common.function_name); + destroy_op_array(&function->op_array TSRMLS_CC); + /* op_arrays are allocated on arena, so we don't have to free them */ +//??? efree_size(function, sizeof(zend_op_array)); } else { - return ZEND_HASH_APPLY_STOP; + ZEND_ASSERT(function->type == ZEND_INTERNAL_FUNCTION); + ZEND_ASSERT(function->common.function_name); + zend_string_release(function->common.function_name); + if (!(function->common.fn_flags & ZEND_ACC_ARENA_ALLOCATED)) { + pefree(function, 1); + } } } -ZEND_API int zend_cleanup_function_data_full(zend_function *function TSRMLS_DC) +ZEND_API void zend_cleanup_op_array_data(zend_op_array *op_array) { - if (function->type == ZEND_USER_FUNCTION) { - zend_cleanup_op_array_data((zend_op_array *) function); + if (op_array->static_variables) { + zend_hash_clean(op_array->static_variables); } - return 0; } -static inline void cleanup_user_class_data(zend_class_entry *ce TSRMLS_DC) +ZEND_API void zend_cleanup_user_class_data(zend_class_entry *ce TSRMLS_DC) { /* Clean all parts that can contain run-time data */ /* Note that only run-time accessed data need to be cleaned up, pre-defined data can not contain objects and thus are not probelmatic */ if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) { - zend_hash_apply(&ce->function_table, (apply_func_t) zend_cleanup_function_data_full TSRMLS_CC); + zend_function *func; + + ZEND_HASH_FOREACH_PTR(&ce->function_table, func) { + if (func->type == ZEND_USER_FUNCTION) { + zend_cleanup_op_array_data((zend_op_array *) func); + } + } ZEND_HASH_FOREACH_END(); } if (ce->static_members_table) { int i; for (i = 0; i < ce->default_static_members_count; i++) { - if (ce->static_members_table[i]) { - zval *p = ce->static_members_table[i]; - ce->static_members_table[i] = NULL; - zval_ptr_dtor(&p); + if (Z_TYPE(ce->static_members_table[i]) != IS_UNDEF) { + zval tmp; + + ZVAL_COPY_VALUE(&tmp, &ce->static_members_table[i]); + ZVAL_UNDEF(&ce->static_members_table[i]); + zval_ptr_dtor(&tmp); } } ce->static_members_table = NULL; } } -static inline void cleanup_internal_class_data(zend_class_entry *ce TSRMLS_DC) +ZEND_API void zend_cleanup_internal_class_data(zend_class_entry *ce TSRMLS_DC) { if (CE_STATIC_MEMBERS(ce)) { int i; @@ -192,31 +183,6 @@ static inline void cleanup_internal_class_data(zend_class_entry *ce TSRMLS_DC) } } -ZEND_API void zend_cleanup_internal_class_data(zend_class_entry *ce TSRMLS_DC) -{ - cleanup_internal_class_data(ce TSRMLS_CC); -} - -ZEND_API int zend_cleanup_user_class_data(zend_class_entry **pce TSRMLS_DC) -{ - if ((*pce)->type == ZEND_USER_CLASS) { - cleanup_user_class_data(*pce TSRMLS_CC); - return ZEND_HASH_APPLY_KEEP; - } else { - return ZEND_HASH_APPLY_STOP; - } -} - -ZEND_API int zend_cleanup_class_data(zend_class_entry **pce TSRMLS_DC) -{ - if ((*pce)->type == ZEND_USER_CLASS) { - cleanup_user_class_data(*pce TSRMLS_CC); - } else { - cleanup_internal_class_data(*pce TSRMLS_CC); - } - return 0; -} - void _destroy_zend_class_traits_info(zend_class_entry *ce) { if (ce->num_traits > 0 && ce->traits) { @@ -228,16 +194,16 @@ void _destroy_zend_class_traits_info(zend_class_entry *ce) while (ce->trait_aliases[i]) { if (ce->trait_aliases[i]->trait_method) { if (ce->trait_aliases[i]->trait_method->method_name) { - efree((char*)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) { - efree((char*)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]->alias) { - efree((char*)ce->trait_aliases[i]->alias); + zend_string_release(ce->trait_aliases[i]->alias); } efree(ce->trait_aliases[i]); @@ -251,8 +217,8 @@ void _destroy_zend_class_traits_info(zend_class_entry *ce) size_t i = 0; while (ce->trait_precedences[i]) { - efree((char*)ce->trait_precedences[i]->trait_method->method_name); - efree((char*)ce->trait_precedences[i]->trait_method->class_name); + 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) { @@ -266,9 +232,9 @@ void _destroy_zend_class_traits_info(zend_class_entry *ce) } } -ZEND_API void destroy_zend_class(zend_class_entry **pce) +ZEND_API void destroy_zend_class(zval *zv) { - zend_class_entry *ce = *pce; + zend_class_entry *ce = Z_PTR_P(zv); if (--ce->refcount > 0) { return; @@ -279,7 +245,7 @@ ZEND_API void destroy_zend_class(zend_class_entry **pce) int i; for (i = 0; i < ce->default_properties_count; i++) { - if (ce->default_properties_table[i]) { + if (Z_TYPE(ce->default_properties_table[i]) != IS_UNDEF) { zval_ptr_dtor(&ce->default_properties_table[i]); } } @@ -289,33 +255,32 @@ ZEND_API void destroy_zend_class(zend_class_entry **pce) int i; for (i = 0; i < ce->default_static_members_count; i++) { - if (ce->default_static_members_table[i]) { + if (Z_TYPE(ce->default_static_members_table[i]) != IS_UNDEF) { zval_ptr_dtor(&ce->default_static_members_table[i]); } } efree(ce->default_static_members_table); } zend_hash_destroy(&ce->properties_info); - str_efree(ce->name); + zend_string_release(ce->name); zend_hash_destroy(&ce->function_table); zend_hash_destroy(&ce->constants_table); if (ce->num_interfaces > 0 && ce->interfaces) { efree(ce->interfaces); } if (ce->info.user.doc_comment) { - efree((char*)ce->info.user.doc_comment); + zend_string_release(ce->info.user.doc_comment); } _destroy_zend_class_traits_info(ce); - efree(ce); break; case ZEND_INTERNAL_CLASS: if (ce->default_properties_table) { int i; for (i = 0; i < ce->default_properties_count; i++) { - if (ce->default_properties_table[i]) { + if (Z_TYPE(ce->default_properties_table[i]) != IS_UNDEF) { zval_internal_ptr_dtor(&ce->default_properties_table[i]); } } @@ -330,7 +295,7 @@ ZEND_API void destroy_zend_class(zend_class_entry **pce) free(ce->default_static_members_table); } zend_hash_destroy(&ce->properties_info); - str_free(ce->name); + zend_string_release(ce->name); zend_hash_destroy(&ce->function_table); zend_hash_destroy(&ce->constants_table); if (ce->num_interfaces > 0) { @@ -341,23 +306,25 @@ ZEND_API void destroy_zend_class(zend_class_entry **pce) } } -void zend_class_add_ref(zend_class_entry **ce) +void zend_class_add_ref(zval *zv) { - (*ce)->refcount++; + zend_class_entry *ce = Z_PTR_P(zv); + + ce->refcount++; } ZEND_API void destroy_op_array(zend_op_array *op_array TSRMLS_DC) { - zend_literal *literal = op_array->literals; - zend_literal *end; - zend_uint i; + zval *literal = op_array->literals; + zval *end; + uint32_t i; if (op_array->static_variables) { zend_hash_destroy(op_array->static_variables); FREE_HASHTABLE(op_array->static_variables); } - if (op_array->run_time_cache) { + if (op_array->run_time_cache && !op_array->function_name) { efree(op_array->run_time_cache); } @@ -365,13 +332,13 @@ ZEND_API void destroy_op_array(zend_op_array *op_array TSRMLS_DC) return; } - efree(op_array->refcount); + efree_size(op_array->refcount, sizeof(*(op_array->refcount))); if (op_array->vars) { i = op_array->last_var; while (i > 0) { i--; - str_efree(op_array->vars[i].name); + zend_string_release(op_array->vars[i]); } efree(op_array->vars); } @@ -379,7 +346,7 @@ ZEND_API void destroy_op_array(zend_op_array *op_array TSRMLS_DC) if (literal) { end = literal + op_array->last_literal; while (literal < end) { - zval_dtor(&literal->constant); + zval_ptr_dtor_nogc(literal); literal++; } efree(op_array->literals); @@ -387,10 +354,10 @@ ZEND_API void destroy_op_array(zend_op_array *op_array TSRMLS_DC) efree(op_array->opcodes); if (op_array->function_name) { - efree((char*)op_array->function_name); + zend_string_release(op_array->function_name); } if (op_array->doc_comment) { - efree((char*)op_array->doc_comment); + zend_string_release(op_array->doc_comment); } if (op_array->brk_cont_array) { efree(op_array->brk_cont_array); @@ -403,9 +370,9 @@ ZEND_API void destroy_op_array(zend_op_array *op_array TSRMLS_DC) } if (op_array->arg_info) { for (i=0; i<op_array->num_args; i++) { - str_efree(op_array->arg_info[i].name); + efree((char*)op_array->arg_info[i].name); if (op_array->arg_info[i].class_name) { - str_efree(op_array->arg_info[i].class_name); + efree((char*)op_array->arg_info[i].class_name); } } efree(op_array->arg_info); @@ -421,16 +388,10 @@ void init_op(zend_op *op TSRMLS_DC) zend_op *get_next_op(zend_op_array *op_array TSRMLS_DC) { - zend_uint next_op_num = op_array->last++; + uint32_t next_op_num = op_array->last++; zend_op *next_op; if (next_op_num >= CG(context).opcodes_size) { - if (op_array->fn_flags & ZEND_ACC_INTERACTIVE) { - /* we messed up */ - zend_printf("Ran out of opcode space!\n" - "You should probably consider writing this huge script into a file!\n"); - zend_bailout(); - } CG(context).opcodes_size *= 4; op_array_alloc_ops(op_array, CG(context).opcodes_size); } @@ -484,33 +445,81 @@ static void zend_extension_op_array_handler(zend_extension *extension, zend_op_a } } -static void zend_check_finally_breakout(zend_op_array *op_array, zend_uint op_num, zend_uint dst_num TSRMLS_DC) +static void zend_check_finally_breakout(zend_op_array *op_array, uint32_t op_num, uint32_t dst_num TSRMLS_DC) { - zend_uint i; + int i; for (i = 0; i < op_array->last_try_catch; i++) { - if (op_array->try_catch_array[i].try_op > op_num) { - break; - } - if ((op_num >= op_array->try_catch_array[i].finally_op + if ((op_num < op_array->try_catch_array[i].finally_op || + op_num >= op_array->try_catch_array[i].finally_end) + && (dst_num >= op_array->try_catch_array[i].finally_op && + dst_num <= op_array->try_catch_array[i].finally_end)) { + CG(in_compilation) = 1; + CG(active_op_array) = op_array; + CG(zend_lineno) = op_array->opcodes[op_num].lineno; + zend_error_noreturn(E_COMPILE_ERROR, "jump into a finally block is disallowed"); + } else if ((op_num >= op_array->try_catch_array[i].finally_op && op_num <= op_array->try_catch_array[i].finally_end) && (dst_num > op_array->try_catch_array[i].finally_end || dst_num < op_array->try_catch_array[i].finally_op)) { CG(in_compilation) = 1; CG(active_op_array) = op_array; CG(zend_lineno) = op_array->opcodes[op_num].lineno; - zend_error(E_COMPILE_ERROR, "jump out of a finally block is disallowed"); + zend_error_noreturn(E_COMPILE_ERROR, "jump out of a finally block is disallowed"); + } + } +} + +static void zend_adjust_fast_call(zend_op_array *op_array, uint32_t fast_call, uint32_t start, uint32_t end TSRMLS_DC) +{ + int i; + uint32_t op_num = 0; + + for (i = 0; i < op_array->last_try_catch; i++) { + if (op_array->try_catch_array[i].finally_op > start + && op_array->try_catch_array[i].finally_end < end) { + op_num = op_array->try_catch_array[i].finally_op; + start = op_array->try_catch_array[i].finally_end; + } + } + + if (op_num) { + /* Must be ZEND_FAST_CALL */ + ZEND_ASSERT(op_array->opcodes[op_num - 2].opcode == ZEND_FAST_CALL); + op_array->opcodes[op_num - 2].extended_value = ZEND_FAST_CALL_FROM_FINALLY; + op_array->opcodes[op_num - 2].op2.opline_num = fast_call; + } +} + +static void zend_resolve_fast_call(zend_op_array *op_array, uint32_t fast_call, uint32_t op_num TSRMLS_DC) +{ + int i; + uint32_t finally_op_num = 0; + + for (i = 0; i < op_array->last_try_catch; i++) { + if (op_num >= op_array->try_catch_array[i].finally_op + && op_num < op_array->try_catch_array[i].finally_end) { + finally_op_num = op_array->try_catch_array[i].finally_op; + } + } + + if (finally_op_num) { + /* Must be ZEND_FAST_CALL */ + ZEND_ASSERT(op_array->opcodes[finally_op_num - 2].opcode == ZEND_FAST_CALL); + if (op_array->opcodes[fast_call].extended_value == 0) { + op_array->opcodes[fast_call].extended_value = ZEND_FAST_CALL_FROM_FINALLY; + op_array->opcodes[fast_call].op2.opline_num = finally_op_num - 2; } } } -static void zend_resolve_finally_call(zend_op_array *op_array, zend_uint op_num, zend_uint dst_num TSRMLS_DC) +static void zend_resolve_finally_call(zend_op_array *op_array, uint32_t op_num, uint32_t dst_num TSRMLS_DC) { - zend_uint start_op; + uint32_t start_op; zend_op *opline; - zend_uint i = op_array->last_try_catch; + uint32_t i = op_array->last_try_catch; - if (dst_num != (zend_uint)-1) { + if (dst_num != (uint32_t)-1) { zend_check_finally_breakout(op_array, op_num, dst_num TSRMLS_CC); } @@ -531,21 +540,33 @@ static void zend_resolve_finally_call(zend_op_array *op_array, zend_uint op_num, opline->opcode = ZEND_FAST_CALL; SET_UNUSED(opline->op1); SET_UNUSED(opline->op2); - opline->op1.opline_num = op_array->try_catch_array[i].finally_op; + zend_adjust_fast_call(op_array, start_op, + op_array->try_catch_array[i].finally_op, + op_array->try_catch_array[i].finally_end TSRMLS_CC); if (op_array->try_catch_array[i].catch_op) { - opline->extended_value = 1; + opline->extended_value = ZEND_FAST_CALL_FROM_CATCH; opline->op2.opline_num = op_array->try_catch_array[i].catch_op; + opline->op1.opline_num = get_next_op_number(op_array); + /* generate a FAST_CALL to hole CALL_FROM_FINALLY */ + opline = get_next_op(op_array TSRMLS_CC); + opline->opcode = ZEND_FAST_CALL; + SET_UNUSED(opline->op1); + SET_UNUSED(opline->op2); + zend_resolve_fast_call(op_array, start_op + 1, op_array->try_catch_array[i].finally_op - 2 TSRMLS_CC); + } else { + zend_resolve_fast_call(op_array, start_op, op_array->try_catch_array[i].finally_op - 2 TSRMLS_CC); } + opline->op1.opline_num = op_array->try_catch_array[i].finally_op; /* generate a sequence of FAST_CALL to upward finally block */ while (i > 0) { i--; if (op_array->try_catch_array[i].finally_op && - op_num >= op_array->try_catch_array[i].try_op && - op_num < op_array->try_catch_array[i].finally_op - 1 && - (dst_num < op_array->try_catch_array[i].try_op || - dst_num > op_array->try_catch_array[i].finally_end)) { - + op_num >= op_array->try_catch_array[i].try_op && + op_num < op_array->try_catch_array[i].finally_op - 1 && + (dst_num < op_array->try_catch_array[i].try_op || + dst_num > op_array->try_catch_array[i].finally_end)) { + opline = get_next_op(op_array TSRMLS_CC); opline->opcode = ZEND_FAST_CALL; SET_UNUSED(opline->op1); @@ -565,15 +586,15 @@ static void zend_resolve_finally_call(zend_op_array *op_array, zend_uint op_num, SET_UNUSED(opline->op2); opline->op1.opline_num = start_op; - break; + break; } } } -static void zend_resolve_finally_ret(zend_op_array *op_array, zend_uint op_num TSRMLS_DC) +static void zend_resolve_finally_ret(zend_op_array *op_array, uint32_t op_num TSRMLS_DC) { int i; - zend_uint catch_op_num = 0, finally_op_num = 0; + uint32_t catch_op_num = 0, finally_op_num = 0; for (i = 0; i < op_array->last_try_catch; i++) { if (op_array->try_catch_array[i].try_op > op_num) { @@ -600,16 +621,16 @@ static void zend_resolve_finally_ret(zend_op_array *op_array, zend_uint op_num T static void zend_resolve_finally_calls(zend_op_array *op_array TSRMLS_DC) { - zend_uint i; + uint32_t i, j; zend_op *opline; - for (i = 0; i < op_array->last; i++) { + for (i = 0, j = op_array->last; i < j; i++) { opline = op_array->opcodes + i; switch (opline->opcode) { case ZEND_RETURN: case ZEND_RETURN_BY_REF: case ZEND_GENERATOR_RETURN: - zend_resolve_finally_call(op_array, i, (zend_uint)-1 TSRMLS_CC); + zend_resolve_finally_call(op_array, i, (uint32_t)-1 TSRMLS_CC); break; case ZEND_BRK: case ZEND_CONT: @@ -617,21 +638,22 @@ static void zend_resolve_finally_calls(zend_op_array *op_array TSRMLS_DC) int nest_levels, array_offset; zend_brk_cont_element *jmp_to; - nest_levels = Z_LVAL(op_array->literals[opline->op2.constant].constant); - array_offset = opline->op1.opline_num; - do { - jmp_to = &op_array->brk_cont_array[array_offset]; - if (nest_levels > 1) { - array_offset = jmp_to->parent; - } - } while (--nest_levels > 0); - zend_resolve_finally_call(op_array, i, opline->opcode == ZEND_BRK ? jmp_to->brk : jmp_to->cont TSRMLS_CC); - break; + nest_levels = Z_LVAL(op_array->literals[opline->op2.constant]); + if ((array_offset = opline->op1.opline_num) != -1) { + do { + jmp_to = &op_array->brk_cont_array[array_offset]; + if (nest_levels > 1) { + array_offset = jmp_to->parent; + } + } while (--nest_levels > 0); + zend_resolve_finally_call(op_array, i, opline->opcode == ZEND_BRK ? jmp_to->brk : jmp_to->cont TSRMLS_CC); + break; + } } case ZEND_GOTO: - if (Z_TYPE(op_array->literals[opline->op2.constant].constant) != IS_LONG) { - zend_uint num = opline->op2.constant; - opline->op2.zv = &op_array->literals[opline->op2.constant].constant; + if (Z_TYPE(op_array->literals[opline->op2.constant]) != IS_LONG) { + uint32_t num = opline->op2.constant; + opline->op2.zv = &op_array->literals[opline->op2.constant]; zend_resolve_goto_label(op_array, opline, 1 TSRMLS_CC); opline->op2.constant = num; } @@ -639,6 +661,9 @@ static void zend_resolve_finally_calls(zend_op_array *op_array TSRMLS_DC) case ZEND_JMP: zend_resolve_finally_call(op_array, i, opline->op1.opline_num TSRMLS_CC); break; + case ZEND_FAST_CALL: + zend_resolve_fast_call(op_array, i, i TSRMLS_CC); + break; case ZEND_FAST_RET: zend_resolve_finally_ret(op_array, i TSRMLS_CC); break; @@ -652,10 +677,10 @@ ZEND_API int pass_two(zend_op_array *op_array TSRMLS_DC) { zend_op *opline, *end; - if (op_array->type!=ZEND_USER_FUNCTION && op_array->type!=ZEND_EVAL_CODE) { + if (!ZEND_USER_CODE(op_array->type)) { return 0; } - if (op_array->has_finally_block) { + if (op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) { zend_resolve_finally_calls(op_array TSRMLS_CC); } if (CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO) { @@ -665,29 +690,39 @@ ZEND_API int pass_two(zend_op_array *op_array TSRMLS_DC) zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_handler, op_array TSRMLS_CC); } - if (!(op_array->fn_flags & ZEND_ACC_INTERACTIVE) && CG(context).vars_size != op_array->last_var) { - op_array->vars = (zend_compiled_variable *) erealloc(op_array->vars, sizeof(zend_compiled_variable)*op_array->last_var); + if (CG(context).vars_size != op_array->last_var) { + 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 (!(op_array->fn_flags & ZEND_ACC_INTERACTIVE) && CG(context).opcodes_size != op_array->last) { + 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; } - if (!(op_array->fn_flags & ZEND_ACC_INTERACTIVE) && CG(context).literals_size != op_array->last_literal) { - op_array->literals = (zend_literal*)erealloc(op_array->literals, sizeof(zend_literal) * op_array->last_literal); + if (CG(context).literals_size != op_array->last_literal) { + op_array->literals = (zval*)erealloc(op_array->literals, sizeof(zval) * op_array->last_literal); CG(context).literals_size = op_array->last_literal; } - opline = op_array->opcodes; end = opline + op_array->last; while (opline < end) { if (opline->op1_type == IS_CONST) { - opline->op1.zv = &op_array->literals[opline->op1.constant].constant; + opline->op1.zv = &op_array->literals[opline->op1.constant]; + } else if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) { + opline->op1.var = (uint32_t)(zend_intptr_t)EX_VAR_NUM_2(NULL, op_array->last_var + opline->op1.var); } if (opline->op2_type == IS_CONST) { - opline->op2.zv = &op_array->literals[opline->op2.constant].constant; + opline->op2.zv = &op_array->literals[opline->op2.constant]; + } else if (opline->op2_type & (IS_VAR|IS_TMP_VAR)) { + opline->op2.var = (uint32_t)(zend_intptr_t)EX_VAR_NUM_2(NULL, op_array->last_var + opline->op2.var); + } + if (opline->result_type & (IS_VAR|IS_TMP_VAR)) { + opline->result.var = (uint32_t)(zend_intptr_t)EX_VAR_NUM_2(NULL, op_array->last_var + opline->result.var); } switch (opline->opcode) { + case ZEND_DECLARE_INHERITED_CLASS: + case ZEND_DECLARE_INHERITED_CLASS_DELAYED: + opline->extended_value = (uint32_t)(zend_intptr_t)EX_VAR_NUM_2(NULL, op_array->last_var + opline->extended_value); + break; case ZEND_GOTO: if (Z_TYPE_P(opline->op2.zv) != IS_LONG) { zend_resolve_goto_label(op_array, opline, 1 TSRMLS_CC); @@ -697,12 +732,19 @@ ZEND_API int pass_two(zend_op_array *op_array TSRMLS_DC) case ZEND_FAST_CALL: opline->op1.jmp_addr = &op_array->opcodes[opline->op1.opline_num]; break; + case ZEND_JMPZNZ: + /* absolute index to relative offset */ + opline->extended_value = (char*)(op_array->opcodes + opline->extended_value) - (char*)opline; + /* break omitted intentionally */ case ZEND_JMPZ: case ZEND_JMPNZ: case ZEND_JMPZ_EX: case ZEND_JMPNZ_EX: case ZEND_JMP_SET: - case ZEND_JMP_SET_VAR: + case ZEND_COALESCE: + case ZEND_NEW: + case ZEND_FE_RESET: + case ZEND_FE_FETCH: opline->op2.jmp_addr = &op_array->opcodes[opline->op2.opline_num]; break; case ZEND_RETURN: @@ -710,7 +752,7 @@ ZEND_API int pass_two(zend_op_array *op_array TSRMLS_DC) if (op_array->fn_flags & ZEND_ACC_GENERATOR) { if (opline->op1_type != IS_CONST || Z_TYPE_P(opline->op1.zv) != IS_NULL) { CG(zend_lineno) = opline->lineno; - zend_error(E_COMPILE_ERROR, "Generators cannot return values using \"return\""); + zend_error_noreturn(E_COMPILE_ERROR, "Generators cannot return values using \"return\""); } opline->opcode = ZEND_GENERATOR_RETURN; @@ -725,11 +767,16 @@ ZEND_API int pass_two(zend_op_array *op_array TSRMLS_DC) return 0; } +int pass_two_wrapper(zval *el TSRMLS_DC) +{ + return pass_two((zend_op_array *) Z_PTR_P(el) TSRMLS_CC); +} + int print_class(zend_class_entry *class_entry TSRMLS_DC) { - printf("Class %s:\n", class_entry->name); - zend_hash_apply(&class_entry->function_table, (apply_func_t) pass_two TSRMLS_CC); - printf("End of class %s.\n\n", class_entry->name); + printf("Class %s:\n", class_entry->name->val); + zend_hash_apply(&class_entry->function_table, pass_two_wrapper TSRMLS_CC); + printf("End of class %s.\n\n", class_entry->name->val); return 0; } @@ -738,13 +785,10 @@ ZEND_API unary_op_type get_unary_op(int opcode) switch (opcode) { case ZEND_BW_NOT: return (unary_op_type) bitwise_not_function; - break; case ZEND_BOOL_NOT: return (unary_op_type) boolean_not_function; - break; default: return (unary_op_type) NULL; - break; } } @@ -754,71 +798,54 @@ ZEND_API binary_op_type get_binary_op(int opcode) case ZEND_ADD: case ZEND_ASSIGN_ADD: return (binary_op_type) add_function; - break; case ZEND_SUB: case ZEND_ASSIGN_SUB: return (binary_op_type) sub_function; - break; case ZEND_MUL: case ZEND_ASSIGN_MUL: return (binary_op_type) mul_function; - break; + case ZEND_POW: + return (binary_op_type) pow_function; case ZEND_DIV: case ZEND_ASSIGN_DIV: return (binary_op_type) div_function; - break; case ZEND_MOD: case ZEND_ASSIGN_MOD: return (binary_op_type) mod_function; - break; case ZEND_SL: case ZEND_ASSIGN_SL: return (binary_op_type) shift_left_function; - break; case ZEND_SR: case ZEND_ASSIGN_SR: return (binary_op_type) shift_right_function; - break; case ZEND_CONCAT: case ZEND_ASSIGN_CONCAT: return (binary_op_type) concat_function; - break; case ZEND_IS_IDENTICAL: return (binary_op_type) is_identical_function; - break; case ZEND_IS_NOT_IDENTICAL: return (binary_op_type) is_not_identical_function; - break; case ZEND_IS_EQUAL: return (binary_op_type) is_equal_function; - break; case ZEND_IS_NOT_EQUAL: return (binary_op_type) is_not_equal_function; - break; case ZEND_IS_SMALLER: return (binary_op_type) is_smaller_function; - break; case ZEND_IS_SMALLER_OR_EQUAL: return (binary_op_type) is_smaller_or_equal_function; - break; case ZEND_BW_OR: case ZEND_ASSIGN_BW_OR: return (binary_op_type) bitwise_or_function; - break; case ZEND_BW_AND: case ZEND_ASSIGN_BW_AND: return (binary_op_type) bitwise_and_function; - break; case ZEND_BW_XOR: case ZEND_ASSIGN_BW_XOR: return (binary_op_type) bitwise_xor_function; - break; case ZEND_BOOL_XOR: return (binary_op_type) boolean_xor_function; - break; default: return (binary_op_type) NULL; - break; } } |