Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement function autoloading #11

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion Zend/zend_API.c
Expand Up @@ -2915,7 +2915,7 @@ static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fca
}
/* Check if function with given name exists.
* This may be a compound name that includes namespace name */
if (EXPECTED((fcc->function_handler = zend_hash_find_ptr(EG(function_table), lmname)) != NULL)) {
if (EXPECTED(ZEND_LOOKUP_FUNCTION_BY_NAME(lmname, fcc->function_handler))) {
if (lmname != Z_STR_P(callable)) {
STR_ALLOCA_FREE(lmname, use_heap);
}
Expand Down
40 changes: 16 additions & 24 deletions Zend/zend_builtin_functions.c
Expand Up @@ -182,6 +182,7 @@ ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_function_exists, 0, 0, 1)
ZEND_ARG_INFO(0, function_name)
ZEND_ARG_INFO(0, autoload)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_class_alias, 0, 0, 2)
Expand Down Expand Up @@ -246,13 +247,13 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_extension_loaded, 0, 0, 1)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_autoload_register, 0, 0, 1)
ZEND_ARG_INFO(0, callback)
ZEND_ARG_INFO(0, type)
ZEND_ARG_INFO(0, prepend)
ZEND_ARG_INFO(0, callback)
ZEND_ARG_INFO(0, type)
ZEND_ARG_INFO(0, prepend)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_autoload_unregister, 0, 0, 1)
ZEND_ARG_INFO(0, callback)
ZEND_ARG_INFO(0, callback)
ZEND_END_ARG_INFO()
/* }}} */

Expand Down Expand Up @@ -324,8 +325,8 @@ static const zend_function_entry builtin_functions[] = { /* {{{ */
ZEND_FE(gc_enabled, arginfo_zend__void)
ZEND_FE(gc_enable, arginfo_zend__void)
ZEND_FE(gc_disable, arginfo_zend__void)
ZEND_NS_FE("php", autoload_register, arginfo_autoload_register)
ZEND_NS_FE("php", autoload_unregister, arginfo_autoload_unregister)
ZEND_NS_FE("php", autoload_register, arginfo_autoload_register)
ZEND_NS_FE("php", autoload_unregister, arginfo_autoload_unregister)
ZEND_FE_END
};
/* }}} */
Expand Down Expand Up @@ -1447,36 +1448,27 @@ ZEND_FUNCTION(trait_exists)
}
/* }}} */

/* {{{ proto bool function_exists(string function_name)
/* {{{ proto bool function_exists(string function_name[, autoload = 1])
Checks if the function exists */
ZEND_FUNCTION(function_exists)
{
char *name;
size_t name_len;
zend_string *name;
zend_function *func;
zend_string *lcname;
zend_bool autoload = 1;

#ifndef FAST_ZPP
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &name_len) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|b", &name, &autoload) == FAILURE) {
return;
}
#else
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_STRING(name, name_len)
ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_STR(name)
Z_PARAM_OPTIONAL
Z_PARAM_BOOL(autoload)
ZEND_PARSE_PARAMETERS_END();
#endif

if (name[0] == '\\') {
/* Ignore leading "\" */
lcname = zend_string_alloc(name_len - 1, 0);
zend_str_tolower_copy(lcname->val, name + 1, name_len - 1);
} else {
lcname = zend_string_alloc(name_len, 0);
zend_str_tolower_copy(lcname->val, name, name_len);
}

func = zend_hash_find_ptr(EG(function_table), lcname);
zend_string_free(lcname);
func = zend_lookup_function_ex(name, NULL, autoload);

