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: 431 493 87.4 %
Date: 2015-05-21 Functions: 25 30 83.3 %
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       65097 : static void zend_extension_op_array_ctor_handler(zend_extension *extension, zend_op_array *op_array)
      33             : {
      34       65097 :         if (extension->op_array_ctor) {
      35           0 :                 extension->op_array_ctor(op_array);
      36             :         }
      37       65097 : }
      38             : 
      39       62941 : static void zend_extension_op_array_dtor_handler(zend_extension *extension, zend_op_array *op_array)
      40             : {
      41       62941 :         if (extension->op_array_dtor) {
      42           0 :                 extension->op_array_dtor(op_array);
      43             :         }
      44       62941 : }
      45             : 
      46       73352 : static void op_array_alloc_ops(zend_op_array *op_array, uint32_t size)
      47             : {
      48       73352 :         op_array->opcodes = erealloc(op_array->opcodes, size * sizeof(zend_op));
      49       73352 : }
      50             : 
      51       65579 : void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_size)
      52             : {
      53       65579 :         op_array->type = type;
      54       65579 :         op_array->arg_flags[0] = 0;
      55       65579 :         op_array->arg_flags[1] = 0;
      56       65579 :         op_array->arg_flags[2] = 0;
      57             : 
      58       65579 :         op_array->refcount = (uint32_t *) emalloc(sizeof(uint32_t));
      59       65579 :         *op_array->refcount = 1;
      60       65579 :         op_array->last = 0;
      61       65579 :         op_array->opcodes = NULL;
      62       65579 :         op_array_alloc_ops(op_array, initial_ops_size);
      63             : 
      64       65579 :         op_array->last_var = 0;
      65       65579 :         op_array->vars = NULL;
      66             : 
      67       65579 :         op_array->T = 0;
      68             : 
      69       65579 :         op_array->function_name = NULL;
      70       65579 :         op_array->filename = zend_get_compiled_filename();
      71       65579 :         op_array->doc_comment = NULL;
      72             : 
      73       65579 :         op_array->arg_info = NULL;
      74       65579 :         op_array->num_args = 0;
      75       65579 :         op_array->required_num_args = 0;
      76             : 
      77       65579 :         op_array->scope = NULL;
      78       65579 :         op_array->prototype = NULL;
      79             : 
      80       65579 :         op_array->brk_cont_array = NULL;
      81       65579 :         op_array->try_catch_array = NULL;
      82       65579 :         op_array->last_brk_cont = 0;
      83             : 
      84       65579 :         op_array->static_variables = NULL;
      85       65579 :         op_array->last_try_catch = 0;
      86             : 
      87       65579 :         op_array->this_var = -1;
      88             : 
      89       65579 :         op_array->fn_flags = 0;
      90             : 
      91       65579 :         op_array->early_binding = -1;
      92             : 
      93       65579 :         op_array->last_literal = 0;
      94       65579 :         op_array->literals = NULL;
      95             : 
      96       65579 :         op_array->run_time_cache = NULL;
      97       65579 :         op_array->cache_size = 0;
      98             : 
      99       65579 :         memset(op_array->reserved, 0, ZEND_MAX_RESERVED_RESOURCES * sizeof(void*));
     100             : 
     101       65579 :         zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_ctor_handler, op_array);
     102       65579 : }
     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   103373941 : ZEND_API void zend_function_dtor(zval *zv)
     116             : {
     117   103373941 :         zend_function *function = Z_PTR_P(zv);
     118             : 
     119   103373941 :         if (function->type == ZEND_USER_FUNCTION) {
     120             :                 ZEND_ASSERT(function->common.function_name);
     121       54260 :                 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   103319681 :                 zend_string_release(function->common.function_name);
     127   103319681 :                 if (!(function->common.fn_flags & ZEND_ACC_ARENA_ALLOCATED)) {
     128   103272345 :                         pefree(function, 1);
     129             :                 }
     130             :         }
     131   103373941 : }
     132             : 
     133       31445 : ZEND_API void zend_cleanup_op_array_data(zend_op_array *op_array)
     134             : {
     135       33484 :         if (op_array->static_variables &&
     136        2039 :             !(GC_FLAGS(op_array->static_variables) & IS_ARRAY_IMMUTABLE)) {
     137        2038 :                 zend_hash_clean(op_array->static_variables);
     138             :         }
     139       31445 : }
     140             : 
     141        9182 : 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        9182 :         if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) {
     147             :                 zend_function *func;
     148             : 
     149       21583 :                 ZEND_HASH_FOREACH_PTR(&ce->function_table, func) {
     150       10107 :                         if (func->type == ZEND_USER_FUNCTION) {
     151       10082 :                                 zend_cleanup_op_array_data((zend_op_array *) func);
     152             :                         }
     153             :                 } ZEND_HASH_FOREACH_END();
     154             :         }
     155        9182 :         if (ce->static_members_table) {
     156         340 :                 zval *static_members = ce->static_members_table;
     157         340 :                 zval *p = static_members;
     158         340 :                 zval *end = p + ce->default_static_members_count;
     159             : 
     160             : 
     161         340 :                 ce->default_static_members_count = 0;
     162         340 :                 ce->default_static_members_table = ce->static_members_table = NULL;
     163        1234 :                 while (p != end) {
     164             :                         i_zval_ptr_dtor(p ZEND_FILE_LINE_CC);
     165         554 :                         p++;
     166             :                 }
     167         338 :                 efree(static_members);
     168             :         }
     169        9180 : }
     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 :                 while (p != end) {
     184             :                         i_zval_ptr_dtor(p ZEND_FILE_LINE_CC);
     185           0 :                         p++;
     186             :                 }
     187           0 :                 efree(static_members);
     188             :         }
     189           0 : }
     190             : 
     191        7443 : void _destroy_zend_class_traits_info(zend_class_entry *ce)
     192             : {
     193        7443 :         if (ce->num_traits > 0 && ce->traits) {
     194         177 :                 efree(ce->traits);
     195             :         }
     196             : 
     197        7443 :         if (ce->trait_aliases) {
     198          45 :                 size_t i = 0;
     199         149 :                 while (ce->trait_aliases[i]) {
     200          59 :                         if (ce->trait_aliases[i]->trait_method) {
     201          59 :                                 if (ce->trait_aliases[i]->trait_method->method_name) {
     202          59 :                                         zend_string_release(ce->trait_aliases[i]->trait_method->method_name);
     203             :                                 }
     204          59 :                                 if (ce->trait_aliases[i]->trait_method->class_name) {
     205          22 :                                         zend_string_release(ce->trait_aliases[i]->trait_method->class_name);
     206             :                                 }
     207          59 :                                 efree(ce->trait_aliases[i]->trait_method);
     208             :                         }
     209             : 
     210          59 :                         if (ce->trait_aliases[i]->alias) {
     211          50 :                                 zend_string_release(ce->trait_aliases[i]->alias);
     212             :                         }
     213             : 
     214          59 :                         efree(ce->trait_aliases[i]);
     215          59 :                         i++;
     216             :                 }
     217             : 
     218          45 :                 efree(ce->trait_aliases);
     219             :         }
     220             : 
     221        7443 :         if (ce->trait_precedences) {
     222           9 :                 size_t i = 0;
     223             : 
     224          31 :                 while (ce->trait_precedences[i]) {
     225          13 :                         zend_string_release(ce->trait_precedences[i]->trait_method->method_name);
     226          13 :                         zend_string_release(ce->trait_precedences[i]->trait_method->class_name);
     227          13 :                         efree(ce->trait_precedences[i]->trait_method);
     228             : 
     229          13 :                         if (ce->trait_precedences[i]->exclude_from_classes) {
     230           5 :                                 size_t j = 0;
     231           5 :                                 zend_trait_precedence *cur_precedence = ce->trait_precedences[i];
     232          15 :                                 while (cur_precedence->exclude_from_classes[j].class_name) {
     233           5 :                                         zend_string_release(cur_precedence->exclude_from_classes[j].class_name);
     234           5 :                                         j++;
     235             :                                 }
     236           5 :                                 efree(ce->trait_precedences[i]->exclude_from_classes);
     237             :                         }
     238          13 :                         efree(ce->trait_precedences[i]);
     239          13 :                         i++;
     240             :                 }
     241           9 :                 efree(ce->trait_precedences);
     242             :         }
     243        7443 : }
     244             : 
     245     3932791 : ZEND_API void destroy_zend_class(zval *zv)
     246             : {
     247             :         zend_property_info *prop_info;
     248     3932791 :         zend_class_entry *ce = Z_PTR_P(zv);
     249             : 
     250     3932791 :         if (--ce->refcount > 0) {
     251        7324 :                 return;
     252             :         }
     253     3925467 :         switch (ce->type) {
     254             :                 case ZEND_USER_CLASS:
     255        7443 :                         if (ce->default_properties_table) {
     256        2252 :                                 zval *p = ce->default_properties_table;
     257        2252 :                                 zval *end = p + ce->default_properties_count;
     258             : 
     259       24786 :                                 while (p != end) {
     260             :                                         i_zval_ptr_dtor(p ZEND_FILE_LINE_CC);
     261       20282 :                                         p++;
     262             :                                 }
     263        2252 :                                 efree(ce->default_properties_table);
     264             :                         }
     265        7443 :                         if (ce->default_static_members_table) {
     266           0 :                                 zval *p = ce->default_static_members_table;
     267           0 :                                 zval *end = p + ce->default_static_members_count;
     268             : 
     269           0 :                                 while (p != end) {
     270             :                                         i_zval_ptr_dtor(p ZEND_FILE_LINE_CC);
     271           0 :                                         p++;
     272             :                                 }
     273           0 :                                 efree(ce->default_static_members_table);
     274             :                         }
     275       48739 :                         ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop_info) {
     276       20648 :                                 if (prop_info->ce == ce || (prop_info->flags & ZEND_ACC_SHADOW)) {
     277        2633 :                                         zend_string_release(prop_info->name);
     278        2633 :                                         if (prop_info->doc_comment) {
     279          53 :                                                 zend_string_release(prop_info->doc_comment);
     280             :                                         }
     281             :                                 }
     282             :                         } ZEND_HASH_FOREACH_END();
     283        7443 :                         zend_hash_destroy(&ce->properties_info);
     284        7443 :                         zend_string_release(ce->name);
     285        7443 :                         zend_hash_destroy(&ce->function_table);
     286        7443 :                         zend_hash_destroy(&ce->constants_table);
     287        7443 :                         if (ce->num_interfaces > 0 && ce->interfaces) {
     288         630 :                                 efree(ce->interfaces);
     289             :                         }
     290        7443 :                         if (ce->info.user.doc_comment) {
     291          71 :                                 zend_string_release(ce->info.user.doc_comment);
     292             :                         }
     293             : 
     294        7443 :                         _destroy_zend_class_traits_info(ce);
     295             : 
     296        7443 :                         break;
     297             :                 case ZEND_INTERNAL_CLASS:
     298     3918024 :                         if (ce->default_properties_table) {
     299     1026648 :                                 zval *p = ce->default_properties_table;
     300     1026648 :                                 zval *end = p + ce->default_properties_count;
     301             : 
     302     7689384 :                                 while (p != end) {
     303     5636088 :                                         zval_internal_ptr_dtor(p);
     304     5636088 :                                         p++;
     305             :                                 }
     306     1026648 :                                 free(ce->default_properties_table);
     307             :                         }
     308     3918024 :                         if (ce->default_static_members_table) {
     309           0 :                                 zval *p = ce->default_static_members_table;
     310           0 :                                 zval *end = p + ce->default_static_members_count;
     311             : 
     312           0 :                                 while (p != end) {
     313           0 :                                         zval_internal_ptr_dtor(p);
     314           0 :                                         p++;
     315             :                                 }
     316           0 :                                 free(ce->default_static_members_table);
     317             :                         }
     318     3918024 :                         zend_hash_destroy(&ce->properties_info);
     319     3918024 :                         zend_string_release(ce->name);
     320     3918024 :                         zend_hash_destroy(&ce->function_table);
     321     3918024 :                         zend_hash_destroy(&ce->constants_table);
     322     3918024 :                         if (ce->num_interfaces > 0) {
     323     1445688 :                                 free(ce->interfaces);
     324             :                         }
     325     3918024 :                         free(ce);
     326             :                         break;
     327             :         }
     328             : }
     329             : 
     330           0 : void zend_class_add_ref(zval *zv)
     331             : {
     332           0 :         zend_class_entry *ce = Z_PTR_P(zv);
     333             : 
     334           0 :         ce->refcount++;
     335           0 : }
     336             : 
     337       82565 : ZEND_API void destroy_op_array(zend_op_array *op_array)
     338             : {
     339       82565 :         zval *literal = op_array->literals;
     340             :         zval *end;
     341             :         uint32_t i;
     342             : 
     343       84728 :         if (op_array->static_variables &&
     344        2163 :             !(GC_FLAGS(op_array->static_variables) & IS_ARRAY_IMMUTABLE)) {
     345        2162 :             if (--GC_REFCOUNT(op_array->static_variables) == 0) {
     346        2162 :                         zend_array_destroy(op_array->static_variables);
     347             :                 }
     348             :         }
     349             : 
     350       82565 :         if (op_array->run_time_cache && !op_array->function_name) {
     351       27843 :                 efree(op_array->run_time_cache);
     352             :         }
     353             : 
     354       82565 :         if (!op_array->refcount || --(*op_array->refcount)>0) {
     355       19106 :                 return;
     356             :         }
     357             : 
     358       63459 :         efree_size(op_array->refcount, sizeof(*(op_array->refcount)));
     359             : 
     360       63459 :         if (op_array->vars) {
     361       46757 :                 i = op_array->last_var;
     362      297107 :                 while (i > 0) {
     363      203593 :                         i--;
     364      203593 :                         zend_string_release(op_array->vars[i]);
     365             :                 }
     366       46757 :                 efree(op_array->vars);
     367             :         }
     368             : 
     369       63459 :         if (literal) {
     370       63424 :                 end = literal + op_array->last_literal;
     371     1179942 :                 while (literal < end) {
     372             :                         zval_ptr_dtor_nogc(literal);
     373     1053094 :                         literal++;
     374             :                 }
     375       63424 :                 efree(op_array->literals);
     376             :         }
     377       63459 :         efree(op_array->opcodes);
     378             : 
     379       63459 :         if (op_array->function_name) {
     380       35928 :                 zend_string_release(op_array->function_name);
     381             :         }
     382       63459 :         if (op_array->doc_comment) {
     383        2395 :                 zend_string_release(op_array->doc_comment);
     384             :         }
     385       63459 :         if (op_array->brk_cont_array) {
     386       12021 :                 efree(op_array->brk_cont_array);
     387             :         }
     388       63459 :         if (op_array->try_catch_array) {
     389        1722 :                 efree(op_array->try_catch_array);
     390             :         }
     391       63459 :         if (op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO) {
     392       63410 :                 zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_dtor_handler, op_array);
     393             :         }
     394       63459 :         if (op_array->arg_info) {
     395       26863 :                 int32_t num_args = op_array->num_args;
     396       26863 :                 zend_arg_info *arg_info = op_array->arg_info;
     397             :                 int32_t i;
     398             : 
     399       26863 :                 if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
     400          85 :                         arg_info--;
     401          85 :                         num_args++;
     402             :                 }
     403       26863 :                 if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
     404          37 :                         num_args++;
     405             :                 }
     406      109852 :                 for (i = 0 ; i < num_args; i++) {
     407       82989 :                         if (arg_info[i].name) {
     408       82904 :                                 zend_string_release(arg_info[i].name);
     409             :                         }
     410       82989 :                         if (arg_info[i].class_name) {
     411         215 :                                 zend_string_release(arg_info[i].class_name);
     412             :                         }
     413             :                 }
     414       26863 :                 efree(arg_info);
     415             :         }
     416             : }
     417             : 
     418     2365497 : void init_op(zend_op *op)
     419             : {
     420     2365497 :         memset(op, 0, sizeof(zend_op));
     421     2365497 :         op->lineno = CG(zend_lineno);
     422     2365497 :         SET_UNUSED(op->result);
     423     2365497 : }
     424             : 
     425     2214689 : zend_op *get_next_op(zend_op_array *op_array)
     426             : {
     427     2214689 :         uint32_t next_op_num = op_array->last++;
     428             :         zend_op *next_op;
     429             : 
     430     2214689 :         if (next_op_num >= CG(context).opcodes_size) {
     431        7773 :                 CG(context).opcodes_size *= 4;
     432        7773 :                 op_array_alloc_ops(op_array, CG(context).opcodes_size);
     433             :         }
     434             : 
     435     2214689 :         next_op = &(op_array->opcodes[next_op_num]);
     436             : 
     437     2214689 :         init_op(next_op);
     438             : 
     439     2214689 :         return next_op;
     440             : }
     441             : 
     442      882637 : int get_next_op_number(zend_op_array *op_array)
     443             : {
     444      882637 :         return op_array->last;
     445             : }
     446             : 
     447       19993 : zend_brk_cont_element *get_next_brk_cont_element(zend_op_array *op_array)
     448             : {
     449       19993 :         op_array->last_brk_cont++;
     450       19993 :         op_array->brk_cont_array = erealloc(op_array->brk_cont_array, sizeof(zend_brk_cont_element)*op_array->last_brk_cont);
     451       19993 :         return &op_array->brk_cont_array[op_array->last_brk_cont-1];
     452             : }
     453             : 
     454           0 : static void zend_update_extended_info(zend_op_array *op_array)
     455             : {
     456           0 :         zend_op *opline = op_array->opcodes, *end=opline+op_array->last;
     457             : 
     458           0 :         while (opline<end) {
     459           0 :                 if (opline->opcode == ZEND_EXT_STMT) {
     460           0 :                         if (opline+1<end) {
     461           0 :                                 if ((opline+1)->opcode == ZEND_EXT_STMT) {
     462           0 :                                         opline->opcode = ZEND_NOP;
     463           0 :                                         opline++;
     464           0 :                                         continue;
     465             :                                 }
     466           0 :                                 if (opline+1<end) {
     467           0 :                                         opline->lineno = (opline+1)->lineno;
     468             :                                 }
     469             :                         } else {
     470           0 :                                 opline->opcode = ZEND_NOP;
     471             :                         }
     472             :                 }
     473           0 :                 opline++;
     474             :         }
     475           0 : }
     476             : 
     477       64657 : static void zend_extension_op_array_handler(zend_extension *extension, zend_op_array *op_array)
     478             : {
     479       64657 :         if (extension->op_array_handler) {
     480           0 :                 extension->op_array_handler(op_array);
     481             :         }
     482       64657 : }
     483             : 
     484         132 : static void zend_check_finally_breakout(zend_op_array *op_array, uint32_t op_num, uint32_t dst_num)
     485             : {
     486             :         int i;
     487             : 
     488         501 :         for (i = 0; i < op_array->last_try_catch; i++) {
     489        1103 :                 if ((op_num < op_array->try_catch_array[i].finally_op ||
     490         156 :                                         op_num >= op_array->try_catch_array[i].finally_end)
     491         343 :                                 && (dst_num >= op_array->try_catch_array[i].finally_op &&
     492         228 :                                          dst_num <= op_array->try_catch_array[i].finally_end)) {
     493           3 :                         CG(in_compilation) = 1;
     494           3 :                         CG(active_op_array) = op_array;
     495           3 :                         CG(zend_lineno) = op_array->opcodes[op_num].lineno;
     496           3 :                         zend_error_noreturn(E_COMPILE_ERROR, "jump into a finally block is disallowed");
     497         964 :                 } else if ((op_num >= op_array->try_catch_array[i].finally_op
     498         528 :                                         && op_num <= op_array->try_catch_array[i].finally_end)
     499          33 :                                 && (dst_num > op_array->try_catch_array[i].finally_end
     500          63 :                                         || dst_num < op_array->try_catch_array[i].finally_op)) {
     501           4 :                         CG(in_compilation) = 1;
     502           4 :                         CG(active_op_array) = op_array;
     503           4 :                         CG(zend_lineno) = op_array->opcodes[op_num].lineno;
     504           4 :                         zend_error_noreturn(E_COMPILE_ERROR, "jump out of a finally block is disallowed");
     505             :                 }
     506             :         }
     507         125 : }
     508             : 
     509          21 : static void zend_adjust_fast_call(zend_op_array *op_array, uint32_t fast_call, uint32_t start, uint32_t end)
     510             : {
     511             :         int i;
     512          21 :         uint32_t op_num = 0;
     513             : 
     514          78 :         for (i = 0; i < op_array->last_try_catch; i++) {
     515         125 :                 if (op_array->try_catch_array[i].finally_op > start
     516          68 :                                 && op_array->try_catch_array[i].finally_end < end) {
     517           0 :                         op_num = op_array->try_catch_array[i].finally_op;
     518           0 :                         start = op_array->try_catch_array[i].finally_end;
     519             :                 }
     520             :         }
     521             : 
     522          21 :         if (op_num) {
     523             :                 /* Must be ZEND_FAST_CALL */
     524             :                 ZEND_ASSERT(op_array->opcodes[op_num - 2].opcode == ZEND_FAST_CALL);
     525           0 :                 op_array->opcodes[op_num - 2].extended_value = ZEND_FAST_CALL_FROM_FINALLY;
     526           0 :                 op_array->opcodes[op_num - 2].op2.opline_num = fast_call;
     527             :         }
     528          21 : }
     529             : 
     530          89 : static void zend_resolve_fast_call(zend_op_array *op_array, uint32_t fast_call, uint32_t op_num)
     531             : {
     532             :         int i;
     533          89 :         uint32_t finally_op_num = 0;
     534             : 
     535         344 :         for (i = 0; i < op_array->last_try_catch; i++) {
     536         601 :                 if (op_num >= op_array->try_catch_array[i].finally_op
     537         346 :                                 && op_num < op_array->try_catch_array[i].finally_end) {
     538          16 :                         finally_op_num = op_array->try_catch_array[i].finally_op;
     539             :                 }
     540             :         }
     541             : 
     542          89 :         if (finally_op_num) {
     543             :                 /* Must be ZEND_FAST_CALL */
     544             :                 ZEND_ASSERT(op_array->opcodes[finally_op_num - 2].opcode == ZEND_FAST_CALL);
     545           9 :                 if (op_array->opcodes[fast_call].extended_value == 0) {
     546           9 :                         op_array->opcodes[fast_call].extended_value = ZEND_FAST_CALL_FROM_FINALLY;
     547           9 :                         op_array->opcodes[fast_call].op2.opline_num = finally_op_num - 2;
     548             :                 }
     549             :         }
     550          89 : }
     551             : 
     552         200 : static void zend_resolve_finally_call(zend_op_array *op_array, uint32_t op_num, uint32_t dst_num)
     553             : {
     554             :         uint32_t start_op;
     555             :         zend_op *opline;
     556         200 :         uint32_t i = op_array->last_try_catch;
     557             : 
     558         200 :         if (dst_num != (uint32_t)-1) {
     559         132 :                 zend_check_finally_breakout(op_array, op_num, dst_num);
     560             :         }
     561             : 
     562             :         /* the backward order is mater */
     563         825 :         while (i > 0) {
     564         460 :                 i--;
     565        1460 :                 if (op_array->try_catch_array[i].finally_op &&
     566         443 :                     op_num >= op_array->try_catch_array[i].try_op &&
     567         375 :                     op_num < op_array->try_catch_array[i].finally_op - 1 &&
     568          91 :                     (dst_num < op_array->try_catch_array[i].try_op ||
     569          91 :                      dst_num > op_array->try_catch_array[i].finally_end)) {
     570             :                         /* we have a jump out of try block that needs executing finally */
     571             :                         uint32_t fast_call_var;
     572             : 
     573             :                         /* Must be ZEND_FAST_RET */
     574             :                         ZEND_ASSERT(op_array->opcodes[op_array->try_catch_array[i].finally_end].opcode == ZEND_FAST_RET);
     575          21 :                         fast_call_var = op_array->opcodes[op_array->try_catch_array[i].finally_end].op1.var;
     576             : 
     577             :                         /* generate a FAST_CALL to finally block */
     578          21 :                     start_op = get_next_op_number(op_array);
     579             : 
     580          21 :                         opline = get_next_op(op_array);
     581          21 :                         opline->opcode = ZEND_FAST_CALL;
     582          21 :                         opline->result_type = IS_TMP_VAR;
     583          21 :                         opline->result.var = fast_call_var;
     584          21 :                         SET_UNUSED(opline->op1);
     585          21 :                         SET_UNUSED(opline->op2);
     586          42 :                         zend_adjust_fast_call(op_array, start_op,
     587          21 :                                         op_array->try_catch_array[i].finally_op,
     588          21 :                                         op_array->try_catch_array[i].finally_end);
     589          21 :                         if (op_array->try_catch_array[i].catch_op) {
     590           7 :                                 opline->extended_value = ZEND_FAST_CALL_FROM_CATCH;
     591           7 :                                 opline->op2.opline_num = op_array->try_catch_array[i].catch_op;
     592           7 :                                 opline->op1.opline_num = get_next_op_number(op_array);
     593             :                                 /* generate a FAST_CALL to hole CALL_FROM_FINALLY */
     594           7 :                                 opline = get_next_op(op_array);
     595           7 :                                 opline->opcode = ZEND_FAST_CALL;
     596           7 :                                 opline->result_type = IS_TMP_VAR;
     597           7 :                                 opline->result.var = fast_call_var;
     598           7 :                                 SET_UNUSED(opline->op1);
     599           7 :                                 SET_UNUSED(opline->op2);
     600           7 :                                 zend_resolve_fast_call(op_array, start_op + 1, op_array->try_catch_array[i].finally_op - 2);
     601             :                         } else {
     602          14 :                                 zend_resolve_fast_call(op_array, start_op, op_array->try_catch_array[i].finally_op - 2);
     603             :                         }
     604          21 :                         opline->op1.opline_num = op_array->try_catch_array[i].finally_op;
     605             : 
     606             :                         /* generate a sequence of FAST_CALL to upward finally block */
     607          66 :                         while (i > 0) {
     608          24 :                                 i--;
     609          80 :                                 if (op_array->try_catch_array[i].finally_op &&
     610          23 :                                         op_num >= op_array->try_catch_array[i].try_op &&
     611          23 :                                         op_num < op_array->try_catch_array[i].finally_op - 1 &&
     612           5 :                                         (dst_num < op_array->try_catch_array[i].try_op ||
     613           5 :                                          dst_num > op_array->try_catch_array[i].finally_end)) {
     614             : 
     615           5 :                                         opline = get_next_op(op_array);
     616           5 :                                         opline->opcode = ZEND_FAST_CALL;
     617           5 :                                         opline->result_type = IS_TMP_VAR;
     618           5 :                                         opline->result.var = fast_call_var;
     619           5 :                                         SET_UNUSED(opline->op1);
     620           5 :                                         SET_UNUSED(opline->op2);
     621           5 :                                         opline->op1.opline_num = op_array->try_catch_array[i].finally_op;
     622             :                                 }
     623             :                         }
     624             : 
     625             :                         /* Finish the sequence with original opcode */
     626          21 :                         opline = get_next_op(op_array);
     627          21 :                         *opline = op_array->opcodes[op_num];
     628             : 
     629             :                         /* Replace original opcode with jump to this sequence */
     630          21 :                         opline = op_array->opcodes + op_num;
     631          21 :                         opline->opcode = ZEND_JMP;
     632          21 :                         SET_UNUSED(opline->op1);
     633          21 :                         SET_UNUSED(opline->op2);
     634          21 :                         opline->op1.opline_num = start_op;
     635             : 
     636          21 :                         break;
     637             :                 }
     638             :         }
     639         193 : }
     640             : 
     641          64 : static void zend_resolve_finally_ret(zend_op_array *op_array, uint32_t op_num)
     642             : {
     643             :         int i;
     644          64 :         uint32_t catch_op_num = 0, finally_op_num = 0;
     645             : 
     646         228 :         for (i = 0; i < op_array->last_try_catch; i++) {
     647         172 :                 if (op_array->try_catch_array[i].try_op > op_num) {
     648           8 :                         break;
     649             :                 }
     650         164 :                 if (op_num < op_array->try_catch_array[i].finally_op) {
     651          23 :                         finally_op_num = op_array->try_catch_array[i].finally_op;
     652             :                 }
     653         164 :                 if (op_num < op_array->try_catch_array[i].catch_op) {
     654          16 :                         catch_op_num = op_array->try_catch_array[i].catch_op;
     655             :                 }
     656             :         }
     657             : 
     658          72 :         if (finally_op_num && (!catch_op_num || catch_op_num >= finally_op_num)) {
     659             :                 /* in case of unhandled exception return to upward finally block */
     660           8 :                 op_array->opcodes[op_num].extended_value = ZEND_FAST_RET_TO_FINALLY;
     661           8 :                 op_array->opcodes[op_num].op2.opline_num = finally_op_num;
     662          56 :         } else if (catch_op_num) {
     663             :                 /* in case of unhandled exception return to upward catch block */
     664          11 :                 op_array->opcodes[op_num].extended_value = ZEND_FAST_RET_TO_CATCH;
     665          11 :                 op_array->opcodes[op_num].op2.opline_num = catch_op_num;
     666             :         }
     667          64 : }
     668             : 
     669          44 : static void zend_resolve_finally_calls(zend_op_array *op_array)
     670             : {
     671             :         uint32_t i, j;
     672             :         zend_op *opline;
     673             : 
     674         784 :         for (i = 0, j = op_array->last; i < j; i++) {
     675         747 :                 opline = op_array->opcodes + i;
     676         747 :                 switch (opline->opcode) {
     677             :                         case ZEND_RETURN:
     678             :                         case ZEND_RETURN_BY_REF:
     679             :                         case ZEND_GENERATOR_RETURN:
     680          68 :                                 zend_resolve_finally_call(op_array, i, (uint32_t)-1);
     681          68 :                                 break;
     682             :                         case ZEND_BRK:
     683             :                         case ZEND_CONT:
     684             :                         {
     685             :                                 int nest_levels, array_offset;
     686             :                                 zend_brk_cont_element *jmp_to;
     687             : 
     688           8 :                                 nest_levels = Z_LVAL(op_array->literals[opline->op2.constant]);
     689           8 :                                 if ((array_offset = opline->op1.opline_num) != -1) {
     690             :                                         do {
     691           8 :                                                 jmp_to = &op_array->brk_cont_array[array_offset];
     692           8 :                                                 if (nest_levels > 1) {
     693           0 :                                                         array_offset = jmp_to->parent;
     694             :                                                 }
     695           8 :                                         } while (--nest_levels > 0);
     696           8 :                                         zend_resolve_finally_call(op_array, i, opline->opcode == ZEND_BRK ? jmp_to->brk : jmp_to->cont);
     697           6 :                                         break;
     698             :                                 }
     699             :                         }
     700             :                         case ZEND_GOTO:
     701          16 :                                 if (Z_TYPE_P(CT_CONSTANT_EX(op_array, opline->op2.constant)) != IS_LONG) {
     702           8 :                                         uint32_t num = opline->op2.constant;
     703             : 
     704           8 :                                         ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline->op2);
     705           8 :                                         zend_resolve_goto_label(op_array, opline, 1);
     706           8 :                                         opline->op2.constant = num;
     707             :                                 }
     708             :                                 /* break omitted intentionally */
     709             :                         case ZEND_JMP:
     710         124 :                                 zend_resolve_finally_call(op_array, i, opline->op1.opline_num);
     711         119 :                                 break;
     712             :                         case ZEND_FAST_CALL:
     713          68 :                                 zend_resolve_fast_call(op_array, i, i);
     714          68 :                                 break;
     715             :                         case ZEND_FAST_RET:
     716          64 :                                 zend_resolve_finally_ret(op_array, i);
     717             :                                 break;
     718             :                         default:
     719             :                                 break;
     720             :                 }
     721             :         }
     722          37 : }
     723             : 
     724       65320 : ZEND_API int pass_two(zend_op_array *op_array)
     725             : {
     726             :         zend_op *opline, *end;
     727             : 
     728       65320 :         if (!ZEND_USER_CODE(op_array->type)) {
     729           0 :                 return 0;
     730             :         }
     731       65320 :         if (op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) {
     732          44 :                 zend_resolve_finally_calls(op_array);
     733             :         }
     734       65313 :         if (CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO) {
     735           0 :                 zend_update_extended_info(op_array);
     736             :         }
     737       65313 :         if (CG(compiler_options) & ZEND_COMPILE_HANDLE_OP_ARRAY) {
     738       65106 :                 zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_handler, op_array);
     739             :         }
     740             : 
     741       65313 :         if (CG(context).vars_size != op_array->last_var) {
     742       47245 :                 op_array->vars = (zend_string**) erealloc(op_array->vars, sizeof(zend_string*)*op_array->last_var);
     743       47245 :                 CG(context).vars_size = op_array->last_var;
     744             :         }
     745       65313 :         if (CG(context).opcodes_size != op_array->last) {
     746       65155 :                 op_array->opcodes = (zend_op *) erealloc(op_array->opcodes, sizeof(zend_op)*op_array->last);
     747       65155 :                 CG(context).opcodes_size = op_array->last;
     748             :         }
     749       65313 :         if (CG(context).literals_size != op_array->last_literal) {
     750       63664 :                 op_array->literals = (zval*)erealloc(op_array->literals, sizeof(zval) * op_array->last_literal);
     751       63664 :                 CG(context).literals_size = op_array->last_literal;
     752             :         }
     753       65313 :         opline = op_array->opcodes;
     754       65313 :         end = opline + op_array->last;
     755     2344816 :         while (opline < end) {
     756     2214193 :                 if (opline->op1_type == IS_CONST) {
     757      431711 :                         ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline->op1);
     758     1782482 :                 } else if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) {
     759      502340 :                         opline->op1.var = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + opline->op1.var);
     760             :                 }
     761     2214193 :                 if (opline->op2_type == IS_CONST) {
     762      556094 :                         ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline->op2);
     763     1658099 :                 } else if (opline->op2_type & (IS_VAR|IS_TMP_VAR)) {
     764      114835 :                         opline->op2.var = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + opline->op2.var);
     765             :                 }
     766     2214193 :                 if (opline->result_type & (IS_VAR|IS_TMP_VAR)) {
     767      922314 :                         opline->result.var = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + opline->result.var);
     768             :                 }
     769     2214193 :                 switch (opline->opcode) {
     770             :                         case ZEND_DECLARE_ANON_INHERITED_CLASS:
     771           2 :                                 ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op1);
     772             :                                 /* break omitted intentionally */
     773             :                         case ZEND_DECLARE_INHERITED_CLASS:
     774             :                         case ZEND_DECLARE_INHERITED_CLASS_DELAYED:
     775        1295 :                                 opline->extended_value = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + opline->extended_value);
     776        1295 :                                 break;
     777             :                         case ZEND_GOTO:
     778          36 :                                 if (Z_TYPE_P(RT_CONSTANT(op_array, opline->op2)) != IS_LONG) {
     779          15 :                                         zend_resolve_goto_label(op_array, opline, 1);
     780             :                                 }
     781             :                                 /* break omitted intentionally */
     782             :                         case ZEND_JMP:
     783             :                         case ZEND_FAST_CALL:
     784             :                         case ZEND_DECLARE_ANON_CLASS:
     785       60412 :                                 ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op1);
     786       60412 :                                 break;
     787             :                         case ZEND_JMPZNZ:
     788             :                                 /* absolute index to relative offset */
     789           0 :                                 opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, opline->extended_value);
     790             :                                 /* break omitted intentionally */
     791             :                         case ZEND_JMPZ:
     792             :                         case ZEND_JMPNZ:
     793             :                         case ZEND_JMPZ_EX:
     794             :                         case ZEND_JMPNZ_EX:
     795             :                         case ZEND_JMP_SET:
     796             :                         case ZEND_COALESCE:
     797             :                         case ZEND_NEW:
     798             :                         case ZEND_FE_RESET_R:
     799             :                         case ZEND_FE_RESET_RW:
     800             :                         case ZEND_ASSERT_CHECK:
     801      136355 :                                 ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op2);
     802      136355 :                                 break;
     803             :                         case ZEND_FE_FETCH_R:
     804             :                         case ZEND_FE_FETCH_RW:
     805       10066 :                                 opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, opline->extended_value);
     806       10066 :                                 break;
     807             :                         case ZEND_VERIFY_RETURN_TYPE:
     808         144 :                                 if (op_array->fn_flags & ZEND_ACC_GENERATOR) {
     809           9 :                                         MAKE_NOP(opline);
     810             :                                 }
     811         144 :                                 break;
     812             :                         case ZEND_RETURN:
     813             :                         case ZEND_RETURN_BY_REF:
     814      108866 :                                 if (op_array->fn_flags & ZEND_ACC_GENERATOR) {
     815         169 :                                         opline->opcode = ZEND_GENERATOR_RETURN;
     816             :                                 }
     817             :                                 break;
     818             :                 }
     819     2214190 :                 ZEND_VM_SET_OPCODE_HANDLER(opline);
     820     2214190 :                 opline++;
     821             :         }
     822             : 
     823       65310 :         op_array->fn_flags |= ZEND_ACC_DONE_PASS_TWO;
     824       65310 :         return 0;
     825             : }
     826             : 
     827           0 : int pass_two_wrapper(zval *el)
     828             : {
     829           0 :         return pass_two((zend_op_array *) Z_PTR_P(el));
     830             : }
     831             : 
     832           0 : int print_class(zend_class_entry *class_entry)
     833             : {
     834           0 :         printf("Class %s:\n", class_entry->name->val);
     835           0 :         zend_hash_apply(&class_entry->function_table, pass_two_wrapper);
     836           0 :         printf("End of class %s.\n\n", class_entry->name->val);
     837           0 :         return 0;
     838             : }
     839             : 
     840         175 : ZEND_API unary_op_type get_unary_op(int opcode)
     841             : {
     842         175 :         switch (opcode) {
     843             :                 case ZEND_BW_NOT:
     844           1 :                         return (unary_op_type) bitwise_not_function;
     845             :                 case ZEND_BOOL_NOT:
     846         174 :                         return (unary_op_type) boolean_not_function;
     847             :                 default:
     848           0 :                         return (unary_op_type) NULL;
     849             :         }
     850             : }
     851             : 
     852        3472 : ZEND_API binary_op_type get_binary_op(int opcode)
     853             : {
     854        3472 :         switch (opcode) {
     855             :                 case ZEND_ADD:
     856             :                 case ZEND_ASSIGN_ADD:
     857         181 :                         return (binary_op_type) add_function;
     858             :                 case ZEND_SUB:
     859             :                 case ZEND_ASSIGN_SUB:
     860         196 :                         return (binary_op_type) sub_function;
     861             :                 case ZEND_MUL:
     862             :                 case ZEND_ASSIGN_MUL:
     863          73 :                         return (binary_op_type) mul_function;
     864             :                 case ZEND_POW:
     865           8 :                         return (binary_op_type) pow_function;
     866             :                 case ZEND_DIV:
     867             :                 case ZEND_ASSIGN_DIV:
     868          26 :                         return (binary_op_type) div_function;
     869             :                 case ZEND_MOD:
     870             :                 case ZEND_ASSIGN_MOD:
     871           4 :                         return (binary_op_type) mod_function;
     872             :                 case ZEND_SL:
     873             :                 case ZEND_ASSIGN_SL:
     874          32 :                         return (binary_op_type) shift_left_function;
     875             :                 case ZEND_SR:
     876             :                 case ZEND_ASSIGN_SR:
     877           3 :                         return (binary_op_type) shift_right_function;
     878             :                 case ZEND_FAST_CONCAT:
     879             :                 case ZEND_CONCAT:
     880             :                 case ZEND_ASSIGN_CONCAT:
     881        1946 :                         return (binary_op_type) concat_function;
     882             :                 case ZEND_IS_IDENTICAL:
     883           1 :                         return (binary_op_type) is_identical_function;
     884             :                 case ZEND_IS_NOT_IDENTICAL:
     885          19 :                         return (binary_op_type) is_not_identical_function;
     886             :                 case ZEND_IS_EQUAL:
     887          80 :                         return (binary_op_type) is_equal_function;
     888             :                 case ZEND_IS_NOT_EQUAL:
     889         395 :                         return (binary_op_type) is_not_equal_function;
     890             :                 case ZEND_IS_SMALLER:
     891          42 :                         return (binary_op_type) is_smaller_function;
     892             :                 case ZEND_IS_SMALLER_OR_EQUAL:
     893           1 :                         return (binary_op_type) is_smaller_or_equal_function;
     894             :                 case ZEND_SPACESHIP:
     895           0 :                         return (binary_op_type) compare_function;
     896             :                 case ZEND_BW_OR:
     897             :                 case ZEND_ASSIGN_BW_OR:
     898         454 :                         return (binary_op_type) bitwise_or_function;
     899             :                 case ZEND_BW_AND:
     900             :                 case ZEND_ASSIGN_BW_AND:
     901           0 :                         return (binary_op_type) bitwise_and_function;
     902             :                 case ZEND_BW_XOR:
     903             :                 case ZEND_ASSIGN_BW_XOR:
     904           9 :                         return (binary_op_type) bitwise_xor_function;
     905             :                 case ZEND_BOOL_XOR:
     906           2 :                         return (binary_op_type) boolean_xor_function;
     907             :                 default:
     908           0 :                         return (binary_op_type) NULL;
     909             :         }
     910             : }
     911             : 
     912             : /*
     913             :  * Local variables:
     914             :  * tab-width: 4
     915             :  * c-basic-offset: 4
     916             :  * indent-tabs-mode: t
     917             :  * End:
     918             :  */

Generated by: LCOV version 1.10

Generated at Thu, 21 May 2015 19:58:51 +0000 (3 days ago)

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