Don't propogate "fake" EX(called_scope) and EX(This) into each internal function.

They need quite seldom and it's cheaper to get them from corresponfing upper stack frame.
This commit is contained in:
Dmitry Stogov 2015-04-23 12:16:37 +03:00
parent 801768f72c
commit 49cf7c5d12
11 changed files with 99 additions and 73 deletions

View File

@ -2864,10 +2864,10 @@ static int zend_is_callable_check_class(zend_string *name, zend_fcall_info_cache
if (!EG(scope)) {
if (error) *error = estrdup("cannot access self:: when no class scope is active");
} else {
fcc->called_scope = EG(current_execute_data) ? EG(current_execute_data)->called_scope : NULL;
fcc->called_scope = zend_get_called_scope(EG(current_execute_data));
fcc->calling_scope = EG(scope);
if (!fcc->object && EG(current_execute_data) && Z_OBJ(EG(current_execute_data)->This)) {
fcc->object = Z_OBJ(EG(current_execute_data)->This);
if (!fcc->object) {
fcc->object = zend_get_this_object(EG(current_execute_data));
}
ret = 1;
}
@ -2877,22 +2877,24 @@ static int zend_is_callable_check_class(zend_string *name, zend_fcall_info_cache
} else if (!EG(scope)->parent) {
if (error) *error = estrdup("cannot access parent:: when current class scope has no parent");
} else {
fcc->called_scope = EG(current_execute_data) ? EG(current_execute_data)->called_scope : NULL;
fcc->called_scope = zend_get_called_scope(EG(current_execute_data));
fcc->calling_scope = EG(scope)->parent;
if (!fcc->object && EG(current_execute_data) && Z_OBJ(EG(current_execute_data)->This)) {
fcc->object = Z_OBJ(EG(current_execute_data)->This);
if (!fcc->object) {
fcc->object = zend_get_this_object(EG(current_execute_data));
}
*strict_class = 1;
ret = 1;
}
} else if (zend_string_equals_literal(lcname, "static")) {
if (!EG(current_execute_data) || !EG(current_execute_data)->called_scope) {
zend_class_entry *called_scope = zend_get_called_scope(EG(current_execute_data));
if (!called_scope) {
if (error) *error = estrdup("cannot access static:: when no class scope is active");
} else {
fcc->called_scope = EG(current_execute_data)->called_scope;
fcc->calling_scope = EG(current_execute_data)->called_scope;
if (!fcc->object && Z_OBJ(EG(current_execute_data)->This)) {
fcc->object = Z_OBJ(EG(current_execute_data)->This);
fcc->called_scope = called_scope;
fcc->calling_scope = called_scope;
if (!fcc->object) {
fcc->object = zend_get_this_object(EG(current_execute_data));
}
*strict_class = 1;
ret = 1;
@ -2906,11 +2908,17 @@ static int zend_is_callable_check_class(zend_string *name, zend_fcall_info_cache
}
scope = ex ? ex->func->common.scope : NULL;
fcc->calling_scope = ce;
if (scope && !fcc->object && EG(current_execute_data) && Z_OBJ(EG(current_execute_data)->This) &&
instanceof_function(Z_OBJCE(EG(current_execute_data)->This), scope) &&
if (scope && !fcc->object) {
zend_object *object = zend_get_this_object(EG(current_execute_data));
if (object &&
instanceof_function(object->ce, scope) &&
instanceof_function(scope, fcc->calling_scope)) {
fcc->object = Z_OBJ(EG(current_execute_data)->This);
fcc->called_scope = Z_OBJCE(EG(current_execute_data)->This);
fcc->object = object;
fcc->called_scope = object->ce;
} else {
fcc->called_scope = fcc->calling_scope;
}
} else {
fcc->called_scope = fcc->object ? fcc->object->ce : fcc->calling_scope;
}
@ -3101,9 +3109,12 @@ get_function_via_handler:
if (fcc->function_handler) {
retval = 1;
call_via_handler = (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) != 0;
if (call_via_handler && !fcc->object && EG(current_execute_data) && Z_OBJ(EG(current_execute_data)->This) &&
instanceof_function(Z_OBJCE(EG(current_execute_data)->This), fcc->calling_scope)) {
fcc->object = Z_OBJ(EG(current_execute_data)->This);
if (call_via_handler && !fcc->object) {
zend_object *object = zend_get_this_object(EG(current_execute_data));
if (object &&
instanceof_function(object->ce, fcc->calling_scope)) {
fcc->object = object;
}
}
}
}

View File

@ -916,12 +916,15 @@ ZEND_FUNCTION(get_class)
Retrieves the "Late Static Binding" class name */
ZEND_FUNCTION(get_called_class)
{
zend_class_entry *called_scope;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
if (EX(called_scope)) {
RETURN_STR_COPY(EX(called_scope)->name);
called_scope = zend_get_called_scope(execute_data);
if (called_scope) {
RETURN_STR_COPY(called_scope->name);
} else if (!EG(scope)) {
zend_error(E_WARNING, "get_called_class() called from outside a class");
}
@ -2304,12 +2307,6 @@ ZEND_FUNCTION(debug_print_backtrace)
/* $this may be passed into regular internal functions */
object = Z_OBJ(call->This);
if (object &&
call &&
call->func->type == ZEND_INTERNAL_FUNCTION &&
!call->func->common.scope) {
object = NULL;
}
if (call->func) {
func = call->func;
@ -2527,12 +2524,6 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int
/* $this may be passed into regular internal functions */
object = call ? Z_OBJ(call->This) : NULL;
if (object &&
call->func &&
call->func->type == ZEND_INTERNAL_FUNCTION &&
!call->func->common.scope) {
object = NULL;
}
if (call && call->func) {
func = call->func;

View File

@ -349,12 +349,11 @@ ZEND_API zval *zend_get_constant_ex(zend_string *cname, zend_class_entry *scope,
}
} else if (class_name_len == sizeof("static")-1 &&
!memcmp(lcname, "static", sizeof("static")-1)) {
if (UNEXPECTED(!EG(current_execute_data)) ||
UNEXPECTED(!EG(current_execute_data)->called_scope)) {
ce = zend_get_called_scope(EG(current_execute_data));
if (UNEXPECTED(!ce)) {
zend_error(E_EXCEPTION | E_ERROR, "Cannot access static:: when no class scope is active");
return NULL;
}
ce = EG(current_execute_data)->called_scope;
} else {
ce = zend_fetch_class(class_name, flags);
}

View File

@ -42,6 +42,8 @@ ZEND_API void execute_ex(zend_execute_data *execute_data);
ZEND_API void execute_internal(zend_execute_data *execute_data, zval *return_value);
ZEND_API zend_class_entry *zend_lookup_class(zend_string *name);
ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, const zval *key, int use_autoload);
ZEND_API zend_class_entry *zend_get_called_scope(zend_execute_data *ex);
ZEND_API zend_object *zend_get_this_object(zend_execute_data *ex);
ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name);
ZEND_API int zend_eval_stringl(char *str, size_t str_len, zval *retval_ptr, char *string_name);
ZEND_API int zend_eval_string_ex(char *str, zval *retval_ptr, char *string_name, int handle_exceptions);

View File

@ -1055,6 +1055,38 @@ ZEND_API zend_class_entry *zend_lookup_class(zend_string *name) /* {{{ */
}
/* }}} */
ZEND_API zend_class_entry *zend_get_called_scope(zend_execute_data *ex) /* {{{ */
{
while (ex) {
if (ex->called_scope) {
return ex->called_scope;
} else if (ex->func) {
if (ex->func->type != ZEND_INTERNAL_FUNCTION || ex->func->common.scope) {
return ex->called_scope;
}
}
ex = ex->prev_execute_data;
}
return NULL;
}
/* }}} */
ZEND_API zend_object *zend_get_this_object(zend_execute_data *ex) /* {{{ */
{
while (ex) {
if (Z_OBJ(ex->This)) {
return Z_OBJ(ex->This);
} else if (ex->func) {
if (ex->func->type != ZEND_INTERNAL_FUNCTION || ex->func->common.scope) {
return Z_OBJ(ex->This);
}
}
ex = ex->prev_execute_data;
}
return NULL;
}
/* }}} */
ZEND_API int zend_eval_stringl(char *str, size_t str_len, zval *retval_ptr, char *string_name) /* {{{ */
{
zval pv;
@ -1311,13 +1343,14 @@ check_fetch_type:
}
return EG(scope)->parent;
case ZEND_FETCH_CLASS_STATIC:
if (UNEXPECTED(!EG(current_execute_data)) || UNEXPECTED(!EG(current_execute_data)->called_scope)) {
ce = zend_get_called_scope(EG(current_execute_data));
if (UNEXPECTED(!ce)) {
int error_type = (fetch_type & ZEND_FETCH_CLASS_EXCEPTION) ?
(E_EXCEPTION | E_ERROR) : E_ERROR;
zend_error(error_type, "Cannot access static:: when no class scope is active");
return NULL;
}
return EG(current_execute_data)->called_scope;
return ce;
case ZEND_FETCH_CLASS_AUTO: {
fetch_sub_type = zend_get_class_fetch_type(class_name);
if (UNEXPECTED(fetch_sub_type != ZEND_FETCH_CLASS_DEFAULT)) {

View File

@ -89,13 +89,16 @@ ZEND_API zval* zend_call_method(zval *object, zend_class_entry *obj_ce, zend_fun
fcic.calling_scope = obj_ce;
if (object) {
fcic.called_scope = Z_OBJCE_P(object);
} else if (obj_ce &&
!(EG(current_execute_data) &&
EG(current_execute_data)->called_scope &&
instanceof_function(EG(current_execute_data)->called_scope, obj_ce))) {
} else {
zend_class_entry *called_scope = zend_get_called_scope(EG(current_execute_data));
if (obj_ce &&
(!called_scope ||
!instanceof_function(called_scope, obj_ce))) {
fcic.called_scope = obj_ce;
} else {
fcic.called_scope = EG(current_execute_data) ? EG(current_execute_data)->called_scope : NULL;
fcic.called_scope = called_scope;
}
}
fcic.object = object ? Z_OBJ_P(object) : NULL;
result = zend_call_function(&fci, &fcic);

View File

@ -1137,6 +1137,7 @@ ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, zend_st
zend_function *fbc = NULL;
char *lc_class_name;
zend_string *lc_function_name;
zend_object *object;
if (EXPECTED(key != NULL)) {
lc_function_name = Z_STR_P(key);
@ -1164,12 +1165,12 @@ ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, zend_st
zend_string_release(lc_function_name);
}
if (ce->__call &&
Z_OBJ(EG(current_execute_data)->This) &&
instanceof_function(Z_OBJCE(EG(current_execute_data)->This), ce)) {
(object = zend_get_this_object(EG(current_execute_data))) != NULL &&
instanceof_function(object->ce, ce)) {
/* Call the top-level defined __call().
* see: tests/classes/__call_004.phpt */
zend_class_entry *call_ce = Z_OBJCE(EG(current_execute_data)->This);
zend_class_entry *call_ce = object->ce;
while (!call_ce->__call) {
call_ce = call_ce->parent;

View File

@ -3391,9 +3391,6 @@ ZEND_VM_HANDLER(129, ZEND_DO_ICALL, ANY, ANY)
SAVE_OPLINE();
EX(call) = call->prev_execute_data;
call->called_scope = EX(called_scope);
Z_OBJ(call->This) = Z_OBJ(EX(This));
call->prev_execute_data = execute_data;
EG(current_execute_data) = call;
@ -3505,9 +3502,6 @@ ZEND_VM_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY)
}
}
call->called_scope = EX(called_scope);
Z_OBJ(call->This) = Z_OBJ(EX(This));
call->prev_execute_data = execute_data;
EG(current_execute_data) = call;
@ -3627,9 +3621,6 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY)
if (fbc->common.scope) {
should_change_scope = 1;
EG(scope) = fbc->common.scope;
} else {
call->called_scope = EX(called_scope);
Z_OBJ(call->This) = Z_OBJ(EX(This));
}
call->prev_execute_data = execute_data;

View File

@ -423,7 +423,7 @@ ZEND_API void zend_execute(zend_op_array *op_array, zval *return_value)
}
execute_data = zend_vm_stack_push_call_frame(ZEND_CALL_TOP_CODE,
(zend_function*)op_array, 0, EG(current_execute_data) ? EG(current_execute_data)->called_scope : NULL, EG(current_execute_data) ? Z_OBJ(EG(current_execute_data)->This) : NULL);
(zend_function*)op_array, 0, zend_get_called_scope(EG(current_execute_data)), zend_get_this_object(EG(current_execute_data)));
if (EG(current_execute_data)) {
execute_data->symbol_table = zend_rebuild_symbol_table();
} else {
@ -548,9 +548,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_ICALL_SPEC_HANDLER(ZEND_OPC
SAVE_OPLINE();
EX(call) = call->prev_execute_data;
call->called_scope = EX(called_scope);
Z_OBJ(call->This) = Z_OBJ(EX(This));
call->prev_execute_data = execute_data;
EG(current_execute_data) = call;
@ -662,9 +659,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER(
}
}
call->called_scope = EX(called_scope);
Z_OBJ(call->This) = Z_OBJ(EX(This));
call->prev_execute_data = execute_data;
EG(current_execute_data) = call;
@ -784,9 +778,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPC
if (fbc->common.scope) {
should_change_scope = 1;
EG(scope) = fbc->common.scope;
} else {
call->called_scope = EX(called_scope);
Z_OBJ(call->This) = Z_OBJ(EX(This));
}
call->prev_execute_data = execute_data;

View File

@ -29,7 +29,7 @@ ZEND_API void zend_{%EXECUTOR_NAME%}(zend_op_array *op_array, zval *return_value
}
execute_data = zend_vm_stack_push_call_frame(ZEND_CALL_TOP_CODE,
(zend_function*)op_array, 0, EG(current_execute_data) ? EG(current_execute_data)->called_scope : NULL, EG(current_execute_data) ? Z_OBJ(EG(current_execute_data)->This) : NULL);
(zend_function*)op_array, 0, zend_get_called_scope(EG(current_execute_data)), zend_get_this_object(EG(current_execute_data)));
if (EG(current_execute_data)) {
execute_data->symbol_table = zend_rebuild_symbol_table();
} else {

View File

@ -4800,6 +4800,7 @@ PHP_FUNCTION(forward_static_call)
zval retval;
zend_fcall_info fci;
zend_fcall_info_cache fci_cache;
zend_class_entry *called_scope;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "f*", &fci, &fci_cache, &fci.params, &fci.param_count) == FAILURE) {
return;
@ -4811,9 +4812,10 @@ PHP_FUNCTION(forward_static_call)
fci.retval = &retval;
if (EX(called_scope) &&
instanceof_function(EX(called_scope), fci_cache.calling_scope)) {
fci_cache.called_scope = EX(called_scope);
called_scope = zend_get_called_scope(execute_data);
if (called_scope &&
instanceof_function(called_scope, fci_cache.calling_scope)) {
fci_cache.called_scope = called_scope;
}
if (zend_call_function(&fci, &fci_cache) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
@ -4829,6 +4831,7 @@ PHP_FUNCTION(forward_static_call_array)
zval *params, retval;
zend_fcall_info fci;
zend_fcall_info_cache fci_cache;
zend_class_entry *called_scope;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "fa/", &fci, &fci_cache, &params) == FAILURE) {
return;
@ -4837,9 +4840,10 @@ PHP_FUNCTION(forward_static_call_array)
zend_fcall_info_args(&fci, params);
fci.retval = &retval;
if (EX(called_scope) &&
instanceof_function(EX(called_scope), fci_cache.calling_scope)) {
fci_cache.called_scope = EX(called_scope);
called_scope = zend_get_called_scope(execute_data);
if (called_scope &&
instanceof_function(called_scope, fci_cache.calling_scope)) {
fci_cache.called_scope = called_scope;
}
if (zend_call_function(&fci, &fci_cache) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {