root/Zend/zend_opcode.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. zend_extension_op_array_ctor_handler
  2. zend_extension_op_array_dtor_handler
  3. op_array_alloc_ops
  4. init_op_array
  5. destroy_zend_function
  6. zend_function_dtor
  7. zend_cleanup_op_array_data
  8. zend_cleanup_function_data
  9. zend_cleanup_function_data_full
  10. cleanup_user_class_data
  11. cleanup_internal_class_data
  12. zend_cleanup_internal_class_data
  13. zend_cleanup_user_class_data
  14. zend_cleanup_class_data
  15. _destroy_zend_class_traits_info
  16. destroy_zend_class
  17. zend_class_add_ref
  18. destroy_op_array
  19. init_op
  20. get_next_op
  21. get_next_op_number
  22. get_next_brk_cont_element
  23. zend_update_extended_info
  24. zend_extension_op_array_handler
  25. zend_check_finally_breakout
  26. zend_adjust_fast_call
  27. zend_resolve_fast_call
  28. zend_resolve_finally_call
  29. zend_resolve_finally_ret
  30. zend_resolve_finally_calls
  31. pass_two
  32. print_class
  33. get_unary_op
  34. get_binary_op

   1 /*
   2    +----------------------------------------------------------------------+
   3    | Zend Engine                                                          |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1998-2016 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 static void zend_extension_op_array_ctor_handler(zend_extension *extension, zend_op_array *op_array TSRMLS_DC)
  33 {
  34         if (extension->op_array_ctor) {
  35                 extension->op_array_ctor(op_array);
  36         }
  37 }
  38 
  39 static void zend_extension_op_array_dtor_handler(zend_extension *extension, zend_op_array *op_array TSRMLS_DC)
  40 {
  41         if (extension->op_array_dtor) {
  42                 extension->op_array_dtor(op_array);
  43         }
  44 }
  45 
  46 static void op_array_alloc_ops(zend_op_array *op_array, zend_uint size)
  47 {
  48         op_array->opcodes = erealloc(op_array->opcodes, size * sizeof(zend_op));
  49 }
  50 
  51 void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_size TSRMLS_DC)
  52 {
  53         op_array->type = type;
  54 
  55         if (CG(interactive)) {
  56                 /* We must avoid a realloc() on the op_array in interactive mode, since pointers to constants
  57                  * will become invalid
  58                  */
  59                 initial_ops_size = INITIAL_INTERACTIVE_OP_ARRAY_SIZE;
  60         }
  61 
  62         op_array->refcount = (zend_uint *) emalloc(sizeof(zend_uint));
  63         *op_array->refcount = 1;
  64         op_array->last = 0;
  65         op_array->opcodes = NULL;
  66         op_array_alloc_ops(op_array, initial_ops_size);
  67 
  68         op_array->last_var = 0;
  69         op_array->vars = NULL;
  70 
  71         op_array->T = 0;
  72 
  73         op_array->nested_calls = 0;
  74         op_array->used_stack = 0;
  75 
  76         op_array->function_name = NULL;
  77         op_array->filename = zend_get_compiled_filename(TSRMLS_C);
  78         op_array->doc_comment = NULL;
  79         op_array->doc_comment_len = 0;
  80 
  81         op_array->arg_info = NULL;
  82         op_array->num_args = 0;
  83         op_array->required_num_args = 0;
  84 
  85         op_array->scope = NULL;
  86 
  87         op_array->brk_cont_array = NULL;
  88         op_array->try_catch_array = NULL;
  89         op_array->last_brk_cont = 0;
  90 
  91         op_array->static_variables = NULL;
  92         op_array->last_try_catch = 0;
  93         op_array->has_finally_block = 0;
  94 
  95         op_array->this_var = -1;
  96 
  97         op_array->fn_flags = CG(interactive)?ZEND_ACC_INTERACTIVE:0;
  98 
  99         op_array->early_binding = -1;
 100 
 101         op_array->last_literal = 0;
 102         op_array->literals = NULL;
 103 
 104         op_array->run_time_cache = NULL;
 105         op_array->last_cache_slot = 0;
 106 
 107         memset(op_array->reserved, 0, ZEND_MAX_RESERVED_RESOURCES * sizeof(void*));
 108 
 109         zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_ctor_handler, op_array TSRMLS_CC);
 110 }
 111 
 112 ZEND_API void destroy_zend_function(zend_function *function TSRMLS_DC)
 113 {
 114         switch (function->type) {
 115                 case ZEND_USER_FUNCTION:
 116                         destroy_op_array((zend_op_array *) function TSRMLS_CC);
 117                         break;
 118                 case ZEND_INTERNAL_FUNCTION:
 119                         /* do nothing */
 120                         break;
 121         }
 122 }
 123 
 124 ZEND_API void zend_function_dtor(zend_function *function)
 125 {
 126         TSRMLS_FETCH();
 127 
 128         destroy_zend_function(function TSRMLS_CC);
 129 }
 130 
 131 static void zend_cleanup_op_array_data(zend_op_array *op_array)
 132 {
 133         if (op_array->static_variables) {
 134                 zend_hash_clean(op_array->static_variables);
 135         }
 136 }
 137 
 138 ZEND_API int zend_cleanup_function_data(zend_function *function TSRMLS_DC)
 139 {
 140         if (function->type == ZEND_USER_FUNCTION) {
 141                 zend_cleanup_op_array_data((zend_op_array *) function);
 142                 return ZEND_HASH_APPLY_KEEP;
 143         } else {
 144                 return ZEND_HASH_APPLY_STOP;
 145         }
 146 }
 147 
 148 ZEND_API int zend_cleanup_function_data_full(zend_function *function TSRMLS_DC)
 149 {
 150         if (function->type == ZEND_USER_FUNCTION) {
 151                 zend_cleanup_op_array_data((zend_op_array *) function);
 152         }
 153         return 0;
 154 }
 155 
 156 static inline void cleanup_user_class_data(zend_class_entry *ce TSRMLS_DC)
 157 {
 158         /* Clean all parts that can contain run-time data */
 159         /* Note that only run-time accessed data need to be cleaned up, pre-defined data can
 160            not contain objects and thus are not probelmatic */
 161         if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) {
 162                 zend_hash_apply(&ce->function_table, (apply_func_t) zend_cleanup_function_data_full TSRMLS_CC);
 163         }
 164         if (ce->static_members_table) {
 165                 zval **static_members = ce->static_members_table;
 166                 int count = ce->default_static_members_count;
 167                 int i;
 168 
 169                 ce->default_static_members_count = 0;
 170                 ce->default_static_members_table = ce->static_members_table = NULL;
 171                 for (i = 0; i < count; i++) {
 172                         zval_ptr_dtor(&static_members[i]);
 173                 }
 174                 efree(static_members);
 175         }
 176 }
 177 
 178 static inline void cleanup_internal_class_data(zend_class_entry *ce TSRMLS_DC)
 179 {
 180         if (CE_STATIC_MEMBERS(ce)) {
 181                 int i;
 182                 
 183                 for (i = 0; i < ce->default_static_members_count; i++) {
 184                         zval_ptr_dtor(&CE_STATIC_MEMBERS(ce)[i]);
 185                 }
 186                 efree(CE_STATIC_MEMBERS(ce));
 187 #ifdef ZTS
 188                 CG(static_members_table)[(zend_intptr_t)(ce->static_members_table)] = NULL;
 189 #else
 190                 ce->static_members_table = NULL;
 191 #endif
 192         }
 193 }
 194 
 195 ZEND_API void zend_cleanup_internal_class_data(zend_class_entry *ce TSRMLS_DC)
 196 {
 197         cleanup_internal_class_data(ce TSRMLS_CC);
 198 }
 199 
 200 ZEND_API int zend_cleanup_user_class_data(zend_class_entry **pce TSRMLS_DC)
 201 {
 202         if ((*pce)->type == ZEND_USER_CLASS) {
 203                 cleanup_user_class_data(*pce TSRMLS_CC);
 204                 return ZEND_HASH_APPLY_KEEP;
 205         } else {
 206                 return ZEND_HASH_APPLY_STOP;
 207         }
 208 }
 209 
 210 ZEND_API int zend_cleanup_class_data(zend_class_entry **pce TSRMLS_DC)
 211 {
 212         if ((*pce)->type == ZEND_USER_CLASS) {
 213                 cleanup_user_class_data(*pce TSRMLS_CC);
 214         } else {
 215                 cleanup_internal_class_data(*pce TSRMLS_CC);
 216         }
 217         return 0;
 218 }
 219 
 220 void _destroy_zend_class_traits_info(zend_class_entry *ce)
 221 {
 222         if (ce->num_traits > 0 && ce->traits) {
 223                 efree(ce->traits);
 224         }
 225         
 226         if (ce->trait_aliases) {
 227                 size_t i = 0;
 228                 while (ce->trait_aliases[i]) {
 229                         if (ce->trait_aliases[i]->trait_method) {
 230                                 if (ce->trait_aliases[i]->trait_method->method_name) {
 231                                         efree((char*)ce->trait_aliases[i]->trait_method->method_name);
 232                                 }
 233                                 if (ce->trait_aliases[i]->trait_method->class_name) {
 234                                         efree((char*)ce->trait_aliases[i]->trait_method->class_name);
 235                                 }
 236                                 efree(ce->trait_aliases[i]->trait_method);
 237                         }
 238                         
 239                         if (ce->trait_aliases[i]->alias) {
 240                                 efree((char*)ce->trait_aliases[i]->alias);
 241                         }
 242                         
 243                         efree(ce->trait_aliases[i]);
 244                         i++;
 245                 }
 246                 
 247                 efree(ce->trait_aliases);
 248         }
 249 
 250         if (ce->trait_precedences) {
 251                 size_t i = 0;
 252                 
 253                 while (ce->trait_precedences[i]) {
 254                         efree((char*)ce->trait_precedences[i]->trait_method->method_name);
 255                         efree((char*)ce->trait_precedences[i]->trait_method->class_name);
 256                         efree(ce->trait_precedences[i]->trait_method);
 257 
 258                         if (ce->trait_precedences[i]->exclude_from_classes) {
 259                                 zend_uint j = 0;
 260                                 zend_trait_precedence *cur_precedence = ce->trait_precedences[i];
 261                                 while (cur_precedence->exclude_from_classes[j]) {
 262                                         efree(cur_precedence->exclude_from_classes[j]);
 263                                         j++;
 264                                 }
 265                                 efree(ce->trait_precedences[i]->exclude_from_classes);
 266                         }
 267                         efree(ce->trait_precedences[i]);
 268                         i++;
 269                 }
 270                 efree(ce->trait_precedences);
 271         }
 272 }
 273 
 274 ZEND_API void destroy_zend_class(zend_class_entry **pce)
 275 {
 276         zend_class_entry *ce = *pce;
 277         
 278         if (--ce->refcount > 0) {
 279                 return;
 280         }
 281         switch (ce->type) {
 282                 case ZEND_USER_CLASS:
 283                         if (ce->default_properties_table) {
 284                                 int i;
 285 
 286                                 for (i = 0; i < ce->default_properties_count; i++) {
 287                                         if (ce->default_properties_table[i]) {
 288                                                 zval_ptr_dtor(&ce->default_properties_table[i]);
 289                                     }
 290                                 }
 291                                 efree(ce->default_properties_table);
 292                         }
 293                         if (ce->default_static_members_table) {
 294                                 int i;
 295 
 296                                 for (i = 0; i < ce->default_static_members_count; i++) {
 297                                         if (ce->default_static_members_table[i]) {
 298                                                 zval_ptr_dtor(&ce->default_static_members_table[i]);
 299                                         }
 300                                 }
 301                                 efree(ce->default_static_members_table);
 302                         }
 303                         zend_hash_destroy(&ce->properties_info);
 304                         str_efree(ce->name);
 305                         zend_hash_destroy(&ce->function_table);
 306                         zend_hash_destroy(&ce->constants_table);
 307                         if (ce->num_interfaces > 0 && ce->interfaces) {
 308                                 efree(ce->interfaces);
 309                         }
 310                         if (ce->info.user.doc_comment) {
 311                                 efree((char*)ce->info.user.doc_comment);
 312                         }
 313                         
 314                         _destroy_zend_class_traits_info(ce);
 315                         
 316                         efree(ce);
 317                         break;
 318                 case ZEND_INTERNAL_CLASS:
 319                         if (ce->default_properties_table) {
 320                                 int i;
 321 
 322                                 for (i = 0; i < ce->default_properties_count; i++) {
 323                                         if (ce->default_properties_table[i]) {
 324                                                 zval_internal_ptr_dtor(&ce->default_properties_table[i]);
 325                                         }
 326                                 }
 327                                 free(ce->default_properties_table);
 328                         }
 329                         if (ce->default_static_members_table) {
 330                                 int i;
 331 
 332                                 for (i = 0; i < ce->default_static_members_count; i++) {
 333                                         zval_internal_ptr_dtor(&ce->default_static_members_table[i]);
 334                                 }
 335                                 free(ce->default_static_members_table);
 336                         }
 337                         zend_hash_destroy(&ce->properties_info);
 338                         str_free(ce->name);
 339                         zend_hash_destroy(&ce->function_table);
 340                         zend_hash_destroy(&ce->constants_table);
 341                         if (ce->num_interfaces > 0) {
 342                                 free(ce->interfaces);
 343                         }
 344                         free(ce);
 345                         break;
 346         }
 347 }
 348 
 349 void zend_class_add_ref(zend_class_entry **ce)
 350 {
 351         (*ce)->refcount++;
 352 }
 353 
 354 ZEND_API void destroy_op_array(zend_op_array *op_array TSRMLS_DC)
 355 {
 356         zend_literal *literal = op_array->literals;
 357         zend_literal *end;
 358         zend_uint i;
 359 
 360         if (op_array->static_variables) {
 361                 zend_hash_destroy(op_array->static_variables);
 362                 FREE_HASHTABLE(op_array->static_variables);
 363         }
 364 
 365         if (op_array->run_time_cache) {
 366                 efree(op_array->run_time_cache);
 367         }
 368 
 369         if (--(*op_array->refcount)>0) {
 370                 return;
 371         }
 372 
 373         efree(op_array->refcount);
 374 
 375         if (op_array->vars) {
 376                 i = op_array->last_var;
 377                 while (i > 0) {
 378                         i--;
 379                         str_efree(op_array->vars[i].name);
 380                 }
 381                 efree(op_array->vars);
 382         }
 383 
 384         if (literal) {
 385                 end = literal + op_array->last_literal;
 386                 while (literal < end) {
 387                         zval_dtor(&literal->constant);
 388                         literal++;
 389                 }
 390                 efree(op_array->literals);
 391         }
 392         efree(op_array->opcodes);
 393 
 394         if (op_array->function_name) {
 395                 efree((char*)op_array->function_name);
 396         }
 397         if (op_array->doc_comment) {
 398                 efree((char*)op_array->doc_comment);
 399         }
 400         if (op_array->brk_cont_array) {
 401                 efree(op_array->brk_cont_array);
 402         }
 403         if (op_array->try_catch_array) {
 404                 efree(op_array->try_catch_array);
 405         }
 406         if (op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO) {
 407                 zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_dtor_handler, op_array TSRMLS_CC);
 408         }
 409         if (op_array->arg_info) {
 410                 for (i=0; i<op_array->num_args; i++) {
 411                         str_efree(op_array->arg_info[i].name);
 412                         if (op_array->arg_info[i].class_name) {
 413                                 str_efree(op_array->arg_info[i].class_name);
 414                         }
 415                 }
 416                 efree(op_array->arg_info);
 417         }
 418 }
 419 
 420 void init_op(zend_op *op TSRMLS_DC)
 421 {
 422         memset(op, 0, sizeof(zend_op));
 423         op->lineno = CG(zend_lineno);
 424         SET_UNUSED(op->result);
 425 }
 426 
 427 zend_op *get_next_op(zend_op_array *op_array TSRMLS_DC)
 428 {
 429         zend_uint next_op_num = op_array->last++;
 430         zend_op *next_op;
 431 
 432         if (next_op_num >= CG(context).opcodes_size) {
 433                 if (op_array->fn_flags & ZEND_ACC_INTERACTIVE) {
 434                         /* we messed up */
 435                         zend_printf("Ran out of opcode space!\n"
 436                                                 "You should probably consider writing this huge script into a file!\n");
 437                         zend_bailout();
 438                 }
 439                 CG(context).opcodes_size *= 4;
 440                 op_array_alloc_ops(op_array, CG(context).opcodes_size);
 441         }
 442         
 443         next_op = &(op_array->opcodes[next_op_num]);
 444         
 445         init_op(next_op TSRMLS_CC);
 446 
 447         return next_op;
 448 }
 449 
 450 int get_next_op_number(zend_op_array *op_array)
 451 {
 452         return op_array->last;
 453 }
 454 
 455 zend_brk_cont_element *get_next_brk_cont_element(zend_op_array *op_array)
 456 {
 457         op_array->last_brk_cont++;
 458         op_array->brk_cont_array = erealloc(op_array->brk_cont_array, sizeof(zend_brk_cont_element)*op_array->last_brk_cont);
 459         return &op_array->brk_cont_array[op_array->last_brk_cont-1];
 460 }
 461 
 462 static void zend_update_extended_info(zend_op_array *op_array TSRMLS_DC)
 463 {
 464         zend_op *opline = op_array->opcodes, *end=opline+op_array->last;
 465 
 466         while (opline<end) {
 467                 if (opline->opcode == ZEND_EXT_STMT) {
 468                         if (opline+1<end) {
 469                                 if ((opline+1)->opcode == ZEND_EXT_STMT) {
 470                                         opline->opcode = ZEND_NOP;
 471                                         opline++;
 472                                         continue;
 473                                 }
 474                                 if (opline+1<end) {
 475                                         opline->lineno = (opline+1)->lineno;
 476                                 }
 477                         } else {
 478                                 opline->opcode = ZEND_NOP;
 479                         }
 480                 }
 481                 opline++;
 482         }
 483 }
 484 
 485 static void zend_extension_op_array_handler(zend_extension *extension, zend_op_array *op_array TSRMLS_DC)
 486 {
 487         if (extension->op_array_handler) {
 488                 extension->op_array_handler(op_array);
 489         }
 490 }
 491 
 492 static void zend_check_finally_breakout(zend_op_array *op_array, zend_uint op_num, zend_uint dst_num TSRMLS_DC)
 493 {
 494         zend_uint i;
 495 
 496         for (i = 0; i < op_array->last_try_catch; i++) {
 497                 if ((op_num < op_array->try_catch_array[i].finally_op ||
 498                                         op_num >= op_array->try_catch_array[i].finally_end)
 499                                 && (dst_num >= op_array->try_catch_array[i].finally_op &&
 500                                          dst_num <= op_array->try_catch_array[i].finally_end)) {
 501                         CG(in_compilation) = 1;
 502                         CG(active_op_array) = op_array;
 503                         CG(zend_lineno) = op_array->opcodes[op_num].lineno;
 504                         zend_error_noreturn(E_COMPILE_ERROR, "jump into a finally block is disallowed");
 505                 } else if ((op_num >= op_array->try_catch_array[i].finally_op 
 506                                         && op_num <= op_array->try_catch_array[i].finally_end)
 507                                 && (dst_num > op_array->try_catch_array[i].finally_end 
 508                                         || dst_num < op_array->try_catch_array[i].finally_op)) {
 509                         CG(in_compilation) = 1;
 510                         CG(active_op_array) = op_array;
 511                         CG(zend_lineno) = op_array->opcodes[op_num].lineno;
 512                         zend_error_noreturn(E_COMPILE_ERROR, "jump out of a finally block is disallowed");
 513                 }
 514         } 
 515 }
 516 
 517 static void zend_adjust_fast_call(zend_op_array *op_array, zend_uint fast_call, zend_uint start, zend_uint end TSRMLS_DC)
 518 {
 519         int i;
 520         zend_uint op_num = 0;
 521 
 522         for (i = 0; i < op_array->last_try_catch; i++) {
 523                 if (op_array->try_catch_array[i].finally_op > start 
 524                                 && op_array->try_catch_array[i].finally_end < end) {
 525                         op_num = op_array->try_catch_array[i].finally_op;
 526                         start = op_array->try_catch_array[i].finally_end;
 527                 }
 528         }
 529 
 530         if (op_num) {
 531                 /* Must be ZEND_FAST_CALL */
 532                 ZEND_ASSERT(op_array->opcodes[op_num - 2].opcode == ZEND_FAST_CALL);
 533                 op_array->opcodes[op_num - 2].extended_value = ZEND_FAST_CALL_FROM_FINALLY;
 534                 op_array->opcodes[op_num - 2].op2.opline_num = fast_call;
 535         }
 536 }
 537 
 538 static void zend_resolve_fast_call(zend_op_array *op_array, zend_uint fast_call, zend_uint op_num TSRMLS_DC)
 539 {
 540         int i;
 541         zend_uint finally_op_num = 0;
 542 
 543         for (i = 0; i < op_array->last_try_catch; i++) {
 544                 if (op_num >= op_array->try_catch_array[i].finally_op
 545                                 && op_num < op_array->try_catch_array[i].finally_end) {
 546                         finally_op_num = op_array->try_catch_array[i].finally_op;
 547                 }
 548         }
 549 
 550         if (finally_op_num) {
 551                 /* Must be ZEND_FAST_CALL */
 552                 ZEND_ASSERT(op_array->opcodes[finally_op_num - 2].opcode == ZEND_FAST_CALL);
 553                 if (op_array->opcodes[fast_call].extended_value == 0) {
 554                         op_array->opcodes[fast_call].extended_value = ZEND_FAST_CALL_FROM_FINALLY;
 555                         op_array->opcodes[fast_call].op2.opline_num = finally_op_num - 2;
 556                 }
 557         } 
 558 }
 559 
 560 static void zend_resolve_finally_call(zend_op_array *op_array, zend_uint op_num, zend_uint dst_num TSRMLS_DC)
 561 {
 562         zend_uint start_op;
 563         zend_op *opline;
 564         zend_uint i = op_array->last_try_catch;
 565 
 566         if (dst_num != (zend_uint)-1) {
 567                 zend_check_finally_breakout(op_array, op_num, dst_num TSRMLS_CC);
 568         }
 569 
 570         /* the backward order is mater */
 571         while (i > 0) {
 572                 i--;
 573                 if (op_array->try_catch_array[i].finally_op &&
 574                     op_num >= op_array->try_catch_array[i].try_op &&
 575                     op_num < op_array->try_catch_array[i].finally_op - 1 &&
 576                     (dst_num < op_array->try_catch_array[i].try_op ||
 577                      dst_num > op_array->try_catch_array[i].finally_end)) {
 578                         /* we have a jump out of try block that needs executing finally */
 579 
 580                         /* generate a FAST_CALL to finally block */
 581                     start_op = get_next_op_number(op_array);
 582 
 583                         opline = get_next_op(op_array TSRMLS_CC);
 584                         opline->opcode = ZEND_FAST_CALL;
 585                         SET_UNUSED(opline->op1);
 586                         SET_UNUSED(opline->op2);
 587                         zend_adjust_fast_call(op_array, start_op,
 588                                         op_array->try_catch_array[i].finally_op,
 589                                         op_array->try_catch_array[i].finally_end TSRMLS_CC);
 590                         if (op_array->try_catch_array[i].catch_op) {
 591                                 opline->extended_value = ZEND_FAST_CALL_FROM_CATCH;
 592                                 opline->op2.opline_num = op_array->try_catch_array[i].catch_op;
 593                                 opline->op1.opline_num = get_next_op_number(op_array);
 594                                 /* generate a FAST_CALL to hole CALL_FROM_FINALLY */
 595                                 opline = get_next_op(op_array TSRMLS_CC);
 596                                 opline->opcode = ZEND_FAST_CALL;
 597                                 SET_UNUSED(opline->op1);
 598                                 SET_UNUSED(opline->op2);
 599                                 zend_resolve_fast_call(op_array, start_op + 1, op_array->try_catch_array[i].finally_op - 2 TSRMLS_CC);
 600                         } else {
 601                                 zend_resolve_fast_call(op_array, start_op, op_array->try_catch_array[i].finally_op - 2 TSRMLS_CC);
 602                         }
 603                         opline->op1.opline_num = op_array->try_catch_array[i].finally_op;
 604 
 605                         /* generate a sequence of FAST_CALL to upward finally block */
 606                         while (i > 0) {
 607                                 i--;
 608                                 if (op_array->try_catch_array[i].finally_op &&
 609                                         op_num >= op_array->try_catch_array[i].try_op &&
 610                                         op_num < op_array->try_catch_array[i].finally_op - 1 &&
 611                                         (dst_num < op_array->try_catch_array[i].try_op ||
 612                                          dst_num > op_array->try_catch_array[i].finally_end)) {
 613 
 614                                         opline = get_next_op(op_array TSRMLS_CC);
 615                                         opline->opcode = ZEND_FAST_CALL;
 616                                         SET_UNUSED(opline->op1);
 617                                         SET_UNUSED(opline->op2);
 618                                         opline->op1.opline_num = op_array->try_catch_array[i].finally_op;
 619                                 }
 620                         }
 621 
 622                         /* Finish the sequence with original opcode */
 623                         opline = get_next_op(op_array TSRMLS_CC);
 624                         *opline = op_array->opcodes[op_num];
 625 
 626                         /* Replace original opcode with jump to this sequence */
 627                         opline = op_array->opcodes + op_num;
 628                         opline->opcode = ZEND_JMP;
 629                         SET_UNUSED(opline->op1);
 630                         SET_UNUSED(opline->op2);
 631                         opline->op1.opline_num = start_op;
 632 
 633                         break;
 634                 }
 635         }       
 636 }
 637 
 638 static void zend_resolve_finally_ret(zend_op_array *op_array, zend_uint op_num TSRMLS_DC)
 639 {
 640         int i;
 641         zend_uint catch_op_num = 0, finally_op_num = 0;
 642 
 643         for (i = 0; i < op_array->last_try_catch; i++) {
 644                 if (op_array->try_catch_array[i].try_op > op_num) {
 645                         break;
 646                 }
 647                 if (op_num < op_array->try_catch_array[i].finally_op) {
 648                         finally_op_num = op_array->try_catch_array[i].finally_op;
 649                 }
 650                 if (op_num < op_array->try_catch_array[i].catch_op) {
 651                         catch_op_num = op_array->try_catch_array[i].catch_op;
 652                 }
 653         }
 654 
 655         if (finally_op_num && (!catch_op_num || catch_op_num >= finally_op_num)) {
 656                 /* in case of unhandled exception return to upward finally block */
 657                 op_array->opcodes[op_num].extended_value = ZEND_FAST_RET_TO_FINALLY;
 658                 op_array->opcodes[op_num].op2.opline_num = finally_op_num;
 659         } else if (catch_op_num) {
 660                 /* in case of unhandled exception return to upward catch block */
 661                 op_array->opcodes[op_num].extended_value = ZEND_FAST_RET_TO_CATCH;
 662                 op_array->opcodes[op_num].op2.opline_num = catch_op_num;
 663         }
 664 }
 665 
 666 static void zend_resolve_finally_calls(zend_op_array *op_array TSRMLS_DC)
 667 {
 668         zend_uint i, j;
 669         zend_op *opline;
 670 
 671         for (i = 0, j = op_array->last; i < j; i++) {
 672                 opline = op_array->opcodes + i;
 673                 switch (opline->opcode) {
 674                         case ZEND_RETURN:
 675                         case ZEND_RETURN_BY_REF:
 676                         case ZEND_GENERATOR_RETURN:
 677                                 zend_resolve_finally_call(op_array, i, (zend_uint)-1 TSRMLS_CC);
 678                                 break;
 679                         case ZEND_BRK:
 680                         case ZEND_CONT:
 681                         {
 682                                 int nest_levels, array_offset;
 683                                 zend_brk_cont_element *jmp_to;
 684 
 685                                 nest_levels = Z_LVAL(op_array->literals[opline->op2.constant].constant);
 686                                 if ((array_offset = opline->op1.opline_num) != -1) {
 687                                         do {
 688                                                 jmp_to = &op_array->brk_cont_array[array_offset];
 689                                                 if (nest_levels > 1) {
 690                                                         array_offset = jmp_to->parent;
 691                                                 }
 692                                         } while (--nest_levels > 0);
 693                                         zend_resolve_finally_call(op_array, i, opline->opcode == ZEND_BRK ? jmp_to->brk : jmp_to->cont TSRMLS_CC);
 694                                         break;
 695                                 }
 696                         }
 697                         case ZEND_GOTO:
 698                                 if (Z_TYPE(op_array->literals[opline->op2.constant].constant) != IS_LONG) {
 699                                         zend_uint num = opline->op2.constant;
 700                                         opline->op2.zv = &op_array->literals[opline->op2.constant].constant;
 701                                         zend_resolve_goto_label(op_array, opline, 1 TSRMLS_CC);
 702                                         opline->op2.constant = num;                                     
 703                                 }
 704                                 /* break omitted intentionally */
 705                         case ZEND_JMP:
 706                                 zend_resolve_finally_call(op_array, i, opline->op1.opline_num TSRMLS_CC);
 707                                 break;
 708                         case ZEND_FAST_CALL:
 709                                 zend_resolve_fast_call(op_array, i, i TSRMLS_CC);
 710                                 break;
 711                         case ZEND_FAST_RET:
 712                                 zend_resolve_finally_ret(op_array, i TSRMLS_CC);
 713                                 break;
 714                         default:
 715                                 break;
 716                 }
 717         }
 718 }
 719 
 720 ZEND_API int pass_two(zend_op_array *op_array TSRMLS_DC)
 721 {
 722         zend_op *opline, *end;
 723 
 724         if (op_array->type!=ZEND_USER_FUNCTION && op_array->type!=ZEND_EVAL_CODE) {
 725                 return 0;
 726         }
 727         if (op_array->has_finally_block) {
 728                 zend_resolve_finally_calls(op_array TSRMLS_CC);
 729         }
 730         if (CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO) {
 731                 zend_update_extended_info(op_array TSRMLS_CC);
 732         }
 733         if (CG(compiler_options) & ZEND_COMPILE_HANDLE_OP_ARRAY) {
 734                 zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_handler, op_array TSRMLS_CC);
 735         }
 736 
 737         if (!(op_array->fn_flags & ZEND_ACC_INTERACTIVE) && CG(context).vars_size != op_array->last_var) {
 738                 op_array->vars = (zend_compiled_variable *) erealloc(op_array->vars, sizeof(zend_compiled_variable)*op_array->last_var);
 739                 CG(context).vars_size = op_array->last_var;
 740         }
 741         if (!(op_array->fn_flags & ZEND_ACC_INTERACTIVE) && CG(context).opcodes_size != op_array->last) {
 742                 op_array->opcodes = (zend_op *) erealloc(op_array->opcodes, sizeof(zend_op)*op_array->last);
 743                 CG(context).opcodes_size = op_array->last;
 744         }
 745         if (!(op_array->fn_flags & ZEND_ACC_INTERACTIVE) && CG(context).literals_size != op_array->last_literal) {
 746                 op_array->literals = (zend_literal*)erealloc(op_array->literals, sizeof(zend_literal) * op_array->last_literal);
 747                 CG(context).literals_size = op_array->last_literal;
 748         }
 749 
 750         opline = op_array->opcodes;
 751         end = opline + op_array->last;
 752         while (opline < end) {
 753                 if (opline->op1_type == IS_CONST) {
 754                         opline->op1.zv = &op_array->literals[opline->op1.constant].constant;
 755                 }
 756                 if (opline->op2_type == IS_CONST) {
 757                         opline->op2.zv = &op_array->literals[opline->op2.constant].constant;
 758                 }
 759                 switch (opline->opcode) {
 760                         case ZEND_GOTO:
 761                                 if (Z_TYPE_P(opline->op2.zv) != IS_LONG) {
 762                                         zend_resolve_goto_label(op_array, opline, 1 TSRMLS_CC);
 763                                 }
 764                                 /* break omitted intentionally */
 765                         case ZEND_JMP:
 766                         case ZEND_FAST_CALL:
 767                                 opline->op1.jmp_addr = &op_array->opcodes[opline->op1.opline_num];
 768                                 break;
 769                         case ZEND_JMPZ:
 770                         case ZEND_JMPNZ:
 771                         case ZEND_JMPZ_EX:
 772                         case ZEND_JMPNZ_EX:
 773                         case ZEND_JMP_SET:
 774                         case ZEND_JMP_SET_VAR:
 775                                 opline->op2.jmp_addr = &op_array->opcodes[opline->op2.opline_num];
 776                                 break;
 777                         case ZEND_RETURN:
 778                         case ZEND_RETURN_BY_REF:
 779                                 if (op_array->fn_flags & ZEND_ACC_GENERATOR) {
 780                                         if (opline->op1_type != IS_CONST || Z_TYPE_P(opline->op1.zv) != IS_NULL) {
 781                                                 CG(zend_lineno) = opline->lineno;
 782                                                 zend_error_noreturn(E_COMPILE_ERROR, "Generators cannot return values using \"return\"");
 783                                         }
 784 
 785                                         opline->opcode = ZEND_GENERATOR_RETURN;
 786                                 }
 787                                 break;
 788                 }
 789                 ZEND_VM_SET_OPCODE_HANDLER(opline);
 790                 opline++;
 791         }
 792 
 793         op_array->fn_flags |= ZEND_ACC_DONE_PASS_TWO;
 794         return 0;
 795 }
 796 
 797 int print_class(zend_class_entry *class_entry TSRMLS_DC)
 798 {
 799         printf("Class %s:\n", class_entry->name);
 800         zend_hash_apply(&class_entry->function_table, (apply_func_t) pass_two TSRMLS_CC);
 801         printf("End of class %s.\n\n", class_entry->name);
 802         return 0;
 803 }
 804 
 805 ZEND_API unary_op_type get_unary_op(int opcode)
 806 {
 807         switch (opcode) {
 808                 case ZEND_BW_NOT:
 809                         return (unary_op_type) bitwise_not_function;
 810                         break;
 811                 case ZEND_BOOL_NOT:
 812                         return (unary_op_type) boolean_not_function;
 813                         break;
 814                 default:
 815                         return (unary_op_type) NULL;
 816                         break;
 817         }
 818 }
 819 
 820 ZEND_API binary_op_type get_binary_op(int opcode)
 821 {
 822         switch (opcode) {
 823                 case ZEND_ADD:
 824                 case ZEND_ASSIGN_ADD:
 825                         return (binary_op_type) add_function;
 826                         break;
 827                 case ZEND_SUB:
 828                 case ZEND_ASSIGN_SUB:
 829                         return (binary_op_type) sub_function;
 830                         break;
 831                 case ZEND_MUL:
 832                 case ZEND_ASSIGN_MUL:
 833                         return (binary_op_type) mul_function;
 834                         break;
 835                 case ZEND_POW:
 836                         return (binary_op_type) pow_function;
 837                         break;
 838                 case ZEND_DIV:
 839                 case ZEND_ASSIGN_DIV:
 840                         return (binary_op_type) div_function;
 841                         break;
 842                 case ZEND_MOD:
 843                 case ZEND_ASSIGN_MOD:
 844                         return (binary_op_type) mod_function;
 845                         break;
 846                 case ZEND_SL:
 847                 case ZEND_ASSIGN_SL:
 848                         return (binary_op_type) shift_left_function;
 849                         break;
 850                 case ZEND_SR:
 851                 case ZEND_ASSIGN_SR:
 852                         return (binary_op_type) shift_right_function;
 853                         break;
 854                 case ZEND_CONCAT:
 855                 case ZEND_ASSIGN_CONCAT:
 856                         return (binary_op_type) concat_function;
 857                         break;
 858                 case ZEND_IS_IDENTICAL:
 859                         return (binary_op_type) is_identical_function;
 860                         break;
 861                 case ZEND_IS_NOT_IDENTICAL:
 862                         return (binary_op_type) is_not_identical_function;
 863                         break;
 864                 case ZEND_IS_EQUAL:
 865                         return (binary_op_type) is_equal_function;
 866                         break;
 867                 case ZEND_IS_NOT_EQUAL:
 868                         return (binary_op_type) is_not_equal_function;
 869                         break;
 870                 case ZEND_IS_SMALLER:
 871                         return (binary_op_type) is_smaller_function;
 872                         break;
 873                 case ZEND_IS_SMALLER_OR_EQUAL:
 874                         return (binary_op_type) is_smaller_or_equal_function;
 875                         break;
 876                 case ZEND_BW_OR:
 877                 case ZEND_ASSIGN_BW_OR:
 878                         return (binary_op_type) bitwise_or_function;
 879                         break;
 880                 case ZEND_BW_AND:
 881                 case ZEND_ASSIGN_BW_AND:
 882                         return (binary_op_type) bitwise_and_function;
 883                         break;
 884                 case ZEND_BW_XOR:
 885                 case ZEND_ASSIGN_BW_XOR:
 886                         return (binary_op_type) bitwise_xor_function;
 887                         break;
 888                 case ZEND_BOOL_XOR:
 889                         return (binary_op_type) boolean_xor_function;
 890                         break;
 891                 default:
 892                         return (binary_op_type) NULL;
 893                         break;
 894         }
 895 }
 896 
 897 /*
 898  * Local variables:
 899  * tab-width: 4
 900  * c-basic-offset: 4
 901  * indent-tabs-mode: t
 902  * End:
 903  */

/* [<][>][^][v][top][bottom][index][help] */