/*
* A bit of a hack, but not a bad one: we see if the handler of the function
Expand Down
7 changes: 5 additions & 2 deletions Zend/zend_interfaces.c
Expand Up @@ -77,8 +77,11 @@ ZEND_API zval* zend_call_method(zval *object, zend_class_entry *obj_ce, zend_fun
}
if (!fn_proxy || !*fn_proxy) {
if ((fcic.function_handler = zend_hash_find_ptr(function_table, Z_STR(fci.function_name))) == NULL) {
/* error at c-level */
zend_error(E_CORE_ERROR, "Couldn't find implementation for method %s%s%s", obj_ce ? obj_ce->name->val : "", obj_ce ? "::" : "", function_name);
/* try autoload before erroring */
if (!obj_ce && !zend_lookup_function(Z_STR(fci.function_name))) {
/* error at c-level */
zend_error(E_CORE_ERROR, "Couldn't find implementation for method %s%s%s", obj_ce ? obj_ce->name->val : "", obj_ce ? "::" : "", function_name);
}
}
if (fn_proxy) {
*fn_proxy = fcic.function_handler;
Expand Down
27 changes: 6 additions & 21 deletions Zend/zend_vm_def.h
Expand Up @@ -2485,17 +2485,16 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMPVAR|CV)
{
USE_OPLINE
zend_function *fbc;
zval *function_name, *func;
zval *function_name;

if (OP2_TYPE == IS_CONST && Z_TYPE_P(EX_CONSTANT(opline->op2)) == IS_STRING) {
function_name = (zval*)(EX_CONSTANT(opline->op2)+1);
if (CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)))) {
fbc = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)));
} else if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(function_name))) == NULL)) {
} else if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_NAME(Z_STR_P(function_name), fbc))) {
SAVE_OPLINE();
zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(EX_CONSTANT(opline->op2)));
} else {
fbc = Z_FUNC_P(func);
CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), fbc);
}

Expand All @@ -2505,7 +2504,6 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMPVAR|CV)
/*CHECK_EXCEPTION();*/
ZEND_VM_NEXT_OPCODE();
} else {
zend_string *lcname;
zend_free_op free_op2;
zend_class_entry *called_scope;
zend_object *object;
Expand All @@ -2515,20 +2513,11 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMPVAR|CV)

ZEND_VM_C_LABEL(try_function_name):
if (OP2_TYPE != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_STRING)) {
if (Z_STRVAL_P(function_name)[0] == '\\') {
lcname = zend_string_alloc(Z_STRLEN_P(function_name) - 1, 0);
zend_str_tolower_copy(lcname->val, Z_STRVAL_P(function_name) + 1, Z_STRLEN_P(function_name) - 1);
} else {
lcname = zend_string_alloc(Z_STRLEN_P(function_name), 0);
zend_str_tolower_copy(lcname->val, Z_STRVAL_P(function_name), Z_STRLEN_P(function_name));
}
if (UNEXPECTED((func = zend_hash_find(EG(function_table), lcname)) == NULL)) {
if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_NAME(Z_STR_P(function_name), fbc))) {
zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(function_name));
}
zend_string_free(lcname);
FREE_OP2();

fbc = Z_FUNC_P(func);
called_scope = NULL;
object = NULL;
} else if (OP2_TYPE != IS_CONST &&
Expand Down Expand Up @@ -2692,17 +2681,15 @@ ZEND_VM_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST)
func_name = EX_CONSTANT(opline->op2) + 1;
if (CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)))) {
fbc = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)));
} else if ((func = zend_hash_find(EG(function_table), Z_STR_P(func_name))) == NULL) {
} else if (!ZEND_LOOKUP_FUNCTION_BY_NAME(Z_STR_P(func_name), fbc)) {
func_name++;
if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(func_name))) == NULL)) {
if (!ZEND_LOOKUP_FUNCTION_BY_NAME(Z_STR_P(func_name), fbc)) {
SAVE_OPLINE();
zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(EX_CONSTANT(opline->op2)));
} else {
fbc = Z_FUNC_P(func);
CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), fbc);
}
} else {
fbc = Z_FUNC_P(func);
CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), fbc);
}

Expand All @@ -2717,16 +2704,14 @@ ZEND_VM_HANDLER(61, ZEND_INIT_FCALL, ANY, CONST)
USE_OPLINE
zend_free_op free_op2;
zval *fname = GET_OP2_ZVAL_PTR(BP_VAR_R);
zval *func;
zend_function *fbc;

