1/* 2 +----------------------------------------------------------------------+ 3 | Zend Engine | 4 +----------------------------------------------------------------------+ 5 | Copyright (c) 1998-2013 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 32static 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 39static 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 46static 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 51void 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->function_name = NULL; 74 op_array->filename = zend_get_compiled_filename(TSRMLS_C); 75 op_array->doc_comment = NULL; 76 op_array->doc_comment_len = 0; 77 78 op_array->arg_info = NULL; 79 op_array->num_args = 0; 80 op_array->required_num_args = 0; 81 82 op_array->scope = NULL; 83 84 op_array->brk_cont_array = NULL; 85 op_array->try_catch_array = NULL; 86 op_array->last_brk_cont = 0; 87 88 op_array->static_variables = NULL; 89 op_array->last_try_catch = 0; 90 91 op_array->this_var = -1; 92 93 op_array->fn_flags = CG(interactive)?ZEND_ACC_INTERACTIVE:0; 94 95 op_array->early_binding = -1; 96 97 op_array->last_literal = 0; 98 op_array->literals = NULL; 99 100 op_array->run_time_cache = NULL; 101 op_array->last_cache_slot = 0; 102 103 memset(op_array->reserved, 0, ZEND_MAX_RESERVED_RESOURCES * sizeof(void*)); 104 105 zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_ctor_handler, op_array TSRMLS_CC); 106} 107 108ZEND_API void destroy_zend_function(zend_function *function TSRMLS_DC) 109{ 110 switch (function->type) { 111 case ZEND_USER_FUNCTION: 112 destroy_op_array((zend_op_array *) function TSRMLS_CC); 113 break; 114 case ZEND_INTERNAL_FUNCTION: 115 /* do nothing */ 116 break; 117 } 118} 119 120ZEND_API void zend_function_dtor(zend_function *function) 121{ 122 TSRMLS_FETCH(); 123 124 destroy_zend_function(function TSRMLS_CC); 125} 126 127static void zend_cleanup_op_array_data(zend_op_array *op_array) 128{ 129 if (op_array->static_variables) { 130 zend_hash_clean(op_array->static_variables); 131 } 132} 133 134ZEND_API int zend_cleanup_function_data(zend_function *function TSRMLS_DC) 135{ 136 if (function->type == ZEND_USER_FUNCTION) { 137 zend_cleanup_op_array_data((zend_op_array *) function); 138 return ZEND_HASH_APPLY_KEEP; 139 } else { 140 return ZEND_HASH_APPLY_STOP; 141 } 142} 143 144ZEND_API int zend_cleanup_function_data_full(zend_function *function TSRMLS_DC) 145{ 146 if (function->type == ZEND_USER_FUNCTION) { 147 zend_cleanup_op_array_data((zend_op_array *) function); 148 } 149 return 0; 150} 151 152static inline void cleanup_user_class_data(zend_class_entry *ce TSRMLS_DC) 153{ 154 /* Clean all parts that can contain run-time data */ 155 /* Note that only run-time accessed data need to be cleaned up, pre-defined data can 156 not contain objects and thus are not probelmatic */ 157 if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) { 158 zend_hash_apply(&ce->function_table, (apply_func_t) zend_cleanup_function_data_full TSRMLS_CC); 159 } 160 if (ce->static_members_table) { 161 int i; 162 163 for (i = 0; i < ce->default_static_members_count; i++) { 164 if (ce->static_members_table[i]) { 165 zval *p = ce->static_members_table[i]; 166 ce->static_members_table[i] = NULL; 167 zval_ptr_dtor(&p); 168 } 169 } 170 ce->static_members_table = NULL; 171 } 172} 173 174static inline void cleanup_internal_class_data(zend_class_entry *ce TSRMLS_DC) 175{ 176 if (CE_STATIC_MEMBERS(ce)) { 177 int i; 178 179 for (i = 0; i < ce->default_static_members_count; i++) { 180 zval_ptr_dtor(&CE_STATIC_MEMBERS(ce)[i]); 181 } 182 efree(CE_STATIC_MEMBERS(ce)); 183#ifdef ZTS 184 CG(static_members_table)[(zend_intptr_t)(ce->static_members_table)] = NULL; 185#else 186 ce->static_members_table = NULL; 187#endif 188 } 189} 190 191ZEND_API void zend_cleanup_internal_class_data(zend_class_entry *ce TSRMLS_DC) 192{ 193 cleanup_internal_class_data(ce TSRMLS_CC); 194} 195 196ZEND_API int zend_cleanup_user_class_data(zend_class_entry **pce TSRMLS_DC) 197{ 198 if ((*pce)->type == ZEND_USER_CLASS) { 199 cleanup_user_class_data(*pce TSRMLS_CC); 200 return ZEND_HASH_APPLY_KEEP; 201 } else { 202 return ZEND_HASH_APPLY_STOP; 203 } 204} 205 206ZEND_API int zend_cleanup_class_data(zend_class_entry **pce TSRMLS_DC) 207{ 208 if ((*pce)->type == ZEND_USER_CLASS) { 209 cleanup_user_class_data(*pce TSRMLS_CC); 210 } else { 211 cleanup_internal_class_data(*pce TSRMLS_CC); 212 } 213 return 0; 214} 215 216void _destroy_zend_class_traits_info(zend_class_entry *ce) 217{ 218 if (ce->num_traits > 0 && ce->traits) { 219 efree(ce->traits); 220 } 221 222 if (ce->trait_aliases) { 223 size_t i = 0; 224 while (ce->trait_aliases[i]) { 225 if (ce->trait_aliases[i]->trait_method) { 226 if (ce->trait_aliases[i]->trait_method->method_name) { 227 efree((char*)ce->trait_aliases[i]->trait_method->method_name); 228 } 229 if (ce->trait_aliases[i]->trait_method->class_name) { 230 efree((char*)ce->trait_aliases[i]->trait_method->class_name); 231 } 232 efree(ce->trait_aliases[i]->trait_method); 233 } 234 235 if (ce->trait_aliases[i]->alias) { 236 efree((char*)ce->trait_aliases[i]->alias); 237 } 238 239 efree(ce->trait_aliases[i]); 240 i++; 241 } 242 243 efree(ce->trait_aliases); 244 } 245 246 if (ce->trait_precedences) { 247 size_t i = 0; 248 249 while (ce->trait_precedences[i]) { 250 efree((char*)ce->trait_precedences[i]->trait_method->method_name); 251 efree((char*)ce->trait_precedences[i]->trait_method->class_name); 252 efree(ce->trait_precedences[i]->trait_method); 253 254 if (ce->trait_precedences[i]->exclude_from_classes) { 255 efree(ce->trait_precedences[i]->exclude_from_classes); 256 } 257 258 efree(ce->trait_precedences[i]); 259 i++; 260 } 261 efree(ce->trait_precedences); 262 } 263} 264 265ZEND_API void destroy_zend_class(zend_class_entry **pce) 266{ 267 zend_class_entry *ce = *pce; 268 269 if (--ce->refcount > 0) { 270 return; 271 } 272 switch (ce->type) { 273 case ZEND_USER_CLASS: 274 if (ce->default_properties_table) { 275 int i; 276 277 for (i = 0; i < ce->default_properties_count; i++) { 278 if (ce->default_properties_table[i]) { 279 zval_ptr_dtor(&ce->default_properties_table[i]); 280 } 281 } 282 efree(ce->default_properties_table); 283 } 284 if (ce->default_static_members_table) { 285 int i; 286 287 for (i = 0; i < ce->default_static_members_count; i++) { 288 if (ce->default_static_members_table[i]) { 289 zval_ptr_dtor(&ce->default_static_members_table[i]); 290 } 291 } 292 efree(ce->default_static_members_table); 293 } 294 zend_hash_destroy(&ce->properties_info); 295 str_efree(ce->name); 296 zend_hash_destroy(&ce->function_table); 297 zend_hash_destroy(&ce->constants_table); 298 if (ce->num_interfaces > 0 && ce->interfaces) { 299 efree(ce->interfaces); 300 } 301 if (ce->info.user.doc_comment) { 302 efree((char*)ce->info.user.doc_comment); 303 } 304 305 _destroy_zend_class_traits_info(ce); 306 307 efree(ce); 308 break; 309 case ZEND_INTERNAL_CLASS: 310 if (ce->default_properties_table) { 311 int i; 312 313 for (i = 0; i < ce->default_properties_count; i++) { 314 if (ce->default_properties_table[i]) { 315 zval_internal_ptr_dtor(&ce->default_properties_table[i]); 316 } 317 } 318 free(ce->default_properties_table); 319 } 320 if (ce->default_static_members_table) { 321 int i; 322 323 for (i = 0; i < ce->default_static_members_count; i++) { 324 zval_internal_ptr_dtor(&ce->default_static_members_table[i]); 325 } 326 free(ce->default_static_members_table); 327 } 328 zend_hash_destroy(&ce->properties_info); 329 str_free(ce->name); 330 zend_hash_destroy(&ce->function_table); 331 zend_hash_destroy(&ce->constants_table); 332 if (ce->num_interfaces > 0) { 333 free(ce->interfaces); 334 } 335 free(ce); 336 break; 337 } 338} 339 340void zend_class_add_ref(zend_class_entry **ce) 341{ 342 (*ce)->refcount++; 343} 344 345ZEND_API void destroy_op_array(zend_op_array *op_array TSRMLS_DC) 346{ 347 zend_literal *literal = op_array->literals; 348 zend_literal *end; 349 zend_uint i; 350 351 if (op_array->static_variables) { 352 zend_hash_destroy(op_array->static_variables); 353 FREE_HASHTABLE(op_array->static_variables); 354 } 355 356 if (op_array->run_time_cache) { 357 efree(op_array->run_time_cache); 358 } 359 360 if (--(*op_array->refcount)>0) { 361 return; 362 } 363 364 efree(op_array->refcount); 365 366 if (op_array->vars) { 367 i = op_array->last_var; 368 while (i > 0) { 369 i--; 370 str_efree(op_array->vars[i].name); 371 } 372 efree(op_array->vars); 373 } 374 375 if (literal) { 376 end = literal + op_array->last_literal; 377 while (literal < end) { 378 zval_dtor(&literal->constant); 379 literal++; 380 } 381 efree(op_array->literals); 382 } 383 efree(op_array->opcodes); 384 385 if (op_array->function_name) { 386 efree((char*)op_array->function_name); 387 } 388 if (op_array->doc_comment) { 389 efree((char*)op_array->doc_comment); 390 } 391 if (op_array->brk_cont_array) { 392 efree(op_array->brk_cont_array); 393 } 394 if (op_array->try_catch_array) { 395 efree(op_array->try_catch_array); 396 } 397 if (op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO) { 398 zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_dtor_handler, op_array TSRMLS_CC); 399 } 400 if (op_array->arg_info) { 401 for (i=0; i<op_array->num_args; i++) { 402 str_efree(op_array->arg_info[i].name); 403 if (op_array->arg_info[i].class_name) { 404 str_efree(op_array->arg_info[i].class_name); 405 } 406 } 407 efree(op_array->arg_info); 408 } 409} 410 411void init_op(zend_op *op TSRMLS_DC) 412{ 413 memset(op, 0, sizeof(zend_op)); 414 op->lineno = CG(zend_lineno); 415 SET_UNUSED(op->result); 416} 417 418zend_op *get_next_op(zend_op_array *op_array TSRMLS_DC) 419{ 420 zend_uint next_op_num = op_array->last++; 421 zend_op *next_op; 422 423 if (next_op_num >= CG(context).opcodes_size) { 424 if (op_array->fn_flags & ZEND_ACC_INTERACTIVE) { 425 /* we messed up */ 426 zend_printf("Ran out of opcode space!\n" 427 "You should probably consider writing this huge script into a file!\n"); 428 zend_bailout(); 429 } 430 CG(context).opcodes_size *= 4; 431 op_array_alloc_ops(op_array, CG(context).opcodes_size); 432 } 433 434 next_op = &(op_array->opcodes[next_op_num]); 435 436 init_op(next_op TSRMLS_CC); 437 438 return next_op; 439} 440 441int get_next_op_number(zend_op_array *op_array) 442{ 443 return op_array->last; 444} 445 446zend_brk_cont_element *get_next_brk_cont_element(zend_op_array *op_array) 447{ 448 op_array->last_brk_cont++; 449 op_array->brk_cont_array = erealloc(op_array->brk_cont_array, sizeof(zend_brk_cont_element)*op_array->last_brk_cont); 450 return &op_array->brk_cont_array[op_array->last_brk_cont-1]; 451} 452 453static void zend_update_extended_info(zend_op_array *op_array TSRMLS_DC) 454{ 455 zend_op *opline = op_array->opcodes, *end=opline+op_array->last; 456 457 while (opline<end) { 458 if (opline->opcode == ZEND_EXT_STMT) { 459 if (opline+1<end) { 460 if ((opline+1)->opcode == ZEND_EXT_STMT) { 461 opline->opcode = ZEND_NOP; 462 opline++; 463 continue; 464 } 465 if (opline+1<end) { 466 opline->lineno = (opline+1)->lineno; 467 } 468 } else { 469 opline->opcode = ZEND_NOP; 470 } 471 } 472 opline++; 473 } 474} 475 476static void zend_extension_op_array_handler(zend_extension *extension, zend_op_array *op_array TSRMLS_DC) 477{ 478 if (extension->op_array_handler) { 479 extension->op_array_handler(op_array); 480 } 481} 482 483ZEND_API int pass_two(zend_op_array *op_array TSRMLS_DC) 484{ 485 zend_op *opline, *end; 486 487 if (op_array->type!=ZEND_USER_FUNCTION && op_array->type!=ZEND_EVAL_CODE) { 488 return 0; 489 } 490 if (CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO) { 491 zend_update_extended_info(op_array TSRMLS_CC); 492 } 493 if (CG(compiler_options) & ZEND_COMPILE_HANDLE_OP_ARRAY) { 494 zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_handler, op_array TSRMLS_CC); 495 } 496 497 if (!(op_array->fn_flags & ZEND_ACC_INTERACTIVE) && CG(context).vars_size != op_array->last_var) { 498 op_array->vars = (zend_compiled_variable *) erealloc(op_array->vars, sizeof(zend_compiled_variable)*op_array->last_var); 499 CG(context).vars_size = op_array->last_var; 500 } 501 if (!(op_array->fn_flags & ZEND_ACC_INTERACTIVE) && CG(context).opcodes_size != op_array->last) { 502 op_array->opcodes = (zend_op *) erealloc(op_array->opcodes, sizeof(zend_op)*op_array->last); 503 CG(context).opcodes_size = op_array->last; 504 } 505 if (!(op_array->fn_flags & ZEND_ACC_INTERACTIVE) && CG(context).literals_size != op_array->last_literal) { 506 op_array->literals = (zend_literal*)erealloc(op_array->literals, sizeof(zend_literal) * op_array->last_literal); 507 CG(context).literals_size = op_array->last_literal; 508 } 509 510 opline = op_array->opcodes; 511 end = opline + op_array->last; 512 while (opline < end) { 513 if (opline->op1_type == IS_CONST) { 514 opline->op1.zv = &op_array->literals[opline->op1.constant].constant; 515 } 516 if (opline->op2_type == IS_CONST) { 517 opline->op2.zv = &op_array->literals[opline->op2.constant].constant; 518 } 519 switch (opline->opcode) { 520 case ZEND_GOTO: 521 if (Z_TYPE_P(opline->op2.zv) != IS_LONG) { 522 zend_resolve_goto_label(op_array, opline, 1 TSRMLS_CC); 523 } 524 /* break omitted intentionally */ 525 case ZEND_JMP: 526 opline->op1.jmp_addr = &op_array->opcodes[opline->op1.opline_num]; 527 break; 528 case ZEND_JMPZ: 529 case ZEND_JMPNZ: 530 case ZEND_JMPZ_EX: 531 case ZEND_JMPNZ_EX: 532 case ZEND_JMP_SET: 533 case ZEND_JMP_SET_VAR: 534 opline->op2.jmp_addr = &op_array->opcodes[opline->op2.opline_num]; 535 break; 536 } 537 ZEND_VM_SET_OPCODE_HANDLER(opline); 538 opline++; 539 } 540 541 op_array->fn_flags |= ZEND_ACC_DONE_PASS_TWO; 542 return 0; 543} 544 545int print_class(zend_class_entry *class_entry TSRMLS_DC) 546{ 547 printf("Class %s:\n", class_entry->name); 548 zend_hash_apply(&class_entry->function_table, (apply_func_t) pass_two TSRMLS_CC); 549 printf("End of class %s.\n\n", class_entry->name); 550 return 0; 551} 552 553ZEND_API unary_op_type get_unary_op(int opcode) 554{ 555 switch (opcode) { 556 case ZEND_BW_NOT: 557 return (unary_op_type) bitwise_not_function; 558 break; 559 case ZEND_BOOL_NOT: 560 return (unary_op_type) boolean_not_function; 561 break; 562 default: 563 return (unary_op_type) NULL; 564 break; 565 } 566} 567 568ZEND_API binary_op_type get_binary_op(int opcode) 569{ 570 switch (opcode) { 571 case ZEND_ADD: 572 case ZEND_ASSIGN_ADD: 573 return (binary_op_type) add_function; 574 break; 575 case ZEND_SUB: 576 case ZEND_ASSIGN_SUB: 577 return (binary_op_type) sub_function; 578 break; 579 case ZEND_MUL: 580 case ZEND_ASSIGN_MUL: 581 return (binary_op_type) mul_function; 582 break; 583 case ZEND_DIV: 584 case ZEND_ASSIGN_DIV: 585 return (binary_op_type) div_function; 586 break; 587 case ZEND_MOD: 588 case ZEND_ASSIGN_MOD: 589 return (binary_op_type) mod_function; 590 break; 591 case ZEND_SL: 592 case ZEND_ASSIGN_SL: 593 return (binary_op_type) shift_left_function; 594 break; 595 case ZEND_SR: 596 case ZEND_ASSIGN_SR: 597 return (binary_op_type) shift_right_function; 598 break; 599 case ZEND_CONCAT: 600 case ZEND_ASSIGN_CONCAT: 601 return (binary_op_type) concat_function; 602 break; 603 case ZEND_IS_IDENTICAL: 604 return (binary_op_type) is_identical_function; 605 break; 606 case ZEND_IS_NOT_IDENTICAL: 607 return (binary_op_type) is_not_identical_function; 608 break; 609 case ZEND_IS_EQUAL: 610 return (binary_op_type) is_equal_function; 611 break; 612 case ZEND_IS_NOT_EQUAL: 613 return (binary_op_type) is_not_equal_function; 614 break; 615 case ZEND_IS_SMALLER: 616 return (binary_op_type) is_smaller_function; 617 break; 618 case ZEND_IS_SMALLER_OR_EQUAL: 619 return (binary_op_type) is_smaller_or_equal_function; 620 break; 621 case ZEND_BW_OR: 622 case ZEND_ASSIGN_BW_OR: 623 return (binary_op_type) bitwise_or_function; 624 break; 625 case ZEND_BW_AND: 626 case ZEND_ASSIGN_BW_AND: 627 return (binary_op_type) bitwise_and_function; 628 break; 629 case ZEND_BW_XOR: 630 case ZEND_ASSIGN_BW_XOR: 631 return (binary_op_type) bitwise_xor_function; 632 break; 633 case ZEND_BOOL_XOR: 634 return (binary_op_type) boolean_xor_function; 635 break; 636 default: 637 return (binary_op_type) NULL; 638 break; 639 } 640} 641 642/* 643 * Local variables: 644 * tab-width: 4 645 * c-basic-offset: 4 646 * indent-tabs-mode: t 647 * End: 648 */ 649