Annotation of embedaddon/php/Zend/zend_opcode.c, revision 1.1

1.1     ! misho       1: /*
        !             2:    +----------------------------------------------------------------------+
        !             3:    | Zend Engine                                                          |
        !             4:    +----------------------------------------------------------------------+
        !             5:    | Copyright (c) 1998-2012 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: zend_opcode.c 321634 2012-01-01 13:15:04Z felipe $ */
        !            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)
        !            47: {
        !            48:        op_array->opcodes = erealloc(op_array->opcodes, (op_array->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:        op_array->backpatch_count = 0;
        !            56:        if (CG(interactive)) {
        !            57:                /* We must avoid a realloc() on the op_array in interactive mode, since pointers to constants
        !            58:                 * will become invalid
        !            59:                 */
        !            60:                initial_ops_size = 8192;
        !            61:        }
        !            62: 
        !            63:        op_array->refcount = (zend_uint *) emalloc(sizeof(zend_uint));
        !            64:        *op_array->refcount = 1;
        !            65:        op_array->size = initial_ops_size;
        !            66:        op_array->last = 0;
        !            67:        op_array->opcodes = NULL;
        !            68:        op_array_alloc_ops(op_array);
        !            69: 
        !            70:        op_array->size_var = 0; /* FIXME:??? */
        !            71:        op_array->last_var = 0;
        !            72:        op_array->vars = NULL;
        !            73: 
        !            74:        op_array->T = 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:        op_array->current_brk_cont = -1;
        !            91: 
        !            92:        op_array->static_variables = NULL;
        !            93:        op_array->last_try_catch = 0;
        !            94: 
        !            95:        op_array->return_reference = 0;
        !            96:        op_array->done_pass_two = 0;
        !            97: 
        !            98:        op_array->this_var = -1;
        !            99: 
        !           100:        op_array->start_op = NULL;
        !           101: 
        !           102:        op_array->fn_flags = CG(interactive)?ZEND_ACC_INTERACTIVE:0;
        !           103: 
        !           104:        op_array->early_binding = -1;
        !           105: 
        !           106:        memset(op_array->reserved, 0, ZEND_MAX_RESERVED_RESOURCES * sizeof(void*));
        !           107: 
        !           108:        zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_ctor_handler, op_array TSRMLS_CC);
        !           109: }
        !           110: 
        !           111: ZEND_API void destroy_zend_function(zend_function *function TSRMLS_DC)
        !           112: {
        !           113:        switch (function->type) {
        !           114:                case ZEND_USER_FUNCTION:
        !           115:                        destroy_op_array((zend_op_array *) function TSRMLS_CC);
        !           116:                        break;
        !           117:                case ZEND_INTERNAL_FUNCTION:
        !           118:                        /* do nothing */
        !           119:                        break;
        !           120:        }
        !           121: }
        !           122: 
        !           123: ZEND_API void zend_function_dtor(zend_function *function)
        !           124: {
        !           125:        TSRMLS_FETCH();
        !           126: 
        !           127:        destroy_zend_function(function TSRMLS_CC);
        !           128: }
        !           129: 
        !           130: static void zend_cleanup_op_array_data(zend_op_array *op_array)
        !           131: {
        !           132:        if (op_array->static_variables) {
        !           133:                zend_hash_clean(op_array->static_variables);
        !           134:        }
        !           135: }
        !           136: 
        !           137: ZEND_API int zend_cleanup_function_data(zend_function *function TSRMLS_DC)
        !           138: {
        !           139:        if (function->type == ZEND_USER_FUNCTION) {
        !           140:                zend_cleanup_op_array_data((zend_op_array *) function);
        !           141:                return ZEND_HASH_APPLY_KEEP;
        !           142:        } else {
        !           143:                return ZEND_HASH_APPLY_STOP;
        !           144:        }
        !           145: }
        !           146: 
        !           147: ZEND_API int zend_cleanup_function_data_full(zend_function *function TSRMLS_DC)
        !           148: {
        !           149:        if (function->type == ZEND_USER_FUNCTION) {
        !           150:                zend_cleanup_op_array_data((zend_op_array *) function);
        !           151:        }
        !           152:        return 0;
        !           153: }
        !           154: 
        !           155: ZEND_API int zend_cleanup_class_data(zend_class_entry **pce TSRMLS_DC)
        !           156: {
        !           157:        if ((*pce)->type == ZEND_USER_CLASS) {
        !           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:                zend_hash_apply(&(*pce)->function_table, (apply_func_t) zend_cleanup_function_data_full TSRMLS_CC);
        !           162:                if ((*pce)->static_members) {
        !           163:                        zend_hash_clean((*pce)->static_members);
        !           164:                        (*pce)->static_members = NULL;
        !           165:                }
        !           166:        } else if (CE_STATIC_MEMBERS(*pce)) {
        !           167:                zend_hash_destroy(CE_STATIC_MEMBERS(*pce));
        !           168:                FREE_HASHTABLE(CE_STATIC_MEMBERS(*pce));
        !           169: #ifdef ZTS
        !           170:                CG(static_members)[(zend_intptr_t)((*pce)->static_members)] = NULL;
        !           171: #else
        !           172:                (*pce)->static_members = NULL;
        !           173: #endif
        !           174:        }
        !           175:        return 0;
        !           176: }
        !           177: 
        !           178: ZEND_API void destroy_zend_class(zend_class_entry **pce)
        !           179: {
        !           180:        zend_class_entry *ce = *pce;
        !           181:        
        !           182:        if (--ce->refcount > 0) {
        !           183:                return;
        !           184:        }
        !           185:        switch (ce->type) {
        !           186:                case ZEND_USER_CLASS:
        !           187:                        zend_hash_destroy(&ce->default_properties);
        !           188:                        zend_hash_destroy(&ce->properties_info);
        !           189:                        zend_hash_destroy(&ce->default_static_members);
        !           190:                        efree(ce->name);
        !           191:                        zend_hash_destroy(&ce->function_table);
        !           192:                        zend_hash_destroy(&ce->constants_table);
        !           193:                        if (ce->num_interfaces > 0 && ce->interfaces) {
        !           194:                                efree(ce->interfaces);
        !           195:                        }
        !           196:                        if (ce->doc_comment) {
        !           197:                                efree(ce->doc_comment);
        !           198:                        }
        !           199:                        efree(ce);
        !           200:                        break;
        !           201:                case ZEND_INTERNAL_CLASS:
        !           202:                        zend_hash_destroy(&ce->default_properties);
        !           203:                        zend_hash_destroy(&ce->properties_info);
        !           204:                        zend_hash_destroy(&ce->default_static_members);
        !           205:                        free(ce->name);
        !           206:                        zend_hash_destroy(&ce->function_table);
        !           207:                        zend_hash_destroy(&ce->constants_table);
        !           208:                        if (ce->num_interfaces > 0) {
        !           209:                                free(ce->interfaces);
        !           210:                        }
        !           211:                        if (ce->doc_comment) {
        !           212:                                free(ce->doc_comment);
        !           213:                        }
        !           214:                        free(ce);
        !           215:                        break;
        !           216:        }
        !           217: }
        !           218: 
        !           219: void zend_class_add_ref(zend_class_entry **ce)
        !           220: {
        !           221:        (*ce)->refcount++;
        !           222: }
        !           223: 
        !           224: ZEND_API void destroy_op_array(zend_op_array *op_array TSRMLS_DC)
        !           225: {
        !           226:        zend_op *opline = op_array->opcodes;
        !           227:        zend_op *end = op_array->opcodes+op_array->last;
        !           228:        zend_uint i;
        !           229: 
        !           230:        if (op_array->static_variables) {
        !           231:                zend_hash_destroy(op_array->static_variables);
        !           232:                FREE_HASHTABLE(op_array->static_variables);
        !           233:        }
        !           234: 
        !           235:        if (--(*op_array->refcount)>0) {
        !           236:                return;
        !           237:        }
        !           238: 
        !           239:        efree(op_array->refcount);
        !           240: 
        !           241:        if (op_array->vars) {
        !           242:                i = op_array->last_var;
        !           243:                while (i > 0) {
        !           244:                        i--;
        !           245:                        efree(op_array->vars[i].name);
        !           246:                }
        !           247:                efree(op_array->vars);
        !           248:        }
        !           249: 
        !           250:        while (opline<end) {
        !           251:                if (opline->op1.op_type==IS_CONST) {
        !           252: #if DEBUG_ZEND>2
        !           253:                        printf("Reducing refcount for %x 1=>0 (destroying)\n", &opline->op1.u.constant);
        !           254: #endif
        !           255:                        zval_dtor(&opline->op1.u.constant);
        !           256:                }
        !           257:                if (opline->op2.op_type==IS_CONST) {
        !           258: #if DEBUG_ZEND>2
        !           259:                        printf("Reducing refcount for %x 1=>0 (destroying)\n", &opline->op2.u.constant);
        !           260: #endif
        !           261:                        zval_dtor(&opline->op2.u.constant);
        !           262:                }
        !           263:                opline++;
        !           264:        }
        !           265:        efree(op_array->opcodes);
        !           266: 
        !           267:        if (op_array->function_name) {
        !           268:                efree(op_array->function_name);
        !           269:        }
        !           270:        if (op_array->doc_comment) {
        !           271:                efree(op_array->doc_comment);
        !           272:        }
        !           273:        if (op_array->brk_cont_array) {
        !           274:                efree(op_array->brk_cont_array);
        !           275:        }
        !           276:        if (op_array->try_catch_array) {
        !           277:                efree(op_array->try_catch_array);
        !           278:        }
        !           279:        if (op_array->done_pass_two) {
        !           280:                zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_dtor_handler, op_array TSRMLS_CC);
        !           281:        }
        !           282:        if (op_array->arg_info) {
        !           283:                for (i=0; i<op_array->num_args; i++) {
        !           284:                        efree((char*)op_array->arg_info[i].name);
        !           285:                        if (op_array->arg_info[i].class_name) {
        !           286:                                efree((char*)op_array->arg_info[i].class_name);
        !           287:                        }
        !           288:                }
        !           289:                efree(op_array->arg_info);
        !           290:        }
        !           291: }
        !           292: 
        !           293: void init_op(zend_op *op TSRMLS_DC)
        !           294: {
        !           295:        memset(op, 0, sizeof(zend_op));
        !           296:        op->lineno = CG(zend_lineno);
        !           297:        SET_UNUSED(op->result);
        !           298: }
        !           299: 
        !           300: zend_op *get_next_op(zend_op_array *op_array TSRMLS_DC)
        !           301: {
        !           302:        zend_uint next_op_num = op_array->last++;
        !           303:        zend_op *next_op;
        !           304: 
        !           305:        if (next_op_num >= op_array->size) {
        !           306:                if (op_array->fn_flags & ZEND_ACC_INTERACTIVE) {
        !           307:                        /* we messed up */
        !           308:                        zend_printf("Ran out of opcode space!\n"
        !           309:                                                "You should probably consider writing this huge script into a file!\n");
        !           310:                        zend_bailout();
        !           311:                }
        !           312:                op_array->size *= 4;
        !           313:                op_array_alloc_ops(op_array);
        !           314:        }
        !           315:        
        !           316:        next_op = &(op_array->opcodes[next_op_num]);
        !           317:        
        !           318:        init_op(next_op TSRMLS_CC);
        !           319: 
        !           320:        return next_op;
        !           321: }
        !           322: 
        !           323: int get_next_op_number(zend_op_array *op_array)
        !           324: {
        !           325:        return op_array->last;
        !           326: }
        !           327: 
        !           328: zend_brk_cont_element *get_next_brk_cont_element(zend_op_array *op_array)
        !           329: {
        !           330:        op_array->last_brk_cont++;
        !           331:        op_array->brk_cont_array = erealloc(op_array->brk_cont_array, sizeof(zend_brk_cont_element)*op_array->last_brk_cont);
        !           332:        return &op_array->brk_cont_array[op_array->last_brk_cont-1];
        !           333: }
        !           334: 
        !           335: static void zend_update_extended_info(zend_op_array *op_array TSRMLS_DC)
        !           336: {
        !           337:        zend_op *opline = op_array->opcodes, *end=opline+op_array->last;
        !           338: 
        !           339:        while (opline<end) {
        !           340:                if (opline->opcode == ZEND_EXT_STMT) {
        !           341:                        if (opline+1<end) {
        !           342:                                if ((opline+1)->opcode == ZEND_EXT_STMT) {
        !           343:                                        opline->opcode = ZEND_NOP;
        !           344:                                        opline++;
        !           345:                                        continue;
        !           346:                                }
        !           347:                                if (opline+1<end) {
        !           348:                                        opline->lineno = (opline+1)->lineno;
        !           349:                                }
        !           350:                        } else {
        !           351:                                opline->opcode = ZEND_NOP;
        !           352:                        }
        !           353:                }
        !           354:                opline++;
        !           355:        }
        !           356: }
        !           357: 
        !           358: static void zend_extension_op_array_handler(zend_extension *extension, zend_op_array *op_array TSRMLS_DC)
        !           359: {
        !           360:        if (extension->op_array_handler) {
        !           361:                extension->op_array_handler(op_array);
        !           362:        }
        !           363: }
        !           364: 
        !           365: ZEND_API int pass_two(zend_op_array *op_array TSRMLS_DC)
        !           366: {
        !           367:        zend_op *opline, *end;
        !           368: 
        !           369:        if (op_array->type!=ZEND_USER_FUNCTION && op_array->type!=ZEND_EVAL_CODE) {
        !           370:                return 0;
        !           371:        }
        !           372:        if (CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO) {
        !           373:                zend_update_extended_info(op_array TSRMLS_CC);
        !           374:        }
        !           375:        if (CG(compiler_options) & ZEND_COMPILE_HANDLE_OP_ARRAY) {
        !           376:                zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_handler, op_array TSRMLS_CC);
        !           377:        }
        !           378: 
        !           379:        if (!(op_array->fn_flags & ZEND_ACC_INTERACTIVE) && op_array->size != op_array->last) {
        !           380:                op_array->opcodes = (zend_op *) erealloc(op_array->opcodes, sizeof(zend_op)*op_array->last);
        !           381:                op_array->size = op_array->last;
        !           382:        }
        !           383: 
        !           384:        opline = op_array->opcodes;
        !           385:        end = opline + op_array->last;
        !           386:        while (opline < end) {
        !           387:                if (opline->op1.op_type == IS_CONST) {
        !           388:                        Z_SET_ISREF(opline->op1.u.constant);
        !           389:                        Z_SET_REFCOUNT(opline->op1.u.constant, 2); /* Make sure is_ref won't be reset */
        !           390:                }
        !           391:                if (opline->op2.op_type == IS_CONST) {
        !           392:                        Z_SET_ISREF(opline->op2.u.constant);
        !           393:                        Z_SET_REFCOUNT(opline->op2.u.constant, 2);
        !           394:                }
        !           395:                switch (opline->opcode) {
        !           396:                        case ZEND_GOTO:
        !           397:                                if (Z_TYPE(opline->op2.u.constant) != IS_LONG) {
        !           398:                                        zend_resolve_goto_label(op_array, opline, 1 TSRMLS_CC);
        !           399:                                }
        !           400:                                /* break omitted intentionally */
        !           401:                        case ZEND_JMP:
        !           402:                                opline->op1.u.jmp_addr = &op_array->opcodes[opline->op1.u.opline_num];
        !           403:                                break;
        !           404:                        case ZEND_JMPZ:
        !           405:                        case ZEND_JMPNZ:
        !           406:                        case ZEND_JMPZ_EX:
        !           407:                        case ZEND_JMPNZ_EX:
        !           408:                        case ZEND_JMP_SET:
        !           409:                                opline->op2.u.jmp_addr = &op_array->opcodes[opline->op2.u.opline_num];
        !           410:                                break;
        !           411:                }
        !           412:                ZEND_VM_SET_OPCODE_HANDLER(opline);
        !           413:                opline++;
        !           414:        }
        !           415:        
        !           416:        op_array->done_pass_two = 1;
        !           417:        return 0;
        !           418: }
        !           419: 
        !           420: int print_class(zend_class_entry *class_entry TSRMLS_DC)
        !           421: {
        !           422:        printf("Class %s:\n", class_entry->name);
        !           423:        zend_hash_apply(&class_entry->function_table, (apply_func_t) pass_two TSRMLS_CC);
        !           424:        printf("End of class %s.\n\n", class_entry->name);
        !           425:        return 0;
        !           426: }
        !           427: 
        !           428: ZEND_API unary_op_type get_unary_op(int opcode)
        !           429: {
        !           430:        switch (opcode) {
        !           431:                case ZEND_BW_NOT:
        !           432:                        return (unary_op_type) bitwise_not_function;
        !           433:                        break;
        !           434:                case ZEND_BOOL_NOT:
        !           435:                        return (unary_op_type) boolean_not_function;
        !           436:                        break;
        !           437:                default:
        !           438:                        return (unary_op_type) NULL;
        !           439:                        break;
        !           440:        }
        !           441: }
        !           442: 
        !           443: ZEND_API binary_op_type get_binary_op(int opcode)
        !           444: {
        !           445:        switch (opcode) {
        !           446:                case ZEND_ADD:
        !           447:                case ZEND_ASSIGN_ADD:
        !           448:                        return (binary_op_type) add_function;
        !           449:                        break;
        !           450:                case ZEND_SUB:
        !           451:                case ZEND_ASSIGN_SUB:
        !           452:                        return (binary_op_type) sub_function;
        !           453:                        break;
        !           454:                case ZEND_MUL:
        !           455:                case ZEND_ASSIGN_MUL:
        !           456:                        return (binary_op_type) mul_function;
        !           457:                        break;
        !           458:                case ZEND_DIV:
        !           459:                case ZEND_ASSIGN_DIV:
        !           460:                        return (binary_op_type) div_function;
        !           461:                        break;
        !           462:                case ZEND_MOD:
        !           463:                case ZEND_ASSIGN_MOD:
        !           464:                        return (binary_op_type) mod_function;
        !           465:                        break;
        !           466:                case ZEND_SL:
        !           467:                case ZEND_ASSIGN_SL:
        !           468:                        return (binary_op_type) shift_left_function;
        !           469:                        break;
        !           470:                case ZEND_SR:
        !           471:                case ZEND_ASSIGN_SR:
        !           472:                        return (binary_op_type) shift_right_function;
        !           473:                        break;
        !           474:                case ZEND_CONCAT:
        !           475:                case ZEND_ASSIGN_CONCAT:
        !           476:                        return (binary_op_type) concat_function;
        !           477:                        break;
        !           478:                case ZEND_IS_IDENTICAL:
        !           479:                        return (binary_op_type) is_identical_function;
        !           480:                        break;
        !           481:                case ZEND_IS_NOT_IDENTICAL:
        !           482:                        return (binary_op_type) is_not_identical_function;
        !           483:                        break;
        !           484:                case ZEND_IS_EQUAL:
        !           485:                        return (binary_op_type) is_equal_function;
        !           486:                        break;
        !           487:                case ZEND_IS_NOT_EQUAL:
        !           488:                        return (binary_op_type) is_not_equal_function;
        !           489:                        break;
        !           490:                case ZEND_IS_SMALLER:
        !           491:                        return (binary_op_type) is_smaller_function;
        !           492:                        break;
        !           493:                case ZEND_IS_SMALLER_OR_EQUAL:
        !           494:                        return (binary_op_type) is_smaller_or_equal_function;
        !           495:                        break;
        !           496:                case ZEND_BW_OR:
        !           497:                case ZEND_ASSIGN_BW_OR:
        !           498:                        return (binary_op_type) bitwise_or_function;
        !           499:                        break;
        !           500:                case ZEND_BW_AND:
        !           501:                case ZEND_ASSIGN_BW_AND:
        !           502:                        return (binary_op_type) bitwise_and_function;
        !           503:                        break;
        !           504:                case ZEND_BW_XOR:
        !           505:                case ZEND_ASSIGN_BW_XOR:
        !           506:                        return (binary_op_type) bitwise_xor_function;
        !           507:                        break;
        !           508:                case ZEND_BOOL_XOR:
        !           509:                        return (binary_op_type) boolean_xor_function;
        !           510:                        break;
        !           511:                default:
        !           512:                        return (binary_op_type) NULL;
        !           513:                        break;
        !           514:        }
        !           515: }
        !           516: 
        !           517: /*
        !           518:  * Local variables:
        !           519:  * tab-width: 4
        !           520:  * c-basic-offset: 4
        !           521:  * indent-tabs-mode: t
        !           522:  * End:
        !           523:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>