if (CACHED_PTR(Z_CACHE_SLOT_P(fname))) {
fbc = CACHED_PTR(Z_CACHE_SLOT_P(fname));
} else if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(fname))) == NULL)) {
} else if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_NAME(Z_STR_P(fname), fbc))) {
SAVE_OPLINE();
zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(fname));
} else {
fbc = Z_FUNC_P(func);
CACHE_PTR(Z_CACHE_SLOT_P(fname), fbc);
}

Expand Down
61 changes: 12 additions & 49 deletions Zend/zend_vm_execute.h
Expand Up @@ -1541,17 +1541,16 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE
{
USE_OPLINE
zend_function *fbc;
zval *function_name, *func;
zval *function_name;

if (IS_CONST == IS_CONST && Z_TYPE_P(EX_CONSTANT(opline->op2)) == IS_STRING) {
function_name = (zval*)(EX_CONSTANT(opline->op2)+1);
if (CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)))) {
fbc = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)));
} else if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(function_name))) == NULL)) {
} else if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_NAME(Z_STR_P(function_name), fbc))) {
SAVE_OPLINE();
zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(EX_CONSTANT(opline->op2)));
} else {
fbc = Z_FUNC_P(func);
CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), fbc);
}

Expand All @@ -1561,7 +1560,6 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE
/*CHECK_EXCEPTION();*/
ZEND_VM_NEXT_OPCODE();
} else {
zend_string *lcname;
zend_free_op free_op2;
zend_class_entry *called_scope;
zend_object *object;
Expand All @@ -1571,19 +1569,10 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE

try_function_name:
if (IS_CONST != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_STRING)) {
if (Z_STRVAL_P(function_name)[0] == '\\') {
lcname = zend_string_alloc(Z_STRLEN_P(function_name) - 1, 0);
zend_str_tolower_copy(lcname->val, Z_STRVAL_P(function_name) + 1, Z_STRLEN_P(function_name) - 1);
} else {
lcname = zend_string_alloc(Z_STRLEN_P(function_name), 0);
zend_str_tolower_copy(lcname->val, Z_STRVAL_P(function_name), Z_STRLEN_P(function_name));
}
if (UNEXPECTED((func = zend_hash_find(EG(function_table), lcname)) == NULL)) {
if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_NAME(Z_STR_P(function_name), fbc))) {
zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(function_name));
}
zend_string_free(lcname);

fbc = Z_FUNC_P(func);
called_scope = NULL;
object = NULL;
} else if (IS_CONST != IS_CONST &&
Expand Down Expand Up @@ -1693,17 +1682,15 @@ static int ZEND_FASTCALL ZEND_INIT_NS_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPC
func_name = EX_CONSTANT(opline->op2) + 1;
if (CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)))) {
fbc = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)));
} else if ((func = zend_hash_find(EG(function_table), Z_STR_P(func_name))) == NULL) {
} else if (!ZEND_LOOKUP_FUNCTION_BY_NAME(Z_STR_P(func_name), fbc)) {
func_name++;
if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(func_name))) == NULL)) {
if (!ZEND_LOOKUP_FUNCTION_BY_NAME(Z_STR_P(func_name), fbc)) {
SAVE_OPLINE();
zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(EX_CONSTANT(opline->op2)));
} else {
fbc = Z_FUNC_P(func);
CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), fbc);
}
} else {
fbc = Z_FUNC_P(func);
CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), fbc);
}

Expand All @@ -1718,16 +1705,14 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER
USE_OPLINE

zval *fname = EX_CONSTANT(opline->op2);
zval *func;
zend_function *fbc;

if (CACHED_PTR(Z_CACHE_SLOT_P(fname))) {
fbc = CACHED_PTR(Z_CACHE_SLOT_P(fname));
} else if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(fname))) == NULL)) {
} else if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_NAME(Z_STR_P(fname), fbc))) {
SAVE_OPLINE();
zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(fname));
} else {
fbc = Z_FUNC_P(func);
CACHE_PTR(Z_CACHE_SLOT_P(fname), fbc);
}

