From 5ea50702d9619fc0c82da80c3f5b1905f72e7ade Mon Sep 17 00:00:00 2001
From: Anthony Ferrara <ircmaxell@gmail.com>
Date: Thu, 29 Aug 2013 18:11:29 -0400
Subject: [PATCH 01/20] Initial concept draft of new zend autoloader

---
 Zend/Makefile.am              |   2 +-
 Zend/zend_API.c               |   2 +-
 Zend/zend_autoload.c          | 249 +++++++++++++++++++++++++
 Zend/zend_autoload.h          |  40 +++++
 Zend/zend_builtin_functions.c |  21 ++-
 Zend/zend_constants.c         |   4 +
 Zend/zend_execute.h           |   3 +
 Zend/zend_execute_API.c       | 143 ++++++++-------
 Zend/zend_globals.h           |   6 +-
 Zend/zend_vm_def.h            |  10 +-
 Zend/zend_vm_execute.h        |  22 +--
 configure.in                  |   3 +-
 ext/spl/php_spl.c             | 330 ++++++----------------------------
 13 files changed, 478 insertions(+), 357 deletions(-)
 create mode 100644 Zend/zend_autoload.c
 create mode 100644 Zend/zend_autoload.h

diff --git a/Zend/Makefile.am b/Zend/Makefile.am
index 6417f3eb141ed..6fe5080d68697 100644
--- a/Zend/Makefile.am
+++ b/Zend/Makefile.am
@@ -18,7 +18,7 @@ libZend_la_SOURCES=\
 	zend_default_classes.c \
 	zend_iterators.c zend_interfaces.c zend_exceptions.c \
 	zend_strtod.c zend_closures.c zend_float.c zend_string.c zend_signal.c \
-	zend_generators.c
+	zend_generators.c zend_autoload.c
 
 libZend_la_LDFLAGS =
 libZend_la_LIBADD = @ZEND_EXTRA_LIBS@
diff --git a/Zend/zend_API.c b/Zend/zend_API.c
index 23ad158b17d44..c657c20b6687e 100644
--- a/Zend/zend_API.c
+++ b/Zend/zend_API.c
@@ -2764,7 +2764,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 (zend_hash_find(EG(function_table), lmname, mlen+1, (void**)&fcc->function_handler) == SUCCESS) {
+		if (zend_lookup_function(lmname, mlen, (void**)&fcc->function_handler) == SUCCESS) {
 			efree(lmname);
 			return 1;
 		}
diff --git a/Zend/zend_autoload.c b/Zend/zend_autoload.c
new file mode 100644
index 0000000000000..8f3abb29c172b
--- /dev/null
+++ b/Zend/zend_autoload.c
@@ -0,0 +1,249 @@
+/*
+   +----------------------------------------------------------------------+
+   | Zend Engine                                                          |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1998-2013 Zend Technologies Ltd. (http://www.zend.com) |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 2.00 of the Zend license,     |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.zend.com/license/2_00.txt.                                |
+   | If you did not receive a copy of the Zend license and are unable to  |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@zend.com so we can mail you a copy immediately.              |
+   +----------------------------------------------------------------------+
+   | Authors: Anthony Ferrara <ircmaxell@php.net>                         |
+   +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "zend.h"
+#include "zend_API.h"
+#include "zend_execute.h"
+#include "zend_globals.h"
+#include "zend_globals_macros.h"
+#include "zend_autoload.h"
+#include "zend_hash.h"
+#include "zend_execute.h"
+#include "zend_interfaces.h"
+#include "zend_exceptions.h"
+
+static char* zend_autoload_get_name_key(zend_fcall_info *fci, int *length, zend_bool *do_free TSRMLS_DC);
+
+int zend_autoload_call(zval* name, long type TSRMLS_DC)
+{
+	zval *ztype, *retval = NULL;
+	char *lc_name;
+	int lc_length;
+	HashTable *symbol_table;
+	HashPosition function_pos;
+	zend_autoload_func *func_info;
+	char dummy = 1;
+
+	if (Z_TYPE_P(name) != IS_STRING) {
+		return FAILURE;
+	}
+
+	switch (type) {
+		case ZEND_AUTOLOAD_CLASS:
+			symbol_table = EG(class_table);
+			break;
+		case ZEND_AUTOLOAD_FUNCTION:
+			symbol_table = EG(function_table);
+			break;
+		default:
+			return FAILURE;
+	}
+
+	lc_length = Z_STRLEN_P(name);
+	lc_name = zend_str_tolower_dup(Z_STRVAL_P(name), lc_length);
+
+	if (EG(autoload_funcs) == NULL || EG(autoload_funcs)->nNumOfElements == 0) {
+		if (type == ZEND_AUTOLOAD_CLASS
+			&& (	
+				EG(autoload_legacy) != NULL
+				|| zend_lookup_function_ex(ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME) - 1, NULL, 0, &EG(autoload_legacy) TSRMLS_CC) == SUCCESS
+			)
+		) {
+			zend_call_method_with_1_params(NULL, NULL, &EG(autoload_legacy), ZEND_AUTOLOAD_FUNC_NAME, &retval, name);
+			if (zend_hash_exists(symbol_table, lc_name, lc_length + 1)) {
+				efree(lc_name);
+				return SUCCESS;
+			}
+		}
+		efree(lc_name);
+		return FAILURE;
+	}
+
+	if (EG(autoload_stack) == NULL) {
+		ALLOC_HASHTABLE(EG(autoload_stack));
+		zend_hash_init(EG(autoload_stack), 0, NULL, NULL, 0);
+	}
+
+	if (zend_hash_add(EG(autoload_stack), lc_name, lc_length, (void**)&dummy, sizeof(char), NULL) == FAILURE) {
+		efree(lc_name);
+		return FAILURE;
+	}
+
+	MAKE_STD_ZVAL(ztype);
+	ZVAL_LONG(ztype, type);
+
+	zend_hash_internal_pointer_reset_ex(EG(autoload_funcs), &function_pos);
+	while(zend_hash_has_more_elements_ex(EG(autoload_funcs), &function_pos) == SUCCESS) {
+		zend_hash_get_current_data_ex(EG(autoload_funcs), (void **) &func_info, &function_pos);
+		if (func_info->type & type) {
+			func_info->fci.retval_ptr_ptr = &retval;
+			zend_fcall_info_argn(&func_info->fci, 2, &name, &ztype);
+			zend_call_function(&func_info->fci, &func_info->fcc TSRMLS_CC);
+			zend_exception_save(TSRMLS_C);
+			if (retval) {
+				zval_ptr_dtor(&retval);
+				retval = NULL;
+			}
+			if (zend_hash_exists(symbol_table, lc_name, lc_length + 1)) {
+				break;
+			}
+		}
+		zend_hash_move_forward_ex(EG(autoload_funcs), &function_pos);
+	}
+	zend_exception_restore(TSRMLS_C);
+
+	Z_DELREF_P(ztype);
+	zend_hash_del(EG(autoload_stack), lc_name, lc_length);
+	efree(lc_name);
+	return SUCCESS;
+}
+
+#define HT_MOVE_TAIL_TO_HEAD(ht)                            \
+    (ht)->pListTail->pListNext = (ht)->pListHead;           \
+    (ht)->pListHead = (ht)->pListTail;                      \
+    (ht)->pListTail = (ht)->pListHead->pListLast;           \
+    (ht)->pListHead->pListNext->pListLast = (ht)->pListHead;\
+    (ht)->pListTail->pListNext = NULL;                      \
+    (ht)->pListHead->pListLast = NULL;
+
+static char* zend_autoload_get_name_key(zend_fcall_info *fci, int *length, zend_bool *do_free TSRMLS_DC) {
+	char *name;
+	switch (Z_TYPE_P(fci->function_name)) {
+		case IS_STRING:
+			*length = Z_STRLEN_P(fci->function_name);
+			return Z_STRVAL_P(fci->function_name);
+			break;
+		case IS_OBJECT:
+			*length = sizeof(zend_object_handle);
+			name = emalloc(*length + 1);
+			*do_free = 1;
+			memcpy(name, &Z_OBJ_HANDLE_P(fci->function_name), *length);
+			name[*length] = '\0';
+			return name;
+			break;
+		default:
+			return 0;
+	}
+}
+
+int zend_autoload_register(zend_autoload_func *func, zend_bool prepend TSRMLS_DC)
+{
+	char *lc_name;
+	zend_bool do_free = 0;
+	int lc_length, status = SUCCESS;
+
+	lc_name = zend_autoload_get_name_key(&func->fci, &lc_length, &do_free);
+	if (lc_name == 0) {
+		zend_error_noreturn(E_ERROR, "Unknown Function Name Type Provided");
+	} else if (do_free) {
+		Z_ADDREF_P(func->callable);
+	}
+
+	if (!EG(autoload_funcs)) {
+		ALLOC_HASHTABLE(EG(autoload_funcs));
+		zend_hash_init(EG(autoload_funcs), 0, NULL, NULL, 0);
+	} else if (zend_hash_exists(EG(autoload_funcs), lc_name, lc_length + 1)) {
+		if (do_free) {
+			efree(lc_name);
+			Z_DELREF_P(func->callable);
+		}
+		return FAILURE;
+	}
+
+	if (zend_hash_add(EG(autoload_funcs), lc_name, lc_length + 1, (void**) func, sizeof(zend_autoload_func), NULL) == FAILURE) {
+		status = FAILURE;
+	} else if (prepend) {
+		HT_MOVE_TAIL_TO_HEAD(EG(autoload_funcs));
+	}
+	if (do_free) {
+		efree(lc_name);
+		Z_DELREF_P(func->callable);
+	}
+	return status;
+}
+
+int zend_autoload_unregister(zval *callable TSRMLS_DC)
+{
+	zend_fcall_info fci;
+	zend_fcall_info_cache fcc;
+	char *lc_name;
+	zend_bool do_free = 0;
+	int lc_length;
+
+	if (zend_fcall_info_init(callable, 0, &fci, &fcc, NULL, NULL) == FAILURE) {
+		return FAILURE;
+	}
+
+	lc_name = zend_autoload_get_name_key(&fci, &lc_length, &do_free);
+	if (lc_name == 0) {
+		return FAILURE;
+	}
+
+	zend_hash_del(EG(autoload_funcs), lc_name, lc_length);
+	if (do_free) {
+		efree(lc_name);
+	}
+
+	return SUCCESS;
+}
+
+ZEND_FUNCTION(autoload_register)
+{
+	zval *callable;
+	zend_autoload_func *func;
+	zend_bool prepend = 0;
+	long type = 0;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_DC, "z|lb", &callable, &type, &prepend) == FAILURE) {
+		return;
+	}
+
+	func = emalloc(sizeof(zend_autoload_func));
+
+	if (zend_fcall_info_init(callable, 0, &func->fci, &func->fcc, NULL, NULL) == FAILURE) {
+		efree(func);
+		zend_error_noreturn(E_ERROR, "Expecting a valid callback");
+	}
+
+	func->callable = callable;
+	Z_ADDREF_P(callable);
+
+	if (!type) {
+		func->type = ZEND_AUTOLOAD_FUNCTION | ZEND_AUTOLOAD_CLASS;
+	} else {
+		func->type = type;
+	}
+
+	if (zend_autoload_register(func, prepend TSRMLS_CC) == FAILURE) {
+		Z_DELREF_P(callable);
+		efree(func);
+	}
+}
+
+ZEND_FUNCTION(autoload_unregister)
+{
+	zval *callable;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_DC, "z", &callable) == FAILURE) {
+		return;
+	}
+	RETVAL_BOOL(zend_autoload_unregister(callable TSRMLS_CC) == SUCCESS);
+}
+
diff --git a/Zend/zend_autoload.h b/Zend/zend_autoload.h
new file mode 100644
index 0000000000000..88f6e12fd3a20
--- /dev/null
+++ b/Zend/zend_autoload.h
@@ -0,0 +1,40 @@
+/*
+   +----------------------------------------------------------------------+
+   | Zend Engine                                                          |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1998-2013 Zend Technologies Ltd. (http://www.zend.com) |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 2.00 of the Zend license,     |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.zend.com/license/2_00.txt.                                |
+   | If you did not receive a copy of the Zend license and are unable to  |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@zend.com so we can mail you a copy immediately.              |
+   +----------------------------------------------------------------------+
+   | Authors: Anthony Ferrara <ircmaxell@php.net>                         |
+   +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+#include "zend.h"
+#include "zend_API.h"
+   
+ZEND_FUNCTION(autoload_register);
+ZEND_FUNCTION(autoload_unregister);
+
+typedef struct {
+   zend_fcall_info fci;
+   zend_fcall_info_cache fcc;
+   zval *callable;
+   long type;
+} zend_autoload_func;
+
+int zend_autoload_call(zval* name, long type TSRMLS_DC);
+int zend_autoload_register(zend_autoload_func* func, zend_bool prepend TSRMLS_DC);
+int zend_autoload_unregister(zval *callable TSRMLS_DC);
+
+#define ZEND_AUTOLOAD_CLASS    1
+#define ZEND_AUTOLOAD_FUNCTION 2
+
+
diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c
index 44a480f2a12f4..d6de0037bb091 100644
--- a/Zend/zend_builtin_functions.c
+++ b/Zend/zend_builtin_functions.c
@@ -22,6 +22,7 @@
 #include "zend.h"
 #include "zend_API.h"
 #include "zend_builtin_functions.h"
+#include "zend_autoload.h"
 #include "zend_constants.h"
 #include "zend_ini.h"
 #include "zend_exceptions.h"
@@ -238,6 +239,16 @@ ZEND_END_ARG_INFO()
 ZEND_BEGIN_ARG_INFO_EX(arginfo_extension_loaded, 0, 0, 1)
 	ZEND_ARG_INFO(0, extension_name)
 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_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_autoload_unregister, 0, 0, 1)
+	ZEND_ARG_INFO(0, callback)
+ZEND_END_ARG_INFO()
 /* }}} */
 
 static const zend_function_entry builtin_functions[] = { /* {{{ */
@@ -307,6 +318,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_FE_END
 };
 /* }}} */
@@ -316,7 +329,6 @@ ZEND_MINIT_FUNCTION(core) { /* {{{ */
 
 	INIT_CLASS_ENTRY(class_entry, "stdClass", NULL);
 	zend_standard_class_def = zend_register_internal_class(&class_entry TSRMLS_CC);
-
 	zend_register_default_classes(TSRMLS_C);
 
 	return SUCCESS;
@@ -1353,8 +1365,9 @@ ZEND_FUNCTION(function_exists)
 	zend_function *func;
 	char *lcname;
 	zend_bool retval;
+	zend_bool autoload = 1;
 	
-	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &name, &name_len, &autoload) == FAILURE) {
 		return;
 	}
 
@@ -1367,7 +1380,7 @@ ZEND_FUNCTION(function_exists)
 		name_len--;
 	}
 
-	retval = (zend_hash_find(EG(function_table), name, name_len+1, (void **)&func) == SUCCESS);
+	retval = (zend_lookup_function_ex(name, name_len+1, NULL, (int) autoload, &func) == SUCCESS);
 	
 	efree(lcname);
 
