Refactoring: use call_frames instead of call_slots

This commit is contained in:
Dmitry Stogov 2014-06-24 02:17:16 +04:00
parent ba45650d63
commit 43477bc7a2
23 changed files with 1701 additions and 1762 deletions

View file

@ -393,17 +393,24 @@ void shutdown_executor(TSRMLS_D) /* {{{ */
/* return class name and "::" or "". */
ZEND_API const char *get_active_class_name(const char **space TSRMLS_DC) /* {{{ */
{
zend_function *func;
if (!zend_is_executing(TSRMLS_C)) {
if (space) {
*space = "";
}
return "";
}
switch (EG(current_execute_data)->function_state.function->type) {
if (EG(current_execute_data)->call && (EG(current_execute_data)->call->flags & ZEND_CALL_DONE)) {
func = EG(current_execute_data)->call->func;
} else {
func = (zend_function*)EG(current_execute_data)->op_array;
}
switch (func->type) {
case ZEND_USER_FUNCTION:
case ZEND_INTERNAL_FUNCTION:
{
zend_class_entry *ce = EG(current_execute_data)->function_state.function->common.scope;
zend_class_entry *ce = func->common.scope;
if (space) {
*space = ce ? "::" : "";
@ -421,12 +428,19 @@ ZEND_API const char *get_active_class_name(const char **space TSRMLS_DC) /* {{{
ZEND_API const char *get_active_function_name(TSRMLS_D) /* {{{ */
{
zend_function *func;
if (!zend_is_executing(TSRMLS_C)) {
return NULL;
}
switch (EG(current_execute_data)->function_state.function->type) {
if (EG(current_execute_data)->call && (EG(current_execute_data)->call->flags & ZEND_CALL_DONE)) {
func = EG(current_execute_data)->call->func;
} else {
func = (zend_function*)EG(current_execute_data)->op_array;
}
switch (func->type) {
case ZEND_USER_FUNCTION: {
zend_string *function_name = ((zend_op_array *) EG(current_execute_data)->function_state.function)->function_name;
zend_string *function_name = func->common.function_name;
if (function_name) {
return function_name->val;
@ -436,7 +450,7 @@ ZEND_API const char *get_active_function_name(TSRMLS_D) /* {{{ */
}
break;
case ZEND_INTERNAL_FUNCTION:
return ((zend_internal_function *) EG(current_execute_data)->function_state.function)->function_name->val;
return func->common.function_name->val;
break;
default:
return NULL;
@ -655,6 +669,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
zend_class_entry *called_scope = NULL;
zend_execute_data execute_data;
zend_fcall_info_cache fci_cache_local;
zend_function *func;
zval tmp;
ZVAL_UNDEF(fci->retval);
@ -719,7 +734,10 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
STR_RELEASE(callable_name);
}
EX(function_state).function = fci_cache->function_handler;
ZEND_VM_STACK_GROW_IF_NEEDED(ZEND_CALL_FRAME_SLOT + fci->param_count);
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);
calling_scope = fci_cache->calling_scope;
called_scope = fci_cache->called_scope;
fci->object = fci_cache->object;
@ -729,24 +747,22 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
return FAILURE;
}
if (EX(function_state).function->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) {
if (EX(function_state).function->common.fn_flags & ZEND_ACC_ABSTRACT) {
zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", EX(function_state).function->common.scope->name->val, EX(function_state).function->common.function_name->val);
if (func->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) {
if (func->common.fn_flags & ZEND_ACC_ABSTRACT) {
zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", func->common.scope->name->val, func->common.function_name->val);
}
if (EX(function_state).function->common.fn_flags & ZEND_ACC_DEPRECATED) {
if (func->common.fn_flags & ZEND_ACC_DEPRECATED) {
zend_error(E_DEPRECATED, "Function %s%s%s() is deprecated",
EX(function_state).function->common.scope ? EX(function_state).function->common.scope->name->val : "",
EX(function_state).function->common.scope ? "::" : "",
EX(function_state).function->common.function_name->val);
func->common.scope ? func->common.scope->name->val : "",
func->common.scope ? "::" : "",
func->common.function_name->val);
}
}
ZEND_VM_STACK_GROW_IF_NEEDED(fci->param_count + 1);
for (i=0; i<fci->param_count; i++) {
zval *param;
if (ARG_SHOULD_BE_SENT_BY_REF(EX(function_state).function, i + 1)) {
if (ARG_SHOULD_BE_SENT_BY_REF(func, i + 1)) {
// TODO: Scalar values don't have reference counters anymore.
// They are assumed to be 1, and they may be easily passed by
// reference now. However, previously scalars with refcount==1
@ -766,19 +782,19 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
(!Z_ISREF(fci->params[i]) && Z_REFCOUNT(fci->params[i]) > 1)) {
if (fci->no_separation &&
!ARG_MAY_BE_SENT_BY_REF(EX(function_state).function, i + 1)) {
!ARG_MAY_BE_SENT_BY_REF(func, i + 1)) {
if (i || UNEXPECTED(ZEND_VM_STACK_ELEMETS(EG(argument_stack)) == (EG(argument_stack)->top))) {
/* hack to clean up the stack */
ZVAL_LONG(&tmp, i);
zend_vm_stack_push(&tmp TSRMLS_CC);
zend_vm_stack_clear_multiple(0 TSRMLS_CC);
zend_vm_stack_free_call_frame(EX(call), 0 TSRMLS_CC);
}
zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given",
i+1,
EX(function_state).function->common.scope ? EX(function_state).function->common.scope->name->val : "",
EX(function_state).function->common.scope ? "::" : "",
EX(function_state).function->common.function_name->val);
func->common.scope ? func->common.scope->name->val : "",
func->common.scope ? "::" : "",
func->common.function_name->val);
return FAILURE;
}
@ -797,7 +813,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
param = &fci->params[i];
} else if (Z_ISREF(fci->params[i]) &&
/* don't separate references for __call */
(EX(function_state).function->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0 ) {
(func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0 ) {
param = &tmp;
ZVAL_DUP(param, Z_REFVAL(fci->params[i]));
} else {
@ -807,13 +823,10 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
zend_vm_stack_push(param TSRMLS_CC);
}
EX(function_state).arguments = zend_vm_stack_top_inc(TSRMLS_C);
ZVAL_LONG(EX(function_state).arguments, fci->param_count);
EG(scope) = calling_scope;
EG(called_scope) = called_scope;
if (!fci->object ||
(EX(function_state).function->common.fn_flags & ZEND_ACC_STATIC)) {
(func->common.fn_flags & ZEND_ACC_STATIC)) {
Z_OBJ(EG(This)) = NULL;
} else {
Z_OBJ(EG(This)) = fci->object;
@ -823,9 +836,9 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
EX(prev_execute_data) = EG(current_execute_data);
EG(current_execute_data) = &execute_data;
if (EX(function_state).function->type == ZEND_USER_FUNCTION) {
if (func->type == ZEND_USER_FUNCTION) {
calling_symbol_table = EG(active_symbol_table);
EG(scope) = EX(function_state).function->common.scope;
EG(scope) = func->common.scope;
if (fci->symbol_table) {
EG(active_symbol_table) = fci->symbol_table;
} else {
@ -833,7 +846,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
}
original_op_array = EG(active_op_array);
EG(active_op_array) = (zend_op_array *) EX(function_state).function;
EG(active_op_array) = (zend_op_array *) func;
original_opline_ptr = EG(opline_ptr);
if (EXPECTED((EG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) == 0)) {
@ -848,15 +861,15 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
zend_clean_and_cache_symbol_table(EG(active_symbol_table) TSRMLS_CC);
}
EG(active_symbol_table) = calling_symbol_table;
} else if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION) {
int call_via_handler = (EX(function_state).function->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0;
} else if (func->type == ZEND_INTERNAL_FUNCTION) {
int call_via_handler = (func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0;
ZVAL_NULL(fci->retval);
if (EX(function_state).function->common.scope) {
EG(scope) = EX(function_state).function->common.scope;
if (func->common.scope) {
EG(scope) = func->common.scope;
}
if (EXPECTED(zend_execute_internal == NULL)) {
/* saves one function call if zend_execute_internal is not used */
EX(function_state).function->internal_function.handler(fci->param_count, fci->retval TSRMLS_CC);
func->internal_function.handler(fci->param_count, fci->retval TSRMLS_CC);
} else {
zend_execute_internal(&execute_data, fci TSRMLS_CC);
}
@ -880,22 +893,22 @@ 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) {
fci->object->handlers->call_method(EX(function_state).function->common.function_name, fci->object, fci->param_count, fci->retval TSRMLS_CC);
fci->object->handlers->call_method(func->common.function_name, fci->object, fci->param_count, fci->retval TSRMLS_CC);
} else {
zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object");
}
if (EX(function_state).function->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
STR_RELEASE(EX(function_state).function->common.function_name);
if (func->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
STR_RELEASE(func->common.function_name);
}
efree(EX(function_state).function);
efree(func);
if (EG(exception)) {
zval_ptr_dtor(fci->retval);
ZVAL_UNDEF(fci->retval);
}
}
zend_vm_stack_clear_multiple(0 TSRMLS_CC);
zend_vm_stack_free_call_frame(EX(call), 0 TSRMLS_CC);
if (Z_OBJ(EG(This))) {
zval_ptr_dtor(&EG(This));