Expand Down Expand Up @@ -1925,17 +1910,16 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA
{
USE_OPLINE
zend_function *fbc;
zval *function_name, *func;
zval *function_name;

if (IS_CV == IS_CONST && Z_TYPE_P(EX_CONSTANT(opline->op2)) == IS_STRING) {
function_name = (zval*)(EX_CONSTANT(opline->op2)+1);
if (CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)))) {
fbc = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)));
} else if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(function_name))) == NULL)) {
} else if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_NAME(Z_STR_P(function_name), fbc))) {
SAVE_OPLINE();
zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(EX_CONSTANT(opline->op2)));
} else {
fbc = Z_FUNC_P(func);
CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), fbc);
}

Expand All @@ -1945,7 +1929,6 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA
/*CHECK_EXCEPTION();*/
ZEND_VM_NEXT_OPCODE();
} else {
zend_string *lcname;
zend_free_op free_op2;
zend_class_entry *called_scope;
zend_object *object;
Expand All @@ -1955,19 +1938,10 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA

try_function_name:
if (IS_CV != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_STRING)) {
if (Z_STRVAL_P(function_name)[0] == '\\') {
lcname = zend_string_alloc(Z_STRLEN_P(function_name) - 1, 0);
zend_str_tolower_copy(lcname->val, Z_STRVAL_P(function_name) + 1, Z_STRLEN_P(function_name) - 1);
} else {
lcname = zend_string_alloc(Z_STRLEN_P(function_name), 0);
zend_str_tolower_copy(lcname->val, Z_STRVAL_P(function_name), Z_STRLEN_P(function_name));
}
if (UNEXPECTED((func = zend_hash_find(EG(function_table), lcname)) == NULL)) {
if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_NAME(Z_STR_P(function_name), fbc))) {
zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(function_name));
}
zend_string_free(lcname);

fbc = Z_FUNC_P(func);
called_scope = NULL;
object = NULL;
} else if (IS_CV != IS_CONST &&
Expand Down Expand Up @@ -2115,17 +2089,16 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMPVAR_HANDLER(ZEND_OPCOD
{
USE_OPLINE
zend_function *fbc;
zval *function_name, *func;
zval *function_name;

if ((IS_TMP_VAR|IS_VAR) == IS_CONST && Z_TYPE_P(EX_CONSTANT(opline->op2)) == IS_STRING) {
function_name = (zval*)(EX_CONSTANT(opline->op2)+1);
if (CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)))) {
fbc = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)));
} else if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(function_name))) == NULL)) {
} else if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_NAME(Z_STR_P(function_name), fbc))) {
SAVE_OPLINE();
zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(EX_CONSTANT(opline->op2)));
} else {
fbc = Z_FUNC_P(func);
CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), fbc);
}

Expand All @@ -2135,7 +2108,6 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMPVAR_HANDLER(ZEND_OPCOD
/*CHECK_EXCEPTION();*/
ZEND_VM_NEXT_OPCODE();
} else {
zend_string *lcname;
zend_free_op free_op2;
zend_class_entry *called_scope;
zend_object *object;
Expand All @@ -2145,20 +2117,11 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMPVAR_HANDLER(ZEND_OPCOD

try_function_name:
if ((IS_TMP_VAR|IS_VAR) != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_STRING)) {
if (Z_STRVAL_P(function_name)[0] == '\\') {
lcname = zend_string_alloc(Z_STRLEN_P(function_name) - 1, 0);
zend_str_tolower_copy(lcname->val, Z_STRVAL_P(function_name) + 1, Z_STRLEN_P(function_name) - 1);
} else {
lcname = zend_string_alloc(Z_STRLEN_P(function_name), 0);
zend_str_tolower_copy(lcname->val, Z_STRVAL_P(function_name), Z_STRLEN_P(function_name));
}
if (UNEXPECTED((func = zend_hash_find(EG(function_table), lcname)) == NULL)) {
if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_NAME(Z_STR_P(function_name), fbc))) {
zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(function_name));
}
zend_string_free(lcname);
zval_ptr_dtor_nogc(free_op2);

fbc = Z_FUNC_P(func);
called_scope = NULL;
object = NULL;
} else if ((IS_TMP_VAR|IS_VAR) != IS_CONST &&
Expand Down