@@ -1831,7 +1844,7 @@ ZEND_FUNCTION(create_function)
 	if (retval==SUCCESS) {
 		zend_function new_function, *func;
 
-		if (zend_hash_find(EG(function_table), LAMBDA_TEMP_FUNCNAME, sizeof(LAMBDA_TEMP_FUNCNAME), (void **) &func)==FAILURE) {
+		if (zend_lookup_function_ex(LAMBDA_TEMP_FUNCNAME, sizeof(LAMBDA_TEMP_FUNCNAME), NULL, 0, &func)==FAILURE) {
 			zend_error(E_ERROR, "Unexpected inconsistency in create_function()");
 			RETURN_FALSE;
 		}
diff --git a/Zend/zend_constants.c b/Zend/zend_constants.c
index 594559d58bf06..7718e9de28a39 100644
--- a/Zend/zend_constants.c
+++ b/Zend/zend_constants.c
@@ -20,6 +20,7 @@
 /* $Id$ */
 
 #include "zend.h"
+#include "zend_autoload.h"
 #include "zend_constants.h"
 #include "zend_execute.h"
 #include "zend_variables.h"
@@ -125,6 +126,9 @@ void zend_register_standard_constants(TSRMLS_D)
 		REGISTER_MAIN_BOOL_CONSTANT("ZEND_DEBUG_BUILD", ZEND_DEBUG, CONST_PERSISTENT | CONST_CS);
 	}
 	REGISTER_MAIN_NULL_CONSTANT("NULL", CONST_PERSISTENT | CONST_CT_SUBST);
+
+	REGISTER_MAIN_LONG_CONSTANT(ZEND_NS_NAME("php", "AUTOLOAD_CLASS"), ZEND_AUTOLOAD_CLASS, CONST_CS | CONST_PERSISTENT);
+	REGISTER_MAIN_LONG_CONSTANT(ZEND_NS_NAME("php", "AUTOLOAD_FUNCTION"), ZEND_AUTOLOAD_FUNCTION, CONST_CS | CONST_PERSISTENT);
 }
 
 
diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h
index ff0758772e48b..6e470060d5b9b 100644
--- a/Zend/zend_execute.h
+++ b/Zend/zend_execute.h
@@ -63,6 +63,9 @@ ZEND_API void execute_internal(zend_execute_data *execute_data_ptr, struct _zend
 ZEND_API int zend_is_true(zval *op);
 ZEND_API int zend_lookup_class(const char *name, int name_length, zend_class_entry ***ce TSRMLS_DC);
 ZEND_API int zend_lookup_class_ex(const char *name, int name_length, const zend_literal *key, int use_autoload, zend_class_entry ***ce TSRMLS_DC);
+ZEND_API int zend_lookup_function(const char *name, int name_length, zend_function **fbc TSRMLS_DC);
+ZEND_API int zend_lookup_function_ex(const char *name, int name_length, const zend_literal *key, int use_autoload, zend_function **fbc TSRMLS_DC);
+
 ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name TSRMLS_DC);
 ZEND_API int zend_eval_stringl(char *str, int str_len, zval *retval_ptr, char *string_name TSRMLS_DC);
 ZEND_API int zend_eval_string_ex(char *str, zval *retval_ptr, char *string_name, int handle_exceptions TSRMLS_DC);
diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c
index 83c221798416f..80048ecb325fe 100644
--- a/Zend/zend_execute_API.c
+++ b/Zend/zend_execute_API.c
@@ -32,6 +32,7 @@
 #include "zend_exceptions.h"
 #include "zend_closures.h"
 #include "zend_generators.h"
+#include "zend_autoload.h"
 #include "zend_vm.h"
 #include "zend_float.h"
 #ifdef HAVE_SYS_TIME_H
@@ -151,8 +152,8 @@ void init_executor(TSRMLS_D) /* {{{ */
 	EG(class_table) = CG(class_table);
 
 	EG(in_execution) = 0;
-	EG(in_autoload) = NULL;
-	EG(autoload_func) = NULL;
+	EG(autoload_funcs) = NULL;
+	EG(autoload_stack) = NULL;
 	EG(error_handling) = EH_NORMAL;
 
 	zend_vm_stack_init(TSRMLS_C);
@@ -325,9 +326,13 @@ void shutdown_executor(TSRMLS_D) /* {{{ */
 		zend_ptr_stack_destroy(&EG(user_error_handlers));
 		zend_ptr_stack_destroy(&EG(user_exception_handlers));
 		zend_objects_store_destroy(&EG(objects_store));
-		if (EG(in_autoload)) {
-			zend_hash_destroy(EG(in_autoload));
-			FREE_HASHTABLE(EG(in_autoload));
+		if (EG(autoload_stack)) {
+			zend_hash_destroy(EG(autoload_stack));
+			FREE_HASHTABLE(EG(autoload_stack));
+		}
+		if (EG(autoload_funcs)) {
+			zend_hash_destroy(EG(autoload_funcs));
+			FREE_HASHTABLE(EG(autoload_funcs));
 		}
 	} zend_end_try();
 
@@ -1010,18 +1015,81 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
 }
 /* }}} */
 
+ZEND_API int zend_lookup_function(const char *name, int name_length, zend_function **fbc TSRMLS_DC) /* {{{ */
+{	
+	return zend_lookup_function_ex(name, name_length, NULL, 1, fbc TSRMLS_CC);
+}
+
+ZEND_API int zend_lookup_function_ex(const char *name, int name_length, const zend_literal *key, int use_autoload, zend_function **fbc TSRMLS_DC)
+{
+	char *lc_name, *lc_free;
+	int lc_length, retval = FAILURE;
+	zend_ulong hash;
+	ALLOCA_FLAG(use_heap)
+	zval *function_name_ptr;
+
+	if (key) {
+		lc_name = Z_STRVAL(key->constant);
+		lc_length = Z_STRLEN(key->constant) + 1;
+		hash = key->hash_value;
+	} else {
+		if (name == NULL || !name_length) {
+			return FAILURE;
+		}
+
+		lc_free = lc_name = do_alloca(name_length + 1, use_heap);
+		zend_str_tolower_copy(lc_name, name, name_length);
+		lc_length = name_length + 1;
+
+		if (lc_name[0] == '\\') {
+			lc_name += 1;
+			lc_length -= 1;
+		}
+
+		hash = zend_inline_hash_func(lc_name, lc_length);
+	}
+	if (zend_hash_quick_find(EG(function_table), lc_name, lc_length, hash, (void **) fbc) == SUCCESS) {
+		if (!key) {
+			free_alloca(lc_free, use_heap);
+		}
+		return SUCCESS;
+	}
+
+	/* The compiler is not-reentrant. Make sure we __autoload_function() only during run-time
+	 * (doesn't impact functionality of __autoload_function()
+	*/
+	if (!use_autoload || zend_is_compiling(TSRMLS_C)) {
+		if (!key) {
+			free_alloca(lc_free, use_heap);
+		}
+		return FAILURE;
+	}
+
+	ALLOC_ZVAL(function_name_ptr);
+	INIT_PZVAL(function_name_ptr);
+	if (name[0] == '\\') {
+		ZVAL_STRINGL(function_name_ptr, name+1, name_length-1, 1);
+	} else {
+		ZVAL_STRINGL(function_name_ptr, name, name_length, 1);
+	}
+	if (zend_autoload_call(function_name_ptr, ZEND_AUTOLOAD_FUNCTION TSRMLS_CC) == SUCCESS &&
+		zend_hash_quick_find(EG(function_table), lc_name, lc_length, hash, (void **) fbc) == SUCCESS) {
+		retval = SUCCESS;
+	}
+
+	if (!key) {
+		free_alloca(lc_free, use_heap);
+	}
+	return retval;
+
+}
+
 ZEND_API int zend_lookup_class_ex(const char *name, int name_length, const zend_literal *key, int use_autoload, zend_class_entry ***ce TSRMLS_DC) /* {{{ */
 {
-	zval **args[1];
-	zval autoload_function;
 	zval *class_name_ptr;
-	zval *retval_ptr = NULL;
-	int retval, lc_length;
+	int lc_length, retval = FAILURE;
 	char *lc_name;
 	char *lc_free;
-	zend_fcall_info fcall_info;
-	zend_fcall_info_cache fcall_cache;
-	char dummy = 1;
 	ulong hash;
 	ALLOCA_FLAG(use_heap)
 
@@ -1063,20 +1131,6 @@ ZEND_API int zend_lookup_class_ex(const char *name, int name_length, const zend_
 		return FAILURE;
 	}
 
-	if (EG(in_autoload) == NULL) {
-		ALLOC_HASHTABLE(EG(in_autoload));
-		zend_hash_init(EG(in_autoload), 0, NULL, NULL, 0);
-	}
-
-	if (zend_hash_quick_add(EG(in_autoload), lc_name, lc_length, hash, (void**)&dummy, sizeof(char), NULL) == FAILURE) {
-		if (!key) {
-			free_alloca(lc_free, use_heap);
-		}
-		return FAILURE;
-	}
-
-	ZVAL_STRINGL(&autoload_function, ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME) - 1, 0);
-
 	ALLOC_ZVAL(class_name_ptr);
 	INIT_PZVAL(class_name_ptr);
 	if (name[0] == '\\') {
@@ -1084,42 +1138,11 @@ ZEND_API int zend_lookup_class_ex(const char *name, int name_length, const zend_
 	} else {
 		ZVAL_STRINGL(class_name_ptr, name, name_length, 1);
 	}
-
-	args[0] = &class_name_ptr;
-
-	fcall_info.size = sizeof(fcall_info);
-	fcall_info.function_table = EG(function_table);
-	fcall_info.function_name = &autoload_function;
-	fcall_info.symbol_table = NULL;
-	fcall_info.retval_ptr_ptr = &retval_ptr;
-	fcall_info.param_count = 1;
-	fcall_info.params = args;
-	fcall_info.object_ptr = NULL;
-	fcall_info.no_separation = 1;
-
-	fcall_cache.initialized = EG(autoload_func) ? 1 : 0;
-	fcall_cache.function_handler = EG(autoload_func);
-	fcall_cache.calling_scope = NULL;
-	fcall_cache.called_scope = NULL;
-	fcall_cache.object_ptr = NULL;
-
-	zend_exception_save(TSRMLS_C);
-	retval = zend_call_function(&fcall_info, &fcall_cache TSRMLS_CC);
-	zend_exception_restore(TSRMLS_C);
-
-	EG(autoload_func) = fcall_cache.function_handler;
-
-	zval_ptr_dtor(&class_name_ptr);
-
-	zend_hash_quick_del(EG(in_autoload), lc_name, lc_length, hash);
-
-	if (retval_ptr) {
-		zval_ptr_dtor(&retval_ptr);
+	if (zend_autoload_call(class_name_ptr, ZEND_AUTOLOAD_CLASS TSRMLS_CC) == SUCCESS &&
+		zend_hash_quick_find(EG(class_table), lc_name, lc_length, hash, (void **) ce) == SUCCESS) {
+		retval = SUCCESS;
 	}
 
-	if (retval == SUCCESS) {
-		retval = zend_hash_quick_find(EG(class_table), lc_name, lc_length, hash, (void **) ce);
-	}
 	if (!key) {
 		free_alloca(lc_free, use_heap);
 	}
diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h
index 19c29c68f324e..ae2c719511982 100644
--- a/Zend/zend_globals.h
+++ b/Zend/zend_globals.h
@@ -206,8 +206,10 @@ struct _zend_executor_globals {
 	int ticks_count;
 
 	zend_bool in_execution;
-	HashTable *in_autoload;
-	zend_function *autoload_func;
+	HashTable *autoload_stack;
+	HashTable *autoload_funcs;
+	zend_function *autoload_legacy;
+
 	zend_bool full_tables_cleanup;
 
 	/* for extended information support */
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index 7e4f7a897d2db..52b1de40cd7e6 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -2637,7 +2637,7 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV)
 		function_name = (zval*)(opline->op2.literal+1);
 		if (CACHED_PTR(opline->op2.literal->cache_slot)) {
 			call->fbc = CACHED_PTR(opline->op2.literal->cache_slot);
-		} else if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(function_name), Z_STRLEN_P(function_name)+1, Z_HASH_P(function_name), (void **) &call->fbc) == FAILURE)) {
+		} else if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL_P(function_name), Z_STRLEN_P(function_name), (zend_literal*) function_name, 1, &call->fbc) == FAILURE)) {
 			SAVE_OPLINE();
 			zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv));
 		} else {
@@ -2666,7 +2666,7 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV)
 			} else {
 				lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen);
 			}
-			if (UNEXPECTED(zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &call->fbc) == FAILURE)) {
+			if (UNEXPECTED(zend_lookup_function(lcname, function_name_strlen, &call->fbc) == FAILURE)) {
 				zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval);
 			}
 			efree(lcname);
@@ -2783,9 +2783,9 @@ ZEND_VM_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST)
 	func_name = opline->op2.literal + 1;
 	if (CACHED_PTR(opline->op2.literal->cache_slot)) {
 		call->fbc = CACHED_PTR(opline->op2.literal->cache_slot);
-	} else if (zend_hash_quick_find(EG(function_table), Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant)+1, func_name->hash_value, (void **) &call->fbc)==FAILURE) {
+	} else if (zend_lookup_function_ex(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name->hash_value, 1, &call->fbc)==FAILURE) {
 		func_name++;
-		if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant)+1, func_name->hash_value, (void **) &call->fbc)==FAILURE)) {
+		if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name->hash_value, 1, &call->fbc)==FAILURE)) {
 			SAVE_OPLINE();
 			zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv));
 		} else {
@@ -2817,7 +2817,7 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, CONST, ANY)
 
 	if (CACHED_PTR(opline->op1.literal->cache_slot)) {
 		EX(function_state).function = CACHED_PTR(opline->op1.literal->cache_slot);
-	} else if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(fname), Z_STRLEN_P(fname)+1, Z_HASH_P(fname), (void **) &EX(function_state).function)==FAILURE)) {
+	} else if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL_P(fname), Z_STRLEN_P(fname), (zend_literal*) fname, 1, &EX(function_state).function)==FAILURE)) {
 	    SAVE_OPLINE();
 		zend_error_noreturn(E_ERROR, "Call to undefined function %s()", fname->value.str.val);
 	} else {
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index 9622fee5e4efa..4f13d7f1aa542 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -1220,7 +1220,7 @@ static int ZEND_FASTCALL  ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE
 		function_name = (zval*)(opline->op2.literal+1);
 		if (CACHED_PTR(opline->op2.literal->cache_slot)) {
 			call->fbc = CACHED_PTR(opline->op2.literal->cache_slot);
-		} else if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(function_name), Z_STRLEN_P(function_name)+1, Z_HASH_P(function_name), (void **) &call->fbc) == FAILURE)) {
+		} else if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL_P(function_name), Z_STRLEN_P(function_name), (zend_literal*) function_name, 1, &call->fbc) == FAILURE)) {
 			SAVE_OPLINE();
 			zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv));
 		} else {
@@ -1249,7 +1249,7 @@ static int ZEND_FASTCALL  ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE
 			} else {
 				lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen);
 			}
-			if (UNEXPECTED(zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &call->fbc) == FAILURE)) {
+			if (UNEXPECTED(zend_lookup_function(lcname, function_name_strlen, &call->fbc) == FAILURE)) {
 				zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval);
 			}
 			efree(lcname);
