Annotation of embedaddon/php/Zend/zend_closures.c, revision 1.1.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: Christian Seiler <chris_se@gmx.net>                         |
                     16:    |          Dmitry Stogov <dmitry@zend.com>                             |
                     17:    |          Marcus Boerger <helly@php.net>                              |
                     18:    +----------------------------------------------------------------------+
                     19: */
                     20: 
                     21: /* $Id: zend_closures.c 321634 2012-01-01 13:15:04Z felipe $ */
                     22: 
                     23: #include "zend.h"
                     24: #include "zend_API.h"
                     25: #include "zend_closures.h"
                     26: #include "zend_exceptions.h"
                     27: #include "zend_interfaces.h"
                     28: #include "zend_objects.h"
                     29: #include "zend_objects_API.h"
                     30: #include "zend_globals.h"
                     31: 
                     32: #define ZEND_CLOSURE_PRINT_NAME "Closure object"
                     33: 
                     34: #define ZEND_CLOSURE_PROPERTY_ERROR() \
                     35:        zend_error(E_RECOVERABLE_ERROR, "Closure object cannot have properties")
                     36: 
                     37: typedef struct _zend_closure {
                     38:        zend_object    std;
                     39:        zend_function  func;
                     40:        HashTable     *debug_info;
                     41: } zend_closure;
                     42: 
                     43: /* non-static since it needs to be referenced */
                     44: ZEND_API zend_class_entry *zend_ce_closure;
                     45: static zend_object_handlers closure_handlers;
                     46: 
                     47: ZEND_METHOD(Closure, __invoke) /* {{{ */
                     48: {
                     49:        zend_function *func = EG(current_execute_data)->function_state.function;
                     50:        zval ***arguments;
                     51:        zval *closure_result_ptr = NULL;
                     52: 
                     53:        arguments = emalloc(sizeof(zval**) * ZEND_NUM_ARGS());
                     54:        if (zend_get_parameters_array_ex(ZEND_NUM_ARGS(), arguments) == FAILURE) {
                     55:                efree(arguments);
                     56:                zend_error(E_RECOVERABLE_ERROR, "Cannot get arguments for calling closure");
                     57:                RETVAL_FALSE;
                     58:        } else if (call_user_function_ex(CG(function_table), NULL, this_ptr, &closure_result_ptr, ZEND_NUM_ARGS(), arguments, 1, NULL TSRMLS_CC) == FAILURE) {
                     59:                RETVAL_FALSE;
                     60:        } else if (closure_result_ptr) {
                     61:                if (Z_ISREF_P(closure_result_ptr) && return_value_ptr) {
                     62:                        if (return_value) {
                     63:                                zval_ptr_dtor(&return_value);
                     64:                        }
                     65:                        *return_value_ptr = closure_result_ptr;
                     66:                } else {
                     67:                        RETVAL_ZVAL(closure_result_ptr, 1, 1);
                     68:                }
                     69:        }
                     70:        efree(arguments);
                     71: 
                     72:        /* destruct the function also, then - we have allocated it in get_method */
                     73:        efree(func->internal_function.function_name);
                     74:        efree(func);
                     75: }
                     76: /* }}} */
                     77: 
                     78: static zend_function *zend_closure_get_constructor(zval *object TSRMLS_DC) /* {{{ */
                     79: {
                     80:        zend_error(E_RECOVERABLE_ERROR, "Instantiation of 'Closure' is not allowed");
                     81:        return NULL;
                     82: }
                     83: /* }}} */
                     84: 
                     85: static int zend_closure_compare_objects(zval *o1, zval *o2 TSRMLS_DC) /* {{{ */
                     86: {
                     87:        return (Z_OBJ_HANDLE_P(o1) != Z_OBJ_HANDLE_P(o2));
                     88: }
                     89: /* }}} */
                     90: 
                     91: ZEND_API zend_function *zend_get_closure_invoke_method(zval *obj TSRMLS_DC) /* {{{ */
                     92: {
                     93:        zend_closure *closure = (zend_closure *)zend_object_store_get_object(obj TSRMLS_CC);    
                     94:        zend_function *invoke = (zend_function*)emalloc(sizeof(zend_function));
                     95: 
                     96:        invoke->common = closure->func.common;
                     97:        invoke->type = ZEND_INTERNAL_FUNCTION;
                     98:        invoke->internal_function.fn_flags = ZEND_ACC_PUBLIC | ZEND_ACC_CALL_VIA_HANDLER;
                     99:        invoke->internal_function.handler = ZEND_MN(Closure___invoke);
                    100:        invoke->internal_function.module = 0;
                    101:        invoke->internal_function.scope = zend_ce_closure;
                    102:        invoke->internal_function.function_name = estrndup(ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1);
                    103:        return invoke;
                    104: }
                    105: /* }}} */
                    106: 
                    107: ZEND_API const zend_function *zend_get_closure_method_def(zval *obj TSRMLS_DC) /* {{{ */
                    108: {
                    109:        zend_closure *closure = (zend_closure *)zend_object_store_get_object(obj TSRMLS_CC);    
                    110:        return &closure->func;
                    111: }
                    112: /* }}} */
                    113: 
                    114: static zend_function *zend_closure_get_method(zval **object_ptr, char *method_name, int method_len TSRMLS_DC) /* {{{ */
                    115: {
                    116:        char *lc_name;
                    117:        ALLOCA_FLAG(use_heap)
                    118: 
                    119:        lc_name = do_alloca(method_len + 1, use_heap);
                    120:        zend_str_tolower_copy(lc_name, method_name, method_len);
                    121:        if ((method_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) &&
                    122:                memcmp(lc_name, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0
                    123:        ) {
                    124:                free_alloca(lc_name, use_heap);
                    125:                return zend_get_closure_invoke_method(*object_ptr TSRMLS_CC);
                    126:        }
                    127:        free_alloca(lc_name, use_heap);
                    128:        return NULL;
                    129: }
                    130: /* }}} */
                    131: 
                    132: static zval *zend_closure_read_property(zval *object, zval *member, int type TSRMLS_DC) /* {{{ */
                    133: {
                    134:        ZEND_CLOSURE_PROPERTY_ERROR();
                    135:        Z_ADDREF(EG(uninitialized_zval));
                    136:        return &EG(uninitialized_zval);
                    137: }
                    138: /* }}} */
                    139: 
                    140: static void zend_closure_write_property(zval *object, zval *member, zval *value TSRMLS_DC) /* {{{ */
                    141: {
                    142:        ZEND_CLOSURE_PROPERTY_ERROR();
                    143: }
                    144: /* }}} */
                    145: 
                    146: static zval **zend_closure_get_property_ptr_ptr(zval *object, zval *member TSRMLS_DC) /* {{{ */
                    147: {
                    148:        ZEND_CLOSURE_PROPERTY_ERROR();
                    149:        return NULL;
                    150: }
                    151: /* }}} */
                    152: 
                    153: static int zend_closure_has_property(zval *object, zval *member, int has_set_exists TSRMLS_DC) /* {{{ */
                    154: {
                    155:        if (has_set_exists != 2) {
                    156:                ZEND_CLOSURE_PROPERTY_ERROR();
                    157:        }
                    158:        return 0;
                    159: }
                    160: /* }}} */
                    161: 
                    162: static void zend_closure_unset_property(zval *object, zval *member TSRMLS_DC) /* {{{ */
                    163: {
                    164:        ZEND_CLOSURE_PROPERTY_ERROR();
                    165: }
                    166: /* }}} */
                    167: 
                    168: static void zend_closure_free_storage(void *object TSRMLS_DC) /* {{{ */
                    169: {
                    170:        zend_closure *closure = (zend_closure *)object;
                    171: 
                    172:        zend_object_std_dtor(&closure->std TSRMLS_CC);
                    173: 
                    174:        if (closure->func.type == ZEND_USER_FUNCTION) {
                    175:                zend_execute_data *ex = EG(current_execute_data);
                    176:                while (ex) {
                    177:                        if (ex->op_array == &closure->func.op_array) {
                    178:                                zend_error(E_ERROR, "Cannot destroy active lambda function");
                    179:                        }
                    180:                        ex = ex->prev_execute_data;
                    181:                }
                    182:                destroy_op_array(&closure->func.op_array TSRMLS_CC);
                    183:        }
                    184: 
                    185:        if (closure->debug_info != NULL) {
                    186:                zend_hash_destroy(closure->debug_info);
                    187:                efree(closure->debug_info);
                    188:        }
                    189: 
                    190:        efree(closure);
                    191: }
                    192: /* }}} */
                    193: 
                    194: static zend_object_value zend_closure_new(zend_class_entry *class_type TSRMLS_DC) /* {{{ */
                    195: {
                    196:        zend_closure *closure;
                    197:        zend_object_value object;
                    198: 
                    199:        closure = emalloc(sizeof(zend_closure));
                    200:        memset(closure, 0, sizeof(zend_closure));
                    201: 
                    202:        zend_object_std_init(&closure->std, class_type TSRMLS_CC);
                    203: 
                    204:        object.handle = zend_objects_store_put(closure, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) zend_closure_free_storage, NULL TSRMLS_CC);
                    205:        object.handlers = &closure_handlers;
                    206: 
                    207:        return object;
                    208: }
                    209: /* }}} */
                    210: 
                    211: int zend_closure_get_closure(zval *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zval **zobj_ptr TSRMLS_DC) /* {{{ */
                    212: {
                    213:        zend_closure *closure;
                    214: 
                    215:        if (Z_TYPE_P(obj) != IS_OBJECT) {
                    216:                return FAILURE;
                    217:        }
                    218: 
                    219:        closure = (zend_closure *)zend_object_store_get_object(obj TSRMLS_CC);
                    220:        *fptr_ptr = &closure->func;
                    221: 
                    222:        if (zobj_ptr) {
                    223:                *zobj_ptr = NULL;
                    224:        }
                    225:        *ce_ptr = NULL;
                    226:        return SUCCESS;
                    227: }
                    228: /* }}} */
                    229: 
                    230: static HashTable *zend_closure_get_debug_info(zval *object, int *is_temp TSRMLS_DC) /* {{{ */
                    231: {
                    232:        zend_closure *closure = (zend_closure *)zend_object_store_get_object(object TSRMLS_CC);
                    233:        zval *val;
                    234:        struct _zend_arg_info *arg_info = closure->func.common.arg_info;
                    235: 
                    236:        *is_temp = 0;
                    237: 
                    238:        if (closure->debug_info == NULL) {
                    239:                ALLOC_HASHTABLE(closure->debug_info);
                    240:                zend_hash_init(closure->debug_info, 1, NULL, ZVAL_PTR_DTOR, 0);
                    241:        }
                    242:        if (closure->debug_info->nApplyCount == 0) {
                    243:                if (closure->func.type == ZEND_USER_FUNCTION && closure->func.op_array.static_variables) {
                    244:                        HashTable *static_variables = closure->func.op_array.static_variables;
                    245:                        MAKE_STD_ZVAL(val);
                    246:                        array_init(val);
                    247:                        zend_hash_copy(Z_ARRVAL_P(val), static_variables, (copy_ctor_func_t)zval_add_ref, NULL, sizeof(zval*));
                    248:                        zend_symtable_update(closure->debug_info, "static", sizeof("static"), (void *) &val, sizeof(zval *), NULL);
                    249:                }
                    250: 
                    251:                if (arg_info) {
                    252:                        zend_uint i, required = closure->func.common.required_num_args;
                    253: 
                    254:                        MAKE_STD_ZVAL(val);
                    255:                        array_init(val);
                    256: 
                    257:                        for (i = 0; i < closure->func.common.num_args; i++) {
                    258:                                char *name, *info;
                    259:                                int name_len, info_len;
                    260:                                if (arg_info->name) {
                    261:                                        name_len = zend_spprintf(&name, 0, "%s$%s",
                    262:                                                                        arg_info->pass_by_reference ? "&" : "",
                    263:                                                                        arg_info->name);
                    264:                                } else {
                    265:                                        name_len = zend_spprintf(&name, 0, "%s$param%d",
                    266:                                                                        arg_info->pass_by_reference ? "&" : "",
                    267:                                                                        i + 1);
                    268:                                }
                    269:                                info_len = zend_spprintf(&info, 0, "%s",
                    270:                                                                i >= required ? "<optional>" : "<required>");
                    271:                                add_assoc_stringl_ex(val, name, name_len + 1, info, info_len, 0);
                    272:                                efree(name);
                    273:                                arg_info++;
                    274:                        }
                    275:                        zend_symtable_update(closure->debug_info, "parameter", sizeof("parameter"), (void *) &val, sizeof(zval *), NULL);
                    276:                }
                    277:        }
                    278: 
                    279:        return closure->debug_info;
                    280: }
                    281: /* }}} */
                    282: 
                    283: static HashTable *zend_closure_get_properties(zval *obj TSRMLS_DC) /* {{{ */
                    284: {
                    285:        zend_closure *closure = (zend_closure *)zend_object_store_get_object(obj TSRMLS_CC);    
                    286: 
                    287:        if (GC_G(gc_active)) {
                    288:                return (closure->func.type == ZEND_USER_FUNCTION) ? closure->func.op_array.static_variables : NULL;
                    289:        }
                    290: 
                    291:        return closure->std.properties;
                    292: }
                    293: /* }}} */
                    294: 
                    295: /* {{{ proto Closure::__construct()
                    296:    Private constructor preventing instantiation */
                    297: ZEND_METHOD(Closure, __construct)
                    298: {
                    299:        zend_error(E_RECOVERABLE_ERROR, "Instantiation of 'Closure' is not allowed");
                    300: }
                    301: /* }}} */
                    302: 
                    303: static const zend_function_entry closure_functions[] = {
                    304:        ZEND_ME(Closure, __construct, NULL, ZEND_ACC_PRIVATE)
                    305:        {NULL, NULL, NULL}
                    306: };
                    307: 
                    308: void zend_register_closure_ce(TSRMLS_D) /* {{{ */
                    309: {
                    310:        zend_class_entry ce;
                    311: 
                    312:        INIT_CLASS_ENTRY(ce, "Closure", closure_functions);
                    313:        zend_ce_closure = zend_register_internal_class(&ce TSRMLS_CC);
                    314:        zend_ce_closure->ce_flags |= ZEND_ACC_FINAL_CLASS;
                    315:        zend_ce_closure->create_object = zend_closure_new;
                    316:        zend_ce_closure->serialize = zend_class_serialize_deny;
                    317:        zend_ce_closure->unserialize = zend_class_unserialize_deny;
                    318: 
                    319:        memcpy(&closure_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
                    320:        closure_handlers.get_constructor = zend_closure_get_constructor;
                    321:        closure_handlers.get_method = zend_closure_get_method;
                    322:        closure_handlers.write_property = zend_closure_write_property;
                    323:        closure_handlers.read_property = zend_closure_read_property;
                    324:        closure_handlers.get_property_ptr_ptr = zend_closure_get_property_ptr_ptr;
                    325:        closure_handlers.has_property = zend_closure_has_property;
                    326:        closure_handlers.unset_property = zend_closure_unset_property;
                    327:        closure_handlers.compare_objects = zend_closure_compare_objects;
                    328:        closure_handlers.clone_obj = NULL;
                    329:        closure_handlers.get_debug_info = zend_closure_get_debug_info;
                    330:        closure_handlers.get_closure = zend_closure_get_closure;
                    331:        closure_handlers.get_properties = zend_closure_get_properties;
                    332: }
                    333: /* }}} */
                    334: 
                    335: static int zval_copy_static_var(zval **p TSRMLS_DC, int num_args, va_list args, zend_hash_key *key) /* {{{ */
                    336: {
                    337:        HashTable *target = va_arg(args, HashTable*);
                    338:        zend_bool is_ref;
                    339:        zval *tmp;
                    340: 
                    341:        if (Z_TYPE_PP(p) & (IS_LEXICAL_VAR|IS_LEXICAL_REF)) {
                    342:                is_ref = Z_TYPE_PP(p) & IS_LEXICAL_REF;
                    343: 
                    344:                if (!EG(active_symbol_table)) {
                    345:                        zend_rebuild_symbol_table(TSRMLS_C);
                    346:                }
                    347:                if (zend_hash_quick_find(EG(active_symbol_table), key->arKey, key->nKeyLength, key->h, (void **) &p) == FAILURE) {
                    348:                        if (is_ref) {
                    349:                                ALLOC_INIT_ZVAL(tmp);
                    350:                                Z_SET_ISREF_P(tmp);
                    351:                                zend_hash_quick_add(EG(active_symbol_table), key->arKey, key->nKeyLength, key->h, &tmp, sizeof(zval*), (void**)&p);
                    352:                        } else {
                    353:                                tmp = EG(uninitialized_zval_ptr);
                    354:                                zend_error(E_NOTICE,"Undefined variable: %s", key->arKey);
                    355:                        }
                    356:                } else {
                    357:                        if (is_ref) {
                    358:                                SEPARATE_ZVAL_TO_MAKE_IS_REF(p);
                    359:                                tmp = *p;
                    360:                        } else if (Z_ISREF_PP(p)) {
                    361:                                ALLOC_INIT_ZVAL(tmp);
                    362:                                *tmp = **p;
                    363:                                zval_copy_ctor(tmp);
                    364:                                Z_SET_REFCOUNT_P(tmp, 0);
                    365:                                Z_UNSET_ISREF_P(tmp);
                    366:                        } else {
                    367:                                tmp = *p;
                    368:                        }
                    369:                }
                    370:        } else {
                    371:                tmp = *p;
                    372:        }
                    373:        if (zend_hash_quick_add(target, key->arKey, key->nKeyLength, key->h, &tmp, sizeof(zval*), NULL) == SUCCESS) {
                    374:                Z_ADDREF_P(tmp);
                    375:        }
                    376:        return ZEND_HASH_APPLY_KEEP;
                    377: }
                    378: /* }}} */
                    379: 
                    380: ZEND_API void zend_create_closure(zval *res, zend_function *func TSRMLS_DC) /* {{{ */
                    381: {
                    382:        zend_closure *closure;
                    383: 
                    384:        object_init_ex(res, zend_ce_closure);
                    385: 
                    386:        closure = (zend_closure *)zend_object_store_get_object(res TSRMLS_CC);
                    387: 
                    388:        closure->func = *func;
                    389:        closure->func.common.prototype = NULL;
                    390: 
                    391:        if (closure->func.type == ZEND_USER_FUNCTION) {
                    392:                if (closure->func.op_array.static_variables) {
                    393:                        HashTable *static_variables = closure->func.op_array.static_variables;
                    394: 
                    395:                        ALLOC_HASHTABLE(closure->func.op_array.static_variables);
                    396:                        zend_hash_init(closure->func.op_array.static_variables, zend_hash_num_elements(static_variables), NULL, ZVAL_PTR_DTOR, 0);
                    397:                        zend_hash_apply_with_arguments(static_variables TSRMLS_CC, (apply_func_args_t)zval_copy_static_var, 1, closure->func.op_array.static_variables);
                    398:                }
                    399:                (*closure->func.op_array.refcount)++;
                    400:        }
                    401: 
                    402:        closure->func.common.scope = NULL;
                    403: }
                    404: /* }}} */
                    405: 
                    406: /*
                    407:  * Local variables:
                    408:  * tab-width: 4
                    409:  * c-basic-offset: 4
                    410:  * indent-tabs-mode: t
                    411:  * End:
                    412:  */

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