PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - Zend - zend_opcode.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 442 502 88.0 %
Date: 2015-06-27 Functions: 26 31 83.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | Zend Engine                                                          |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1998-2015 Zend Technologies Ltd. (http://www.zend.com) |
       6             :    +----------------------------------------------------------------------+
       7             :    | This source file is subject to version 2.00 of the Zend license,     |
       8             :    | that is bundled with this package in the file LICENSE, and is        |
       9             :    | available through the world-wide-web at the following url:           |
      10             :    | http://www.zend.com/license/2_00.txt.                                |
      11             :    | If you did not receive a copy of the Zend license and are unable to  |
      12             :    | obtain it through the world-wide-web, please send a note to          |
      13             :    | license@zend.com so we can mail you a copy immediately.              |
      14             :    +----------------------------------------------------------------------+
      15             :    | Authors: Andi Gutmans <andi@zend.com>                                |
      16             :    |          Zeev Suraski <zeev@zend.com>                                |
      17             :    +----------------------------------------------------------------------+
      18             : */
      19             : 
      20             : /* $Id$ */
      21             : 
      22             : #include <stdio.h>
      23             : 
      24             : #include "zend.h"
      25             : #include "zend_alloc.h"
      26             : #include "zend_compile.h"
      27             : #include "zend_extensions.h"
      28             : #include "zend_API.h"
      29             : 
      30             : #include "zend_vm.h"
      31             : 
      32       65466 : static void zend_extension_op_array_ctor_handler(zend_extension *extension, zend_op_array *op_array)
      33             : {
      34       65466 :         if (extension->op_array_ctor) {
      35           0 :                 extension->op_array_ctor(op_array);
      36             :         }
      37       65466 : }
      38             : 
      39       63286 : static void zend_extension_op_array_dtor_handler(zend_extension *extension, zend_op_array *op_array)
      40             : {
      41       63286 :         if (extension->op_array_dtor) {
      42           0 :                 extension->op_array_dtor(op_array);
      43             :         }
      44       63286 : }
      45             : 
      46       73733 : static void op_array_alloc_ops(zend_op_array *op_array, uint32_t size)
      47             : {
      48       73733 :         op_array->opcodes = erealloc(op_array->opcodes, size * sizeof(zend_op));
      49       73733 : }
      50             : 
      51       65951 : void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_size)
      52             : {
      53       65951 :         op_array->type = type;
      54       65951 :         op_array->arg_flags[0] = 0;
      55       65951 :         op_array->arg_flags[1] = 0;
      56       65951 :         op_array->arg_flags[2] = 0;
      57             : 
      58       65951 :         op_array->refcount = (uint32_t *) emalloc(sizeof(uint32_t));
      59       65951 :         *op_array->refcount = 1;
      60       65951 :         op_array->last = 0;
      61       65951 :         op_array->opcodes = NULL;
      62       65951 :         op_array_alloc_ops(op_array, initial_ops_size);
      63             : 
      64       65951 :         op_array->last_var = 0;
      65       65951 :         op_array->vars = NULL;
      66             : 
      67       65951 :         op_array->T = 0;
      68             : 
      69       65951 :         op_array->function_name = NULL;
      70       65951 :         op_array->filename = zend_get_compiled_filename();
      71       65951 :         op_array->doc_comment = NULL;
      72             : 
      73       65951 :         op_array->arg_info = NULL;
      74       65951 :         op_array->num_args = 0;
      75       65951 :         op_array->required_num_args = 0;
      76             : 
      77       65951 :         op_array->scope = NULL;
      78       65951 :         op_array->prototype = NULL;
      79             : 
      80       65951 :         op_array->brk_cont_array = NULL;
      81       65951 :         op_array->try_catch_array = NULL;
      82       65951 :         op_array->last_brk_cont = 0;
      83             : 
      84       65951 :         op_array->static_variables = NULL;
      85       65951 :         op_array->last_try_catch = 0;
      86             : 
      87       65951 :         op_array->this_var = -1;
      88             : 
      89       65951 :         op_array->fn_flags = 0;
      90             : 
      91       65951 :         op_array->early_binding = -1;
      92             : 
      93       65951 :         op_array->last_literal = 0;
      94       65951 :         op_array->literals = NULL;
      95             : 
      96       65951 :         op_array->run_time_cache = NULL;
      97       65951 :         op_array->cache_size = 0;
      98             : 
      99       65951 :         memset(op_array->reserved, 0, ZEND_MAX_RESERVED_RESOURCES * sizeof(void*));
     100             : 
     101       65951 :         zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_ctor_handler, op_array);
     102       65951 : }
     103             : 
     104           4 : ZEND_API void destroy_zend_function(zend_function *function)
     105             : {
     106           4 :         if (function->type == ZEND_USER_FUNCTION) {
     107           4 :                 destroy_op_array(&function->op_array);
     108             :         } else {
     109             :                 ZEND_ASSERT(function->type == ZEND_INTERNAL_FUNCTION);
     110             :                 ZEND_ASSERT(function->common.function_name);
     111           0 :                 zend_string_release(function->common.function_name);
     112             :         }
     113           4 : }
     114             : 
     115   104240682 : ZEND_API void zend_function_dtor(zval *zv)
     116             : {
     117   104240682 :         zend_function *function = Z_PTR_P(zv);
     118             : 
     119   104240682 :         if (function->type == ZEND_USER_FUNCTION) {
     120             :                 ZEND_ASSERT(function->common.function_name);
     121       54533 :                 destroy_op_array(&function->op_array);
     122             :                 /* op_arrays are allocated on arena, so we don't have to free them */
     123             :         } else {
     124             :                 ZEND_ASSERT(function->type == ZEND_INTERNAL_FUNCTION);
     125             :                 ZEND_ASSERT(function->common.function_name);
     126   104186149 :                 zend_string_release(function->common.function_name);
     127   104186149 :                 if (!(function->common.fn_flags & ZEND_ACC_ARENA_ALLOCATED)) {
     128   104138734 :                         pefree(function, 1);
     129             :                 }
     130             :         }
     131   104240682 : }
     132             : 
     133       31500 : ZEND_API void zend_cleanup_op_array_data(zend_op_array *op_array)
     134             : {
     135       33541 :         if (op_array->static_variables &&
     136        2041 :             !(GC_FLAGS(op_array->static_variables) & IS_ARRAY_IMMUTABLE)) {
     137        2040 :                 zend_hash_clean(op_array->static_variables);
     138             :         }
     139       31500 : }
     140             : 
     141        9240 : ZEND_API void zend_cleanup_user_class_data(zend_class_entry *ce)
     142             : {
     143             :         /* Clean all parts that can contain run-time data */
     144             :         /* Note that only run-time accessed data need to be cleaned up, pre-defined data can
     145             :            not contain objects and thus are not probelmatic */
     146        9240 :         if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) {
     147             :                 zend_function *func;
     148             : 
     149       21628 :                 ZEND_HASH_FOREACH_PTR(&ce->function_table, func) {
     150       10127 :                         if (func->type == ZEND_USER_FUNCTION) {
     151       10102 :                                 zend_cleanup_op_array_data((zend_op_array *) func);
     152             :                         }
     153             :                 } ZEND_HASH_FOREACH_END();
     154             :         }
     155        9240 :         if (ce->static_members_table) {
     156         344 :                 zval *static_members = ce->static_members_table;
     157         344 :                 zval *p = static_members;
     158         344 :                 zval *end = p + ce->default_static_members_count;
     159             : 
     160             : 
     161         344 :                 ce->default_static_members_count = 0;
     162         344 :                 ce->default_static_members_table = ce->static_members_table = NULL;
     163        1310 :                 while (p != end) {
     164             :                         i_zval_ptr_dtor(p ZEND_FILE_LINE_CC);
     165         622 :                         p++;
     166             :                 }
     167         342 :                 efree(static_members);
     168             :         }
     169        9238 : }
     170             : 
     171           0 : ZEND_API void zend_cleanup_internal_class_data(zend_class_entry *ce)
     172             : {
     173           0 :         if (CE_STATIC_MEMBERS(ce)) {
     174           0 :                 zval *static_members = CE_STATIC_MEMBERS(ce);
     175           0 :                 zval *p = static_members;
     176           0 :                 zval *end = p + ce->default_static_members_count;
     177             : 
     178             : #ifdef ZTS
     179             :                 CG(static_members_table)[(zend_intptr_t)(ce->static_members_table)] = NULL;
     180             : #else
     181           0 :                 ce->static_members_table = NULL;
     182             : #endif
     183           0 :                 ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
     184           0 :                 while (p != end) {
     185             :                         i_zval_ptr_dtor(p ZEND_FILE_LINE_CC);
     186           0 :                         p++;
     187             :                 }
     188           0 :                 efree(static_members);
     189             :         }
     190           0 : }
     191             : 
     192        7494 : void _destroy_zend_class_traits_info(zend_class_entry *ce)
     193             : {
     194        7494 :         if (ce->num_traits > 0 && ce->traits) {
     195         181 :                 efree(ce->traits);
     196             :         }
     197             : 
     198        7494 :         if (ce->trait_aliases) {
     199          47 :                 size_t i = 0;
     200         165 :                 while (ce->trait_aliases[i]) {
     201          71 :                         if (ce->trait_aliases[i]->trait_method) {
     202          71 :                                 if (ce->trait_aliases[i]->trait_method->method_name) {
     203          71 :                                         zend_string_release(ce->trait_aliases[i]->trait_method->method_name);
     204             :                                 }
     205          71 :                                 if (ce->trait_aliases[i]->trait_method->class_name) {
     206          31 :                                         zend_string_release(ce->trait_aliases[i]->trait_method->class_name);
     207             :                                 }
     208          71 :                                 efree(ce->trait_aliases[i]->trait_method);
     209             :                         }
     210             : 
     211          71 :                         if (ce->trait_aliases[i]->alias) {
     212          61 :                                 zend_string_release(ce->trait_aliases[i]->alias);
     213             :                         }
     214             : 
     215          71 :                         efree(ce->trait_aliases[i]);
     216          71 :                         i++;
     217             :                 }
     218             : 
     219          47 :                 efree(ce->trait_aliases);
     220             :         }
     221             : 
     222        7494 :         if (ce->trait_precedences) {
     223          11 :                 size_t i = 0;
     224             : 
     225          37 :                 while (ce->trait_precedences[i]) {
     226          15 :                         zend_string_release(ce->trait_precedences[i]->trait_method->method_name);
     227          15 :                         zend_string_release(ce->trait_precedences[i]->trait_method->class_name);
     228          15 :                         efree(ce->trait_precedences[i]->trait_method);
     229             : 
     230          15 :                         if (ce->trait_precedences[i]->exclude_from_classes) {
     231           4 :                                 size_t j = 0;
     232           4 :                                 zend_trait_precedence *cur_precedence = ce->trait_precedences[i];
     233          12 :                                 while (cur_precedence->exclude_from_classes[j].class_name) {
     234           4 :                                         zend_string_release(cur_precedence->exclude_from_classes[j].class_name);
     235           4 :                                         j++;
     236             :                                 }
     237           4 :                                 efree(ce->trait_precedences[i]->exclude_from_classes);
     238             :                         }
     239          15 :                         efree(ce->trait_precedences[i]);
     240          15 :                         i++;
     241             :                 }
     242          11 :                 efree(ce->trait_precedences);
     243             :         }
     244        7494 : }
     245             : 
     246     3978849 : ZEND_API void destroy_zend_class(zval *zv)
     247             : {
     248             :         zend_property_info *prop_info;
     249     3978849 :         zend_class_entry *ce = Z_PTR_P(zv);
     250             : 
     251     3978849 :         if (--ce->refcount > 0) {
     252        7375 :                 return;
     253             :         }
     254     3971474 :         switch (ce->type) {
     255             :                 case ZEND_USER_CLASS:
     256        7494 :                         if (ce->default_properties_table) {
     257        2258 :                                 zval *p = ce->default_properties_table;
     258        2258 :                                 zval *end = p + ce->default_properties_count;
     259             : 
     260       24887 :                                 while (p != end) {
     261             :                                         i_zval_ptr_dtor(p ZEND_FILE_LINE_CC);
     262       20371 :                                         p++;
     263             :                                 }
     264        2258 :                                 efree(ce->default_properties_table);
     265             :                         }
     266        7494 :                         if (ce->default_static_members_table) {
     267           0 :                                 zval *p = ce->default_static_members_table;
     268           0 :                                 zval *end = p + ce->default_static_members_count;
     269             : 
     270           0 :                                 while (p != end) {
     271             :                                         i_zval_ptr_dtor(p ZEND_FILE_LINE_CC);
     272           0 :                                         p++;
     273             :                                 }
     274           0 :                                 efree(ce->default_static_members_table);
     275             :                         }
     276       49104 :                         ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop_info) {
     277       20805 :                                 if (prop_info->ce == ce || (prop_info->flags & ZEND_ACC_SHADOW)) {
     278        2777 :                                         zend_string_release(prop_info->name);
     279        2777 :                                         if (prop_info->doc_comment) {
     280          53 :                                                 zend_string_release(prop_info->doc_comment);
     281             :                                         }
     282             :                                 }
     283             :                         } ZEND_HASH_FOREACH_END();
     284        7494 :                         zend_hash_destroy(&ce->properties_info);
     285        7494 :                         zend_string_release(ce->name);
     286        7494 :                         zend_hash_destroy(&ce->function_table);
     287        7494 :                         zend_hash_destroy(&ce->constants_table);
     288        7494 :                         if (ce->num_interfaces > 0 && ce->interfaces) {
     289         661 :                                 efree(ce->interfaces);
     290             :                         }
     291        7494 :                         if (ce->info.user.doc_comment) {
     292          71 :                                 zend_string_release(ce->info.user.doc_comment);
     293             :                         }
     294             : 
     295        7494 :                         _destroy_zend_class_traits_info(ce);
     296             : 
     297        7494 :                         break;
     298             :                 case ZEND_INTERNAL_CLASS:
     299     3963980 :                         if (ce->default_properties_table) {
     300     1012080 :                                 zval *p = ce->default_properties_table;
     301     1012080 :                                 zval *end = p + ce->default_properties_count;
     302             : 
     303     7548430 :                                 while (p != end) {
     304     5524270 :                                         zval_internal_ptr_dtor(p);
     305     5524270 :                                         p++;
     306             :                                 }
     307     1012080 :                                 free(ce->default_properties_table);
     308             :                         }
     309     3963980 :                         if (ce->default_static_members_table) {
     310           0 :                                 zval *p = ce->default_static_members_table;
     311           0 :                                 zval *end = p + ce->default_static_members_count;
     312             : 
     313           0 :                                 while (p != end) {
     314           0 :                                         zval_internal_ptr_dtor(p);
     315           0 :                                         p++;
     316             :                                 }
     317           0 :                                 free(ce->default_static_members_table);
     318             :                         }
     319     3963980 :                         zend_hash_destroy(&ce->properties_info);
     320     3963980 :                         zend_string_release(ce->name);
     321     3963980 :                         zend_hash_destroy(&ce->function_table);
     322     3963980 :                         zend_hash_destroy(&ce->constants_table);
     323     3963980 :                         if (ce->num_interfaces > 0) {
     324     2045245 :                                 free(ce->interfaces);
     325             :                         }
     326     3963980 :                         free(ce);
     327             :                         break;
     328             :         }
     329             : }
     330             : 
     331           0 : void zend_class_add_ref(zval *zv)
     332             : {
     333           0 :         zend_class_entry *ce = Z_PTR_P(zv);
     334             : 
     335           0 :         ce->refcount++;
     336           0 : }
     337             : 
     338       82982 : ZEND_API void destroy_op_array(zend_op_array *op_array)
     339             : {
     340       82982 :         zval *literal = op_array->literals;
     341             :         zval *end;
     342             :         uint32_t i;
     343             : 
     344       85148 :         if (op_array->static_variables &&
     345        2166 :             !(GC_FLAGS(op_array->static_variables) & IS_ARRAY_IMMUTABLE)) {
     346        2165 :             if (--GC_REFCOUNT(op_array->static_variables) == 0) {
     347        2165 :                         zend_array_destroy(op_array->static_variables);
     348             :                 }
     349             :         }
     350             : 
     351       82982 :         if (op_array->run_time_cache && !op_array->function_name) {
     352       27978 :                 efree(op_array->run_time_cache);
     353             :         }
     354             : 
     355       82982 :         if (!op_array->refcount || --(*op_array->refcount)>0) {
     356       19173 :                 return;
     357             :         }
     358             : 
     359       63809 :         efree_size(op_array->refcount, sizeof(*(op_array->refcount)));
     360             : 
     361       63809 :         if (op_array->vars) {
     362       46858 :                 i = op_array->last_var;
     363      298048 :                 while (i > 0) {
     364      204332 :                         i--;
     365      204332 :                         zend_string_release(op_array->vars[i]);
     366             :                 }
     367       46858 :                 efree(op_array->vars);
     368             :         }
     369             : 
     370       63809 :         if (literal) {
     371       63773 :                 end = literal + op_array->last_literal;
     372     1182745 :                 while (literal < end) {
     373             :                         zval_ptr_dtor_nogc(literal);
     374     1055199 :                         literal++;
     375             :                 }
     376       63773 :                 efree(op_array->literals);
     377             :         }
     378       63809 :         efree(op_array->opcodes);
     379             : 
     380       63809 :         if (op_array->function_name) {
     381       36143 :                 zend_string_release(op_array->function_name);
     382             :         }
     383       63809 :         if (op_array->doc_comment) {
     384        2395 :                 zend_string_release(op_array->doc_comment);
     385             :         }
     386       63809 :         if (op_array->brk_cont_array) {
     387       12054 :                 efree(op_array->brk_cont_array);
     388             :         }
     389       63809 :         if (op_array->try_catch_array) {
     390        1731 :                 efree(op_array->try_catch_array);
     391             :         }
     392       63809 :         if (op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO) {
     393       63758 :                 zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_dtor_handler, op_array);
     394             :         }
     395       63809 :         if (op_array->arg_info) {
     396       26901 :                 int32_t num_args = op_array->num_args;
     397       26901 :                 zend_arg_info *arg_info = op_array->arg_info;
     398             :                 int32_t i;
     399             : 
     400       26901 :                 if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
     401          91 :                         arg_info--;
     402          91 :                         num_args++;
     403             :                 }
     404       26901 :                 if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
     405          38 :                         num_args++;
     406             :                 }
     407      110350 :                 for (i = 0 ; i < num_args; i++) {
     408       83449 :                         if (arg_info[i].name) {
     409       83358 :                                 zend_string_release(arg_info[i].name);
     410             :                         }
     411       83449 :                         if (arg_info[i].class_name) {
     412         225 :                                 zend_string_release(arg_info[i].class_name);
     413             :                         }
     414             :                 }
     415       26901 :                 efree(arg_info);
     416             :         }
     417             : }
     418             : 
     419     2377497 : void init_op(zend_op *op)
     420             : {
     421     2377497 :         memset(op, 0, sizeof(zend_op));
     422     2377497 :         op->lineno = CG(zend_lineno);
     423     2377497 :         SET_UNUSED(op->result);
     424     2377497 : }
     425             : 
     426     2226493 : zend_op *get_next_op(zend_op_array *op_array)
     427             : {
     428     2226493 :         uint32_t next_op_num = op_array->last++;
     429             :         zend_op *next_op;
     430             : 
     431     2226493 :         if (next_op_num >= CG(context).opcodes_size) {
     432        7782 :                 CG(context).opcodes_size *= 4;
     433        7782 :                 op_array_alloc_ops(op_array, CG(context).opcodes_size);
     434             :         }
     435             : 
     436     2226493 :         next_op = &(op_array->opcodes[next_op_num]);
     437             : 
     438     2226493 :         init_op(next_op);
     439             : 
     440     2226493 :         return next_op;
     441             : }
     442             : 
     443      796453 : int get_next_op_number(zend_op_array *op_array)
     444             : {
     445      796453 :         return op_array->last;
     446             : }
     447             : 
     448       20089 : zend_brk_cont_element *get_next_brk_cont_element(zend_op_array *op_array)
     449             : {
     450       20089 :         op_array->last_brk_cont++;
     451       20089 :         op_array->brk_cont_array = erealloc(op_array->brk_cont_array, sizeof(zend_brk_cont_element)*op_array->last_brk_cont);
     452       20089 :         return &op_array->brk_cont_array[op_array->last_brk_cont-1];
     453             : }
     454             : 
     455           0 : static void zend_update_extended_info(zend_op_array *op_array)
     456             : {
     457           0 :         zend_op *opline = op_array->opcodes, *end=opline+op_array->last;
     458             : 
     459           0 :         while (opline<end) {
     460           0 :                 if (opline->opcode == ZEND_EXT_STMT) {
     461           0 :                         if (opline+1<end) {
     462           0 :                                 if ((opline+1)->opcode == ZEND_EXT_STMT) {
     463           0 :                                         opline->opcode = ZEND_NOP;
     464           0 :                                         opline++;
     465           0 :                                         continue;
     466             :                                 }
     467           0 :                                 if (opline+1<end) {
     468           0 :                                         opline->lineno = (opline+1)->lineno;
     469             :                                 }
     470             :                         } else {
     471           0 :                                 opline->opcode = ZEND_NOP;
     472             :                         }
     473             :                 }
     474           0 :                 opline++;
     475             :         }
     476           0 : }
     477             : 
     478       65021 : static void zend_extension_op_array_handler(zend_extension *extension, zend_op_array *op_array)
     479             : {
     480       65021 :         if (extension->op_array_handler) {
     481           0 :                 extension->op_array_handler(op_array);
     482             :         }
     483       65021 : }
     484             : 
     485         130 : static void zend_check_finally_breakout(zend_op_array *op_array, uint32_t op_num, uint32_t dst_num)
     486             : {
     487             :         int i;
     488             : 
     489         497 :         for (i = 0; i < op_array->last_try_catch; i++) {
     490        1099 :                 if ((op_num < op_array->try_catch_array[i].finally_op ||
     491         156 :                                         op_num >= op_array->try_catch_array[i].finally_end)
     492         341 :                                 && (dst_num >= op_array->try_catch_array[i].finally_op &&
     493         228 :                                          dst_num <= op_array->try_catch_array[i].finally_end)) {
     494           3 :                         CG(in_compilation) = 1;
     495           3 :                         CG(active_op_array) = op_array;
     496           3 :                         CG(zend_lineno) = op_array->opcodes[op_num].lineno;
     497           3 :                         zend_error_noreturn(E_COMPILE_ERROR, "jump into a finally block is disallowed");
     498         960 :                 } else if ((op_num >= op_array->try_catch_array[i].finally_op
     499         526 :                                         && op_num <= op_array->try_catch_array[i].finally_end)
     500          33 :                                 && (dst_num > op_array->try_catch_array[i].finally_end
     501          63 :                                         || dst_num < op_array->try_catch_array[i].finally_op)) {
     502           4 :                         CG(in_compilation) = 1;
     503           4 :                         CG(active_op_array) = op_array;
     504           4 :                         CG(zend_lineno) = op_array->opcodes[op_num].lineno;
     505           4 :                         zend_error_noreturn(E_COMPILE_ERROR, "jump out of a finally block is disallowed");
     506             :                 }
     507             :         }
     508         123 : }
     509             : 
     510          21 : static void zend_adjust_fast_call(zend_op_array *op_array, uint32_t fast_call, uint32_t start, uint32_t end)
     511             : {
     512             :         int i;
     513          21 :         uint32_t op_num = 0;
     514             : 
     515          78 :         for (i = 0; i < op_array->last_try_catch; i++) {
     516         125 :                 if (op_array->try_catch_array[i].finally_op > start
     517          68 :                                 && op_array->try_catch_array[i].finally_end < end) {
     518           0 :                         op_num = op_array->try_catch_array[i].finally_op;
     519           0 :                         start = op_array->try_catch_array[i].finally_end;
     520             :                 }
     521             :         }
     522             : 
     523          21 :         if (op_num) {
     524             :                 /* Must be ZEND_FAST_CALL */
     525             :                 ZEND_ASSERT(op_array->opcodes[op_num - 2].opcode == ZEND_FAST_CALL);
     526           0 :                 op_array->opcodes[op_num - 2].extended_value = ZEND_FAST_CALL_FROM_FINALLY;
     527           0 :                 op_array->opcodes[op_num - 2].op2.opline_num = fast_call;
     528             :         }
     529          21 : }
     530             : 
     531          89 : static void zend_resolve_fast_call(zend_op_array *op_array, uint32_t fast_call, uint32_t op_num)
     532             : {
     533             :         int i;
     534          89 :         uint32_t finally_op_num = 0;
     535             : 
     536         344 :         for (i = 0; i < op_array->last_try_catch; i++) {
     537         601 :                 if (op_num >= op_array->try_catch_array[i].finally_op
     538         346 :                                 && op_num < op_array->try_catch_array[i].finally_end) {
     539          16 :                         finally_op_num = op_array->try_catch_array[i].finally_op;
     540             :                 }
     541             :         }
     542             : 
     543          89 :         if (finally_op_num) {
     544             :                 /* Must be ZEND_FAST_CALL */
     545             :                 ZEND_ASSERT(op_array->opcodes[finally_op_num - 2].opcode == ZEND_FAST_CALL);
     546           9 :                 if (op_array->opcodes[fast_call].extended_value == 0) {
     547           9 :                         op_array->opcodes[fast_call].extended_value = ZEND_FAST_CALL_FROM_FINALLY;
     548           9 :                         op_array->opcodes[fast_call].op2.opline_num = finally_op_num - 2;
     549             :                 }
     550             :         }
     551          89 : }
     552             : 
     553         198 : static void zend_resolve_finally_call(zend_op_array *op_array, uint32_t op_num, uint32_t dst_num)
     554             : {
     555             :         uint32_t start_op;
     556             :         zend_op *opline;
     557         198 :         uint32_t i = op_array->last_try_catch;
     558             : 
     559         198 :         if (dst_num != (uint32_t)-1) {
     560         130 :                 zend_check_finally_breakout(op_array, op_num, dst_num);
     561             :         }
     562             : 
     563             :         /* the backward order is mater */
     564         819 :         while (i > 0) {
     565         458 :                 i--;
     566        1450 :                 if (op_array->try_catch_array[i].finally_op &&
     567         441 :                     op_num >= op_array->try_catch_array[i].try_op &&
     568         373 :                     op_num < op_array->try_catch_array[i].finally_op - 1 &&
     569          89 :                     (dst_num < op_array->try_catch_array[i].try_op ||
     570          89 :                      dst_num > op_array->try_catch_array[i].finally_end)) {
     571             :                         /* we have a jump out of try block that needs executing finally */
     572             :                         uint32_t fast_call_var;
     573             : 
     574             :                         /* Must be ZEND_FAST_RET */
     575             :                         ZEND_ASSERT(op_array->opcodes[op_array->try_catch_array[i].finally_end].opcode == ZEND_FAST_RET);
     576          21 :                         fast_call_var = op_array->opcodes[op_array->try_catch_array[i].finally_end].op1.var;
     577             : 
     578             :                         /* generate a FAST_CALL to finally block */
     579          21 :                     start_op = get_next_op_number(op_array);
     580             : 
     581          21 :                         opline = get_next_op(op_array);
     582          21 :                         opline->opcode = ZEND_FAST_CALL;
     583          21 :                         opline->result_type = IS_TMP_VAR;
     584          21 :                         opline->result.var = fast_call_var;
     585          21 :                         SET_UNUSED(opline->op1);
     586          21 :                         SET_UNUSED(opline->op2);
     587          42 :                         zend_adjust_fast_call(op_array, start_op,
     588          21 :                                         op_array->try_catch_array[i].finally_op,
     589          21 :                                         op_array->try_catch_array[i].finally_end);
     590          21 :                         if (op_array->try_catch_array[i].catch_op) {
     591           7 :                                 opline->extended_value = ZEND_FAST_CALL_FROM_CATCH;
     592           7 :                                 opline->op2.opline_num = op_array->try_catch_array[i].catch_op;
     593           7 :                                 opline->op1.opline_num = get_next_op_number(op_array);
     594             :                                 /* generate a FAST_CALL to hole CALL_FROM_FINALLY */
     595           7 :                                 opline = get_next_op(op_array);
     596           7 :                                 opline->opcode = ZEND_FAST_CALL;
     597           7 :                                 opline->result_type = IS_TMP_VAR;
     598           7 :                                 opline->result.var = fast_call_var;
     599           7 :                                 SET_UNUSED(opline->op1);
     600           7 :                                 SET_UNUSED(opline->op2);
     601           7 :                                 zend_resolve_fast_call(op_array, start_op + 1, op_array->try_catch_array[i].finally_op - 2);
     602             :                         } else {
     603          14 :                                 zend_resolve_fast_call(op_array, start_op, op_array->try_catch_array[i].finally_op - 2);
     604             :                         }
     605          21 :                         opline->op1.opline_num = op_array->try_catch_array[i].finally_op;
     606             : 
     607             :                         /* generate a sequence of FAST_CALL to upward finally block */
     608          66 :                         while (i > 0) {
     609          24 :                                 i--;
     610          80 :                                 if (op_array->try_catch_array[i].finally_op &&
     611          23 :                                         op_num >= op_array->try_catch_array[i].try_op &&
     612          23 :                                         op_num < op_array->try_catch_array[i].finally_op - 1 &&
     613           5 :                                         (dst_num < op_array->try_catch_array[i].try_op ||
     614           5 :                                          dst_num > op_array->try_catch_array[i].finally_end)) {
     615             : 
     616           5 :                                         opline = get_next_op(op_array);
     617           5 :                                         opline->opcode = ZEND_FAST_CALL;
     618           5 :                                         opline->result_type = IS_TMP_VAR;
     619           5 :                                         opline->result.var = fast_call_var;
     620           5 :                                         SET_UNUSED(opline->op1);
     621           5 :                                         SET_UNUSED(opline->op2);
     622           5 :                                         opline->op1.opline_num = op_array->try_catch_array[i].finally_op;
     623             :                                 }
     624             :                         }
     625             : 
     626             :                         /* Finish the sequence with original opcode */
     627          21 :                         opline = get_next_op(op_array);
     628          21 :                         *opline = op_array->opcodes[op_num];
     629             : 
     630             :                         /* Replace original opcode with jump to this sequence */
     631          21 :                         opline = op_array->opcodes + op_num;
     632          21 :                         opline->opcode = ZEND_JMP;
     633          21 :                         SET_UNUSED(opline->op1);
     634          21 :                         SET_UNUSED(opline->op2);
     635          21 :                         opline->op1.opline_num = start_op;
     636             : 
     637          21 :                         break;
     638             :                 }
     639             :         }
     640         191 : }
     641             : 
     642          64 : static void zend_resolve_finally_ret(zend_op_array *op_array, uint32_t op_num)
     643             : {
     644             :         int i;
     645          64 :         uint32_t catch_op_num = 0, finally_op_num = 0;
     646             : 
     647         228 :         for (i = 0; i < op_array->last_try_catch; i++) {
     648         172 :                 if (op_array->try_catch_array[i].try_op > op_num) {
     649           8 :                         break;
     650             :                 }
     651         164 :                 if (op_num < op_array->try_catch_array[i].finally_op) {
     652          23 :                         finally_op_num = op_array->try_catch_array[i].finally_op;
     653             :                 }
     654         164 :                 if (op_num < op_array->try_catch_array[i].catch_op) {
     655          16 :                         catch_op_num = op_array->try_catch_array[i].catch_op;
     656             :                 }
     657             :         }
     658             : 
     659          72 :         if (finally_op_num && (!catch_op_num || catch_op_num >= finally_op_num)) {
     660             :                 /* in case of unhandled exception return to upward finally block */
     661           8 :                 op_array->opcodes[op_num].extended_value = ZEND_FAST_RET_TO_FINALLY;
     662           8 :                 op_array->opcodes[op_num].op2.opline_num = finally_op_num;
     663          56 :         } else if (catch_op_num) {
     664             :                 /* in case of unhandled exception return to upward catch block */
     665          11 :                 op_array->opcodes[op_num].extended_value = ZEND_FAST_RET_TO_CATCH;
     666          11 :                 op_array->opcodes[op_num].op2.opline_num = catch_op_num;
     667             :         }
     668          64 : }
     669             : 
     670        2155 : static uint32_t zend_get_brk_cont_target(const zend_op_array *op_array, const zend_op *opline) {
     671        2155 :         int nest_levels = opline->op2.num;
     672        2155 :         int array_offset = opline->op1.num;
     673             :         zend_brk_cont_element *jmp_to;
     674             :         do {
     675        2178 :                 jmp_to = &op_array->brk_cont_array[array_offset];
     676        2178 :                 if (nest_levels > 1) {
     677          23 :                         array_offset = jmp_to->parent;
     678             :                 }
     679        2178 :         } while (--nest_levels > 0);
     680             : 
     681        2155 :         return opline->opcode == ZEND_BRK ? jmp_to->brk : jmp_to->cont;
     682             : }
     683             : 
     684          44 : static void zend_resolve_finally_calls(zend_op_array *op_array)
     685             : {
     686             :         uint32_t i, j;
     687             :         zend_op *opline;
     688             : 
     689         777 :         for (i = 0, j = op_array->last; i < j; i++) {
     690         740 :                 opline = op_array->opcodes + i;
     691         740 :                 switch (opline->opcode) {
     692             :                         case ZEND_RETURN:
     693             :                         case ZEND_RETURN_BY_REF:
     694             :                         case ZEND_GENERATOR_RETURN:
     695          68 :                                 zend_resolve_finally_call(op_array, i, (uint32_t)-1);
     696          68 :                                 break;
     697             :                         case ZEND_BRK:
     698             :                         case ZEND_CONT:
     699           8 :                                 zend_resolve_finally_call(op_array, i, zend_get_brk_cont_target(op_array, opline));
     700           6 :                                 break;
     701             :                         case ZEND_GOTO:
     702          16 :                                 if (Z_TYPE_P(CT_CONSTANT_EX(op_array, opline->op2.constant)) != IS_LONG) {
     703           8 :                                         uint32_t num = opline->op2.constant;
     704             : 
     705           8 :                                         ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline->op2);
     706           8 :                                         zend_resolve_goto_label(op_array, opline, 1);
     707           8 :                                         opline->op2.constant = num;
     708             :                                 }
     709             :                                 /* break omitted intentionally */
     710             :                         case ZEND_JMP:
     711         122 :                                 zend_resolve_finally_call(op_array, i, opline->op1.opline_num);
     712         117 :                                 break;
     713             :                         case ZEND_FAST_CALL:
     714          68 :                                 zend_resolve_fast_call(op_array, i, i);
     715          68 :                                 break;
     716             :                         case ZEND_FAST_RET:
     717          64 :                                 zend_resolve_finally_ret(op_array, i);
     718             :                                 break;
     719             :                         default:
     720             :                                 break;
     721             :                 }
     722             :         }
     723          37 : }
     724             : 
     725       65687 : ZEND_API int pass_two(zend_op_array *op_array)
     726             : {
     727             :         zend_op *opline, *end;
     728             : 
     729       65687 :         if (!ZEND_USER_CODE(op_array->type)) {
     730           0 :                 return 0;
     731             :         }
     732       65687 :         if (op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) {
     733          44 :                 zend_resolve_finally_calls(op_array);
     734             :         }
     735       65680 :         if (CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO) {
     736           0 :                 zend_update_extended_info(op_array);
     737             :         }
     738       65680 :         if (CG(compiler_options) & ZEND_COMPILE_HANDLE_OP_ARRAY) {
     739       65473 :                 zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_handler, op_array);
     740             :         }
     741             : 
     742       65680 :         if (CG(context).vars_size != op_array->last_var) {
     743       47349 :                 op_array->vars = (zend_string**) erealloc(op_array->vars, sizeof(zend_string*)*op_array->last_var);
     744       47349 :                 CG(context).vars_size = op_array->last_var;
     745             :         }
     746       65680 :         if (CG(context).opcodes_size != op_array->last) {
     747       65515 :                 op_array->opcodes = (zend_op *) erealloc(op_array->opcodes, sizeof(zend_op)*op_array->last);
     748       65515 :                 CG(context).opcodes_size = op_array->last;
     749             :         }
     750       65680 :         if (CG(context).literals_size != op_array->last_literal) {
     751       64173 :                 op_array->literals = (zval*)erealloc(op_array->literals, sizeof(zval) * op_array->last_literal);
     752       64173 :                 CG(context).literals_size = op_array->last_literal;
     753             :         }
     754       65680 :         opline = op_array->opcodes;
     755       65680 :         end = opline + op_array->last;
     756     2357352 :         while (opline < end) {
     757     2225995 :                 if (opline->op1_type == IS_CONST) {
     758      433925 :                         ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline->op1);
     759     1792070 :                 } else if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) {
     760      505523 :                         opline->op1.var = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + opline->op1.var);
     761             :                 }
     762     2225995 :                 if (opline->op2_type == IS_CONST) {
     763      555688 :                         ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline->op2);
     764     1670307 :                 } else if (opline->op2_type & (IS_VAR|IS_TMP_VAR)) {
     765      115152 :                         opline->op2.var = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + opline->op2.var);
     766             :                 }
     767     2225995 :                 if (opline->result_type & (IS_VAR|IS_TMP_VAR)) {
     768      926991 :                         opline->result.var = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + opline->result.var);
     769             :                 }
     770     2225995 :                 switch (opline->opcode) {
     771             :                         case ZEND_DECLARE_ANON_INHERITED_CLASS:
     772           2 :                                 ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op1);
     773             :                                 /* break omitted intentionally */
     774             :                         case ZEND_DECLARE_INHERITED_CLASS:
     775             :                         case ZEND_DECLARE_INHERITED_CLASS_DELAYED:
     776        1294 :                                 opline->extended_value = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + opline->extended_value);
     777        1294 :                                 break;
     778             :                         case ZEND_BRK:
     779             :                         case ZEND_CONT:
     780             :                                 {
     781        2147 :                                         uint32_t jmp_target = zend_get_brk_cont_target(op_array, opline);
     782        2147 :                                         opline->opcode = ZEND_JMP;
     783        2147 :                                         opline->op1.opline_num = jmp_target;
     784        2147 :                                         opline->op2.num = 0;
     785        2147 :                                         ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op1);
     786             :                                 }
     787        2147 :                                 break;
     788             :                         case ZEND_GOTO:
     789          34 :                                 if (Z_TYPE_P(RT_CONSTANT(op_array, opline->op2)) != IS_LONG) {
     790          15 :                                         zend_resolve_goto_label(op_array, opline, 1);
     791             :                                 }
     792             :                                 /* break omitted intentionally */
     793             :                         case ZEND_JMP:
     794             :                         case ZEND_FAST_CALL:
     795             :                         case ZEND_DECLARE_ANON_CLASS:
     796       60684 :                                 ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op1);
     797       60684 :                                 break;
     798             :                         case ZEND_JMPZNZ:
     799             :                                 /* absolute index to relative offset */
     800           0 :                                 opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, opline->extended_value);
     801             :                                 /* break omitted intentionally */
     802             :                         case ZEND_JMPZ:
     803             :                         case ZEND_JMPNZ:
     804             :                         case ZEND_JMPZ_EX:
     805             :                         case ZEND_JMPNZ_EX:
     806             :                         case ZEND_JMP_SET:
     807             :                         case ZEND_COALESCE:
     808             :                         case ZEND_NEW:
     809             :                         case ZEND_FE_RESET_R:
     810             :                         case ZEND_FE_RESET_RW:
     811             :                         case ZEND_ASSERT_CHECK:
     812      136765 :                                 ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op2);
     813      136765 :                                 break;
     814             :                         case ZEND_FE_FETCH_R:
     815             :                         case ZEND_FE_FETCH_RW:
     816       10103 :                                 opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, opline->extended_value);
     817       10103 :                                 break;
     818             :                         case ZEND_VERIFY_RETURN_TYPE:
     819         158 :                                 if (op_array->fn_flags & ZEND_ACC_GENERATOR) {
     820           9 :                                         MAKE_NOP(opline);
     821             :                                 }
     822         158 :                                 break;
     823             :                         case ZEND_RETURN:
     824             :                         case ZEND_RETURN_BY_REF:
     825      109274 :                                 if (op_array->fn_flags & ZEND_ACC_GENERATOR) {
     826         173 :                                         opline->opcode = ZEND_GENERATOR_RETURN;
     827             :                                 }
     828             :                                 break;
     829             :                 }
     830     2225992 :                 ZEND_VM_SET_OPCODE_HANDLER(opline);
     831     2225992 :                 opline++;
     832             :         }
     833             : 
     834       65677 :         op_array->fn_flags |= ZEND_ACC_DONE_PASS_TWO;
     835       65677 :         return 0;
     836             : }
     837             : 
     838           0 : int pass_two_wrapper(zval *el)
     839             : {
     840           0 :         return pass_two((zend_op_array *) Z_PTR_P(el));
     841             : }
     842             : 
     843           0 : int print_class(zend_class_entry *class_entry)
     844             : {
     845           0 :         printf("Class %s:\n", class_entry->name->val);
     846           0 :         zend_hash_apply(&class_entry->function_table, pass_two_wrapper);
     847           0 :         printf("End of class %s.\n\n", class_entry->name->val);
     848           0 :         return 0;
     849             : }
     850             : 
     851         304 : ZEND_API unary_op_type get_unary_op(int opcode)
     852             : {
     853         304 :         switch (opcode) {
     854             :                 case ZEND_BW_NOT:
     855          84 :                         return (unary_op_type) bitwise_not_function;
     856             :                 case ZEND_BOOL_NOT:
     857         220 :                         return (unary_op_type) boolean_not_function;
     858             :                 default:
     859           0 :                         return (unary_op_type) NULL;
     860             :         }
     861             : }
     862             : 
     863        3567 : ZEND_API binary_op_type get_binary_op(int opcode)
     864             : {
     865        3567 :         switch (opcode) {
     866             :                 case ZEND_ADD:
     867             :                 case ZEND_ASSIGN_ADD:
     868         181 :                         return (binary_op_type) add_function;
     869             :                 case ZEND_SUB:
     870             :                 case ZEND_ASSIGN_SUB:
     871         197 :                         return (binary_op_type) sub_function;
     872             :                 case ZEND_MUL:
     873             :                 case ZEND_ASSIGN_MUL:
     874          73 :                         return (binary_op_type) mul_function;
     875             :                 case ZEND_POW:
     876           8 :                         return (binary_op_type) pow_function;
     877             :                 case ZEND_DIV:
     878             :                 case ZEND_ASSIGN_DIV:
     879          27 :                         return (binary_op_type) div_function;
     880             :                 case ZEND_MOD:
     881             :                 case ZEND_ASSIGN_MOD:
     882           4 :                         return (binary_op_type) mod_function;
     883             :                 case ZEND_SL:
     884             :                 case ZEND_ASSIGN_SL:
     885          33 :                         return (binary_op_type) shift_left_function;
     886             :                 case ZEND_SR:
     887             :                 case ZEND_ASSIGN_SR:
     888           3 :                         return (binary_op_type) shift_right_function;
     889             :                 case ZEND_FAST_CONCAT:
     890             :                 case ZEND_CONCAT:
     891             :                 case ZEND_ASSIGN_CONCAT:
     892        1947 :                         return (binary_op_type) concat_function;
     893             :                 case ZEND_IS_IDENTICAL:
     894           3 :                         return (binary_op_type) is_identical_function;
     895             :                 case ZEND_IS_NOT_IDENTICAL:
     896          19 :                         return (binary_op_type) is_not_identical_function;
     897             :                 case ZEND_IS_EQUAL:
     898          79 :                         return (binary_op_type) is_equal_function;
     899             :                 case ZEND_IS_NOT_EQUAL:
     900         399 :                         return (binary_op_type) is_not_equal_function;
     901             :                 case ZEND_IS_SMALLER:
     902          45 :                         return (binary_op_type) is_smaller_function;
     903             :                 case ZEND_IS_SMALLER_OR_EQUAL:
     904           1 :                         return (binary_op_type) is_smaller_or_equal_function;
     905             :                 case ZEND_SPACESHIP:
     906           3 :                         return (binary_op_type) compare_function;
     907             :                 case ZEND_BW_OR:
     908             :                 case ZEND_ASSIGN_BW_OR:
     909         454 :                         return (binary_op_type) bitwise_or_function;
     910             :                 case ZEND_BW_AND:
     911             :                 case ZEND_ASSIGN_BW_AND:
     912          80 :                         return (binary_op_type) bitwise_and_function;
     913             :                 case ZEND_BW_XOR:
     914             :                 case ZEND_ASSIGN_BW_XOR:
     915           9 :                         return (binary_op_type) bitwise_xor_function;
     916             :                 case ZEND_BOOL_XOR:
     917           2 :                         return (binary_op_type) boolean_xor_function;
     918             :                 default:
     919           0 :                         return (binary_op_type) NULL;
     920             :         }
     921             : }
     922             : 
     923             : /*
     924             :  * Local variables:
     925             :  * tab-width: 4
     926             :  * c-basic-offset: 4
     927             :  * indent-tabs-mode: t
     928             :  * End:
     929             :  */

Generated by: LCOV version 1.10

Generated at Sat, 27 Jun 2015 09:41:05 +0000 (7 days ago)

Copyright © 2005-2015 The PHP Group
All rights reserved.