@@ -1366,9 +1366,9 @@ static int ZEND_FASTCALL  ZEND_INIT_NS_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPC
 	func_name = opline->op2.literal + 1;
 	if (CACHED_PTR(opline->op2.literal->cache_slot)) {
 		call->fbc = CACHED_PTR(opline->op2.literal->cache_slot);
-	} else if (zend_hash_quick_find(EG(function_table), Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant)+1, func_name->hash_value, (void **) &call->fbc)==FAILURE) {
+	} else if (zend_lookup_function_ex(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name->hash_value, 1, &call->fbc)==FAILURE) {
 		func_name++;
-		if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant)+1, func_name->hash_value, (void **) &call->fbc)==FAILURE)) {
+		if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name->hash_value, 1, &call->fbc)==FAILURE)) {
 			SAVE_OPLINE();
 			zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv));
 		} else {
@@ -1545,7 +1545,7 @@ static int ZEND_FASTCALL  ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H
 		function_name = (zval*)(opline->op2.literal+1);
 		if (CACHED_PTR(opline->op2.literal->cache_slot)) {
 			call->fbc = CACHED_PTR(opline->op2.literal->cache_slot);
-		} else if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(function_name), Z_STRLEN_P(function_name)+1, Z_HASH_P(function_name), (void **) &call->fbc) == FAILURE)) {
+		} else if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL_P(function_name), Z_STRLEN_P(function_name), (zend_literal*) function_name, 1, &call->fbc) == FAILURE)) {
 			SAVE_OPLINE();
 			zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv));
 		} else {
@@ -1574,7 +1574,7 @@ static int ZEND_FASTCALL  ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H
 			} else {
 				lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen);
 			}
-			if (UNEXPECTED(zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &call->fbc) == FAILURE)) {
+			if (UNEXPECTED(zend_lookup_function(lcname, function_name_strlen, &call->fbc) == FAILURE)) {
 				zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval);
 			}
 			efree(lcname);
@@ -1732,7 +1732,7 @@ static int ZEND_FASTCALL  ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H
 		function_name = (zval*)(opline->op2.literal+1);
 		if (CACHED_PTR(opline->op2.literal->cache_slot)) {
 			call->fbc = CACHED_PTR(opline->op2.literal->cache_slot);
-		} else if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(function_name), Z_STRLEN_P(function_name)+1, Z_HASH_P(function_name), (void **) &call->fbc) == FAILURE)) {
+		} else if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL_P(function_name), Z_STRLEN_P(function_name), (zend_literal*) function_name, 1, &call->fbc) == FAILURE)) {
 			SAVE_OPLINE();
 			zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv));
 		} else {
@@ -1761,7 +1761,7 @@ static int ZEND_FASTCALL  ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H
 			} else {
 				lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen);
 			}
-			if (UNEXPECTED(zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &call->fbc) == FAILURE)) {
+			if (UNEXPECTED(zend_lookup_function(lcname, function_name_strlen, &call->fbc) == FAILURE)) {
 				zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval);
 			}
 			efree(lcname);
@@ -1957,7 +1957,7 @@ static int ZEND_FASTCALL  ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA
 		function_name = (zval*)(opline->op2.literal+1);
 		if (CACHED_PTR(opline->op2.literal->cache_slot)) {
 			call->fbc = CACHED_PTR(opline->op2.literal->cache_slot);
-		} else if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(function_name), Z_STRLEN_P(function_name)+1, Z_HASH_P(function_name), (void **) &call->fbc) == FAILURE)) {
+		} else if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL_P(function_name), Z_STRLEN_P(function_name), (zend_literal*) function_name, 1, &call->fbc) == FAILURE)) {
 			SAVE_OPLINE();
 			zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv));
 		} else {
@@ -1986,7 +1986,7 @@ static int ZEND_FASTCALL  ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA
 			} else {
 				lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen);
 			}
-			if (UNEXPECTED(zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &call->fbc) == FAILURE)) {
+			if (UNEXPECTED(zend_lookup_function(lcname, function_name_strlen, &call->fbc) == FAILURE)) {
 				zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval);
 			}
 			efree(lcname);
@@ -2311,7 +2311,7 @@ static int ZEND_FASTCALL  ZEND_DO_FCALL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_A
 
 	if (CACHED_PTR(opline->op1.literal->cache_slot)) {
 		EX(function_state).function = CACHED_PTR(opline->op1.literal->cache_slot);
-	} else if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(fname), Z_STRLEN_P(fname)+1, Z_HASH_P(fname), (void **) &EX(function_state).function)==FAILURE)) {
+	} else if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL_P(fname), Z_STRLEN_P(fname), (zend_literal*) fname, 1, &EX(function_state).function)==FAILURE)) {
 	    SAVE_OPLINE();
 		zend_error_noreturn(E_ERROR, "Call to undefined function %s()", fname->value.str.val);
 	} else {
diff --git a/configure.in b/configure.in
index 16738fe30ab67..f346bd111339d 100644
--- a/configure.in
+++ b/configure.in
@@ -1475,7 +1475,8 @@ PHP_ADD_SOURCES(Zend, \
     zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \
     zend_ini.c zend_qsort.c zend_multibyte.c zend_ts_hash.c zend_stream.c \
     zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c zend_gc.c \
-    zend_closures.c zend_float.c zend_string.c zend_signal.c zend_generators.c)
+    zend_closures.c zend_float.c zend_string.c zend_signal.c zend_generators.c\
+    zend_autoload.c)
 
 if test -r "$abs_srcdir/Zend/zend_objects.c"; then
   PHP_ADD_SOURCES(Zend, zend_objects.c zend_object_handlers.c zend_objects_API.c zend_default_classes.c)
diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c
index 716990d80f02a..8ce82168297d8 100644
--- a/ext/spl/php_spl.c
+++ b/ext/spl/php_spl.c
@@ -39,6 +39,7 @@
 #include "spl_heap.h"
 #include "zend_exceptions.h"
 #include "zend_interfaces.h"
+#include "zend_autoload.h"
 #include "ext/standard/php_rand.h"
 #include "ext/standard/php_lcg.h"
 #include "main/snprintf.h"
@@ -391,65 +392,20 @@ PHP_FUNCTION(spl_autoload_extensions)
 	}
 } /* }}} */
 
-typedef struct {
-	zend_function *func_ptr;
-	zval *obj;
-	zval *closure;
-	zend_class_entry *ce;
-} autoload_func_info;
-
-static void autoload_func_info_dtor(autoload_func_info *alfi)
-{
-	if (alfi->obj) {
-		zval_ptr_dtor(&alfi->obj);
-	}
-	if (alfi->closure) {
-		zval_ptr_dtor(&alfi->closure);
-	}
-}
-
 /* {{{ proto void spl_autoload_call(string class_name)
  Try all registerd autoload function to load the requested class */
 PHP_FUNCTION(spl_autoload_call)
 {
-	zval *class_name, *retval = NULL;
-	int class_name_len;
-	char *func_name, *lc_name;
-	uint func_name_len;
-	ulong dummy;
-	HashPosition function_pos;
-	autoload_func_info *alfi;
+	zval *class_name;
 
 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &class_name) == FAILURE || Z_TYPE_P(class_name) != IS_STRING) {
 		return;
 	}
 
-	if (SPL_G(autoload_functions)) {
-		int l_autoload_running = SPL_G(autoload_running);
-		SPL_G(autoload_running) = 1;
-		class_name_len = Z_STRLEN_P(class_name);
-		lc_name = zend_str_tolower_dup(Z_STRVAL_P(class_name), class_name_len);
-		zend_hash_internal_pointer_reset_ex(SPL_G(autoload_functions), &function_pos);
-		while(zend_hash_has_more_elements_ex(SPL_G(autoload_functions), &function_pos) == SUCCESS) {
-			zend_hash_get_current_key_ex(SPL_G(autoload_functions), &func_name, &func_name_len, &dummy, 0, &function_pos);
-			zend_hash_get_current_data_ex(SPL_G(autoload_functions), (void **) &alfi, &function_pos);
-			zend_call_method(alfi->obj ? &alfi->obj : NULL, alfi->ce, &alfi->func_ptr, func_name, func_name_len, &retval, 1, class_name, NULL TSRMLS_CC);
-			zend_exception_save(TSRMLS_C);
-			if (retval) {
-				zval_ptr_dtor(&retval);
-				retval = NULL;
-			}
-			if (zend_hash_exists(EG(class_table), lc_name, class_name_len + 1)) {
-				break;
-			}
-			zend_hash_move_forward_ex(SPL_G(autoload_functions), &function_pos);
-		}
-		zend_exception_restore(TSRMLS_C);
-		efree(lc_name);
-		SPL_G(autoload_running) = l_autoload_running;
-	} else {
-		/* do not use or overwrite &EG(autoload_func) here */
+	if (EG(autoload_funcs) == NULL) {
 		zend_call_method_with_1_params(NULL, NULL, NULL, "spl_autoload", NULL, class_name);
+	} else {
+		zend_autoload_call(class_name, ZEND_AUTOLOAD_CLASS);
 	}
 } /* }}} */
 
@@ -465,159 +421,78 @@ PHP_FUNCTION(spl_autoload_call)
  Register given function as __autoload() implementation */
 PHP_FUNCTION(spl_autoload_register)
 {
-	char *func_name, *error = NULL;
-	int  func_name_len;
-	char *lc_name = NULL;
+	char *error = NULL;
 	zval *zcallable = NULL;
 	zend_bool do_throw = 1;
 	zend_bool prepend  = 0;
-	zend_function *spl_func_ptr;
-	autoload_func_info alfi;
-	zval *obj_ptr;
-	zend_fcall_info_cache fcc;
+	zend_autoload_func *func;
 
 	if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "|zbb", &zcallable, &do_throw, &prepend) == FAILURE) {
 		return;
 	}
 
