diff options
author | Dmitry Stogov <dmitry@zend.com> | 2014-07-02 22:01:25 +0400 |
---|---|---|
committer | Dmitry Stogov <dmitry@zend.com> | 2014-07-02 22:01:25 +0400 |
commit | 412ad4b25417d261c0a8c43f788d5c110593d891 (patch) | |
tree | 43a257a7d074bf976c02d0d35da80fde24f54705 /Zend/zend_execute_API.c | |
parent | 0b1cfdf390632a0bf0b27516399b09813500c299 (diff) | |
download | php-git-412ad4b25417d261c0a8c43f788d5c110593d891.tar.gz |
Uinified call frame handling for user and internal functions.
Now EG(current_execute_data) always point to the call frame of the currently executed function.
Diffstat (limited to 'Zend/zend_execute_API.c')
-rw-r--r-- | Zend/zend_execute_API.c | 122 |
1 files changed, 80 insertions, 42 deletions
diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 2ba582942a..e91812d195 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -401,11 +401,7 @@ ZEND_API const char *get_active_class_name(const char **space TSRMLS_DC) /* {{{ return ""; } - if (EG(current_execute_data)->call && (EG(current_execute_data)->call->flags & ZEND_CALL_DONE)) { - func = EG(current_execute_data)->call->func; - } else { - func = EG(current_execute_data)->func; - } + func = EG(current_execute_data)->func; switch (func->type) { case ZEND_USER_FUNCTION: case ZEND_INTERNAL_FUNCTION: @@ -433,11 +429,7 @@ ZEND_API const char *get_active_function_name(TSRMLS_D) /* {{{ */ if (!zend_is_executing(TSRMLS_C)) { return NULL; } - if (EG(current_execute_data)->call && (EG(current_execute_data)->call->flags & ZEND_CALL_DONE)) { - func = EG(current_execute_data)->call->func; - } else { - func = EG(current_execute_data)->func; - } + func = EG(current_execute_data)->func; switch (func->type) { case ZEND_USER_FUNCTION: { zend_string *function_name = func->common.function_name; @@ -667,9 +659,11 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS zend_op **original_opline_ptr; zend_class_entry *calling_scope = NULL; zend_class_entry *called_scope = NULL; - zend_execute_data execute_data; + zend_execute_data *call, dummy_execute_data; zend_fcall_info_cache fci_cache_local; zend_function *func; + zend_object *orig_object; + zend_class_entry *orig_scope, *orig_called_scope; zval tmp; ZVAL_UNDEF(fci->retval); @@ -690,20 +684,28 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS break; } + orig_object = Z_OBJ(EG(This)); + orig_scope = EG(scope); + orig_called_scope = EG(called_scope); + /* Initialize execute_data */ - if (EG(current_execute_data)) { - execute_data = *EG(current_execute_data); - EX(object) = Z_OBJ(EG(This)); - EX(scope) = EG(scope); - EX(called_scope) = EG(called_scope); - EX(func) = NULL; - EX(opline) = NULL; - } else { + if (!EG(current_execute_data)) { /* This only happens when we're called outside any execute()'s * It shouldn't be strictly necessary to NULL execute_data out, * but it may make bugs easier to spot */ - memset(&execute_data, 0, sizeof(zend_execute_data)); + memset(&dummy_execute_data, 0, sizeof(zend_execute_data)); + EG(current_execute_data) = &dummy_execute_data; + } else if (EG(current_execute_data)->opline && + EG(current_execute_data)->opline->opcode != ZEND_DO_FCALL) { + /* Insert fake frame in case of include or magic calls */ + dummy_execute_data = *EG(current_execute_data); + dummy_execute_data.prev_execute_data = EG(current_execute_data); + dummy_execute_data.call = NULL; + dummy_execute_data.prev_nested_call = NULL; + dummy_execute_data.opline = NULL; + dummy_execute_data.func = NULL; + EG(current_execute_data) = &dummy_execute_data; } if (!fci_cache || !fci_cache->initialized) { @@ -722,6 +724,9 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS if (callable_name) { STR_RELEASE(callable_name); } + if (EG(current_execute_data) == &dummy_execute_data) { + EG(current_execute_data) = dummy_execute_data.prev_execute_data; + } return FAILURE; } else if (error) { /* Capitalize the first latter of the error message */ @@ -735,13 +740,16 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS } func = fci_cache->function_handler; - EX(call) = zend_vm_stack_push_call_frame(func, fci->param_count, ZEND_CALL_DONE, fci_cache->called_scope, fci_cache->object, NULL TSRMLS_CC); + call = zend_vm_stack_push_call_frame(func, fci->param_count, ZEND_CALL_DONE, fci_cache->called_scope, fci_cache->object, NULL TSRMLS_CC); calling_scope = fci_cache->calling_scope; called_scope = fci_cache->called_scope; fci->object = fci_cache->object; if (fci->object && (!EG(objects_store).object_buckets || !IS_OBJ_VALID(EG(objects_store).object_buckets[fci->object->handle]))) { + if (EG(current_execute_data) == &dummy_execute_data) { + EG(current_execute_data) = dummy_execute_data.prev_execute_data; + } return FAILURE; } @@ -783,16 +791,19 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS !ARG_MAY_BE_SENT_BY_REF(func, i + 1)) { if (i) { /* hack to clean up the stack */ - EX(call)->num_args = i; - zend_vm_stack_free_args(EX(call) TSRMLS_CC); + call->num_args = i; + zend_vm_stack_free_args(call TSRMLS_CC); } - zend_vm_stack_free_call_frame(EX(call) TSRMLS_CC); + zend_vm_stack_free_call_frame(call TSRMLS_CC); zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given", i+1, func->common.scope ? func->common.scope->name->val : "", func->common.scope ? "::" : "", func->common.function_name->val); + if (EG(current_execute_data) == &dummy_execute_data) { + EG(current_execute_data) = dummy_execute_data.prev_execute_data; + } return FAILURE; } @@ -808,33 +819,33 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS } else if (Z_REFCOUNTED(fci->params[i])) { Z_ADDREF(fci->params[i]); } - param = ZEND_CALL_ARG(EX(call), i+1); + param = ZEND_CALL_ARG(call, i+1); ZVAL_COPY_VALUE(param, &fci->params[i]); } else if (Z_ISREF(fci->params[i]) && /* don't separate references for __call */ (func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0 ) { param = &tmp; - param = ZEND_CALL_ARG(EX(call), i+1); + param = ZEND_CALL_ARG(call, i+1); ZVAL_DUP(param, Z_REFVAL(fci->params[i])); } else { - param = ZEND_CALL_ARG(EX(call), i+1); + param = ZEND_CALL_ARG(call, i+1); ZVAL_COPY(param, &fci->params[i]); } } - EX(call)->num_args = fci->param_count; + call->num_args = fci->param_count; EG(scope) = calling_scope; EG(called_scope) = called_scope; if (!fci->object || (func->common.fn_flags & ZEND_ACC_STATIC)) { - Z_OBJ(EG(This)) = EX(call)->object = NULL; + Z_OBJ(EG(This)) = call->object = NULL; } else { Z_OBJ(EG(This)) = fci->object; Z_ADDREF(EG(This)); } - EX(prev_execute_data) = EG(current_execute_data); - EG(current_execute_data) = &execute_data; + call->prev_nested_call = EG(current_execute_data)->call; + EG(current_execute_data)->call = call; if (func->type == ZEND_USER_FUNCTION) { calling_symbol_table = EG(active_symbol_table); @@ -867,14 +878,20 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS if (func->common.scope) { EG(scope) = func->common.scope; } + call->opline = NULL; + call->call = NULL; + call->prev_execute_data = EG(current_execute_data); + EG(current_execute_data) = call; if (EXPECTED(zend_execute_internal == NULL)) { /* saves one function call if zend_execute_internal is not used */ func->internal_function.handler(fci->param_count, fci->retval TSRMLS_CC); } else { - zend_execute_internal(&execute_data, fci TSRMLS_CC); + zend_execute_internal(call->prev_execute_data, fci TSRMLS_CC); } - zend_vm_stack_free_args(EX(call) TSRMLS_CC); - zend_vm_stack_free_call_frame(EX(call) TSRMLS_CC); + EG(current_execute_data) = call->prev_execute_data; + zend_vm_stack_free_args(call TSRMLS_CC); + EG(current_execute_data)->call = call->prev_nested_call; + zend_vm_stack_free_call_frame(call TSRMLS_CC); /* We shouldn't fix bad extensions here, because it can break proper ones (Bug #34045) @@ -896,11 +913,20 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS /* Not sure what should be done here if it's a static method */ if (fci->object) { + call->opline = NULL; + call->call = NULL; + call->prev_execute_data = EG(current_execute_data); + EG(current_execute_data) = call; fci->object->handlers->call_method(func->common.function_name, fci->object, fci->param_count, fci->retval TSRMLS_CC); + EG(current_execute_data) = call->prev_execute_data; } else { zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object"); } + zend_vm_stack_free_args(call TSRMLS_CC); + EG(current_execute_data)->call = call->prev_nested_call; + zend_vm_stack_free_call_frame(call TSRMLS_CC); + if (func->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) { STR_RELEASE(func->common.function_name); } @@ -916,10 +942,12 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS zval_ptr_dtor(&EG(This)); } - Z_OBJ(EG(This)) = EX(object); - EG(scope) = EX(scope); - EG(called_scope) = EX(called_scope); - EG(current_execute_data) = EX(prev_execute_data); + Z_OBJ(EG(This)) = orig_object; + EG(scope) = orig_scope; + EG(called_scope) = orig_called_scope; + if (EG(current_execute_data) == &dummy_execute_data) { + EG(current_execute_data) = dummy_execute_data.prev_execute_data; + } if (EG(exception)) { zend_throw_exception_internal(NULL TSRMLS_CC); @@ -1689,10 +1717,15 @@ ZEND_API int zend_set_local_var(zend_string *name, zval *value, int force TSRMLS if (!EG(active_symbol_table)) { int i; zend_execute_data *execute_data = EG(current_execute_data); - zend_op_array *op_array = &execute_data->func->op_array; + zend_op_array *op_array; zend_ulong h = STR_HASH_VAL(name); - if (op_array) { + while (execute_data && (!execute_data->func || !ZEND_USER_CODE(execute_data->func->common.type))) { + execute_data = execute_data->prev_execute_data; + } + + if (execute_data && execute_data->func) { + op_array = &execute_data->func->op_array; for (i = 0; i < op_array->last_var; i++) { if (op_array->vars[i]->h == h && op_array->vars[i]->len == name->len && @@ -1722,10 +1755,15 @@ ZEND_API int zend_set_local_var_str(const char *name, int len, zval *value, int if (!EG(active_symbol_table)) { int i; zend_execute_data *execute_data = EG(current_execute_data); - zend_op_array *op_array = &execute_data->func->op_array; + zend_op_array *op_array; zend_ulong h = zend_hash_func(name, len); - if (op_array) { + while (execute_data && (!execute_data->func || !ZEND_USER_CODE(execute_data->func->common.type))) { + execute_data = execute_data->prev_execute_data; + } + + if (execute_data && execute_data->func) { + op_array = &execute_data->func->op_array; for (i = 0; i < op_array->last_var; i++) { if (op_array->vars[i]->h == h && op_array->vars[i]->len == len && |