Back to index

php5  5.3.10
zend_opcode.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | Zend Engine                                                          |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1998-2012 Zend Technologies Ltd. (http://www.zend.com) |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 2.00 of the Zend license,     |
00008    | that is bundled with this package in the file LICENSE, and is        | 
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.zend.com/license/2_00.txt.                                |
00011    | If you did not receive a copy of the Zend license and are unable to  |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@zend.com so we can mail you a copy immediately.              |
00014    +----------------------------------------------------------------------+
00015    | Authors: Andi Gutmans <andi@zend.com>                                |
00016    |          Zeev Suraski <zeev@zend.com>                                |
00017    +----------------------------------------------------------------------+
00018 */
00019 
00020 /* $Id: zend_opcode.c 321634 2012-01-01 13:15:04Z felipe $ */
00021 
00022 #include <stdio.h>
00023 
00024 #include "zend.h"
00025 #include "zend_alloc.h"
00026 #include "zend_compile.h"
00027 #include "zend_extensions.h"
00028 #include "zend_API.h"
00029 
00030 #include "zend_vm.h"
00031 
00032 static void zend_extension_op_array_ctor_handler(zend_extension *extension, zend_op_array *op_array TSRMLS_DC)
00033 {
00034        if (extension->op_array_ctor) {
00035               extension->op_array_ctor(op_array);
00036        }
00037 }
00038 
00039 static void zend_extension_op_array_dtor_handler(zend_extension *extension, zend_op_array *op_array TSRMLS_DC)
00040 {
00041        if (extension->op_array_dtor) {
00042               extension->op_array_dtor(op_array);
00043        }
00044 }
00045 
00046 static void op_array_alloc_ops(zend_op_array *op_array)
00047 {
00048        op_array->opcodes = erealloc(op_array->opcodes, (op_array->size)*sizeof(zend_op));
00049 }
00050 
00051 void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_size TSRMLS_DC)
00052 {
00053        op_array->type = type;
00054 
00055        op_array->backpatch_count = 0;
00056        if (CG(interactive)) {
00057               /* We must avoid a realloc() on the op_array in interactive mode, since pointers to constants
00058                * will become invalid
00059                */
00060               initial_ops_size = 8192;
00061        }
00062 
00063        op_array->refcount = (zend_uint *) emalloc(sizeof(zend_uint));
00064        *op_array->refcount = 1;
00065        op_array->size = initial_ops_size;
00066        op_array->last = 0;
00067        op_array->opcodes = NULL;
00068        op_array_alloc_ops(op_array);
00069 
00070        op_array->size_var = 0; /* FIXME:??? */
00071        op_array->last_var = 0;
00072        op_array->vars = NULL;
00073 
00074        op_array->T = 0;
00075 
00076        op_array->function_name = NULL;
00077        op_array->filename = zend_get_compiled_filename(TSRMLS_C);
00078        op_array->doc_comment = NULL;
00079        op_array->doc_comment_len = 0;
00080 
00081        op_array->arg_info = NULL;
00082        op_array->num_args = 0;
00083        op_array->required_num_args = 0;
00084 
00085        op_array->scope = NULL;
00086 
00087        op_array->brk_cont_array = NULL;
00088        op_array->try_catch_array = NULL;
00089        op_array->last_brk_cont = 0;
00090        op_array->current_brk_cont = -1;
00091 
00092        op_array->static_variables = NULL;
00093        op_array->last_try_catch = 0;
00094 
00095        op_array->return_reference = 0;
00096        op_array->done_pass_two = 0;
00097 
00098        op_array->this_var = -1;
00099 
00100        op_array->start_op = NULL;
00101 
00102        op_array->fn_flags = CG(interactive)?ZEND_ACC_INTERACTIVE:0;
00103 
00104        op_array->early_binding = -1;
00105 
00106        memset(op_array->reserved, 0, ZEND_MAX_RESERVED_RESOURCES * sizeof(void*));
00107 
00108        zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_ctor_handler, op_array TSRMLS_CC);
00109 }
00110 
00111 ZEND_API void destroy_zend_function(zend_function *function TSRMLS_DC)
00112 {
00113        switch (function->type) {
00114               case ZEND_USER_FUNCTION:
00115                      destroy_op_array((zend_op_array *) function TSRMLS_CC);
00116                      break;
00117               case ZEND_INTERNAL_FUNCTION:
00118                      /* do nothing */
00119                      break;
00120        }
00121 }
00122 
00123 ZEND_API void zend_function_dtor(zend_function *function)
00124 {
00125        TSRMLS_FETCH();
00126 
00127        destroy_zend_function(function TSRMLS_CC);
00128 }
00129 
00130 static void zend_cleanup_op_array_data(zend_op_array *op_array)
00131 {
00132        if (op_array->static_variables) {
00133               zend_hash_clean(op_array->static_variables);
00134        }
00135 }
00136 
00137 ZEND_API int zend_cleanup_function_data(zend_function *function TSRMLS_DC)
00138 {
00139        if (function->type == ZEND_USER_FUNCTION) {
00140               zend_cleanup_op_array_data((zend_op_array *) function);
00141               return ZEND_HASH_APPLY_KEEP;
00142        } else {
00143               return ZEND_HASH_APPLY_STOP;
00144        }
00145 }
00146 
00147 ZEND_API int zend_cleanup_function_data_full(zend_function *function TSRMLS_DC)
00148 {
00149        if (function->type == ZEND_USER_FUNCTION) {
00150               zend_cleanup_op_array_data((zend_op_array *) function);
00151        }
00152        return 0;
00153 }
00154 
00155 ZEND_API int zend_cleanup_class_data(zend_class_entry **pce TSRMLS_DC)
00156 {
00157        if ((*pce)->type == ZEND_USER_CLASS) {
00158               /* Clean all parts that can contain run-time data */
00159               /* Note that only run-time accessed data need to be cleaned up, pre-defined data can
00160                  not contain objects and thus are not probelmatic */
00161               zend_hash_apply(&(*pce)->function_table, (apply_func_t) zend_cleanup_function_data_full TSRMLS_CC);
00162               if ((*pce)->static_members) {
00163                      zend_hash_clean((*pce)->static_members);
00164                      (*pce)->static_members = NULL;
00165               }
00166        } else if (CE_STATIC_MEMBERS(*pce)) {
00167               zend_hash_destroy(CE_STATIC_MEMBERS(*pce));
00168               FREE_HASHTABLE(CE_STATIC_MEMBERS(*pce));
00169 #ifdef ZTS
00170               CG(static_members)[(zend_intptr_t)((*pce)->static_members)] = NULL;
00171 #else
00172               (*pce)->static_members = NULL;
00173 #endif
00174        }
00175        return 0;
00176 }
00177 
00178 ZEND_API void destroy_zend_class(zend_class_entry **pce)
00179 {
00180        zend_class_entry *ce = *pce;
00181        
00182        if (--ce->refcount > 0) {
00183               return;
00184        }
00185        switch (ce->type) {
00186               case ZEND_USER_CLASS:
00187                      zend_hash_destroy(&ce->default_properties);
00188                      zend_hash_destroy(&ce->properties_info);
00189                      zend_hash_destroy(&ce->default_static_members);
00190                      efree(ce->name);
00191                      zend_hash_destroy(&ce->function_table);
00192                      zend_hash_destroy(&ce->constants_table);
00193                      if (ce->num_interfaces > 0 && ce->interfaces) {
00194                             efree(ce->interfaces);
00195                      }
00196                      if (ce->doc_comment) {
00197                             efree(ce->doc_comment);
00198                      }
00199                      efree(ce);
00200                      break;
00201               case ZEND_INTERNAL_CLASS:
00202                      zend_hash_destroy(&ce->default_properties);
00203                      zend_hash_destroy(&ce->properties_info);
00204                      zend_hash_destroy(&ce->default_static_members);
00205                      free(ce->name);
00206                      zend_hash_destroy(&ce->function_table);
00207                      zend_hash_destroy(&ce->constants_table);
00208                      if (ce->num_interfaces > 0) {
00209                             free(ce->interfaces);
00210                      }
00211                      if (ce->doc_comment) {
00212                             free(ce->doc_comment);
00213                      }
00214                      free(ce);
00215                      break;
00216        }
00217 }
00218 
00219 void zend_class_add_ref(zend_class_entry **ce)
00220 {
00221        (*ce)->refcount++;
00222 }
00223 
00224 ZEND_API void destroy_op_array(zend_op_array *op_array TSRMLS_DC)
00225 {
00226        zend_op *opline = op_array->opcodes;
00227        zend_op *end = op_array->opcodes+op_array->last;
00228        zend_uint i;
00229 
00230        if (op_array->static_variables) {
00231               zend_hash_destroy(op_array->static_variables);
00232               FREE_HASHTABLE(op_array->static_variables);
00233        }
00234 
00235        if (--(*op_array->refcount)>0) {
00236               return;
00237        }
00238 
00239        efree(op_array->refcount);
00240 
00241        if (op_array->vars) {
00242               i = op_array->last_var;
00243               while (i > 0) {
00244                      i--;
00245                      efree(op_array->vars[i].name);
00246               }
00247               efree(op_array->vars);
00248        }
00249 
00250        while (opline<end) {
00251               if (opline->op1.op_type==IS_CONST) {
00252 #if DEBUG_ZEND>2
00253                      printf("Reducing refcount for %x 1=>0 (destroying)\n", &opline->op1.u.constant);
00254 #endif
00255                      zval_dtor(&opline->op1.u.constant);
00256               }
00257               if (opline->op2.op_type==IS_CONST) {
00258 #if DEBUG_ZEND>2
00259                      printf("Reducing refcount for %x 1=>0 (destroying)\n", &opline->op2.u.constant);
00260 #endif
00261                      zval_dtor(&opline->op2.u.constant);
00262               }
00263               opline++;
00264        }
00265        efree(op_array->opcodes);
00266 
00267        if (op_array->function_name) {
00268               efree(op_array->function_name);
00269        }
00270        if (op_array->doc_comment) {
00271               efree(op_array->doc_comment);
00272        }
00273        if (op_array->brk_cont_array) {
00274               efree(op_array->brk_cont_array);
00275        }
00276        if (op_array->try_catch_array) {
00277               efree(op_array->try_catch_array);
00278        }
00279        if (op_array->done_pass_two) {
00280               zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_dtor_handler, op_array TSRMLS_CC);
00281        }
00282        if (op_array->arg_info) {
00283               for (i=0; i<op_array->num_args; i++) {
00284                      efree((char*)op_array->arg_info[i].name);
00285                      if (op_array->arg_info[i].class_name) {
00286                             efree((char*)op_array->arg_info[i].class_name);
00287                      }
00288               }
00289               efree(op_array->arg_info);
00290        }
00291 }
00292 
00293 void init_op(zend_op *op TSRMLS_DC)
00294 {
00295        memset(op, 0, sizeof(zend_op));
00296        op->lineno = CG(zend_lineno);
00297        SET_UNUSED(op->result);
00298 }
00299 
00300 zend_op *get_next_op(zend_op_array *op_array TSRMLS_DC)
00301 {
00302        zend_uint next_op_num = op_array->last++;
00303        zend_op *next_op;
00304 
00305        if (next_op_num >= op_array->size) {
00306               if (op_array->fn_flags & ZEND_ACC_INTERACTIVE) {
00307                      /* we messed up */
00308                      zend_printf("Ran out of opcode space!\n"
00309                                           "You should probably consider writing this huge script into a file!\n");
00310                      zend_bailout();
00311               }
00312               op_array->size *= 4;
00313               op_array_alloc_ops(op_array);
00314        }
00315        
00316        next_op = &(op_array->opcodes[next_op_num]);
00317        
00318        init_op(next_op TSRMLS_CC);
00319 
00320        return next_op;
00321 }
00322 
00323 int get_next_op_number(zend_op_array *op_array)
00324 {
00325        return op_array->last;
00326 }
00327 
00328 zend_brk_cont_element *get_next_brk_cont_element(zend_op_array *op_array)
00329 {
00330        op_array->last_brk_cont++;
00331        op_array->brk_cont_array = erealloc(op_array->brk_cont_array, sizeof(zend_brk_cont_element)*op_array->last_brk_cont);
00332        return &op_array->brk_cont_array[op_array->last_brk_cont-1];
00333 }
00334 
00335 static void zend_update_extended_info(zend_op_array *op_array TSRMLS_DC)
00336 {
00337        zend_op *opline = op_array->opcodes, *end=opline+op_array->last;
00338 
00339        while (opline<end) {
00340               if (opline->opcode == ZEND_EXT_STMT) {
00341                      if (opline+1<end) {
00342                             if ((opline+1)->opcode == ZEND_EXT_STMT) {
00343                                    opline->opcode = ZEND_NOP;
00344                                    opline++;
00345                                    continue;
00346                             }
00347                             if (opline+1<end) {
00348                                    opline->lineno = (opline+1)->lineno;
00349                             }
00350                      } else {
00351                             opline->opcode = ZEND_NOP;
00352                      }
00353               }
00354               opline++;
00355        }
00356 }
00357 
00358 static void zend_extension_op_array_handler(zend_extension *extension, zend_op_array *op_array TSRMLS_DC)
00359 {
00360        if (extension->op_array_handler) {
00361               extension->op_array_handler(op_array);
00362        }
00363 }
00364 
00365 ZEND_API int pass_two(zend_op_array *op_array TSRMLS_DC)
00366 {
00367        zend_op *opline, *end;
00368 
00369        if (op_array->type!=ZEND_USER_FUNCTION && op_array->type!=ZEND_EVAL_CODE) {
00370               return 0;
00371        }
00372        if (CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO) {
00373               zend_update_extended_info(op_array TSRMLS_CC);
00374        }
00375        if (CG(compiler_options) & ZEND_COMPILE_HANDLE_OP_ARRAY) {
00376               zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_handler, op_array TSRMLS_CC);
00377        }
00378 
00379        if (!(op_array->fn_flags & ZEND_ACC_INTERACTIVE) && op_array->size != op_array->last) {
00380               op_array->opcodes = (zend_op *) erealloc(op_array->opcodes, sizeof(zend_op)*op_array->last);
00381               op_array->size = op_array->last;
00382        }
00383 
00384        opline = op_array->opcodes;
00385        end = opline + op_array->last;
00386        while (opline < end) {
00387               if (opline->op1.op_type == IS_CONST) {
00388                      Z_SET_ISREF(opline->op1.u.constant);
00389                      Z_SET_REFCOUNT(opline->op1.u.constant, 2); /* Make sure is_ref won't be reset */
00390               }
00391               if (opline->op2.op_type == IS_CONST) {
00392                      Z_SET_ISREF(opline->op2.u.constant);
00393                      Z_SET_REFCOUNT(opline->op2.u.constant, 2);
00394               }
00395               switch (opline->opcode) {
00396                      case ZEND_GOTO:
00397                             if (Z_TYPE(opline->op2.u.constant) != IS_LONG) {
00398                                    zend_resolve_goto_label(op_array, opline, 1 TSRMLS_CC);
00399                             }
00400                             /* break omitted intentionally */
00401                      case ZEND_JMP:
00402                             opline->op1.u.jmp_addr = &op_array->opcodes[opline->op1.u.opline_num];
00403                             break;
00404                      case ZEND_JMPZ:
00405                      case ZEND_JMPNZ:
00406                      case ZEND_JMPZ_EX:
00407                      case ZEND_JMPNZ_EX:
00408                      case ZEND_JMP_SET:
00409                             opline->op2.u.jmp_addr = &op_array->opcodes[opline->op2.u.opline_num];
00410                             break;
00411               }
00412               ZEND_VM_SET_OPCODE_HANDLER(opline);
00413               opline++;
00414        }
00415        
00416        op_array->done_pass_two = 1;
00417        return 0;
00418 }
00419 
00420 int print_class(zend_class_entry *class_entry TSRMLS_DC)
00421 {
00422        printf("Class %s:\n", class_entry->name);
00423        zend_hash_apply(&class_entry->function_table, (apply_func_t) pass_two TSRMLS_CC);
00424        printf("End of class %s.\n\n", class_entry->name);
00425        return 0;
00426 }
00427 
00428 ZEND_API unary_op_type get_unary_op(int opcode)
00429 {
00430        switch (opcode) {
00431               case ZEND_BW_NOT:
00432                      return (unary_op_type) bitwise_not_function;
00433                      break;
00434               case ZEND_BOOL_NOT:
00435                      return (unary_op_type) boolean_not_function;
00436                      break;
00437               default:
00438                      return (unary_op_type) NULL;
00439                      break;
00440        }
00441 }
00442 
00443 ZEND_API binary_op_type get_binary_op(int opcode)
00444 {
00445        switch (opcode) {
00446               case ZEND_ADD:
00447               case ZEND_ASSIGN_ADD:
00448                      return (binary_op_type) add_function;
00449                      break;
00450               case ZEND_SUB:
00451               case ZEND_ASSIGN_SUB:
00452                      return (binary_op_type) sub_function;
00453                      break;
00454               case ZEND_MUL:
00455               case ZEND_ASSIGN_MUL:
00456                      return (binary_op_type) mul_function;
00457                      break;
00458               case ZEND_DIV:
00459               case ZEND_ASSIGN_DIV:
00460                      return (binary_op_type) div_function;
00461                      break;
00462               case ZEND_MOD:
00463               case ZEND_ASSIGN_MOD:
00464                      return (binary_op_type) mod_function;
00465                      break;
00466               case ZEND_SL:
00467               case ZEND_ASSIGN_SL:
00468                      return (binary_op_type) shift_left_function;
00469                      break;
00470               case ZEND_SR:
00471               case ZEND_ASSIGN_SR:
00472                      return (binary_op_type) shift_right_function;
00473                      break;
00474               case ZEND_CONCAT:
00475               case ZEND_ASSIGN_CONCAT:
00476                      return (binary_op_type) concat_function;
00477                      break;
00478               case ZEND_IS_IDENTICAL:
00479                      return (binary_op_type) is_identical_function;
00480                      break;
00481               case ZEND_IS_NOT_IDENTICAL:
00482                      return (binary_op_type) is_not_identical_function;
00483                      break;
00484               case ZEND_IS_EQUAL:
00485                      return (binary_op_type) is_equal_function;
00486                      break;
00487               case ZEND_IS_NOT_EQUAL:
00488                      return (binary_op_type) is_not_equal_function;
00489                      break;
00490               case ZEND_IS_SMALLER:
00491                      return (binary_op_type) is_smaller_function;
00492                      break;
00493               case ZEND_IS_SMALLER_OR_EQUAL:
00494                      return (binary_op_type) is_smaller_or_equal_function;
00495                      break;
00496               case ZEND_BW_OR:
00497               case ZEND_ASSIGN_BW_OR:
00498                      return (binary_op_type) bitwise_or_function;
00499                      break;
00500               case ZEND_BW_AND:
00501               case ZEND_ASSIGN_BW_AND:
00502                      return (binary_op_type) bitwise_and_function;
00503                      break;
00504               case ZEND_BW_XOR:
00505               case ZEND_ASSIGN_BW_XOR:
00506                      return (binary_op_type) bitwise_xor_function;
00507                      break;
00508               case ZEND_BOOL_XOR:
00509                      return (binary_op_type) boolean_xor_function;
00510                      break;
00511               default:
00512                      return (binary_op_type) NULL;
00513                      break;
00514        }
00515 }
00516 
00517 /*
00518  * Local variables:
00519  * tab-width: 4
00520  * c-basic-offset: 4
00521  * indent-tabs-mode: t
00522  * End:
00523  */