-	if (ZEND_NUM_ARGS()) {
-		if (Z_TYPE_P(zcallable) == IS_STRING) {
-			if (Z_STRLEN_P(zcallable) == sizeof("spl_autoload_call") - 1) {
-				if (!zend_binary_strcasecmp(Z_STRVAL_P(zcallable), sizeof("spl_autoload_call"), "spl_autoload_call", sizeof("spl_autoload_call"))) {
-					if (do_throw) {
-						zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Function spl_autoload_call() cannot be registered");
-					}
-					RETURN_FALSE;
-				}
-			}
-		}
-	
-		if (!zend_is_callable_ex(zcallable, NULL, IS_CALLABLE_STRICT, &func_name, &func_name_len, &fcc, &error TSRMLS_CC)) {
-			alfi.ce = fcc.calling_scope;
-			alfi.func_ptr = fcc.function_handler;
-			obj_ptr = fcc.object_ptr;
-			if (Z_TYPE_P(zcallable) == IS_ARRAY) {
-				if (!obj_ptr && alfi.func_ptr && !(alfi.func_ptr->common.fn_flags & ZEND_ACC_STATIC)) {
-					if (do_throw) {
-						zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Passed array specifies a non static method but no object (%s)", error);
-					}
-					if (error) {
-						efree(error);
-					}
-					efree(func_name);
-					RETURN_FALSE;
-				}
-				else if (do_throw) {
-					zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Passed array does not specify %s %smethod (%s)", alfi.func_ptr ? "a callable" : "an existing", !obj_ptr ? "static " : "", error);
-				}
-				if (error) {
-					efree(error);
-				}
-				efree(func_name);
-				RETURN_FALSE;
-			} else if (Z_TYPE_P(zcallable) == IS_STRING) {
-				if (do_throw) {
-					zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Function '%s' not %s (%s)", func_name, alfi.func_ptr ? "callable" : "found", error);
-				}
-				if (error) {
-					efree(error);
-				}
-				efree(func_name);
-				RETURN_FALSE;
-			} else {
+	func = emalloc(sizeof(zend_autoload_func));
+	func->type = ZEND_AUTOLOAD_CLASS;
+
+	if (!ZEND_NUM_ARGS()) {
+		MAKE_STD_ZVAL(zcallable);
+		ZVAL_STRING(zcallable, "spl_autoload", 1);
+	}
+
+	if (zend_fcall_info_init(zcallable, IS_CALLABLE_STRICT, &func->fci, &func->fcc, NULL, &error) == FAILURE) {
+		if (Z_TYPE_P(zcallable) == IS_ARRAY) {
+			if (!func->fcc.object_ptr && func->fcc.function_handler && !(func->fcc.function_handler->common.fn_flags & ZEND_ACC_STATIC)) {
 				if (do_throw) {
-					zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Illegal value passed (%s)", error);
+					zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Passed array specifies a non static method but no object (%s)", error);
 				}
+				efree(func);
 				if (error) {
 					efree(error);
 				}
-				efree(func_name);
 				RETURN_FALSE;
 			}
-		}
-		alfi.closure = NULL;
-		alfi.ce = fcc.calling_scope;
-		alfi.func_ptr = fcc.function_handler;
-		obj_ptr = fcc.object_ptr;
-		if (error) {
-			efree(error);
-		}
-	
-		lc_name = safe_emalloc(func_name_len, 1, sizeof(long) + 1);
-		zend_str_tolower_copy(lc_name, func_name, func_name_len);
-		efree(func_name);
-
-		if (Z_TYPE_P(zcallable) == IS_OBJECT) {
-			alfi.closure = zcallable;
-			Z_ADDREF_P(zcallable);
-
-			lc_name = erealloc(lc_name, func_name_len + 2 + sizeof(zend_object_handle));
-			memcpy(lc_name + func_name_len, &Z_OBJ_HANDLE_P(zcallable),
-				sizeof(zend_object_handle));
-			func_name_len += sizeof(zend_object_handle);
-			lc_name[func_name_len] = '\0';
-		}
-
-		if (SPL_G(autoload_functions) && zend_hash_exists(SPL_G(autoload_functions), (char*)lc_name, func_name_len+1)) {
-			if (alfi.closure) {
-				Z_DELREF_P(zcallable);
+			else if (do_throw) {
+				zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Passed array does not specify %s %smethod (%s)", func->fcc.function_handler ? "a callable" : "an existing", !func->fcc.object_ptr ? "static " : "", error);
 			}
-			goto skip;
-		}
-
-		if (obj_ptr && !(alfi.func_ptr->common.fn_flags & ZEND_ACC_STATIC)) {
-			/* add object id to the hash to ensure uniqueness, for more reference look at bug #40091 */
-			lc_name = erealloc(lc_name, func_name_len + 2 + sizeof(zend_object_handle));
-			memcpy(lc_name + func_name_len, &Z_OBJ_HANDLE_P(obj_ptr), sizeof(zend_object_handle));
-			func_name_len += sizeof(zend_object_handle);
-			lc_name[func_name_len] = '\0';
-			alfi.obj = obj_ptr;
-			Z_ADDREF_P(alfi.obj);
+			efree(func);
+			if (error) {
+				efree(error);
+			}
+			RETURN_FALSE;
+		} else if (Z_TYPE_P(zcallable) == IS_STRING) {
+			if (do_throw) {
+				zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Function '%s' not %s (%s)", Z_STRVAL_P(zcallable), func->fcc.function_handler ? "callable" : "found", error);
+			}
+			efree(func);
+			if (error) {
+				efree(error);
+			}
+			RETURN_FALSE;
 		} else {
-			alfi.obj = NULL;
-		}
-
-		if (!SPL_G(autoload_functions)) {
-			ALLOC_HASHTABLE(SPL_G(autoload_functions));
-			zend_hash_init(SPL_G(autoload_functions), 1, NULL, (dtor_func_t) autoload_func_info_dtor, 0);
-		}
-
-		zend_hash_find(EG(function_table), "spl_autoload", sizeof("spl_autoload"), (void **) &spl_func_ptr);
-
-		if (EG(autoload_func) == spl_func_ptr) { /* registered already, so we insert that first */
-			autoload_func_info spl_alfi;
-
-			spl_alfi.func_ptr = spl_func_ptr;
-			spl_alfi.obj = NULL;
-			spl_alfi.ce = NULL;
-			spl_alfi.closure = NULL;
-			zend_hash_add(SPL_G(autoload_functions), "spl_autoload", sizeof("spl_autoload"), &spl_alfi, sizeof(autoload_func_info), NULL);
-			if (prepend && SPL_G(autoload_functions)->nNumOfElements > 1) {
-				/* Move the newly created element to the head of the hashtable */
-				HT_MOVE_TAIL_TO_HEAD(SPL_G(autoload_functions));
+			if (do_throw) {
+				zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Illegal value passed (%s)", error);
 			}
-		}
-
-		if (zend_hash_add(SPL_G(autoload_functions), lc_name, func_name_len+1, &alfi.func_ptr, sizeof(autoload_func_info), NULL) == FAILURE) {
-			if (obj_ptr && !(alfi.func_ptr->common.fn_flags & ZEND_ACC_STATIC)) {
-				Z_DELREF_P(alfi.obj);
-			}				
-			if (alfi.closure) {
-				Z_DELREF_P(alfi.closure);
+			efree(func);
+			if (error) {
+				efree(error);
 			}
+			RETURN_FALSE;
 		}
-		if (prepend && SPL_G(autoload_functions)->nNumOfElements > 1) {
-			/* Move the newly created element to the head of the hashtable */
-			HT_MOVE_TAIL_TO_HEAD(SPL_G(autoload_functions));
-		}
-skip:
-		efree(lc_name);
+	}
+	func->callable = zcallable;
+	if (ZEND_NUM_ARGS()) {
+		Z_ADDREF_P(func->callable);
+	}
+	if (error) {
+		efree(error);
 	}
 
-	if (SPL_G(autoload_functions)) {
-		zend_hash_find(EG(function_table), "spl_autoload_call", sizeof("spl_autoload_call"), (void **) &EG(autoload_func));
-	} else {
-		zend_hash_find(EG(function_table), "spl_autoload", sizeof("spl_autoload"), (void **) &EG(autoload_func));
+	if (zend_autoload_register(func, prepend TSRMLS_CC) == FAILURE) {
+		if (ZEND_NUM_ARGS()) {
+			Z_DELREF_P(func->callable);
+		}
+		efree(func);
+		RETURN_FALSE;
 	}
 	RETURN_TRUE;
 } /* }}} */
@@ -628,11 +503,7 @@ PHP_FUNCTION(spl_autoload_unregister)
 {
 	char *func_name, *error = NULL;
 	int func_name_len;
-	char *lc_name = NULL;
 	zval *zcallable;
-	int success = FAILURE;
-	zend_function *spl_func_ptr;
-	zval *obj_ptr;
 	zend_fcall_info_cache fcc;
 
 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zcallable) == FAILURE) {
@@ -649,54 +520,11 @@ PHP_FUNCTION(spl_autoload_unregister)
 		}
 		RETURN_FALSE;
 	}
-	obj_ptr = fcc.object_ptr;
 	if (error) {
 		efree(error);
 	}
 
-	lc_name = safe_emalloc(func_name_len, 1, sizeof(long) + 1);
-	zend_str_tolower_copy(lc_name, func_name, func_name_len);
-	efree(func_name);
-
-	if (Z_TYPE_P(zcallable) == IS_OBJECT) {
-		lc_name = erealloc(lc_name, func_name_len + 2 + sizeof(zend_object_handle));
-		memcpy(lc_name + func_name_len, &Z_OBJ_HANDLE_P(zcallable),
-			sizeof(zend_object_handle));
-		func_name_len += sizeof(zend_object_handle);
-		lc_name[func_name_len] = '\0';
-	}
-
-	if (SPL_G(autoload_functions)) {
-		if (func_name_len == sizeof("spl_autoload_call")-1 && !strcmp(lc_name, "spl_autoload_call")) {
-			/* remove all */
-			zend_hash_destroy(SPL_G(autoload_functions));
-			FREE_HASHTABLE(SPL_G(autoload_functions));
-			SPL_G(autoload_functions) = NULL;
-			EG(autoload_func) = NULL;
-			success = SUCCESS;
-		} else {
-			/* remove specific */
-			success = zend_hash_del(SPL_G(autoload_functions), lc_name, func_name_len+1);
-			if (success != SUCCESS && obj_ptr) {
-				lc_name = erealloc(lc_name, func_name_len + 2 + sizeof(zend_object_handle));
-				memcpy(lc_name + func_name_len, &Z_OBJ_HANDLE_P(obj_ptr), sizeof(zend_object_handle));
-				func_name_len += sizeof(zend_object_handle);
-				lc_name[func_name_len] = '\0';
-				success = zend_hash_del(SPL_G(autoload_functions), lc_name, func_name_len+1);
-			}
-		}
-	} else if (func_name_len == sizeof("spl_autoload")-1 && !strcmp(lc_name, "spl_autoload")) {
-		/* register single spl_autoload() */
-		zend_hash_find(EG(function_table), "spl_autoload", sizeof("spl_autoload"), (void **) &spl_func_ptr);
-
-		if (EG(autoload_func) == spl_func_ptr) {
-			success = SUCCESS;
-			EG(autoload_func) = NULL;
-		}
-	}
-
-	efree(lc_name);
-	RETURN_BOOL(success == SUCCESS);
+	RETURN_BOOL(zend_autoload_unregister(&fcc TSRMLS_CC) == SUCCESS);
 } /* }}} */
 
 /* {{{ proto false|array spl_autoload_functions()
@@ -704,14 +532,12 @@ PHP_FUNCTION(spl_autoload_unregister)
 PHP_FUNCTION(spl_autoload_functions)
 {
 	zend_function *fptr;
-	HashPosition function_pos;
-	autoload_func_info *alfi;
 
 	if (zend_parse_parameters_none() == FAILURE) {
 		return;
 	}
 	
-	if (!EG(autoload_func)) {
+	if (!EG(autoload_funcs)) {
 		if (zend_hash_find(EG(function_table), ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME), (void **) &fptr) == SUCCESS) {
 			array_init(return_value);
 			add_next_index_stringl(return_value, ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME)-1, 1);
@@ -720,48 +546,8 @@ PHP_FUNCTION(spl_autoload_functions)
 		RETURN_FALSE;
 	}
 
-	zend_hash_find(EG(function_table), "spl_autoload_call", sizeof("spl_autoload_call"), (void **) &fptr);
-
-	if (EG(autoload_func) == fptr) {
-		array_init(return_value);
-		zend_hash_internal_pointer_reset_ex(SPL_G(autoload_functions), &function_pos);
-		while(zend_hash_has_more_elements_ex(SPL_G(autoload_functions), &function_pos) == SUCCESS) {
-			zend_hash_get_current_data_ex(SPL_G(autoload_functions), (void **) &alfi, &function_pos);
-			if (alfi->closure) {
-				Z_ADDREF_P(alfi->closure);
-				add_next_index_zval(return_value, alfi->closure);
-			} else if (alfi->func_ptr->common.scope) {
-				zval *tmp;
-				MAKE_STD_ZVAL(tmp);
-				array_init(tmp);
-
-				if (alfi->obj) {
-					Z_ADDREF_P(alfi->obj);
-					add_next_index_zval(tmp, alfi->obj);
-				} else {
-					add_next_index_string(tmp, alfi->ce->name, 1);
-				}
-				add_next_index_string(tmp, alfi->func_ptr->common.function_name, 1);
-				add_next_index_zval(return_value, tmp);
-			} else {
-				if (strncmp(alfi->func_ptr->common.function_name, "__lambda_func", sizeof("__lambda_func") - 1)) {
-					add_next_index_string(return_value, alfi->func_ptr->common.function_name, 1);
-				} else {
-				   char *key;
-				   uint len;
-				   long dummy;
-				   zend_hash_get_current_key_ex(SPL_G(autoload_functions), &key, &len, &dummy, 0, &function_pos); 
-				   add_next_index_stringl(return_value, key, len - 1, 1);
-				}
-			}
+	/* TODO: Update SPL Functions */
 
-			zend_hash_move_forward_ex(SPL_G(autoload_functions), &function_pos);
-		}
-		return;
-	}
-
-	array_init(return_value);
-	add_next_index_string(return_value, EG(autoload_func)->common.function_name, 1);
 } /* }}} */
 
 /* {{{ proto string spl_object_hash(object obj)

From b2f07349fce355aa393890833f6cab8f285ffdbb Mon Sep 17 00:00:00 2001
From: ircmaxell <ircmaxell@gmail.com>
Date: Thu, 29 Aug 2013 21:06:33 -0400
Subject: [PATCH 02/20] More progress

---
 Zend/zend.h            |  1 +
 Zend/zend_autoload.c   |  7 +++++--
 Zend/zend_autoload.h   |  6 +++---
 Zend/zend_constants.c  | 10 ++++++++++
 Zend/zend_execute.h    |  3 +++
 Zend/zend_vm_def.h     | 10 +++++-----
 Zend/zend_vm_execute.h | 22 +++++++++++-----------
 7 files changed, 38 insertions(+), 21 deletions(-)

diff --git a/Zend/zend.h b/Zend/zend.h
index 1377fd566594b..326787c7f01af 100644
--- a/Zend/zend.h
+++ b/Zend/zend.h
@@ -596,6 +596,7 @@ typedef int (*zend_write_func_t)(const char *str, uint str_length);
 #define IS_LEXICAL_VAR				0x020
 #define IS_LEXICAL_REF				0x040
 #define IS_CONSTANT_IN_NAMESPACE	0x100
+#define IS_CONSTANT_IN_AUTOLOAD		0x200
 
 /* overloaded elements data types */
 #define OE_IS_ARRAY		(1<<0)
diff --git a/Zend/zend_autoload.c b/Zend/zend_autoload.c
index 8f3abb29c172b..84a5906e57f1d 100644
--- a/Zend/zend_autoload.c
+++ b/Zend/zend_autoload.c
@@ -31,7 +31,7 @@
 
 static char* zend_autoload_get_name_key(zend_fcall_info *fci, int *length, zend_bool *do_free TSRMLS_DC);
 
-int zend_autoload_call(zval* name, long type TSRMLS_DC)
+int zend_autoload_call(const zval* name, long type TSRMLS_DC)
 {
 	zval *ztype, *retval = NULL;
 	char *lc_name;
@@ -52,6 +52,9 @@ int zend_autoload_call(zval* name, long type TSRMLS_DC)
 		case ZEND_AUTOLOAD_FUNCTION:
 			symbol_table = EG(function_table);
 			break;
+		case ZEND_AUTOLOAD_CONSTANT:
+			symbol_table = EG(zend_constants);
+			break;
 		default:
 			return FAILURE;
 	}
@@ -226,7 +229,7 @@ ZEND_FUNCTION(autoload_register)
 	Z_ADDREF_P(callable);
 
 	if (!type) {
-		func->type = ZEND_AUTOLOAD_FUNCTION | ZEND_AUTOLOAD_CLASS;
+		func->type = ZEND_AUTOLOAD_ALL;
 	} else {
 		func->type = type;
 	}
diff --git a/Zend/zend_autoload.h b/Zend/zend_autoload.h
index 88f6e12fd3a20..87d4bf54abe7d 100644
--- a/Zend/zend_autoload.h
+++ b/Zend/zend_autoload.h
@@ -30,11 +30,11 @@ typedef struct {
    long type;
 } zend_autoload_func;
 
-int zend_autoload_call(zval* name, long type TSRMLS_DC);
+int zend_autoload_call(const zval* name, long type TSRMLS_DC);
 int zend_autoload_register(zend_autoload_func* func, zend_bool prepend TSRMLS_DC);
 int zend_autoload_unregister(zval *callable TSRMLS_DC);
 
 #define ZEND_AUTOLOAD_CLASS    1
 #define ZEND_AUTOLOAD_FUNCTION 2
-
-
+#define ZEND_AUTOLOAD_CONSTANT 4
+#define ZEND_AUTOLOAD_ALL      (~0)
diff --git a/Zend/zend_constants.c b/Zend/zend_constants.c
index 7718e9de28a39..dc76ec66a6ee8 100644
--- a/Zend/zend_constants.c
+++ b/Zend/zend_constants.c
@@ -129,6 +129,10 @@ void zend_register_standard_constants(TSRMLS_D)
 
 	REGISTER_MAIN_LONG_CONSTANT(ZEND_NS_NAME("php", "AUTOLOAD_CLASS"), ZEND_AUTOLOAD_CLASS, CONST_CS | CONST_PERSISTENT);
 	REGISTER_MAIN_LONG_CONSTANT(ZEND_NS_NAME("php", "AUTOLOAD_FUNCTION"), ZEND_AUTOLOAD_FUNCTION, CONST_CS | CONST_PERSISTENT);
+	REGISTER_MAIN_LONG_CONSTANT(ZEND_NS_NAME("php", "AUTOLOAD_CONSTANT"), ZEND_AUTOLOAD_CONSTANT, CONST_CS | CONST_PERSISTENT);
+	REGISTER_MAIN_LONG_CONSTANT(ZEND_NS_NAME("php", "AUTOLOAD_ALL"), ZEND_AUTOLOAD_ALL, CONST_CS | CONST_PERSISTENT);
+
+
 }
 
 
@@ -458,6 +462,9 @@ zend_constant *zend_quick_get_constant(const zend_literal *key, ulong flags TSRM
 
 						key--;
 						if (!zend_get_special_constant(Z_STRVAL(key->constant), Z_STRLEN(key->constant), &c TSRMLS_CC)) {
+							if (!(flags & IS_CONSTANT_IN_AUTOLOAD) && zend_autoload_call(&key->constant, ZEND_AUTOLOAD_CONSTANT TSRMLS_CC) == SUCCESS) {
+								return zend_quick_get_constant(key, flags | IS_CONSTANT_IN_AUTOLOAD TSRMLS_CC);
+							}
 							return NULL;
 						}
 					}
@@ -465,6 +472,9 @@ zend_constant *zend_quick_get_constant(const zend_literal *key, ulong flags TSRM
 			} else {
 				key--;
 				if (!zend_get_special_constant(Z_STRVAL(key->constant), Z_STRLEN(key->constant), &c TSRMLS_CC)) {
+					if (!(flags & IS_CONSTANT_IN_AUTOLOAD) && zend_autoload_call(&key->constant, ZEND_AUTOLOAD_CONSTANT TSRMLS_CC) == SUCCESS) {
+						return zend_quick_get_constant(key, flags | IS_CONSTANT_IN_AUTOLOAD TSRMLS_CC);
+					}
 					return NULL;
 				}
 			}
diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h
index 6e470060d5b9b..43c8f5bc02b0c 100644
--- a/Zend/zend_execute.h
+++ b/Zend/zend_execute.h
@@ -66,6 +66,9 @@ ZEND_API int zend_lookup_class_ex(const char *name, int name_length, const zend_
 ZEND_API int zend_lookup_function(const char *name, int name_length, zend_function **fbc TSRMLS_DC);
 ZEND_API int zend_lookup_function_ex(const char *name, int name_length, const zend_literal *key, int use_autoload, zend_function **fbc TSRMLS_DC);
 
+#define ZEND_LOOKUP_FUNCTION_BY_NAME(name, name_length, fbc) (zend_hash_find(EG(function_table), (name), (name_length) + 1, (void**) (fbc)) == SUCCESS || zend_lookup_function((name), (name_length), (fbc)) == SUCCESS)
+#define ZEND_LOOKUP_FUNCTION_BY_LITERAL(name, name_length, literal, fbc) (zend_hash_quick_find(EG(function_table), (name), (name_length) + 1, Z_HASH_P(literal), (void**) (fbc)) == SUCCESS || zend_lookup_function_ex((name), (name_length), (zend_literal*) (literal), 1, (fbc)) == SUCCESS)
+
 ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name TSRMLS_DC);
 ZEND_API int zend_eval_stringl(char *str, int str_len, zval *retval_ptr, char *string_name TSRMLS_DC);
 ZEND_API int zend_eval_string_ex(char *str, zval *retval_ptr, char *string_name, int handle_exceptions TSRMLS_DC);
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index 52b1de40cd7e6..d03706cc41114 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -2637,7 +2637,7 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV)
 		function_name = (zval*)(opline->op2.literal+1);
 		if (CACHED_PTR(opline->op2.literal->cache_slot)) {
 			call->fbc = CACHED_PTR(opline->op2.literal->cache_slot);
-		} else if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL_P(function_name), Z_STRLEN_P(function_name), (zend_literal*) function_name, 1, &call->fbc) == FAILURE)) {
+		} else if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_LITERAL(Z_STRVAL_P(function_name), Z_STRLEN_P(function_name), function_name, &call->fbc))) {
 			SAVE_OPLINE();
 			zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv));
 		} else {
@@ -2666,7 +2666,7 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV)
 			} else {
 				lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen);
 			}
-			if (UNEXPECTED(zend_lookup_function(lcname, function_name_strlen, &call->fbc) == FAILURE)) {
+			if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_NAME(lcname, function_name_strlen, &call->fbc))) {
 				zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval);
 			}
 			efree(lcname);
@@ -2783,9 +2783,9 @@ ZEND_VM_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST)
 	func_name = opline->op2.literal + 1;
 	if (CACHED_PTR(opline->op2.literal->cache_slot)) {
 		call->fbc = CACHED_PTR(opline->op2.literal->cache_slot);
-	} else if (zend_lookup_function_ex(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name->hash_value, 1, &call->fbc)==FAILURE) {
+	} else if (!ZEND_LOOKUP_FUNCTION_BY_LITERAL(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name->hash_value, &call->fbc)) {
 		func_name++;
-		if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name->hash_value, 1, &call->fbc)==FAILURE)) {
+		if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_LITERAL(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name->hash_value, &call->fbc))) {
 			SAVE_OPLINE();
 			zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv));
 		} else {
@@ -2817,7 +2817,7 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, CONST, ANY)
 
 	if (CACHED_PTR(opline->op1.literal->cache_slot)) {
 		EX(function_state).function = CACHED_PTR(opline->op1.literal->cache_slot);
-	} else if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL_P(fname), Z_STRLEN_P(fname), (zend_literal*) fname, 1, &EX(function_state).function)==FAILURE)) {
+	} else if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_LITERAL(Z_STRVAL_P(fname), Z_STRLEN_P(fname), fname, &EX(function_state).function))) {
 	    SAVE_OPLINE();
 		zend_error_noreturn(E_ERROR, "Call to undefined function %s()", fname->value.str.val);
 	} else {
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index 4f13d7f1aa542..f7bb4866dd31e 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -1220,7 +1220,7 @@ static int ZEND_FASTCALL  ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE
 		function_name = (zval*)(opline->op2.literal+1);
 		if (CACHED_PTR(opline->op2.literal->cache_slot)) {
 			call->fbc = CACHED_PTR(opline->op2.literal->cache_slot);
-		} else if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL_P(function_name), Z_STRLEN_P(function_name), (zend_literal*) function_name, 1, &call->fbc) == FAILURE)) {
+		} else if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_LITERAL(Z_STRVAL_P(function_name), Z_STRLEN_P(function_name), function_name, &call->fbc))) {
 			SAVE_OPLINE();
 			zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv));
 		} else {
@@ -1249,7 +1249,7 @@ static int ZEND_FASTCALL  ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE
 			} else {
 				lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen);
 			}
-			if (UNEXPECTED(zend_lookup_function(lcname, function_name_strlen, &call->fbc) == FAILURE)) {
+			if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_NAME(lcname, function_name_strlen, &call->fbc))) {
 				zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval);
 			}
 			efree(lcname);
@@ -1366,9 +1366,9 @@ static int ZEND_FASTCALL  ZEND_INIT_NS_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPC
 	func_name = opline->op2.literal + 1;
 	if (CACHED_PTR(opline->op2.literal->cache_slot)) {
 		call->fbc = CACHED_PTR(opline->op2.literal->cache_slot);
-	} else if (zend_lookup_function_ex(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name->hash_value, 1, &call->fbc)==FAILURE) {
+	} else if (!ZEND_LOOKUP_FUNCTION_BY_LITERAL(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name->hash_value, &call->fbc)) {
 		func_name++;
-		if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name->hash_value, 1, &call->fbc)==FAILURE)) {
+		if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_LITERAL(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name->hash_value, &call->fbc))) {
 			SAVE_OPLINE();
 			zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv));
 		} else {
@@ -1545,7 +1545,7 @@ static int ZEND_FASTCALL  ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H
 		function_name = (zval*)(opline->op2.literal+1);
 		if (CACHED_PTR(opline->op2.literal->cache_slot)) {
 			call->fbc = CACHED_PTR(opline->op2.literal->cache_slot);
-		} else if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL_P(function_name), Z_STRLEN_P(function_name), (zend_literal*) function_name, 1, &call->fbc) == FAILURE)) {
+		} else if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_LITERAL(Z_STRVAL_P(function_name), Z_STRLEN_P(function_name), function_name, &call->fbc))) {
 			SAVE_OPLINE();
 			zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv));
 		} else {
@@ -1574,7 +1574,7 @@ static int ZEND_FASTCALL  ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H
 			} else {
 				lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen);
 			}
-			if (UNEXPECTED(zend_lookup_function(lcname, function_name_strlen, &call->fbc) == FAILURE)) {
+			if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_NAME(lcname, function_name_strlen, &call->fbc))) {
 				zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval);
 			}
 			efree(lcname);
@@ -1732,7 +1732,7 @@ static int ZEND_FASTCALL  ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H
 		function_name = (zval*)(opline->op2.literal+1);
 		if (CACHED_PTR(opline->op2.literal->cache_slot)) {
 			call->fbc = CACHED_PTR(opline->op2.literal->cache_slot);
-		} else if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL_P(function_name), Z_STRLEN_P(function_name), (zend_literal*) function_name, 1, &call->fbc) == FAILURE)) {
+		} else if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_LITERAL(Z_STRVAL_P(function_name), Z_STRLEN_P(function_name), function_name, &call->fbc))) {
 			SAVE_OPLINE();
 			zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv));
 		} else {
@@ -1761,7 +1761,7 @@ static int ZEND_FASTCALL  ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H
 			} else {
 				lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen);
 			}
-			if (UNEXPECTED(zend_lookup_function(lcname, function_name_strlen, &call->fbc) == FAILURE)) {
+			if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_NAME(lcname, function_name_strlen, &call->fbc))) {
 				zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval);
 			}
 			efree(lcname);
@@ -1957,7 +1957,7 @@ static int ZEND_FASTCALL  ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA
 		function_name = (zval*)(opline->op2.literal+1);
 		if (CACHED_PTR(opline->op2.literal->cache_slot)) {
 			call->fbc = CACHED_PTR(opline->op2.literal->cache_slot);
-		} else if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL_P(function_name), Z_STRLEN_P(function_name), (zend_literal*) function_name, 1, &call->fbc) == FAILURE)) {
+		} else if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_LITERAL(Z_STRVAL_P(function_name), Z_STRLEN_P(function_name), function_name, &call->fbc))) {
 			SAVE_OPLINE();
 			zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv));
 		} else {
@@ -1986,7 +1986,7 @@ static int ZEND_FASTCALL  ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA
 			} else {
 				lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen);
 			}
-			if (UNEXPECTED(zend_lookup_function(lcname, function_name_strlen, &call->fbc) == FAILURE)) {
+			if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_NAME(lcname, function_name_strlen, &call->fbc))) {
 				zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval);
 			}
 			efree(lcname);
@@ -2311,7 +2311,7 @@ static int ZEND_FASTCALL  ZEND_DO_FCALL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_A
 
 	if (CACHED_PTR(opline->op1.literal->cache_slot)) {
 		EX(function_state).function = CACHED_PTR(opline->op1.literal->cache_slot);
-	} else if (UNEXPECTED(zend_lookup_function_ex(Z_STRVAL_P(fname), Z_STRLEN_P(fname), (zend_literal*) fname, 1, &EX(function_state).function)==FAILURE)) {
+	} else if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_LITERAL(Z_STRVAL_P(fname), Z_STRLEN_P(fname), fname, &EX(function_state).function))) {
 	    SAVE_OPLINE();
 		zend_error_noreturn(E_ERROR, "Call to undefined function %s()", fname->value.str.val);
 	} else {

From d10dc034a370ba87c53c90bbdb020f2d88a90800 Mon Sep 17 00:00:00 2001
From: Anthony Ferrara <ircmaxell@gmail.com>
Date: Fri, 30 Aug 2013 11:34:05 -0400
Subject: [PATCH 03/20] More work, fixing memleaks and behavior

---
 Zend/zend_autoload.c          | 19 +++++++++++--------
 Zend/zend_builtin_functions.c |  2 +-
 Zend/zend_execute_API.c       |  4 ++--
 Zend/zend_vm_def.h            |  4 ++--
 Zend/zend_vm_execute.h        |  4 ++--
 ext/spl/php_spl.c             |  3 ++-
 6 files changed, 20 insertions(+), 16 deletions(-)

diff --git a/Zend/zend_autoload.c b/Zend/zend_autoload.c
index 84a5906e57f1d..28d2ecbd2e312 100644
--- a/Zend/zend_autoload.c
+++ b/Zend/zend_autoload.c
@@ -30,6 +30,7 @@
 #include "zend_exceptions.h"
 
 static char* zend_autoload_get_name_key(zend_fcall_info *fci, int *length, zend_bool *do_free TSRMLS_DC);
+static void zend_autoload_func_dtor(zend_autoload_func *func);
 
 int zend_autoload_call(const zval* name, long type TSRMLS_DC)
 {
@@ -112,7 +113,7 @@ int zend_autoload_call(const zval* name, long type TSRMLS_DC)
 	}
 	zend_exception_restore(TSRMLS_C);
 
-	Z_DELREF_P(ztype);
+	zval_ptr_dtor(&ztype);
 	zend_hash_del(EG(autoload_stack), lc_name, lc_length);
 	efree(lc_name);
 	return SUCCESS;
@@ -146,6 +147,12 @@ static char* zend_autoload_get_name_key(zend_fcall_info *fci, int *length, zend_
 	}
 }
 
+static void zend_autoload_func_dtor(zend_autoload_func *func) {
+	if (func->callable) {
+		zval_ptr_dtor(&func->callable);
+	}
+}
+
 int zend_autoload_register(zend_autoload_func *func, zend_bool prepend TSRMLS_DC)
 {
 	char *lc_name;
@@ -155,17 +162,14 @@ int zend_autoload_register(zend_autoload_func *func, zend_bool prepend TSRMLS_DC
 	lc_name = zend_autoload_get_name_key(&func->fci, &lc_length, &do_free);
 	if (lc_name == 0) {
 		zend_error_noreturn(E_ERROR, "Unknown Function Name Type Provided");
-	} else if (do_free) {
-		Z_ADDREF_P(func->callable);
 	}
 
 	if (!EG(autoload_funcs)) {
 		ALLOC_HASHTABLE(EG(autoload_funcs));
-		zend_hash_init(EG(autoload_funcs), 0, NULL, NULL, 0);
+		zend_hash_init(EG(autoload_funcs), 1, NULL, (dtor_func_t) zend_autoload_func_dtor, 0);
 	} else if (zend_hash_exists(EG(autoload_funcs), lc_name, lc_length + 1)) {
 		if (do_free) {
 			efree(lc_name);
-			Z_DELREF_P(func->callable);
 		}
 		return FAILURE;
 	}
@@ -177,7 +181,6 @@ int zend_autoload_register(zend_autoload_func *func, zend_bool prepend TSRMLS_DC
 	}
 	if (do_free) {
 		efree(lc_name);
-		Z_DELREF_P(func->callable);
 	}
 	return status;
 }
@@ -235,9 +238,9 @@ ZEND_FUNCTION(autoload_register)
 	}
 
 	if (zend_autoload_register(func, prepend TSRMLS_CC) == FAILURE) {
-		Z_DELREF_P(callable);
-		efree(func);
+		zval_ptr_dtor(&callable);
 	}
+	efree(func);
 }
 
 ZEND_FUNCTION(autoload_unregister)
diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c
index d6de0037bb091..d967a6adac3ca 100644
--- a/Zend/zend_builtin_functions.c
+++ b/Zend/zend_builtin_functions.c
@@ -1380,7 +1380,7 @@ ZEND_FUNCTION(function_exists)
 		name_len--;
 	}
 
-	retval = (zend_lookup_function_ex(name, name_len+1, NULL, (int) autoload, &func) == SUCCESS);
+	retval = (zend_lookup_function_ex(name, name_len, NULL, (int) autoload, &func) == SUCCESS);
 	
 	efree(lcname);
 
diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c
index 80048ecb325fe..e714ffa7ceecb 100644
--- a/Zend/zend_execute_API.c
+++ b/Zend/zend_execute_API.c
@@ -1065,8 +1065,7 @@ ZEND_API int zend_lookup_function_ex(const char *name, int name_length, const ze
 		return FAILURE;
 	}
 
-	ALLOC_ZVAL(function_name_ptr);
-	INIT_PZVAL(function_name_ptr);
+	ALLOC_INIT_ZVAL(function_name_ptr);
 	if (name[0] == '\\') {
 		ZVAL_STRINGL(function_name_ptr, name+1, name_length-1, 1);
 	} else {
@@ -1076,6 +1075,7 @@ ZEND_API int zend_lookup_function_ex(const char *name, int name_length, const ze
 		zend_hash_quick_find(EG(function_table), lc_name, lc_length, hash, (void **) fbc) == SUCCESS) {
 		retval = SUCCESS;
 	}
+	zval_ptr_dtor(&function_name_ptr);
 
 	if (!key) {
 		free_alloca(lc_free, use_heap);
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index d03706cc41114..ece52b2f029af 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -2783,9 +2783,9 @@ ZEND_VM_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST)
 	func_name = opline->op2.literal + 1;
 	if (CACHED_PTR(opline->op2.literal->cache_slot)) {
 		call->fbc = CACHED_PTR(opline->op2.literal->cache_slot);
-	} else if (!ZEND_LOOKUP_FUNCTION_BY_LITERAL(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name->hash_value, &call->fbc)) {
+	} else if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant) + 1, func_name->hash_value, (void**) &call->fbc) == FAILURE)) {
 		func_name++;
-		if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_LITERAL(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name->hash_value, &call->fbc))) {
+		if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_LITERAL(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name, &call->fbc))) {
 			SAVE_OPLINE();
 			zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv));
 		} else {
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index f7bb4866dd31e..71e357480995c 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -1366,9 +1366,9 @@ static int ZEND_FASTCALL  ZEND_INIT_NS_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPC
 	func_name = opline->op2.literal + 1;
 	if (CACHED_PTR(opline->op2.literal->cache_slot)) {
 		call->fbc = CACHED_PTR(opline->op2.literal->cache_slot);
-	} else if (!ZEND_LOOKUP_FUNCTION_BY_LITERAL(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name->hash_value, &call->fbc)) {
+	} else if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant) + 1, func_name->hash_value, (void**) &call->fbc) == FAILURE)) {
 		func_name++;
-		if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_LITERAL(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name->hash_value, &call->fbc))) {
+		if (UNEXPECTED(!ZEND_LOOKUP_FUNCTION_BY_LITERAL(Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant), func_name, &call->fbc))) {
 			SAVE_OPLINE();
 			zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv));
 		} else {
diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c
index 8ce82168297d8..ddfbbd7dd227e 100644
--- a/ext/spl/php_spl.c
+++ b/ext/spl/php_spl.c
@@ -489,11 +489,12 @@ PHP_FUNCTION(spl_autoload_register)
 
 	if (zend_autoload_register(func, prepend TSRMLS_CC) == FAILURE) {
 		if (ZEND_NUM_ARGS()) {
-			Z_DELREF_P(func->callable);
+			zval_ptr_dtor(&func->callable);
 		}
 		efree(func);
 		RETURN_FALSE;
 	}
+	efree(func);
 	RETURN_TRUE;
 } /* }}} */
 

From 5e71fb581f82cb3fd19da70731d6617113f08ea0 Mon Sep 17 00:00:00 2001
From: Anthony Ferrara <ircmaxell@gmail.com>
Date: Fri, 30 Aug 2013 13:27:20 -0400
Subject: [PATCH 04/20] Refactor out the lookup in is_callable

---
 Zend/zend_API.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Zend/zend_API.c b/Zend/zend_API.c
index c657c20b6687e..28143e6ffcf5b 100644
--- a/Zend/zend_API.c
+++ b/Zend/zend_API.c
@@ -2764,7 +2764,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 (zend_lookup_function(lmname, mlen, (void**)&fcc->function_handler) == SUCCESS) {
+		if (ZEND_LOOKUP_FUNCTION_BY_NAME(lmname, mlen, &fcc->function_handler)) {
 			efree(lmname);
 			return 1;
 		}

From 2efdc970f051eb69352252e4ff45fa5ba16ff7ec Mon Sep 17 00:00:00 2001
From: Anthony Ferrara <ircmaxell@gmail.com>
Date: Fri, 30 Aug 2013 13:35:25 -0400
Subject: [PATCH 05/20] Remove lowercasing components

---
 Zend/zend_execute_API.c | 29 +++++++----------------------
 1 file changed, 7 insertions(+), 22 deletions(-)

diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c
index e714ffa7ceecb..bea33d3a53bb4 100644
--- a/Zend/zend_execute_API.c
+++ b/Zend/zend_execute_API.c
@@ -1022,12 +1022,13 @@ ZEND_API int zend_lookup_function(const char *name, int name_length, zend_functi
 
 ZEND_API int zend_lookup_function_ex(const char *name, int name_length, const zend_literal *key, int use_autoload, zend_function **fbc TSRMLS_DC)
 {
-	char *lc_name, *lc_free;
-	int lc_length, retval = FAILURE;
+	char *lc_name;
+	int lc_length;
+	int retval = FAILURE;
 	zend_ulong hash;
-	ALLOCA_FLAG(use_heap)
 	zval *function_name_ptr;
 
+
 	if (key) {
 		lc_name = Z_STRVAL(key->constant);
 		lc_length = Z_STRLEN(key->constant) + 1;
@@ -1036,22 +1037,12 @@ ZEND_API int zend_lookup_function_ex(const char *name, int name_length, const ze
 		if (name == NULL || !name_length) {
 			return FAILURE;
 		}
-
-		lc_free = lc_name = do_alloca(name_length + 1, use_heap);
-		zend_str_tolower_copy(lc_name, name, name_length);
-		lc_length = name_length + 1;
-
-		if (lc_name[0] == '\\') {
-			lc_name += 1;
-			lc_length -= 1;
-		}
-
+		lc_name = name;
+		lc_length = name_length;
 		hash = zend_inline_hash_func(lc_name, lc_length);
 	}
 	if (zend_hash_quick_find(EG(function_table), lc_name, lc_length, hash, (void **) fbc) == SUCCESS) {
-		if (!key) {
-			free_alloca(lc_free, use_heap);
-		}
+
 		return SUCCESS;
 	}
 
@@ -1059,9 +1050,6 @@ ZEND_API int zend_lookup_function_ex(const char *name, int name_length, const ze
 	 * (doesn't impact functionality of __autoload_function()
 	*/
 	if (!use_autoload || zend_is_compiling(TSRMLS_C)) {
-		if (!key) {
-			free_alloca(lc_free, use_heap);
-		}
 		return FAILURE;
 	}
 
@@ -1077,9 +1065,6 @@ ZEND_API int zend_lookup_function_ex(const char *name, int name_length, const ze
 	}
 	zval_ptr_dtor(&function_name_ptr);
 
-	if (!key) {
-		free_alloca(lc_free, use_heap);
-	}
 	return retval;
 
 }

From 6aa5b0370965e03284deced557d99d250046ff6e Mon Sep 17 00:00:00 2001
From: Anthony Ferrara <ircmaxell@gmail.com>
Date: Fri, 30 Aug 2013 14:09:26 -0400
Subject: [PATCH 06/20] Fix memory leak, and clean up a bit

---
 Zend/zend_autoload.c    | 1 +
 Zend/zend_execute_API.c | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/Zend/zend_autoload.c b/Zend/zend_autoload.c
index 28d2ecbd2e312..a42c8b321bd76 100644
--- a/Zend/zend_autoload.c
+++ b/Zend/zend_autoload.c
@@ -111,6 +111,7 @@ int zend_autoload_call(const zval* name, long type TSRMLS_DC)
 		}
 		zend_hash_move_forward_ex(EG(autoload_funcs), &function_pos);
 	}
+	zend_fcall_info_args_clear(&func_info->fci, 1);
 	zend_exception_restore(TSRMLS_C);
 
 	zval_ptr_dtor(&ztype);
diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c
index bea33d3a53bb4..e58898bb33127 100644
--- a/Zend/zend_execute_API.c
+++ b/Zend/zend_execute_API.c
@@ -1127,7 +1127,7 @@ ZEND_API int zend_lookup_class_ex(const char *name, int name_length, const zend_
 		zend_hash_quick_find(EG(class_table), lc_name, lc_length, hash, (void **) ce) == SUCCESS) {
 		retval = SUCCESS;
 	}
-
+	zval_ptr_dtor(&class_name_ptr);
 	if (!key) {
 		free_alloca(lc_free, use_heap);
 	}

From cdac9d7c6412a04dcd5b49a2e11b638a82399530 Mon Sep 17 00:00:00 2001
From: krakjoe <joe.watkins@live.co.uk>
Date: Sat, 21 Dec 2013 20:18:22 +0000
Subject: [PATCH 07/20] fix build

---
 Zend/zend_execute_API.c | 3 +++
 Zend/zend_globals.h     | 1 +
 Zend/zend_vm_opcodes.h  | 2 +-
 3 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c
index 6bf17088b9c72..4fc10e6b6d0c8 100644
--- a/Zend/zend_execute_API.c
+++ b/Zend/zend_execute_API.c
@@ -1084,11 +1084,14 @@ ZEND_API int zend_lookup_function_ex(const char *name, int name_length, const ze
 
 ZEND_API int zend_lookup_class_ex(const char *name, int name_length, const zend_literal *key, int use_autoload, zend_class_entry ***ce TSRMLS_DC) /* {{{ */
 {
+	zval autoload_function;
 	zval *class_name_ptr;
 	int lc_length, retval = FAILURE;
 	char *lc_name;
 	char *lc_free;
 	ulong hash;
+	char dummy = 1;
+	
 	ALLOCA_FLAG(use_heap)
 
 	if (key) {
diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h
index 051916ecae6f4..04ce8b4a7109b 100644
--- a/Zend/zend_globals.h
+++ b/Zend/zend_globals.h
@@ -207,6 +207,7 @@ struct _zend_executor_globals {
 	zend_bool in_execution;
 	HashTable *autoload_stack;
 	HashTable *autoload_funcs;
+	HashTable *in_autoload;
 	zend_function *autoload_legacy;
 
 	zend_bool full_tables_cleanup;
diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h
index 663e216183001..184462d51e681 100644
--- a/Zend/zend_vm_opcodes.h
+++ b/Zend/zend_vm_opcodes.h
@@ -337,4 +337,4 @@ const char *zend_vm_opcodes_map[] = {
 	"ZEND_RECV_VARIADIC",
 };
 
-#endif
\ No newline at end of file
+#endif

From 8657f772269b0f031470c66d280484397d2129db Mon Sep 17 00:00:00 2001
From: krakjoe <joe.watkins@live.co.uk>
Date: Sat, 21 Dec 2013 20:42:02 +0000
Subject: [PATCH 08/20] fix call to unload

---
 ext/spl/php_spl.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c
index ddfbbd7dd227e..8bf633adaf57e 100644
--- a/ext/spl/php_spl.c
+++ b/ext/spl/php_spl.c
@@ -525,7 +525,7 @@ PHP_FUNCTION(spl_autoload_unregister)
 		efree(error);
 	}
 
-	RETURN_BOOL(zend_autoload_unregister(&fcc TSRMLS_CC) == SUCCESS);
+	RETURN_BOOL(zend_autoload_unregister(zcallable TSRMLS_CC) == SUCCESS);
 } /* }}} */
 
 /* {{{ proto false|array spl_autoload_functions()

From 8a73ed4bc9382dde15da3b868b94be45fceb0b73 Mon Sep 17 00:00:00 2001
From: krakjoe <joe.watkins@live.co.uk>
Date: Sat, 21 Dec 2013 21:21:33 +0000
Subject: [PATCH 09/20] fix build

---
 Zend/zend_execute_API.c | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c
index 4fc10e6b6d0c8..5436b6b71310d 100644
--- a/Zend/zend_execute_API.c
+++ b/Zend/zend_execute_API.c
@@ -1090,8 +1090,6 @@ ZEND_API int zend_lookup_class_ex(const char *name, int name_length, const zend_
 	char *lc_name;
 	char *lc_free;
 	ulong hash;
-	char dummy = 1;
-	
 	ALLOCA_FLAG(use_heap)
 
 	if (key) {
@@ -1145,12 +1143,18 @@ ZEND_API int zend_lookup_class_ex(const char *name, int name_length, const zend_
 		zend_hash_init(EG(in_autoload), 0, NULL, NULL, 0);
 	}
 
-	if (zend_hash_quick_add(EG(in_autoload), lc_name, lc_length, hash, (void**)&dummy, sizeof(char), NULL) == FAILURE) {
-		if (!key) {
-			free_alloca(lc_free, use_heap);
+	
+	{	
+		char unused = 1;
+		
+		if (zend_hash_quick_add(EG(in_autoload), lc_name, lc_length, hash, (void**)&unused, sizeof(char), NULL) == FAILURE) {
+			if (!key) {
+				free_alloca(lc_free, use_heap);
+			}
+			return FAILURE;
 		}
-		return FAILURE;
 	}
+	
 
 	ZVAL_STRINGL(&autoload_function, ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME) - 1, 0);
 

From f16b075dbde494516635c6c0f385d87f0e50322a Mon Sep 17 00:00:00 2001
From: krakjoe <joe.watkins@live.co.uk>
Date: Sat, 21 Dec 2013 22:16:20 +0000
Subject: [PATCH 10/20] fix patch, run tests

---
 Zend/zend.c                   |  2 ++
 Zend/zend_builtin_functions.c |  2 +-
 Zend/zend_execute_API.c       | 11 +++++++----
 3 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/Zend/zend.c b/Zend/zend.c
index ad45028d4be85..bd71269cd4ef0 100644
--- a/Zend/zend.c
+++ b/Zend/zend.c
@@ -581,6 +581,8 @@ static void executor_globals_ctor(zend_executor_globals *executor_globals TSRMLS
 #endif
 	EG(saved_fpu_cw_ptr) = NULL;
 	EG(active) = 0;
+	EG(autoload_legacy) = NULL;
+	EG(autoload_stack) = NULL;
 }
 /* }}} */
 
diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c
index 9e95194fe5950..f60c1b1aa8e3e 100644
--- a/Zend/zend_builtin_functions.c
+++ b/Zend/zend_builtin_functions.c
@@ -1390,7 +1390,7 @@ ZEND_FUNCTION(function_exists)
 		name_len--;
 	}
 
-	retval = (zend_lookup_function_ex(name, name_len, NULL, (int) autoload, &func) == SUCCESS);
+	retval = (zend_lookup_function_ex(lcname, name_len+1, NULL, (int) autoload, &func) == SUCCESS);
 	
 	efree(lcname);
 
diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c
index 5436b6b71310d..af97cc3345ea0 100644
--- a/Zend/zend_execute_API.c
+++ b/Zend/zend_execute_API.c
@@ -1054,8 +1054,8 @@ ZEND_API int zend_lookup_function_ex(const char *name, int name_length, const ze
 		lc_length = name_length;
 		hash = zend_inline_hash_func(lc_name, lc_length);
 	}
+	
 	if (zend_hash_quick_find(EG(function_table), lc_name, lc_length, hash, (void **) fbc) == SUCCESS) {
-
 		return SUCCESS;
 	}
 
@@ -1072,10 +1072,13 @@ ZEND_API int zend_lookup_function_ex(const char *name, int name_length, const ze
 	} else {
 		ZVAL_STRINGL(function_name_ptr, name, name_length, 1);
 	}
-	if (zend_autoload_call(function_name_ptr, ZEND_AUTOLOAD_FUNCTION TSRMLS_CC) == SUCCESS &&
-		zend_hash_quick_find(EG(function_table), lc_name, lc_length, hash, (void **) fbc) == SUCCESS) {
-		retval = SUCCESS;
+	
+	if (zend_autoload_call(function_name_ptr, ZEND_AUTOLOAD_FUNCTION TSRMLS_CC) != SUCCESS) {
+		/* do something, or not */
 	}
+	
+	retval = zend_hash_quick_find(
+		EG(function_table), lc_name, lc_length, hash, (void **) fbc);
 	zval_ptr_dtor(&function_name_ptr);
 
 	return retval;

From dfa13d9a24c11ca67a7fdd8ab2428eaee6525f6e Mon Sep 17 00:00:00 2001
From: krakjoe <joe.watkins@live.co.uk>
Date: Sat, 21 Dec 2013 22:26:24 +0000
Subject: [PATCH 11/20] plug leaks

---
 Zend/zend.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/Zend/zend.c b/Zend/zend.c
index bd71269cd4ef0..dca072e129c6b 100644
--- a/Zend/zend.c
+++ b/Zend/zend.c
@@ -966,6 +966,16 @@ ZEND_API void zend_deactivate(TSRMLS_D) /* {{{ */
 	}
 #endif
 
+	if (EG(autoload_stack)) {
+		zend_hash_destroy(EG(autoload_stack));
+		FREE_HASHTABLE(EG(autoload_stack));
+	}
+	
+	if (EG(in_autoload)) {
+		zend_hash_destroy(EG(in_autoload));
+		FREE_HASHTABLE(EG(in_autoload));
+	}
+
 #if GC_BENCH
 	fprintf(stderr, "GC Statistics\n");
 	fprintf(stderr, "-------------\n");

From c34abb56fe57719eca9be6010f4a3182ba4a1fa5 Mon Sep 17 00:00:00 2001
From: krakjoe <joe.watkins@live.co.uk>
Date: Sun, 22 Dec 2013 07:48:48 +0000
Subject: [PATCH 12/20] fix most tests in Zend, three remain

---
 Zend/zend.c                   | 10 ----------
 Zend/zend_autoload.c          | 10 ++++++++--
 Zend/zend_builtin_functions.c |  2 +-
 Zend/zend_execute_API.c       | 12 ++++++++++++
 4 files changed, 21 insertions(+), 13 deletions(-)

diff --git a/Zend/zend.c b/Zend/zend.c
index dca072e129c6b..bd71269cd4ef0 100644
--- a/Zend/zend.c
+++ b/Zend/zend.c
@@ -966,16 +966,6 @@ ZEND_API void zend_deactivate(TSRMLS_D) /* {{{ */
 	}
 #endif
 
-	if (EG(autoload_stack)) {
-		zend_hash_destroy(EG(autoload_stack));
-		FREE_HASHTABLE(EG(autoload_stack));
-	}
-	
-	if (EG(in_autoload)) {
-		zend_hash_destroy(EG(in_autoload));
-		FREE_HASHTABLE(EG(in_autoload));
-	}
-
 #if GC_BENCH
 	fprintf(stderr, "GC Statistics\n");
 	fprintf(stderr, "-------------\n");
diff --git a/Zend/zend_autoload.c b/Zend/zend_autoload.c
index a42c8b321bd76..6d32f84076f4b 100644
--- a/Zend/zend_autoload.c
+++ b/Zend/zend_autoload.c
@@ -67,14 +67,20 @@ int zend_autoload_call(const zval* name, long type TSRMLS_DC)
 		if (type == ZEND_AUTOLOAD_CLASS
 			&& (	
 				EG(autoload_legacy) != NULL
-				|| zend_lookup_function_ex(ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME) - 1, NULL, 0, &EG(autoload_legacy) TSRMLS_CC) == SUCCESS
+				|| zend_lookup_function_ex(ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME), NULL, 0, &EG(autoload_legacy) TSRMLS_CC) == SUCCESS
 			)
 		) {
-			zend_call_method_with_1_params(NULL, NULL, &EG(autoload_legacy), ZEND_AUTOLOAD_FUNC_NAME, &retval, name);
+			zend_call_method_with_1_params(NULL, NULL, &EG(autoload_legacy), ZEND_AUTOLOAD_FUNC_NAME, &retval, (zval*) name);
 			if (zend_hash_exists(symbol_table, lc_name, lc_length + 1)) {
+				if (retval) {
+					zval_ptr_dtor(&retval);
+				}
 				efree(lc_name);
 				return SUCCESS;
 			}
+			if (retval) {
+				zval_ptr_dtor(&retval);
+			}
 		}
 		efree(lc_name);
 		return FAILURE;
diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c
index f60c1b1aa8e3e..4c2030f42b703 100644
--- a/Zend/zend_builtin_functions.c
+++ b/Zend/zend_builtin_functions.c
@@ -1390,7 +1390,7 @@ ZEND_FUNCTION(function_exists)
 		name_len--;
 	}
 
-	retval = (zend_lookup_function_ex(lcname, name_len+1, NULL, (int) autoload, &func) == SUCCESS);
+	retval = (zend_lookup_function_ex(name, name_len+1, NULL, (int) autoload, &func) == SUCCESS);
 	
 	efree(lcname);
 
diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c
index af97cc3345ea0..fc007c38eef52 100644
--- a/Zend/zend_execute_API.c
+++ b/Zend/zend_execute_API.c
@@ -326,13 +326,25 @@ void shutdown_executor(TSRMLS_D) /* {{{ */
 		zend_ptr_stack_destroy(&EG(user_error_handlers));
 		zend_ptr_stack_destroy(&EG(user_exception_handlers));
 		zend_objects_store_destroy(&EG(objects_store));
+		
+	} zend_end_try();
+	
+	zend_try {
+		/* shutdown autoload */
 		if (EG(autoload_stack)) {
 			zend_hash_destroy(EG(autoload_stack));
 			FREE_HASHTABLE(EG(autoload_stack));
+			EG(autoload_stack) = NULL;
 		}
 		if (EG(autoload_funcs)) {
 			zend_hash_destroy(EG(autoload_funcs));
 			FREE_HASHTABLE(EG(autoload_funcs));
+			EG(autoload_funcs) = NULL;
+		}
+		if (EG(in_autoload)) {
+			zend_hash_destroy(EG(in_autoload));
+			FREE_HASHTABLE(EG(in_autoload));
+			EG(in_autoload) = NULL;
 		}
 	} zend_end_try();
 

From cfa2f6f627e4c7bbafc201e935484362a3da1bbb Mon Sep 17 00:00:00 2001
From: krakjoe <joe.watkins@live.co.uk>
Date: Sun, 22 Dec 2013 09:00:59 +0000
Subject: [PATCH 13/20] fix register autoload array callable

---
 Zend/zend_autoload.c | 26 ++++++++++++++++++++++----
 1 file changed, 22 insertions(+), 4 deletions(-)

diff --git a/Zend/zend_autoload.c b/Zend/zend_autoload.c
index 6d32f84076f4b..c2eaba07ddcda 100644
--- a/Zend/zend_autoload.c
+++ b/Zend/zend_autoload.c
@@ -29,7 +29,7 @@
 #include "zend_interfaces.h"
 #include "zend_exceptions.h"
 
-static char* zend_autoload_get_name_key(zend_fcall_info *fci, int *length, zend_bool *do_free TSRMLS_DC);
+static char* zend_autoload_get_name_key(zend_fcall_info *fci, zend_fcall_info_cache *fcc, int *length, zend_bool *do_free TSRMLS_DC);
 static void zend_autoload_func_dtor(zend_autoload_func *func);
 
 int zend_autoload_call(const zval* name, long type TSRMLS_DC)
@@ -134,7 +134,7 @@ int zend_autoload_call(const zval* name, long type TSRMLS_DC)
     (ht)->pListTail->pListNext = NULL;                      \
     (ht)->pListHead->pListLast = NULL;
 
-static char* zend_autoload_get_name_key(zend_fcall_info *fci, int *length, zend_bool *do_free TSRMLS_DC) {
+static char* zend_autoload_get_name_key(zend_fcall_info *fci, zend_fcall_info_cache *fcc, int *length, zend_bool *do_free TSRMLS_DC) {
 	char *name;
 	switch (Z_TYPE_P(fci->function_name)) {
 		case IS_STRING:
@@ -149,6 +149,24 @@ static char* zend_autoload_get_name_key(zend_fcall_info *fci, int *length, zend_
 			name[*length] = '\0';
 			return name;
 			break;
+		case IS_ARRAY:
+			if (fcc->function_handler->common.scope) {
+				zend_function *func = fcc->function_handler;
+				zend_class_entry *ce = func->common.scope;
+				
+				*do_free = 1;
+				if (ce) {
+					*length = strlen(func->common.function_name) + ce->name_length + 2;
+					name = emalloc(*length + 1);
+					memcpy(name, ce->name, ce->name_length);
+					memcpy(&name[ce->name_length], "::", sizeof("::")-1);
+					memcpy(&name[ce->name_length+sizeof("::")-1], 
+						func->common.function_name, strlen(func->common.function_name));
+					name[*length] = 0;
+					return name;
+				}
+			}
+			break;
 		default:
 			return 0;
 	}
@@ -166,7 +184,7 @@ int zend_autoload_register(zend_autoload_func *func, zend_bool prepend TSRMLS_DC
 	zend_bool do_free = 0;
 	int lc_length, status = SUCCESS;
 
-	lc_name = zend_autoload_get_name_key(&func->fci, &lc_length, &do_free);
+	lc_name = zend_autoload_get_name_key(&func->fci, &func->fcc, &lc_length, &do_free);
 	if (lc_name == 0) {
 		zend_error_noreturn(E_ERROR, "Unknown Function Name Type Provided");
 	}
@@ -204,7 +222,7 @@ int zend_autoload_unregister(zval *callable TSRMLS_DC)
 		return FAILURE;
 	}
 
-	lc_name = zend_autoload_get_name_key(&fci, &lc_length, &do_free);
+	lc_name = zend_autoload_get_name_key(&fci, &fcc, &lc_length, &do_free);
 	if (lc_name == 0) {
 		return FAILURE;
 	}

From 3cf2f1f1c05bd43d92789f098dec4eff74fd6807 Mon Sep 17 00:00:00 2001
From: krakjoe <joe.watkins@live.co.uk>
Date: Sun, 22 Dec 2013 09:06:33 +0000
Subject: [PATCH 14/20] fix error conditions test, prototype for
 function_exists

---
 Zend/tests/function_exists_error.phpt | 6 +++---
 Zend/zend_builtin_functions.c         | 4 ++--
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/Zend/tests/function_exists_error.phpt b/Zend/tests/function_exists_error.phpt
index cbc3908f12b30..1a696d47c171b 100644
--- a/Zend/tests/function_exists_error.phpt
+++ b/Zend/tests/function_exists_error.phpt
@@ -13,7 +13,7 @@ $arg_0 = "ABC";
 $extra_arg = 1;
 
 echo "\nToo many arguments\n";
-var_dump(function_exists($arg_0, $extra_arg));
+var_dump(function_exists($arg_0, true, $extra_arg));
 
 echo "\nToo few arguments\n";
 var_dump(function_exists());
@@ -25,12 +25,12 @@ var_dump(function_exists());
 
 Too many arguments
 
-Warning: function_exists() expects exactly 1 parameter, 2 given in %s on line %d
+Warning: function_exists() expects at most 2 parameters, 3 given in %s on line %d
 NULL
 
 Too few arguments
 
-Warning: function_exists() expects exactly 1 parameter, 0 given in %s on line %d
+Warning: function_exists() expects at least 1 parameter, 0 given in %s on line %d
 NULL
 ===Done===
 
diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c
index 4c2030f42b703..11c841f729364 100644
--- a/Zend/zend_builtin_functions.c
+++ b/Zend/zend_builtin_functions.c
@@ -1366,8 +1366,8 @@ ZEND_FUNCTION(trait_exists)
 /* }}} */
 
 
-/* {{{ proto bool function_exists(string function_name) 
-   Checks if the function exists */
+/* {{{ proto bool function_exists(string function_name [, boolean autoload = true]) 
+   Checks if the function exists, optionally and by default invoking autoloaders */
 ZEND_FUNCTION(function_exists)
 {
 	char *name;

From 2212f244ea68a93b2affaad3293ceb7ced4cbb37 Mon Sep 17 00:00:00 2001
From: krakjoe <joe.watkins@live.co.uk>
Date: Sun, 22 Dec 2013 09:10:31 +0000
Subject: [PATCH 15/20] correct test

---
 Zend/tests/function_exists_error.phpt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Zend/tests/function_exists_error.phpt b/Zend/tests/function_exists_error.phpt
index 1a696d47c171b..f3f2f6f89cbde 100644
--- a/Zend/tests/function_exists_error.phpt
+++ b/Zend/tests/function_exists_error.phpt
@@ -3,7 +3,7 @@ Test function_exists() function : error conditions
 --FILE--
 <?php
 /* 
- * proto bool function_exists(string function_name)
+ * proto bool function_exists(string function_name [, boolean autoload = true])
  * Function is implemented in Zend/zend_builtin_functions.c
 */ 
 

From e2d73a2aae005f5c4141ead8f3844fe2e7143271 Mon Sep 17 00:00:00 2001
From: krakjoe <joe.watkins@live.co.uk>
Date: Sun, 22 Dec 2013 10:47:32 +0000
Subject: [PATCH 16/20] be compatible with phpdbg

---
 Zend/zend_autoload.c    | 3 +++
 Zend/zend_execute_API.c | 1 +
 2 files changed, 4 insertions(+)

diff --git a/Zend/zend_autoload.c b/Zend/zend_autoload.c
index c2eaba07ddcda..0fff2bc51f353 100644
--- a/Zend/zend_autoload.c
+++ b/Zend/zend_autoload.c
@@ -71,10 +71,12 @@ int zend_autoload_call(const zval* name, long type TSRMLS_DC)
 			)
 		) {
 			zend_call_method_with_1_params(NULL, NULL, &EG(autoload_legacy), ZEND_AUTOLOAD_FUNC_NAME, &retval, (zval*) name);
+			zend_exception_save(TSRMLS_C);
 			if (zend_hash_exists(symbol_table, lc_name, lc_length + 1)) {
 				if (retval) {
 					zval_ptr_dtor(&retval);
 				}
+				zend_exception_restore(TSRMLS_C);
 				efree(lc_name);
 				return SUCCESS;
 			}
@@ -82,6 +84,7 @@ int zend_autoload_call(const zval* name, long type TSRMLS_DC)
 				zval_ptr_dtor(&retval);
 			}
 		}
+		zend_exception_restore(TSRMLS_C);
 		efree(lc_name);
 		return FAILURE;
 	}
diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c
index fc007c38eef52..9135da23283ae 100644
--- a/Zend/zend_execute_API.c
+++ b/Zend/zend_execute_API.c
@@ -346,6 +346,7 @@ void shutdown_executor(TSRMLS_D) /* {{{ */
 			FREE_HASHTABLE(EG(in_autoload));
 			EG(in_autoload) = NULL;
 		}
+		EG(autoload_legacy) = NULL;
 	} zend_end_try();
 
 	zend_shutdown_fpu(TSRMLS_C);

From 2b68179ecf222ad8fb9fd8dc6396897c7f175b42 Mon Sep 17 00:00:00 2001
From: krakjoe <joe.watkins@live.co.uk>
Date: Sun, 22 Dec 2013 11:54:42 +0000
Subject: [PATCH 17/20] fix zts build

---
 Zend/tests/bug61011.phpt      |  2 +-
 Zend/zend_autoload.c          | 57 ++++++++++++++++++-----------------
 Zend/zend_builtin_functions.c |  4 +--
 Zend/zend_execute.h           |  4 +--
 ext/spl/php_spl.c             |  4 +--
 5 files changed, 36 insertions(+), 35 deletions(-)

diff --git a/Zend/tests/bug61011.phpt b/Zend/tests/bug61011.phpt
index bce0e33209b3a..4efefc2ff5e21 100644
--- a/Zend/tests/bug61011.phpt
+++ b/Zend/tests/bug61011.phpt
@@ -5,7 +5,7 @@ Bug #61011 (Crash when an exception is thrown by __autoload accessing a static p
 function __autoload($name) {
 	throw new Exception($name);
 }
-try { 
+try {
 	echo AAA::$a; //zend_fetch_var_address_helper
 } catch (Exception $e) {
 	try {
diff --git a/Zend/zend_autoload.c b/Zend/zend_autoload.c
index 0fff2bc51f353..53f79bdf96b2d 100644
--- a/Zend/zend_autoload.c
+++ b/Zend/zend_autoload.c
@@ -63,38 +63,37 @@ int zend_autoload_call(const zval* name, long type TSRMLS_DC)
 	lc_length = Z_STRLEN_P(name);
 	lc_name = zend_str_tolower_dup(Z_STRVAL_P(name), lc_length);
 
-	if (EG(autoload_funcs) == NULL || EG(autoload_funcs)->nNumOfElements == 0) {
-		if (type == ZEND_AUTOLOAD_CLASS
-			&& (	
-				EG(autoload_legacy) != NULL
-				|| zend_lookup_function_ex(ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME), NULL, 0, &EG(autoload_legacy) TSRMLS_CC) == SUCCESS
-			)
-		) {
-			zend_call_method_with_1_params(NULL, NULL, &EG(autoload_legacy), ZEND_AUTOLOAD_FUNC_NAME, &retval, (zval*) name);
-			zend_exception_save(TSRMLS_C);
-			if (zend_hash_exists(symbol_table, lc_name, lc_length + 1)) {
+	/* run legacy autoloader */
+	{
+		zend_bool loaded = 0;
+		
+		if (EG(autoload_funcs) == NULL || EG(autoload_funcs)->nNumOfElements == 0) {
+			if (type == ZEND_AUTOLOAD_CLASS
+				&& (	
+					EG(autoload_legacy) != NULL
+					|| zend_lookup_function_ex(ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME), NULL, 0, &EG(autoload_legacy) TSRMLS_CC) == SUCCESS
+				)
+			) {
+				zend_call_method_with_1_params(NULL, NULL, &EG(autoload_legacy), ZEND_AUTOLOAD_FUNC_NAME, &retval, (zval*) name);
+				loaded = zend_hash_exists(
+					symbol_table, lc_name, lc_length + 1);
 				if (retval) {
 					zval_ptr_dtor(&retval);
 				}
-				zend_exception_restore(TSRMLS_C);
-				efree(lc_name);
-				return SUCCESS;
-			}
-			if (retval) {
-				zval_ptr_dtor(&retval);
 			}
+			efree(lc_name);
+			
+			return (loaded) ? SUCCESS : FAILURE;
 		}
-		zend_exception_restore(TSRMLS_C);
-		efree(lc_name);
-		return FAILURE;
 	}
-
+	
 	if (EG(autoload_stack) == NULL) {
 		ALLOC_HASHTABLE(EG(autoload_stack));
 		zend_hash_init(EG(autoload_stack), 0, NULL, NULL, 0);
 	}
 
-	if (zend_hash_add(EG(autoload_stack), lc_name, lc_length, (void**)&dummy, sizeof(char), NULL) == FAILURE) {
+	if (zend_hash_add(EG(autoload_stack), lc_name, lc_length+1, (void**)&dummy, sizeof(char), NULL) == FAILURE) {
+		printf("failed to add to autoload stack\n");
 		efree(lc_name);
 		return FAILURE;
 	}
@@ -107,7 +106,7 @@ int zend_autoload_call(const zval* name, long type TSRMLS_DC)
 		zend_hash_get_current_data_ex(EG(autoload_funcs), (void **) &func_info, &function_pos);
 		if (func_info->type & type) {
 			func_info->fci.retval_ptr_ptr = &retval;
-			zend_fcall_info_argn(&func_info->fci, 2, &name, &ztype);
+			zend_fcall_info_argn(&func_info->fci TSRMLS_CC, 2, &name, &ztype);
 			zend_call_function(&func_info->fci, &func_info->fcc TSRMLS_CC);
 			zend_exception_save(TSRMLS_C);
 			if (retval) {
@@ -173,6 +172,8 @@ static char* zend_autoload_get_name_key(zend_fcall_info *fci, zend_fcall_info_ca
 		default:
 			return 0;
 	}
+	
+	return 0;
 }
 
 static void zend_autoload_func_dtor(zend_autoload_func *func) {
@@ -187,7 +188,7 @@ int zend_autoload_register(zend_autoload_func *func, zend_bool prepend TSRMLS_DC
 	zend_bool do_free = 0;
 	int lc_length, status = SUCCESS;
 
-	lc_name = zend_autoload_get_name_key(&func->fci, &func->fcc, &lc_length, &do_free);
+	lc_name = zend_autoload_get_name_key(&func->fci, &func->fcc, &lc_length, &do_free TSRMLS_CC);
 	if (lc_name == 0) {
 		zend_error_noreturn(E_ERROR, "Unknown Function Name Type Provided");
 	}
@@ -221,11 +222,11 @@ int zend_autoload_unregister(zval *callable TSRMLS_DC)
 	zend_bool do_free = 0;
 	int lc_length;
 
-	if (zend_fcall_info_init(callable, 0, &fci, &fcc, NULL, NULL) == FAILURE) {
+	if (zend_fcall_info_init(callable, 0, &fci, &fcc, NULL, NULL TSRMLS_CC) == FAILURE) {
 		return FAILURE;
 	}
 
-	lc_name = zend_autoload_get_name_key(&fci, &fcc, &lc_length, &do_free);
+	lc_name = zend_autoload_get_name_key(&fci, &fcc, &lc_length, &do_free TSRMLS_CC);
 	if (lc_name == 0) {
 		return FAILURE;
 	}
@@ -245,13 +246,13 @@ ZEND_FUNCTION(autoload_register)
 	zend_bool prepend = 0;
 	long type = 0;
 
-	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_DC, "z|lb", &callable, &type, &prepend) == FAILURE) {
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|lb", &callable, &type, &prepend) == FAILURE) {
 		return;
 	}
 
 	func = emalloc(sizeof(zend_autoload_func));
 
-	if (zend_fcall_info_init(callable, 0, &func->fci, &func->fcc, NULL, NULL) == FAILURE) {
+	if (zend_fcall_info_init(callable, 0, &func->fci, &func->fcc, NULL, NULL TSRMLS_CC) == FAILURE) {
 		efree(func);
 		zend_error_noreturn(E_ERROR, "Expecting a valid callback");
 	}
@@ -275,7 +276,7 @@ ZEND_FUNCTION(autoload_unregister)
 {
 	zval *callable;
 
-	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_DC, "z", &callable) == FAILURE) {
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &callable) == FAILURE) {
 		return;
 	}
 	RETVAL_BOOL(zend_autoload_unregister(callable TSRMLS_CC) == SUCCESS);
diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c
index 11c841f729364..0e0f729596f14 100644
--- a/Zend/zend_builtin_functions.c
+++ b/Zend/zend_builtin_functions.c
@@ -1390,7 +1390,7 @@ ZEND_FUNCTION(function_exists)
 		name_len--;
 	}
 
-	retval = (zend_lookup_function_ex(name, name_len+1, NULL, (int) autoload, &func) == SUCCESS);
+	retval = (zend_lookup_function_ex(name, name_len+1, NULL, (int) autoload, &func TSRMLS_CC) == SUCCESS);
 	
 	efree(lcname);
 
@@ -1847,7 +1847,7 @@ ZEND_FUNCTION(create_function)
 	if (retval==SUCCESS) {
 		zend_function new_function, *func;
 
-		if (zend_lookup_function_ex(LAMBDA_TEMP_FUNCNAME, sizeof(LAMBDA_TEMP_FUNCNAME), NULL, 0, &func)==FAILURE) {
+		if (zend_lookup_function_ex(LAMBDA_TEMP_FUNCNAME, sizeof(LAMBDA_TEMP_FUNCNAME), NULL, 0, &func TSRMLS_CC)==FAILURE) {
 			zend_error(E_ERROR, "Unexpected inconsistency in create_function()");
 			RETURN_FALSE;
 		}
diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h
index 7070125f1e065..19b56e72aa7d4 100644
--- a/Zend/zend_execute.h
+++ b/Zend/zend_execute.h
@@ -66,8 +66,8 @@ ZEND_API int zend_lookup_class_ex(const char *name, int name_length, const zend_
 ZEND_API int zend_lookup_function(const char *name, int name_length, zend_function **fbc TSRMLS_DC);
 ZEND_API int zend_lookup_function_ex(const char *name, int name_length, const zend_literal *key, int use_autoload, zend_function **fbc TSRMLS_DC);
 
-#define ZEND_LOOKUP_FUNCTION_BY_NAME(name, name_length, fbc) (zend_hash_find(EG(function_table), (name), (name_length) + 1, (void**) (fbc)) == SUCCESS || zend_lookup_function((name), (name_length), (fbc)) == SUCCESS)
-#define ZEND_LOOKUP_FUNCTION_BY_LITERAL(name, name_length, literal, fbc) (zend_hash_quick_find(EG(function_table), (name), (name_length) + 1, Z_HASH_P(literal), (void**) (fbc)) == SUCCESS || zend_lookup_function_ex((name), (name_length), (zend_literal*) (literal), 1, (fbc)) == SUCCESS)
+#define ZEND_LOOKUP_FUNCTION_BY_NAME(name, name_length, fbc) (zend_hash_find(EG(function_table), (name), (name_length) + 1, (void**) (fbc)) == SUCCESS || zend_lookup_function((name), (name_length), (fbc) TSRMLS_CC) == SUCCESS)
+#define ZEND_LOOKUP_FUNCTION_BY_LITERAL(name, name_length, literal, fbc) (zend_hash_quick_find(EG(function_table), (name), (name_length) + 1, Z_HASH_P(literal), (void**) (fbc)) == SUCCESS || zend_lookup_function_ex((name), (name_length), (zend_literal*) (literal), 1, (fbc) TSRMLS_CC) == SUCCESS)
 
 ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name TSRMLS_DC);
 ZEND_API int zend_eval_stringl(char *str, int str_len, zval *retval_ptr, char *string_name TSRMLS_DC);
diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c
index 8bf633adaf57e..82017127c7d8a 100644
--- a/ext/spl/php_spl.c
+++ b/ext/spl/php_spl.c
@@ -405,7 +405,7 @@ PHP_FUNCTION(spl_autoload_call)
 	if (EG(autoload_funcs) == NULL) {
 		zend_call_method_with_1_params(NULL, NULL, NULL, "spl_autoload", NULL, class_name);
 	} else {
-		zend_autoload_call(class_name, ZEND_AUTOLOAD_CLASS);
+		zend_autoload_call(class_name, ZEND_AUTOLOAD_CLASS TSRMLS_CC);
 	}
 } /* }}} */
 
@@ -439,7 +439,7 @@ PHP_FUNCTION(spl_autoload_register)
 		ZVAL_STRING(zcallable, "spl_autoload", 1);
 	}
 
-	if (zend_fcall_info_init(zcallable, IS_CALLABLE_STRICT, &func->fci, &func->fcc, NULL, &error) == FAILURE) {
+	if (zend_fcall_info_init(zcallable, IS_CALLABLE_STRICT, &func->fci, &func->fcc, NULL, &error TSRMLS_CC) == FAILURE) {
 		if (Z_TYPE_P(zcallable) == IS_ARRAY) {
 			if (!func->fcc.object_ptr && func->fcc.function_handler && !(func->fcc.function_handler->common.fn_flags & ZEND_ACC_STATIC)) {
 				if (do_throw) {

From 92fe9491f5a1b6e7837ce31abd9e8c00e498156e Mon Sep 17 00:00:00 2001
From: krakjoe <joe.watkins@live.co.uk>
Date: Sun, 22 Dec 2013 12:09:47 +0000
Subject: [PATCH 18/20] all tests pass

---
 Zend/zend_execute_API.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c
index 9135da23283ae..796f40be2c619 100644
--- a/Zend/zend_execute_API.c
+++ b/Zend/zend_execute_API.c
@@ -1186,6 +1186,8 @@ ZEND_API int zend_lookup_class_ex(const char *name, int name_length, const zend_
 		retval = SUCCESS;
 	}
 	zval_ptr_dtor(&class_name_ptr);
+	zend_hash_del(EG(in_autoload), lc_name, lc_length);
+	
 	if (!key) {
 		free_alloca(lc_free, use_heap);
 	}

From ed22ad919f4ab5948c85c8deebcdee185fccf348 Mon Sep 17 00:00:00 2001
From: krakjoe <joe.watkins@live.co.uk>
Date: Sun, 22 Dec 2013 12:18:58 +0000
Subject: [PATCH 19/20] remove debug printing, add author line

---
 Zend/zend_autoload.c | 2 +-
 Zend/zend_autoload.h | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/Zend/zend_autoload.c b/Zend/zend_autoload.c
index 53f79bdf96b2d..5226769099947 100644
--- a/Zend/zend_autoload.c
+++ b/Zend/zend_autoload.c
@@ -13,6 +13,7 @@
    | license@zend.com so we can mail you a copy immediately.              |
    +----------------------------------------------------------------------+
    | Authors: Anthony Ferrara <ircmaxell@php.net>                         |
+   | Authors: Joe Watkins <krakjoe@php.net>                               |
    +----------------------------------------------------------------------+
 */
 
@@ -93,7 +94,6 @@ int zend_autoload_call(const zval* name, long type TSRMLS_DC)
 	}
 
 	if (zend_hash_add(EG(autoload_stack), lc_name, lc_length+1, (void**)&dummy, sizeof(char), NULL) == FAILURE) {
-		printf("failed to add to autoload stack\n");
 		efree(lc_name);
 		return FAILURE;
 	}
diff --git a/Zend/zend_autoload.h b/Zend/zend_autoload.h
index 87d4bf54abe7d..de6134cda5ddc 100644
--- a/Zend/zend_autoload.h
+++ b/Zend/zend_autoload.h
@@ -13,6 +13,7 @@
    | license@zend.com so we can mail you a copy immediately.              |
    +----------------------------------------------------------------------+
    | Authors: Anthony Ferrara <ircmaxell@php.net>                         |
+   | Authors: Joe Watkins <krakjoe@php.net>                               |
    +----------------------------------------------------------------------+
 */
 

From c1b56c0885ab42604274629958af8050d5bf3342 Mon Sep 17 00:00:00 2001
From: krakjoe <joe.watkins@live.co.uk>
Date: Sun, 22 Dec 2013 13:26:48 +0000
Subject: [PATCH 20/20] ...

---
 NEWS | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/NEWS b/NEWS
index 51361215cb7bf..6bb92f7905aed 100644
--- a/NEWS
+++ b/NEWS
@@ -1,12 +1,6 @@
 PHP                                                                        NEWS
 |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-<<<<<<< HEAD
 ?? ??? 20??, PHP 5.7.0 
-=======
-<<<<<<< HEAD
-?? ??? 20??, PHP 5.6.0 
-=======
-?? ??? 2013, PHP 5.5.8
 
 - Core:
   . Disallowed JMP into a finally block. (Laruence)