[PATCH 3/4] packages/lang/php5: Upgrade APC patch
authorJo-Philipp Wich <jow@openwrt.org>
Fri, 22 Jan 2010 01:20:13 +0000 (01:20 +0000)
committerJo-Philipp Wich <jow@openwrt.org>
Fri, 22 Jan 2010 01:20:13 +0000 (01:20 +0000)
This patch upgrades the APC module patch to version 3.1.3p1 with
support for php 5.3 branch.
Signed-off-by: Michael Heimpold <michael.heimpold@s2000.tu-chemnitz.de>
SVN-Revision: 19268

lang/php5/patches/002-uts_domainname.patch [deleted file]
lang/php5/patches/005-APC.patch

diff --git a/lang/php5/patches/002-uts_domainname.patch b/lang/php5/patches/002-uts_domainname.patch
deleted file mode 100644 (file)
index e69de29..0000000
index 8eb204e1c06e3a3d5ec7f7d10aec9f4d1d3bafbe..d11859e2e16d25b1cfecb5313c9451b0a73d9068 100644 (file)
-diff -ubrN php-5.2.5-orig/ext/apc/apc.c php-5.2.5/ext/apc/apc.c
---- php-5.2.5-orig/ext/apc/apc.c       1969-12-31 18:00:00.000000000 -0600
-+++ php-5.2.5/ext/apc/apc.c    2007-12-26 16:51:32.000000000 -0600
-@@ -0,0 +1,554 @@
+diff -Naur php-5.3.1.orig/ext/apc/apc_bin.c php-5.3.1/ext/apc/apc_bin.c
+--- php-5.3.1.orig/ext/apc/apc_bin.c   1970-01-01 01:00:00.000000000 +0100
++++ php-5.3.1/ext/apc/apc_bin.c        1970-01-01 10:13:08.000000000 +0100
+@@ -0,0 +1,946 @@
 +/*
 +  +----------------------------------------------------------------------+
 +  | APC                                                                  |
 +  +----------------------------------------------------------------------+
-+  | Copyright (c) 2006 The PHP Group                                     |
++  | Copyright (c) 2009 The PHP Group                                     |
 +  +----------------------------------------------------------------------+
 +  | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt                                  |
++  | http://www.php.net/license/3_01.txt.                                 |
 +  | If you did not receive a copy of the PHP license and are unable to   |
 +  | obtain it through the world-wide-web, please send a note to          |
 +  | license@php.net so we can mail you a copy immediately.               |
 +  +----------------------------------------------------------------------+
-+  | Authors: Daniel Cowgill <dcowgill@communityconnect.com>              |
-+  |          George Schlossnagle <george@omniti.com>                     |
-+  |          Rasmus Lerdorf <rasmus@php.net>                             |
-+  |          Arun C. Murthy <arunc@yahoo-inc.com>                        |
-+  |          Gopal Vijayaraghavan <gopalv@yahoo-inc.com>                 |
++  | Authors: Brian Shire <shire@php.net>                                 |
 +  +----------------------------------------------------------------------+
 +
-+   This software was contributed to PHP by Community Connect Inc. in 2002
-+   and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
-+   Future revisions and derivatives of this source code must acknowledge
-+   Community Connect Inc. as the original contributor of this module by
-+   leaving this note intact in the source code.
++ */
 +
-+   All other licensing and usage conditions are those of the PHP Group.
++/* $Id: apc_bin.c 284580 2009-07-22 06:05:31Z kalle $ */
 +
++/* Creates a binary architecture specific output to a string or file containing
++ * the current cache contents for both fies and user variables.  This is accomplished
++ * via the apc_copy_* functions and "swizzling" pointer values to a position
++ * independent value, and unswizzling them on restoration.
 + */
 +
-+/* $Id: apc.c,v 3.18 2007/11/29 22:15:53 shire Exp $ */
++#include "apc_globals.h"
++#include "apc_bin.h"
++#include "apc_zend.h"
++#include "apc_sma.h"
++#include "apc_pool.h"
++#include "ext/standard/md5.h"
++#include "ext/standard/crc32.h"
 +
-+#include "apc.h"
-+#include <regex.h>      /* for POSIX regular expressions */
-+#include "php.h"
++extern apc_cache_t* apc_cache;
++extern apc_cache_t* apc_user_cache;
 +
-+#define NELEMS(a) (sizeof(a)/sizeof((a)[0]))
++extern int _apc_store(char *strkey, int strkey_len, const zval *val, const uint ttl, const int exclusive TSRMLS_DC); /* this is hacky */
 +
-+/* {{{ memory allocation wrappers */
++#define APC_BINDUMP_DEBUG 0
 +
-+void* apc_emalloc(size_t n)
-+{
-+    void* p = malloc(n);
-+    if (p == NULL) {
-+        apc_eprint("apc_emalloc: malloc failed to allocate %u bytes:", n);
-+    }
-+    return p;
-+}
 +
-+void* apc_erealloc(void* p, size_t n)
-+{
-+    p = realloc(p, n);
-+    if (p == NULL) {
-+        apc_eprint("apc_erealloc: realloc failed to allocate %u bytes:", n);
-+    }
-+    return p;
-+}
++#if APC_BINDUMP_DEBUG
 +
-+void apc_efree(void* p)
-+{
-+    if (p == NULL) {
-+        apc_eprint("apc_efree: attempt to free null pointer");
-+    }
-+    free(p);
-+}
++#define SWIZZLE(bd, ptr)  \
++    do { \
++        if((long)bd < (long)ptr && (ulong)ptr < ((long)bd + bd->size)) { \
++            printf("SWIZZLE: %x ~> ", ptr); \
++            ptr = (void*)((long)(ptr) - (long)(bd)); \
++            printf("%x in %s on line %d", ptr, __FILE__, __LINE__); \
++        } else if((long)ptr > bd->size) { /* not swizzled */ \
++            apc_eprint("pointer to be swizzled is not within allowed memory range! (%x < %x < %x) in %s on %d", (long)bd, ptr, ((long)bd + bd->size), __FILE__, __LINE__); \
++        } \
++        printf("\n"); \
++    } while(0);
 +
-+char* apc_estrdup(const char* s)
-+{
-+    int len;
-+    char* dup;
++#define UNSWIZZLE(bd, ptr)  \
++    do { \
++      printf("UNSWIZZLE: %x -> ", ptr); \
++      ptr = (void*)((long)(ptr) + (long)(bd)); \
++      printf("%x in %s on line %d \n", ptr, __FILE__, __LINE__); \
++    } while(0);
 +
-+    if (s == NULL) {
-+        return NULL;
-+    }
-+    len = strlen(s);
-+    dup = (char*) malloc(len+1);
-+    if (dup == NULL) {
-+        apc_eprint("apc_estrdup: malloc failed to allocate %u bytes:", len+1);
-+    }
-+    memcpy(dup, s, len);
-+    dup[len] = '\0';
-+    return dup;
-+}
++#else    /* !APC_BINDUMP_DEBUG */
 +
-+void* apc_xstrdup(const char* s, apc_malloc_t f)
-+{
-+    return s != NULL ? apc_xmemcpy(s, strlen(s)+1, f) : NULL;
-+}
++#define SWIZZLE(bd, ptr) \
++    do { \
++        if((long)bd < (long)ptr && (ulong)ptr < ((long)bd + bd->size)) { \
++            ptr = (void*)((long)(ptr) - (long)(bd)); \
++        } else if((ulong)ptr > bd->size) { /* not swizzled */ \
++            apc_eprint("pointer to be swizzled is not within allowed memory range! (%x < %x < %x) in %s on %d", (long)bd, ptr, ((long)bd + bd->size), __FILE__, __LINE__); \
++        } \
++    } while(0);
 +
-+void* apc_xmemcpy(const void* p, size_t n, apc_malloc_t f)
-+{
-+    void* q;
++#define UNSWIZZLE(bd, ptr) \
++    do { \
++      ptr = (void*)((long)(ptr) + (long)(bd)); \
++    } while(0);
 +
-+    if (p != NULL && (q = f(n)) != NULL) {
-+        memcpy(q, p, n);
-+        return q;
-+    }
-+    return NULL;
-+}
++#endif
 +
-+/* }}} */
 +
-+/* {{{ console display functions */
++static void *apc_bd_alloc(size_t size);
++static void apc_bd_free(void *ptr);
++static void *apc_bd_alloc_ex(void *ptr_new, size_t size);
 +
-+static void my_log(int level, const char* fmt, va_list args)
-+{
-+    static const char* level_strings[] = {
-+        "apc-debug",
-+        "apc-notice",
-+        "apc-warning",
-+        "apc-error"
-+    };
-+    static const int num_levels = NELEMS(level_strings);
++typedef void (*apc_swizzle_cb_t)(apc_bd_t *bd, zend_llist *ll, void *ptr TSRMLS_DC);
 +
-+    time_t now;
-+    char* buf;          /* for ctime */
++#if APC_BINDUMP_DEBUG
++#define apc_swizzle_ptr(bd, ll, ptr) _apc_swizzle_ptr(bd, ll, (void*)ptr, __FILE__, __LINE__ TSRMLS_CC)
++#else
++#define apc_swizzle_ptr(bd, ll, ptr) _apc_swizzle_ptr(bd, ll, (void*)ptr, NULL, 0 TSRMLS_CC)
++#endif
 +
-+    fflush(stdout);
++static void _apc_swizzle_ptr(apc_bd_t *bd, zend_llist *ll, void **ptr, const char* file, int line TSRMLS_DC);
++static void apc_swizzle_function(apc_bd_t *bd, zend_llist *ll, zend_function *func TSRMLS_DC);
++static void apc_swizzle_class_entry(apc_bd_t *bd, zend_llist *ll, zend_class_entry *ce TSRMLS_DC);
++static void apc_swizzle_hashtable(apc_bd_t *bd, zend_llist *ll, HashTable *ht, apc_swizzle_cb_t swizzle_cb, int is_ptr TSRMLS_DC);
++static void apc_swizzle_zval(apc_bd_t *bd, zend_llist *ll, zval *zv TSRMLS_DC);
++static void apc_swizzle_op_array(apc_bd_t *bd, zend_llist *ll, zend_op_array *op_array TSRMLS_DC);
++static void apc_swizzle_property_info(apc_bd_t *bd, zend_llist *ll, zend_property_info *pi TSRMLS_DC);
++static void apc_swizzle_function_entry(apc_bd_t *bd, zend_llist *ll, const zend_function_entry *fe TSRMLS_DC);
++static void apc_swizzle_arg_info_array(apc_bd_t *bd, zend_llist *ll, const zend_arg_info* arg_info_array, uint num_args TSRMLS_DC);
 +
-+    if (level < 0)
-+        level = 0;
-+    else if (level >= num_levels)
-+        level = num_levels-1;
-+    
-+    now = time(0);
-+    buf = ctime(&now);  /* TODO: replace with reentrant impl */
-+    buf[24] = '\0';
++static apc_bd_t* apc_swizzle_bd(apc_bd_t* bd, zend_llist *ll TSRMLS_DC);
++static int apc_unswizzle_bd(apc_bd_t *bd, int flags TSRMLS_DC);
 +
-+    fprintf(stderr, "[%s] [%s] ", buf, level_strings[level]);
-+    vfprintf(stderr, fmt, args);
 +
-+    if (fmt[0] != '\0' && fmt[strlen(fmt)-1] == ':') {
-+        fprintf(stderr, " %s", strerror(errno));
-+    }
-+    fprintf(stderr, "\n");
++/* {{{ apc_bd_alloc
++ *  callback for copy_* functions */
++static void *apc_bd_alloc(size_t size) {
++    return apc_bd_alloc_ex(NULL, size);
++} /* }}} */
 +
-+    if (level == APC_ERROR) {
-+        exit(2);
++
++/* {{{ apc_bd_free
++ *  callback for copy_* functions */
++static void apc_bd_free(void *ptr) {
++    size_t *size;
++    TSRMLS_FETCH();
++    if(zend_hash_index_find(&APCG(apc_bd_alloc_list), (ulong)ptr, (void**)&size) == FAILURE) {
++        apc_eprint("apc_bd_free could not free pointer (not found in list: %x)", ptr);
 +    }
-+}
++    APCG(apc_bd_alloc_ptr) = (void*)((size_t)APCG(apc_bd_alloc_ptr) - *size);
++    zend_hash_index_del(&APCG(apc_bd_alloc_list), (ulong)ptr);
++} /* }}} */
 +
-+void apc_log(int level, const char* fmt, ...)
-+{
-+    va_list args;
-+    va_start(args, fmt);
-+    my_log(level, fmt, args);
-+    va_end(args);
-+}
 +
-+void apc_eprint(const char* fmt, ...)
-+{
-+    va_list args;
-+    va_start(args, fmt);
-+    my_log(APC_ERROR, fmt, args);
-+    va_end(args);
-+}
++/* {{{ apc_bd_alloc_ex
++ *  set ranges or allocate a block of data from an already (e)malloc'd range.
++ *  if ptr_new is not NULL, it will reset the pointer to start at ptr_new,
++ *  with a range of size.  If ptr_new is NULL, returns the next available
++ *  block of given size.
++ */
++static void *apc_bd_alloc_ex(void *ptr_new, size_t size) {
++    void *rval;
++    TSRMLS_FETCH();
 +
-+void apc_wprint(const char* fmt, ...)
-+{
-+    va_list args;
-+    va_start(args, fmt);
-+    my_log(APC_WARNING, fmt, args);
-+    va_end(args);
-+}
++    rval = APCG(apc_bd_alloc_ptr);
++    if(ptr_new != NULL) {  /* reset ptrs */
++      APCG(apc_bd_alloc_ptr) = ptr_new;
++      APCG(apc_bd_alloc_ubptr) = (void*)((unsigned char *) ptr_new + size);
++    } else {  /* alloc block */
++      APCG(apc_bd_alloc_ptr) = (void*)((size_t)APCG(apc_bd_alloc_ptr) + size);
++#if APC_BINDUMP_DEBUG
++      apc_nprint("apc_bd_alloc: rval: 0x%x  ptr: 0x%x  ubptr: 0x%x  size: %d", rval, APCG(apc_bd_alloc_ptr), APCG(apc_bd_alloc_ubptr), size);
++#endif
++      if(APCG(apc_bd_alloc_ptr) > APCG(apc_bd_alloc_ubptr)) {
++          apc_eprint("Exceeded bounds check in apc_bd_alloc_ex by %d bytes.", (unsigned char *) APCG(apc_bd_alloc_ptr) - (unsigned char *) APCG(apc_bd_alloc_ubptr));
++      }
++      zend_hash_index_update(&APCG(apc_bd_alloc_list), (ulong)rval, &size, sizeof(size_t), NULL);
++    }
 +
-+void apc_nprint(const char* fmt, ...)
-+{
-+    va_list args;
-+    va_start(args, fmt);
-+    my_log(APC_NOTICE, fmt, args);
-+    va_end(args);
-+}
++    return rval;
++} /* }}} */
 +
-+void apc_dprint(const char* fmt, ...)
-+{
-+#ifdef APC_DEBUG
-+    va_list args;
-+    va_start(args, fmt);
-+    my_log(APC_DBG, fmt, args);
-+    va_end(args);
++
++/* {{{ _apc_swizzle_ptr */
++static void _apc_swizzle_ptr(apc_bd_t *bd, zend_llist *ll, void **ptr, const char* file, int line TSRMLS_DC) {
++    if(*ptr) {
++        if((long)bd < (long)*ptr && (ulong)*ptr < ((long)bd + bd->size)) {
++            zend_llist_add_element(ll, &ptr);
++#if APC_BINDUMP_DEBUG
++            printf("[%06d] apc_swizzle_ptr: %x -> %x ", zend_llist_count(ll), ptr, *ptr);
++            printf(" in %s on line %d \n", file, line);
 +#endif
-+}
++        } else if((ulong)ptr > bd->size) {
++            apc_eprint("pointer to be swizzled is not within allowed memory range! (%x < %x < %x) in %s on %d", (long)bd, *ptr, ((long)bd + bd->size), file, line); \
++        }
++    }
++} /* }}} */
 +
-+/* }}} */
 +
-+/* {{{ string and text manipulation */
++/* {{{ apc_swizzle_op_array */
++static void apc_swizzle_op_array(apc_bd_t *bd, zend_llist *ll, zend_op_array *op_array TSRMLS_DC) {
++    uint i;
 +
-+char* apc_append(const char* s, const char* t)
-+{
-+    int slen;
-+    int tlen;
-+    char* p;
++#ifdef ZEND_ENGINE_2
++    apc_swizzle_arg_info_array(bd, ll, op_array->arg_info, op_array->num_args TSRMLS_CC);
++    apc_swizzle_ptr(bd, ll, &op_array->arg_info);
++#else
++    if (op_array->arg_types) {
++        apc_swizzle_ptr(bd, ll, &op_array->arg_types);
++    }
++#endif
 +
-+    slen = strlen(s);
-+    tlen = strlen(t);
++    apc_swizzle_ptr(bd, ll, &op_array->function_name);
++    apc_swizzle_ptr(bd, ll, &op_array->filename);
++    apc_swizzle_ptr(bd, ll, &op_array->refcount);
 +
-+    p = (char*) apc_emalloc((slen + tlen + 1) * sizeof(char));
-+    memcpy(p, s, slen);
-+    memcpy(p + slen, t, tlen + 1);
++    /* swizzle op_array */
++    for(i=0; i < op_array->last; i++) {
++        if(op_array->opcodes[i].result.op_type == IS_CONST) {
++            apc_swizzle_zval(bd, ll, &op_array->opcodes[i].result.u.constant TSRMLS_CC);
++        }
++        if(op_array->opcodes[i].op1.op_type == IS_CONST) {
++            apc_swizzle_zval(bd, ll, &op_array->opcodes[i].op1.u.constant TSRMLS_CC);
++        }
++        if(op_array->opcodes[i].op2.op_type == IS_CONST) {
++            apc_swizzle_zval(bd, ll, &op_array->opcodes[i].op2.u.constant TSRMLS_CC);
++        }
++        switch (op_array->opcodes[i].opcode) {
++            case ZEND_JMP:
++                apc_swizzle_ptr(bd, ll, &op_array->opcodes[i].op1.u.jmp_addr);
++            case ZEND_JMPZ:
++            case ZEND_JMPNZ:
++            case ZEND_JMPZ_EX:
++            case ZEND_JMPNZ_EX:
++                apc_swizzle_ptr(bd, ll, &op_array->opcodes[i].op2.u.jmp_addr);
++        }
++    }
++    apc_swizzle_ptr(bd, ll, &op_array->opcodes);
 +
-+    return p;
-+}
++    /* break-continue array ptr */
++    if(op_array->brk_cont_array) {
++        apc_swizzle_ptr(bd, ll, &op_array->brk_cont_array);
++    }
 +
-+char* apc_substr(const char* s, int start, int length)
-+{
-+    char* substr;
-+    int src_len = strlen(s);
++    /* static voriables */
++    if(op_array->static_variables) {
++        apc_swizzle_hashtable(bd, ll, op_array->static_variables, (apc_swizzle_cb_t)apc_swizzle_zval, 1 TSRMLS_CC);
++        apc_swizzle_ptr(bd, ll, &op_array->static_variables);
++    }
 +
-+    /* bring start into range */
-+    if (start < 0) {
-+        start = 0;
++#ifdef ZEND_ENGINE_2
++    /* try-catch */
++    if(op_array->try_catch_array) {
++        apc_swizzle_ptr(bd, ll, &op_array->try_catch_array);
 +    }
-+    else if (start >= src_len) {
-+        start = src_len - 1;
++#endif
++
++#ifdef ZEND_ENGINE_2_1 /* PHP 5.1 */
++    /* vars */
++    if(op_array->vars) {
++        for(i=0; (signed int) i < op_array->last_var; i++) {
++            apc_swizzle_ptr(bd, ll, &op_array->vars[i].name);
++        }
++        apc_swizzle_ptr(bd, ll, &op_array->vars);
 +    }
++#endif
 +
-+    /* bring length into range */
-+    if (length < 0 || src_len - start < length) {
-+        length = src_len - start;
++#ifdef ZEND_ENGINE_2
++    /* doc comment */
++    if(op_array->doc_comment) {
++        apc_swizzle_ptr(bd, ll, &op_array->doc_comment);
 +    }
++#endif
 +
-+    /* create the substring */
-+    substr = apc_xmemcpy(s + start, length + 1, apc_emalloc);
-+    substr[length] = '\0';
-+    return substr;
-+}
++} /* }}} */
 +
-+char** apc_tokenize(const char* s, char delim)
-+{
-+    char** tokens;      /* array of tokens, NULL terminated */
-+    int size;           /* size of tokens array */
-+    int n;              /* index of next token in tokens array */
-+    int cur;            /* current position in input string */
-+    int end;            /* final legal position in input string */
-+    int next;           /* position of next delimiter in input */
-+    
-+    if (!s) {
-+        return NULL;
++
++/* {{{ apc_swizzle_function */
++static void apc_swizzle_function(apc_bd_t *bd, zend_llist *ll, zend_function *func TSRMLS_DC) {
++    apc_swizzle_op_array(bd, ll, &func->op_array TSRMLS_CC);
++#ifdef ZEND_ENGINE_2
++    if(func->common.scope) {
++        apc_swizzle_ptr(bd, ll, &func->common.scope);
 +    }
++#endif
++} /* }}} */
 +
-+    size = 2;
-+    n    = 0;
-+    cur  = 0;
-+    end  = strlen(s) - 1;
-+    
-+    tokens = (char**) apc_emalloc(size * sizeof(char*));
-+    tokens[n] = NULL;
 +
-+    while (cur <= end) {
-+        /* search for the next delimiter */
-+        char* p = strchr(s + cur, delim);
-+        next = p ? p-s : end+1;
++/* {{{ apc_swizzle_class_entry */
++static void apc_swizzle_class_entry(apc_bd_t *bd, zend_llist *ll, zend_class_entry *ce TSRMLS_DC) {
 +
-+        /* resize token array if necessary */
-+        if (n == size-1) {
-+            size *= 2;
-+            tokens = (char**) apc_erealloc(tokens, size * sizeof(char*));
-+        }
++    uint i;
 +
-+        /* save the current token */
-+        tokens[n] = apc_substr(s, cur, next-cur);
++    if(ce->name) {
++        apc_swizzle_ptr(bd, ll, &ce->name);
++    }
 +
-+        tokens[++n] = NULL;
-+        cur = next + 1;
++    if(ce->doc_comment) {
++        apc_swizzle_ptr(bd, ll, &ce->doc_comment);
 +    }
 +
-+    return tokens;
-+}
-+
-+/* }}} */
-+
-+/* {{{ filesystem functions */
++#ifndef ZEND_ENGINE_2
++    apc_swizzle_ptr(bd, ll, &ce->refcount);
++#endif
 +
-+#ifdef PHP_WIN32
-+int apc_win32_stat(const char *path, struct stat *buf TSRMLS_DC)
-+{
-+    char rpath[MAXPATHLEN];
-+    BY_HANDLE_FILE_INFORMATION fi;
-+    HANDLE f;
-+    
-+    if (VCWD_STAT(path, buf)) {
-+        return -1;
-+    }
++    apc_swizzle_hashtable(bd, ll, &ce->function_table, (apc_swizzle_cb_t)apc_swizzle_function, 0 TSRMLS_CC);
++    apc_swizzle_hashtable(bd, ll, &ce->default_properties, (apc_swizzle_cb_t)apc_swizzle_zval, 1 TSRMLS_CC);
 +
-+    VCWD_REALPATH(path, rpath);
-+    f = CreateFile(rpath, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_READONLY, NULL);
-+    GetFileInformationByHandle(f, &fi);
-+    buf->st_ino = (ino_t)fi.nFileIndexLow;
-+    CloseHandle (f);
-+    return 0;
-+}
++#ifdef ZEND_ENGINE_2
++    apc_swizzle_hashtable(bd, ll, &ce->properties_info, (apc_swizzle_cb_t)apc_swizzle_property_info, 0 TSRMLS_CC);
 +#endif
 +
-+int apc_search_paths(const char* filename, const char* path, apc_fileinfo_t* fileinfo)
-+{
-+    char** paths;
-+    char *exec_fname;
-+    int exec_fname_length;
-+    int found = 0;
-+    int i;
-+    TSRMLS_FETCH();
-+
-+    assert(filename && fileinfo);
++    apc_swizzle_hashtable(bd, ll, &ce->default_static_members, (apc_swizzle_cb_t)apc_swizzle_zval, 1 TSRMLS_CC);
 +
-+    if (IS_ABSOLUTE_PATH(filename, strlen(filename)) && apc_stat(filename, &fileinfo->st_buf) == 0) {
-+        strncpy(fileinfo->fullpath, filename, MAXPATHLEN);
-+        return 0;
++    if(ce->static_members != &ce->default_static_members) {
++        apc_swizzle_hashtable(bd, ll, ce->static_members, (apc_swizzle_cb_t)apc_swizzle_zval, 1 TSRMLS_CC);
++    } else {
++        apc_swizzle_ptr(bd, ll, &ce->static_members);
 +    }
 +
-+    paths = apc_tokenize(path, DEFAULT_DIR_SEPARATOR);
-+    if (!paths)
-+        return -1;
++    apc_swizzle_hashtable(bd, ll, &ce->constants_table, (apc_swizzle_cb_t)apc_swizzle_zval, 1 TSRMLS_CC);
 +
-+    /* for each directory in paths, look for filename inside */
-+    for (i = 0; paths[i]; i++) {
-+        snprintf(fileinfo->fullpath, sizeof(fileinfo->fullpath), "%s%c%s", paths[i], DEFAULT_SLASH, filename);
-+        if (apc_stat(fileinfo->fullpath, &fileinfo->st_buf) == 0) {
-+            found = 1;
-+            break;
++    if(ce->builtin_functions) {
++        for(i=0; ce->builtin_functions[i].fname; i++) {
++            apc_swizzle_function_entry(bd, ll, &ce->builtin_functions[i] TSRMLS_CC);
 +        }
 +    }
 +
-+    /* check in path of the calling scripts' current working directory */
-+    /* modified from main/streams/plain_wrapper.c */
-+    if(!found && zend_is_executing(TSRMLS_C)) {
-+        exec_fname = zend_get_executed_filename(TSRMLS_C);
-+        exec_fname_length = strlen(exec_fname);
-+        while((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length]));
-+        if((exec_fname && exec_fname[0] != '[') && exec_fname_length > 0) {
-+            /* not: [no active file] or no path */
-+            memcpy(fileinfo->fullpath, exec_fname, exec_fname_length);
-+            fileinfo->fullpath[exec_fname_length] = DEFAULT_SLASH;
-+            strcpy(fileinfo->fullpath +exec_fname_length +1, filename);
-+            /* apc_wprint("filename: %s, exec_fname: %s, fileinfo->fullpath: %s", filename, exec_fname, fileinfo->fullpath); */
-+            if (apc_stat(fileinfo->fullpath, &fileinfo->st_buf) == 0) {
-+                found = 1;
-+            }
-+        }
-+    }
-+    
-+    /* free the value returned by apc_tokenize */
-+    for (i = 0; paths[i]; i++) {
-+        apc_efree(paths[i]);
-+    }
-+    apc_efree(paths);
++    apc_swizzle_ptr(bd, ll, &ce->constructor);
++    apc_swizzle_ptr(bd, ll, &ce->destructor);
++    apc_swizzle_ptr(bd, ll, &ce->clone);
++    apc_swizzle_ptr(bd, ll, &ce->__get);
++    apc_swizzle_ptr(bd, ll, &ce->__set);
++    apc_swizzle_ptr(bd, ll, &ce->__unset);
++    apc_swizzle_ptr(bd, ll, &ce->__isset);
++    apc_swizzle_ptr(bd, ll, &ce->__call);
++    apc_swizzle_ptr(bd, ll, &ce->serialize_func);
++    apc_swizzle_ptr(bd, ll, &ce->unserialize_func);
 +
-+    return found ? 0 : -1;
-+}
++#ifdef ZEND_ENGINE_2_2
++    apc_swizzle_ptr(bd, ll, &ce->__tostring);
++#endif
 +
-+/* }}} */
++    apc_swizzle_ptr(bd, ll, &ce->filename);
++} /* }}} */
 +
-+/* {{{ regular expression wrapper functions */
 +
-+typedef struct {
-+    regex_t *reg;
-+    unsigned char type;
-+} apc_regex;
++/* {{{ apc_swizzle_property_info */
++static void apc_swizzle_property_info(apc_bd_t *bd, zend_llist *ll, zend_property_info *pi TSRMLS_DC) {
++    apc_swizzle_ptr(bd, ll, &pi->name);
++    apc_swizzle_ptr(bd, ll, &pi->doc_comment);
 +
-+void* apc_regex_compile_array(char* patterns[])
-+{
-+    apc_regex** regs;
-+    int npat;
-+    int i;
++#ifdef ZEND_ENGINE_2_2
++    apc_swizzle_ptr(bd, ll, &pi->ce);
++#endif
++} /* }}} */
 +
-+    if (!patterns)
-+        return NULL;
 +
-+    /* count the number of patterns in patterns */
-+    for (npat = 0; patterns[npat] != NULL; npat++) {}
++/* {{{ apc_swizzle_function_entry */
++static void apc_swizzle_function_entry(apc_bd_t *bd, zend_llist *ll, const zend_function_entry *fe TSRMLS_DC) {
++    apc_swizzle_ptr(bd, ll, &fe->fname);
++    apc_swizzle_arg_info_array(bd, ll, fe->arg_info, fe->num_args TSRMLS_CC);
++    apc_swizzle_ptr(bd, ll, &fe->arg_info);
++} /* }}} */
++
 +
-+    if (npat == 0)
-+        return NULL;
++/* {{{ apc_swizzle_arg_info_array */
++static void apc_swizzle_arg_info_array(apc_bd_t *bd, zend_llist *ll, const zend_arg_info* arg_info_array, uint num_args TSRMLS_DC) {
++    if(arg_info_array) {
++        uint i;
 +
-+    /* allocate the array of compiled expressions */
-+    regs = (apc_regex**) apc_emalloc(sizeof(apc_regex*) * (npat + 1));
-+    for (i = 0; i <= npat; i++) {
-+        regs[i] = (apc_regex *) apc_emalloc(sizeof(apc_regex));
-+        regs[i]->reg = NULL;
-+        regs[i]->type = APC_NEGATIVE_MATCH;
++        for(i=0; i < num_args; i++) {
++            apc_swizzle_ptr(bd, ll, &arg_info_array[i].name);
++            apc_swizzle_ptr(bd, ll, &arg_info_array[i].class_name);
++        }
 +    }
 +
-+    /* compile the expressions */
-+    for (i = 0; i < npat; i++) {
-+        char *pattern = patterns[i];
-+        if(pattern[0]=='+') { regs[i]->type = APC_POSITIVE_MATCH; pattern = patterns[i]+sizeof(char); }
-+        else if(pattern[0]=='-') { regs[i]->type = APC_NEGATIVE_MATCH; pattern = patterns[i]+sizeof(char); }
++} /* }}} */
++
++
++/* {{{ apc_swizzle_hashtable */
++static void apc_swizzle_hashtable(apc_bd_t *bd, zend_llist *ll, HashTable *ht, apc_swizzle_cb_t swizzle_cb, int is_ptr TSRMLS_DC) {
++    uint i;
++    Bucket **bp, **bp_prev;
++
++    bp = &ht->pListHead;
++    while(*bp) {
++        bp_prev = bp;
++        bp = &(*bp)->pListNext;
++        if(is_ptr) {
++            swizzle_cb(bd, ll, *(void**)(*bp_prev)->pData TSRMLS_CC);
++            apc_swizzle_ptr(bd, ll, (*bp_prev)->pData);
++        } else {
++            swizzle_cb(bd, ll, (void**)(*bp_prev)->pData TSRMLS_CC);
++        }
++        apc_swizzle_ptr(bd, ll, &(*bp_prev)->pData);
++        if((*bp_prev)->pDataPtr) {
++            apc_swizzle_ptr(bd, ll, &(*bp_prev)->pDataPtr);
++        }
++        if((*bp_prev)->pListLast) {
++            apc_swizzle_ptr(bd, ll, &(*bp_prev)->pListLast);
++        }
++        if((*bp_prev)->pNext) {
++            apc_swizzle_ptr(bd, ll, &(*bp_prev)->pNext);
++        }
++        if((*bp_prev)->pLast) {
++            apc_swizzle_ptr(bd, ll, &(*bp_prev)->pLast);
++        }
++        apc_swizzle_ptr(bd, ll, bp_prev);
++    }
++    for(i=0; i < ht->nTableSize; i++) {
++        if(ht->arBuckets[i]) {
++            apc_swizzle_ptr(bd, ll, &ht->arBuckets[i]);
++        }
++    }
++    apc_swizzle_ptr(bd, ll, &ht->pListTail);
 +
-+        regs[i]->reg = (regex_t*) apc_emalloc(sizeof(regex_t));
++    apc_swizzle_ptr(bd, ll, &ht->arBuckets);
++} /* }}} */
 +
-+        if (regcomp(regs[i]->reg, pattern, REG_EXTENDED | REG_NOSUB) != 0) {
-+            apc_wprint("apc_regex_compile_array: invalid expression '%s'",
-+                       pattern);
 +
-+            apc_regex_destroy_array(regs);
++/* {{{ apc_swizzle_zval */
++static void apc_swizzle_zval(apc_bd_t *bd, zend_llist *ll, zval *zv TSRMLS_DC) {
 +
-+            return NULL;
++    if(APCG(copied_zvals).nTableSize) {
++        if(zend_hash_index_exists(&APCG(copied_zvals), (ulong)zv)) {
++          return;
 +        }
++        zend_hash_index_update(&APCG(copied_zvals), (ulong)zv, (void**)&zv, sizeof(zval*), NULL);
 +    }
 +
-+    return (void*) regs;
-+}
++    switch(zv->type & ~IS_CONSTANT_INDEX) {
++        case IS_NULL:
++        case IS_LONG:
++        case IS_DOUBLE:
++        case IS_BOOL:
++        case IS_RESOURCE:
++            /* nothing to do */
++            break;
++        case IS_CONSTANT:
++        case IS_STRING:
++            apc_swizzle_ptr(bd, ll, &zv->value.str.val);
++            break;
++        case IS_ARRAY:
++        case IS_CONSTANT_ARRAY:
++            apc_swizzle_hashtable(bd, ll, zv->value.ht, (apc_swizzle_cb_t)apc_swizzle_zval, 1 TSRMLS_CC);
++            apc_swizzle_ptr(bd, ll, &zv->value.ht);
++            break;
++        case IS_OBJECT:
++            break;
++        default:
++            assert(0); /* shouldn't happen */
++    }
++} /* }}} */
 +
-+void apc_regex_destroy_array(void* p)
-+{
-+    if (p != NULL) {
-+        apc_regex** regs = (apc_regex**) p;
-+        int i;
 +
-+        for (i = 0; regs[i]->reg != NULL; i++) {
-+            regfree(regs[i]->reg);
-+            apc_efree(regs[i]->reg);
-+            apc_efree(regs[i]);
++/* {{{ apc_swizzle_bd */
++static apc_bd_t* apc_swizzle_bd(apc_bd_t* bd, zend_llist *ll TSRMLS_DC) {
++    int count, i;
++    PHP_MD5_CTX context;
++    unsigned char digest[16];
++    register php_uint32 crc;
++    php_uint32 crcinit = 0;
++    char *crc_p;
++    void ***ptr;
++    void ***ptr_list;
++
++    count = zend_llist_count(ll);
++    ptr_list = emalloc(count * sizeof(void**));
++    ptr = zend_llist_get_first(ll);
++    for(i=0; i < count; i++) {
++#if APC_BINDUMP_DEBUG
++        printf("[%06d] ", i+1);
++#endif
++        SWIZZLE(bd, **ptr); /* swizzle ptr */
++        if((long)bd < (long)*ptr && (ulong)*ptr < ((long)bd + bd->size)) {  /* exclude ptrs that aren't actually included in the ptr list */
++#if APC_BINDUMP_DEBUG
++            printf("[------] ");
++#endif
++            SWIZZLE(bd, *ptr);  /* swizzle ptr list */
++            ptr_list[i] = *ptr;
 +        }
-+        apc_efree(regs);
++        ptr = zend_llist_get_next(ll);
 +    }
-+}
++    SWIZZLE(bd, bd->entries);
 +
-+int apc_regex_match_array(void* p, const char* input)
-+{
-+    apc_regex** regs;
++    if(count > 0) {
++        bd = erealloc(bd, bd->size + (count * sizeof(void**)));
++        bd->num_swizzled_ptrs = count;
++        bd->swizzled_ptrs = (void***)((unsigned char *)bd + bd->size -2);   /* extra -1 for null termination */
++        bd->size += count * sizeof(void**);
++        memcpy(bd->swizzled_ptrs, ptr_list, count * sizeof(void**));
++        SWIZZLE(bd, bd->swizzled_ptrs);
++    } else {
++        bd->num_swizzled_ptrs = 0;
++        bd->swizzled_ptrs = NULL;
++    }
++    ((char*)bd)[bd->size-1] = 0;  /* silence null termination for zval strings */
++    efree(ptr_list);
++    bd->swizzled = 1;
++
++    /* Generate MD5/CRC32 checksum */
++    for(i=0; i<16; i++) { bd->md5[i] = 0; }
++    bd->crc=0;
++    PHP_MD5Init(&context);
++    PHP_MD5Update(&context, (const unsigned char*)bd, bd->size);
++    PHP_MD5Final(digest, &context);
++    crc = crcinit^0xFFFFFFFF;
++    crc_p = (char*)bd;
++    for(i=bd->size; i--; ++crc_p) {
++      crc = ((crc >> 8) & 0x00FFFFFF) ^ crc32tab[(crc ^ (*crc_p)) & 0xFF ];
++    }
++    memcpy(bd->md5, digest, 16);
++    bd->crc = crc;
++
++    return bd;
++} /* }}} */
++
++
++/* {{{ apc_unswizzle_bd */
++static int apc_unswizzle_bd(apc_bd_t *bd, int flags TSRMLS_DC) {
 +    int i;
++    unsigned char md5_orig[16];
++    unsigned char digest[16];
++    PHP_MD5_CTX context;
++    register php_uint32 crc;
++    php_uint32 crcinit = 0;
++    php_uint32 crc_orig;
++    char *crc_p;
++
++    /* Verify the md5 or crc32 before we unswizzle */
++    memcpy(md5_orig, bd->md5, 16);
++    for(i=0; i<16; i++) { bd->md5[i] = 0; }
++    crc_orig = bd->crc;
++    bd->crc=0;
++    if(flags & APC_BIN_VERIFY_MD5) {
++        PHP_MD5Init(&context);
++        PHP_MD5Update(&context, (const unsigned char*)bd, bd->size);
++        PHP_MD5Final(digest, &context);
++        if(memcmp(md5_orig, digest, 16)) {
++            apc_eprint("MD5 checksum of binary dump failed.");
++            memcpy(bd->md5, md5_orig, 16); /* add back md5 checksum */
++            return -1;
++        }
++    }
++    if(flags & APC_BIN_VERIFY_CRC32) {
++        crc = crcinit^0xFFFFFFFF;
++        crc_p = (char*)bd;
++        for(i=bd->size; i--; ++crc_p) {
++          crc = ((crc >> 8) & 0x00FFFFFF) ^ crc32tab[(crc ^ (*crc_p)) & 0xFF ];
++        }
++        if(crc_orig != crc) {
++            apc_eprint("CRC32 checksum of binary dump failed.");
++            bd->crc = crc_orig;
++            return -1;
++        }
++    }
++    memcpy(bd->md5, md5_orig, 16); /* add back md5 checksum */
++    bd->crc = crc_orig;
 +
-+    if (!p)
-+        return 0;
++    UNSWIZZLE(bd, bd->entries);
++    UNSWIZZLE(bd, bd->swizzled_ptrs);
++    for(i=0; i < bd->num_swizzled_ptrs; i++) {
++        if(bd->swizzled_ptrs[i]) {
++            UNSWIZZLE(bd, bd->swizzled_ptrs[i]);
++            if(*bd->swizzled_ptrs[i] && (*bd->swizzled_ptrs[i] < (void*)bd)) {
++                UNSWIZZLE(bd, *bd->swizzled_ptrs[i]);
++            }
++        }
++    }
 +
-+    regs = (apc_regex**) p;
-+    for (i = 0; regs[i]->reg != NULL; i++)
-+        if (regexec(regs[i]->reg, input, 0, NULL, 0) == 0)
-+            return (int)(regs[i]->type);
++    bd->swizzled=0;
 +
 +    return 0;
-+}
++} /* }}} */
 +
-+/* }}} */
 +
-+/* {{{ crc32 implementation */
++/* {{{ apc_bin_checkfilter */
++static int apc_bin_checkfilter(HashTable *filter, const char *key, uint key_len) {
++    zval **zptr;
 +
-+/* this table was generated by crc32gen() */
-+static unsigned int crc32tab[] = {
-+    /*   0 */  0x00000000, 0x3b83984b, 0x77073096, 0x4c84a8dd, 
-+    /*   4 */  0xee0e612c, 0xd58df967, 0x990951ba, 0xa28ac9f1, 
-+    /*   8 */  0x076dc419, 0x3cee5c52, 0x706af48f, 0x4be96cc4, 
-+    /*  12 */  0xe963a535, 0xd2e03d7e, 0x9e6495a3, 0xa5e70de8, 
-+    /*  16 */  0x0edb8832, 0x35581079, 0x79dcb8a4, 0x425f20ef, 
-+    /*  20 */  0xe0d5e91e, 0xdb567155, 0x97d2d988, 0xac5141c3, 
-+    /*  24 */  0x09b64c2b, 0x3235d460, 0x7eb17cbd, 0x4532e4f6, 
-+    /*  28 */  0xe7b82d07, 0xdc3bb54c, 0x90bf1d91, 0xab3c85da, 
-+    /*  32 */  0x1db71064, 0x2634882f, 0x6ab020f2, 0x5133b8b9, 
-+    /*  36 */  0xf3b97148, 0xc83ae903, 0x84be41de, 0xbf3dd995, 
-+    /*  40 */  0x1adad47d, 0x21594c36, 0x6ddde4eb, 0x565e7ca0, 
-+    /*  44 */  0xf4d4b551, 0xcf572d1a, 0x83d385c7, 0xb8501d8c, 
-+    /*  48 */  0x136c9856, 0x28ef001d, 0x646ba8c0, 0x5fe8308b, 
-+    /*  52 */  0xfd62f97a, 0xc6e16131, 0x8a65c9ec, 0xb1e651a7, 
-+    /*  56 */  0x14015c4f, 0x2f82c404, 0x63066cd9, 0x5885f492, 
-+    /*  60 */  0xfa0f3d63, 0xc18ca528, 0x8d080df5, 0xb68b95be, 
-+    /*  64 */  0x3b6e20c8, 0x00edb883, 0x4c69105e, 0x77ea8815, 
-+    /*  68 */  0xd56041e4, 0xeee3d9af, 0xa2677172, 0x99e4e939, 
-+    /*  72 */  0x3c03e4d1, 0x07807c9a, 0x4b04d447, 0x70874c0c, 
-+    /*  76 */  0xd20d85fd, 0xe98e1db6, 0xa50ab56b, 0x9e892d20, 
-+    /*  80 */  0x35b5a8fa, 0x0e3630b1, 0x42b2986c, 0x79310027, 
-+    /*  84 */  0xdbbbc9d6, 0xe038519d, 0xacbcf940, 0x973f610b, 
-+    /*  88 */  0x32d86ce3, 0x095bf4a8, 0x45df5c75, 0x7e5cc43e, 
-+    /*  92 */  0xdcd60dcf, 0xe7559584, 0xabd13d59, 0x9052a512, 
-+    /*  96 */  0x26d930ac, 0x1d5aa8e7, 0x51de003a, 0x6a5d9871, 
-+    /* 100 */  0xc8d75180, 0xf354c9cb, 0xbfd06116, 0x8453f95d, 
-+    /* 104 */  0x21b4f4b5, 0x1a376cfe, 0x56b3c423, 0x6d305c68, 
-+    /* 108 */  0xcfba9599, 0xf4390dd2, 0xb8bda50f, 0x833e3d44, 
-+    /* 112 */  0x2802b89e, 0x138120d5, 0x5f058808, 0x64861043, 
-+    /* 116 */  0xc60cd9b2, 0xfd8f41f9, 0xb10be924, 0x8a88716f, 
-+    /* 120 */  0x2f6f7c87, 0x14ece4cc, 0x58684c11, 0x63ebd45a, 
-+    /* 124 */  0xc1611dab, 0xfae285e0, 0xb6662d3d, 0x8de5b576, 
-+    /* 128 */  0x76dc4190, 0x4d5fd9db, 0x01db7106, 0x3a58e94d, 
-+    /* 132 */  0x98d220bc, 0xa351b8f7, 0xefd5102a, 0xd4568861, 
-+    /* 136 */  0x71b18589, 0x4a321dc2, 0x06b6b51f, 0x3d352d54, 
-+    /* 140 */  0x9fbfe4a5, 0xa43c7cee, 0xe8b8d433, 0xd33b4c78, 
-+    /* 144 */  0x7807c9a2, 0x438451e9, 0x0f00f934, 0x3483617f, 
-+    /* 148 */  0x9609a88e, 0xad8a30c5, 0xe10e9818, 0xda8d0053, 
-+    /* 152 */  0x7f6a0dbb, 0x44e995f0, 0x086d3d2d, 0x33eea566, 
-+    /* 156 */  0x91646c97, 0xaae7f4dc, 0xe6635c01, 0xdde0c44a, 
-+    /* 160 */  0x6b6b51f4, 0x50e8c9bf, 0x1c6c6162, 0x27eff929, 
-+    /* 164 */  0x856530d8, 0xbee6a893, 0xf262004e, 0xc9e19805, 
-+    /* 168 */  0x6c0695ed, 0x57850da6, 0x1b01a57b, 0x20823d30, 
-+    /* 172 */  0x8208f4c1, 0xb98b6c8a, 0xf50fc457, 0xce8c5c1c, 
-+    /* 176 */  0x65b0d9c6, 0x5e33418d, 0x12b7e950, 0x2934711b, 
-+    /* 180 */  0x8bbeb8ea, 0xb03d20a1, 0xfcb9887c, 0xc73a1037, 
-+    /* 184 */  0x62dd1ddf, 0x595e8594, 0x15da2d49, 0x2e59b502, 
-+    /* 188 */  0x8cd37cf3, 0xb750e4b8, 0xfbd44c65, 0xc057d42e, 
-+    /* 192 */  0x4db26158, 0x7631f913, 0x3ab551ce, 0x0136c985, 
-+    /* 196 */  0xa3bc0074, 0x983f983f, 0xd4bb30e2, 0xef38a8a9, 
-+    /* 200 */  0x4adfa541, 0x715c3d0a, 0x3dd895d7, 0x065b0d9c, 
-+    /* 204 */  0xa4d1c46d, 0x9f525c26, 0xd3d6f4fb, 0xe8556cb0, 
-+    /* 208 */  0x4369e96a, 0x78ea7121, 0x346ed9fc, 0x0fed41b7, 
-+    /* 212 */  0xad678846, 0x96e4100d, 0xda60b8d0, 0xe1e3209b, 
-+    /* 216 */  0x44042d73, 0x7f87b538, 0x33031de5, 0x088085ae, 
-+    /* 220 */  0xaa0a4c5f, 0x9189d414, 0xdd0d7cc9, 0xe68ee482, 
-+    /* 224 */  0x5005713c, 0x6b86e977, 0x270241aa, 0x1c81d9e1, 
-+    /* 228 */  0xbe0b1010, 0x8588885b, 0xc90c2086, 0xf28fb8cd, 
-+    /* 232 */  0x5768b525, 0x6ceb2d6e, 0x206f85b3, 0x1bec1df8, 
-+    /* 236 */  0xb966d409, 0x82e54c42, 0xce61e49f, 0xf5e27cd4, 
-+    /* 240 */  0x5edef90e, 0x655d6145, 0x29d9c998, 0x125a51d3, 
-+    /* 244 */  0xb0d09822, 0x8b530069, 0xc7d7a8b4, 0xfc5430ff, 
-+    /* 248 */  0x59b33d17, 0x6230a55c, 0x2eb40d81, 0x153795ca, 
-+    /* 252 */  0xb7bd5c3b, 0x8c3ec470, 0xc0ba6cad, 0xfb39f4e6, 
-+};
++    if(filter == NULL) {
++        return 1;
++    }
 +
-+unsigned int apc_crc32(const char* buf, int len)
-+{
-+    int i;
-+    int k;
-+    unsigned int crc;
++    if(zend_hash_find(filter, (char*)key, key_len, (void**)&zptr) == SUCCESS) {
++        if(Z_TYPE_PP(zptr) == IS_LONG && Z_LVAL_PP(zptr) == 0) {
++            return 0;
++        }
++    } else {
++        return 0;
++    }
 +
-+    /* preconditioning */
-+    crc = 0xFFFFFFFF;
-+    
-+    for (i = 0; i < len; i++) {
-+        k = (crc ^ buf[i]) & 0x000000FF;
-+        crc = ((crc >> 8) & 0x00FFFFFF) ^ crc32tab[k];
++
++    return 1;
++} /* }}} */
++
++/* {{{ apc_bin_fixup_op_array */
++static inline void apc_bin_fixup_op_array(zend_op_array *op_array) {
++    ulong i;
++    for (i = 0; i < op_array->last; i++) {
++        op_array->opcodes[i].handler = zend_opcode_handlers[APC_OPCODE_HANDLER_DECODE(&op_array->opcodes[i])];
 +    }
++}
++/* }}} */
 +
-+    /* postconditioning */
-+    return ~crc;
++/* {{{ apc_bin_fixup_class_entry */
++static inline void apc_bin_fixup_class_entry(zend_class_entry *ce) {
++    zend_function *fe;
++    HashPosition hpos;
++
++    /* fixup the opcodes in each method */
++    zend_hash_internal_pointer_reset_ex(&ce->function_table, &hpos);
++    while(zend_hash_get_current_data_ex(&ce->function_table, (void**)&fe, &hpos) == SUCCESS) {
++        apc_bin_fixup_op_array(&fe->op_array);
++        zend_hash_move_forward_ex(&ce->function_table, &hpos);
++    }
++
++    /* fixup hashtable destructor pointers */
++    ce->function_table.pDestructor = (dtor_func_t)zend_function_dtor;
++    ce->default_properties.pDestructor = (dtor_func_t)zval_ptr_dtor_wrapper;
++    ce->properties_info.pDestructor = (dtor_func_t)zval_ptr_dtor_wrapper;
++    ce->default_static_members.pDestructor = (dtor_func_t)zval_ptr_dtor_wrapper;
++    if (ce->static_members) {
++        ce->static_members->pDestructor = (dtor_func_t)zval_ptr_dtor_wrapper;
++    }
++    ce->constants_table.pDestructor = (dtor_func_t)zval_ptr_dtor_wrapper;
 +}
++/* }}} */
++
++/* {{{ apc_bin_dump */
++apc_bd_t* apc_bin_dump(HashTable *files, HashTable *user_vars TSRMLS_DC) {
 +
-+/* crc32gen: generate the nth (0..255) crc32 table value */
-+#if 0
-+static unsigned long crc32gen(int n)
-+{
 +    int i;
-+    unsigned long crc;
-+    
-+    crc = n;
-+    for (i = 8; i >= 0; i--) {
-+        if (crc & 1) {
-+            crc = (crc >> 1) ^ 0xEDB88320;
++    uint fcount;
++    slot_t *sp;
++    apc_bd_entry_t *ep;
++    int count=0;
++    apc_bd_t *bd;
++    zend_llist ll;
++    zend_function *efp, *sfp;
++    long size=0;
++    apc_context_t ctxt;
++    void *pool_ptr;
++
++    zend_llist_init(&ll, sizeof(void*), NULL, 0);
++    zend_hash_init(&APCG(apc_bd_alloc_list), 0, NULL, NULL, 0);
++
++    /* flip the hash for faster filter checking */
++    files = apc_flip_hash(files);
++    user_vars = apc_flip_hash(user_vars);
++
++    /* get size and entry counts */
++    for(i=0; i < apc_user_cache->num_slots; i++) {
++        sp = apc_user_cache->slots[i];
++        for(; sp != NULL; sp = sp->next) {
++            if(apc_bin_checkfilter(user_vars, sp->key.data.user.identifier, sp->key.data.user.identifier_len+1)) {
++                size += sizeof(apc_bd_entry_t*) + sizeof(apc_bd_entry_t);
++                size += sp->value->mem_size - (sizeof(apc_cache_entry_t) - sizeof(apc_cache_entry_value_t));
++                count++;
++            }
 +        }
-+        else {
-+            crc >>= 1;
++    }
++    for(i=0; i < apc_cache->num_slots; i++) {
++        sp = apc_cache->slots[i];
++        for(; sp != NULL; sp = sp->next) {
++            if(sp->key.type == APC_CACHE_KEY_FPFILE) {
++                if(apc_bin_checkfilter(files, sp->key.data.fpfile.fullpath, sp->key.data.fpfile.fullpath_len+1)) {
++                    size += sizeof(apc_bd_entry_t*) + sizeof(apc_bd_entry_t);
++                    size += sp->value->mem_size - (sizeof(apc_cache_entry_t) - sizeof(apc_cache_entry_value_t));
++                    count++;
++                }
++            } else {
++                /* TODO: Currently we don't support APC_CACHE_KEY_FILE type.  We need to store the path and re-stat on load */
++                apc_wprint("Excluding some files from apc_bin_dump[file].  Cached files must be included using full path with apc.stat=0.");
++            }
 +        }
 +    }
-+    return crc;
-+}
++
++    size += sizeof(apc_bd_t) +1;  /* +1 for null termination */
++    bd = emalloc(size);
++    bd->size = size;
++    pool_ptr = emalloc(sizeof(apc_pool));
++    apc_bd_alloc_ex(pool_ptr, sizeof(apc_pool));
++    ctxt.pool = apc_pool_create(APC_UNPOOL, apc_bd_alloc, apc_bd_free, NULL, NULL);  /* ideally the pool wouldn't be alloc'd as part of this */
++    if (!ctxt.pool) { /* TODO need to cleanup */
++        apc_wprint("Unable to allocate memory for pool.");
++        return NULL;
++    }
++    ctxt.copy = APC_COPY_IN_USER;  /* avoid stupid ALLOC_ZVAL calls here, hack */
++    apc_bd_alloc_ex( (void*)((long)bd + sizeof(apc_bd_t)), bd->size - sizeof(apc_bd_t) -1);
++    bd->num_entries = count;
++    bd->entries = apc_bd_alloc_ex(NULL, sizeof(apc_bd_entry_t) * count);
++
++    /* User entries */
++    zend_hash_init(&APCG(copied_zvals), 0, NULL, NULL, 0);
++    count = 0;
++    for(i=0; i < apc_user_cache->num_slots; i++) {
++        sp = apc_user_cache->slots[i];
++        for(; sp != NULL; sp = sp->next) {
++            if(apc_bin_checkfilter(user_vars, sp->key.data.user.identifier, sp->key.data.user.identifier_len+1)) {
++                ep = &bd->entries[count];
++                ep->type = sp->value->type;
++                ep->val.user.info = apc_bd_alloc(sp->value->data.user.info_len+1);
++                memcpy(ep->val.user.info, sp->value->data.user.info, sp->value->data.user.info_len+1);
++                ep->val.user.info_len = sp->value->data.user.info_len;
++                ep->val.user.val = apc_copy_zval(NULL, sp->value->data.user.val, &ctxt);
++                ep->val.user.ttl = sp->value->data.user.ttl;
++
++                /* swizzle pointers */
++                apc_swizzle_ptr(bd, &ll, &bd->entries[count].val.user.info);
++                zend_hash_clean(&APCG(copied_zvals));
++                apc_swizzle_zval(bd, &ll, bd->entries[count].val.user.val TSRMLS_CC);
++                apc_swizzle_ptr(bd, &ll, &bd->entries[count].val.user.val);
++
++                count++;
++            }
++        }
++    }
++    zend_hash_destroy(&APCG(copied_zvals));
++    APCG(copied_zvals).nTableSize=0;
++
++    /* File entries */
++    for(i=0; i < apc_cache->num_slots; i++) {
++        for(sp=apc_cache->slots[i]; sp != NULL; sp = sp->next) {
++            if(sp->key.type == APC_CACHE_KEY_FPFILE) {
++                if(apc_bin_checkfilter(files, sp->key.data.fpfile.fullpath, sp->key.data.fpfile.fullpath_len+1)) {
++                    ep = &bd->entries[count];
++                    ep->type = sp->key.type;
++                    ep->val.file.filename = apc_bd_alloc(strlen(sp->value->data.file.filename)+1);
++                    strcpy(ep->val.file.filename, sp->value->data.file.filename);
++                    ep->val.file.op_array = apc_copy_op_array(NULL, sp->value->data.file.op_array, &ctxt TSRMLS_CC);
++
++                    for(ep->num_functions=0; sp->value->data.file.functions[ep->num_functions].function != NULL;) { ep->num_functions++; }
++                    ep->val.file.functions = apc_bd_alloc(sizeof(apc_function_t) * ep->num_functions);
++                    for(fcount=0; fcount < ep->num_functions; fcount++) {
++                        memcpy(&ep->val.file.functions[fcount], &sp->value->data.file.functions[fcount], sizeof(apc_function_t));
++                        ep->val.file.functions[fcount].name = apc_xmemcpy(sp->value->data.file.functions[fcount].name, sp->value->data.file.functions[fcount].name_len+1, apc_bd_alloc);
++                        ep->val.file.functions[fcount].name_len = sp->value->data.file.functions[fcount].name_len;
++                        ep->val.file.functions[fcount].function = apc_bd_alloc(sizeof(zend_function));
++                        efp = ep->val.file.functions[fcount].function;
++                        sfp = sp->value->data.file.functions[fcount].function;
++                        switch(sfp->type) {
++                            case ZEND_INTERNAL_FUNCTION:
++                            case ZEND_OVERLOADED_FUNCTION:
++                                efp->op_array = sfp->op_array;
++                                break;
++                            case ZEND_USER_FUNCTION:
++                            case ZEND_EVAL_CODE:
++                                apc_copy_op_array(&efp->op_array, &sfp->op_array, &ctxt TSRMLS_CC);
++                                break;
++                            default:
++                                assert(0);
++                        }
++#ifdef ZEND_ENGINE_2
++                        efp->common.prototype = NULL;
++                        efp->common.fn_flags = sfp->common.fn_flags & (~ZEND_ACC_IMPLEMENTED_ABSTRACT);
 +#endif
++                        apc_swizzle_ptr(bd, &ll, &ep->val.file.functions[fcount].name);
++                        apc_swizzle_ptr(bd, &ll, (void**)&ep->val.file.functions[fcount].function);
++                        apc_swizzle_op_array(bd, &ll, &efp->op_array TSRMLS_CC);
++                    }
 +
-+/* }}} */
 +
-+/*
-+ * Local variables:
-+ * tab-width: 4
-+ * c-basic-offset: 4
-+ * End:
-+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
-+ * vim<600: expandtab sw=4 ts=4 sts=4
-+ */
-diff -ubrN php-5.2.5-orig/ext/apc/apc_cache.c php-5.2.5/ext/apc/apc_cache.c
---- php-5.2.5-orig/ext/apc/apc_cache.c 1969-12-31 18:00:00.000000000 -0600
-+++ php-5.2.5/ext/apc/apc_cache.c      2007-12-26 16:51:32.000000000 -0600
-@@ -0,0 +1,1343 @@
-+/*
-+  +----------------------------------------------------------------------+
-+  | APC                                                                  |
-+  +----------------------------------------------------------------------+
-+  | Copyright (c) 2006 The PHP Group                                     |
-+  +----------------------------------------------------------------------+
-+  | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt                                  |
-+  | If you did not receive a copy of the PHP license and are unable to   |
-+  | obtain it through the world-wide-web, please send a note to          |
-+  | license@php.net so we can mail you a copy immediately.               |
-+  +----------------------------------------------------------------------+
-+  | Authors: Daniel Cowgill <dcowgill@communityconnect.com>              |
-+  |          Rasmus Lerdorf <rasmus@php.net>                             |
-+  |          Arun C. Murthy <arunc@yahoo-inc.com>                        |
-+  |          Gopal Vijayaraghavan <gopalv@yahoo-inc.com>                 |
-+  +----------------------------------------------------------------------+
++                    for(ep->num_classes=0; sp->value->data.file.classes[ep->num_classes].class_entry != NULL;) { ep->num_classes++; }
++                    ep->val.file.classes = apc_bd_alloc(sizeof(apc_class_t) * ep->num_classes);
++                    for(fcount=0; fcount < ep->num_classes; fcount++) {
++                        ep->val.file.classes[fcount].name = apc_xmemcpy(sp->value->data.file.classes[fcount].name, sp->value->data.file.classes[fcount].name_len+1, apc_bd_alloc);
++                        ep->val.file.classes[fcount].name_len = sp->value->data.file.classes[fcount].name_len;
++                        ep->val.file.classes[fcount].class_entry = apc_copy_class_entry(NULL, sp->value->data.file.classes[fcount].class_entry, &ctxt);
++                        ep->val.file.classes[fcount].parent_name = apc_xstrdup(sp->value->data.file.classes[fcount].parent_name, apc_bd_alloc);
 +
-+   This software was contributed to PHP by Community Connect Inc. in 2002
-+   and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
-+   Future revisions and derivatives of this source code must acknowledge
-+   Community Connect Inc. as the original contributor of this module by
-+   leaving this note intact in the source code.
++                        apc_swizzle_ptr(bd, &ll, &ep->val.file.classes[fcount].name);
++                        apc_swizzle_ptr(bd, &ll, &ep->val.file.classes[fcount].parent_name);
++                        apc_swizzle_class_entry(bd, &ll, ep->val.file.classes[fcount].class_entry TSRMLS_CC);
++                        apc_swizzle_ptr(bd, &ll, &ep->val.file.classes[fcount].class_entry);
++                    }
 +
-+   All other licensing and usage conditions are those of the PHP Group.
++                    apc_swizzle_ptr(bd, &ll, &bd->entries[count].val.file.filename);
++                    apc_swizzle_op_array(bd, &ll, bd->entries[count].val.file.op_array TSRMLS_CC);
++                    apc_swizzle_ptr(bd, &ll, &bd->entries[count].val.file.op_array);
++                    apc_swizzle_ptr(bd, &ll, (void**)&ep->val.file.functions);
++                    apc_swizzle_ptr(bd, &ll, (void**)&ep->val.file.classes);
 +
-+ */
++                    count++;
++                } else {
++                    /* TODO: Currently we don't support APC_CACHE_KEY_FILE type.  We need to store the path and re-stat on load */
++                }
++            }
++        }
++    }
 +
-+/* $Id: apc_cache.c,v 3.145 2007/10/05 23:06:56 gopalv Exp $ */
++    /* append swizzle pointer list to bd */
++    bd = apc_swizzle_bd(bd, &ll TSRMLS_CC);
++    zend_llist_destroy(&ll);
++    zend_hash_destroy(&APCG(apc_bd_alloc_list));
 +
-+#include "apc_cache.h"
-+#include "apc_lock.h"
-+#include "apc_sma.h"
-+#include "apc_globals.h"
-+#include "SAPI.h"
-+#include "ext/standard/php_var.h"
-+#include "ext/standard/php_smart_str.h"
++    if(files) {
++        zend_hash_destroy(files);
++        efree(files);
++    }
++    if(user_vars) {
++        zend_hash_destroy(user_vars);
++        efree(user_vars);
++    }
 +
-+/* TODO: rehash when load factor exceeds threshold */
++    efree(pool_ptr);
 +
-+#define CHECK(p) { if ((p) == NULL) return NULL; }
++    return bd;
++} /* }}} */
 +
-+/* {{{ locking macros */
-+#define CREATE_LOCK(lock)     apc_lck_create(NULL, 0, 1, lock)
-+#define DESTROY_LOCK(c) apc_lck_destroy(c->header->lock)
-+#define LOCK(c)         { HANDLE_BLOCK_INTERRUPTIONS(); apc_lck_lock(c->header->lock); }
-+#define RDLOCK(c)       { HANDLE_BLOCK_INTERRUPTIONS(); apc_lck_rdlock(c->header->lock); }
-+#define UNLOCK(c)       { apc_lck_unlock(c->header->lock); HANDLE_UNBLOCK_INTERRUPTIONS(); }
-+/* }}} */
 +
-+/* {{{ struct definition: slot_t */
-+typedef struct slot_t slot_t;
-+struct slot_t {
-+    apc_cache_key_t key;        /* slot key */
-+    apc_cache_entry_t* value;   /* slot value */
-+    slot_t* next;               /* next slot in linked list */
-+    int num_hits;               /* number of hits to this bucket */
-+    time_t creation_time;       /* time slot was initialized */
-+    time_t deletion_time;       /* time slot was removed from cache */
-+    time_t access_time;         /* time slot was last accessed */
-+};
-+/* }}} */
++/* {{{ apc_bin_load */
++int apc_bin_load(apc_bd_t *bd, int flags TSRMLS_DC) {
 +
-+/* {{{ struct definition: header_t
-+   Any values that must be shared among processes should go in here. */
-+typedef struct header_t header_t;
-+struct header_t {
-+    apc_lck_t lock;              /* read/write lock (exclusive blocking cache lock) */
-+    apc_lck_t wrlock;           /* write lock (non-blocking used to prevent cache slams) */
-+    int num_hits;               /* total successful hits in cache */
-+    int num_misses;             /* total unsuccessful hits in cache */
-+    int num_inserts;            /* total successful inserts in cache */
-+    slot_t* deleted_list;       /* linked list of to-be-deleted slots */
-+    time_t start_time;          /* time the above counters were reset */
-+    int expunges;               /* total number of expunges */
-+    zend_bool busy;             /* Flag to tell clients when we are busy cleaning the cache */
-+    int num_entries;            /* Statistic on the number of entries */
-+    size_t mem_size;            /* Statistic on the memory size used by this cache */
-+};
-+/* }}} */
++    apc_bd_entry_t *ep;
++    uint i, i2;
++    int ret;
++    time_t t;
++    zend_op_array *alloc_op_array = NULL;
++    apc_function_t *alloc_functions = NULL;
++    apc_class_t *alloc_classes = NULL;
++    apc_cache_entry_t *cache_entry;
++    apc_cache_key_t cache_key;
++    apc_context_t ctxt;
++
++    if (bd->swizzled) {
++        if(apc_unswizzle_bd(bd, flags TSRMLS_CC) < 0) {
++            return -1;
++        }
++    }
 +
-+/* {{{ struct definition: apc_cache_t */
-+struct apc_cache_t {
-+    void* shmaddr;              /* process (local) address of shared cache */
-+    header_t* header;           /* cache header (stored in SHM) */
-+    slot_t** slots;             /* array of cache slots (stored in SHM) */
-+    int num_slots;              /* number of slots in cache */
-+    int gc_ttl;                 /* maximum time on GC list for a slot */
-+    int ttl;                    /* if slot is needed and entry's access time is older than this ttl, remove it */
-+};
-+/* }}} */
++    t = apc_time();
 +
-+/* {{{ struct definition local_slot_t */
-+typedef struct local_slot_t local_slot_t;
-+struct local_slot_t {
-+    slot_t *original;           /* the original slot in shm */
-+    int num_hits;               /* number of hits */
-+    time_t creation_time;       /* creation time */
-+    apc_cache_entry_t *value;   /* shallow copy of slot->value */
-+    local_slot_t *next;         /* only for dead list */
-+};
-+/* }}} */
-+/* {{{ struct definition apc_local_cache_t */
-+struct apc_local_cache_t {
-+    apc_cache_t* shmcache;      /* the real cache in shm */
-+    local_slot_t* slots;        /* process (local) cache of objects */
-+    local_slot_t* dead_list;    /* list of objects pending removal */
-+    int num_slots;              /* number of slots in cache */
-+    int ttl;                    /* time to live */
-+    int num_hits;               /* number of hits */
-+    int generation;             /* every generation lives between expunges */
-+};
-+/* }}} */
++    for(i = 0; i < bd->num_entries; i++) {
++        ctxt.pool = apc_pool_create(APC_SMALL_POOL, apc_sma_malloc, apc_sma_free, apc_sma_protect, apc_sma_unprotect);
++        if (!ctxt.pool) { /* TODO need to cleanup previous pools */
++            apc_wprint("Unable to allocate memory for pool.");
++            goto failure;
++        }
++        ep = &bd->entries[i];
++        switch (ep->type) {
++            case APC_CACHE_KEY_FILE:
++                /* TODO: Currently we don't support APC_CACHE_KEY_FILE type.  We need to store the path and re-stat on load (or something else perhaps?) */
++                break;
++            case APC_CACHE_KEY_FPFILE:
++                ctxt.copy = APC_COPY_IN_OPCODE;
 +
-+/* {{{ key_equals */
-+#define key_equals(a, b) (a.inode==b.inode && a.device==b.device)
-+/* }}} */
++                HANDLE_BLOCK_INTERRUPTIONS();
++#if NONBLOCKING_LOCK_AVAILABLE
++                if(APCG(write_lock)) {
++                    if(!apc_cache_write_lock(apc_cache)) {
++                        HANDLE_UNBLOCK_INTERRUPTIONS();
++                        return -1;
++                    }
++                }
++#endif
++                if(! (alloc_op_array = apc_copy_op_array(NULL, ep->val.file.op_array, &ctxt TSRMLS_CC))) {
++                    goto failure;
++                }
++                apc_bin_fixup_op_array(alloc_op_array);
 +
-+/* {{{ hash */
-+static unsigned int hash(apc_cache_key_t key)
-+{
-+    return key.data.file.device + key.data.file.inode;
-+}
-+/* }}} */
++                if(! (alloc_functions = apc_sma_malloc(sizeof(apc_function_t) * (ep->num_functions + 1)))) {
++                    goto failure;
++                }
++                for(i2=0; i2 < ep->num_functions; i2++) {
++                    if(! (alloc_functions[i2].name = apc_xmemcpy(ep->val.file.functions[i2].name, ep->val.file.functions[i2].name_len+1, apc_sma_malloc))) {
++                        goto failure;
++                    }
++                    alloc_functions[i2].name_len = ep->val.file.functions[i2].name_len;
++                    if(! (alloc_functions[i2].function = apc_sma_malloc(sizeof(zend_function)))) {
++                        goto failure;
++                    }
++                    switch(ep->val.file.functions[i2].function->type) {
++                        case ZEND_INTERNAL_FUNCTION:
++                        case ZEND_OVERLOADED_FUNCTION:
++                            alloc_functions[i2].function->op_array = ep->val.file.functions[i2].function->op_array;
++                            break;
++                        case ZEND_USER_FUNCTION:
++                        case ZEND_EVAL_CODE:
++                            if (!apc_copy_op_array(&alloc_functions[i2].function->op_array, &ep->val.file.functions[i2].function->op_array, &ctxt TSRMLS_CC)) {
++                                goto failure;
++                            }
++                            apc_bin_fixup_op_array(&alloc_functions[i2].function->op_array);
++                            break;
++                        default:
++                            assert(0);
++                    }
++#ifdef ZEND_ENGINE_2
++                    alloc_functions[i2].function->common.prototype=NULL;
++                    alloc_functions[i2].function->common.fn_flags=ep->val.file.functions[i2].function->common.fn_flags & (~ZEND_ACC_IMPLEMENTED_ABSTRACT);
++#endif
++                }
++                alloc_functions[i2].name = NULL;
++                alloc_functions[i2].function = NULL;
 +
-+/* {{{ string_nhash_8 */
-+static unsigned int string_nhash_8(const char *s, size_t len)
-+{
-+    register const unsigned int *iv = (const unsigned int *)s;
-+    register unsigned int h = 0;
-+    register const unsigned int *e  = (const unsigned int *)(s + len - (len % sizeof(unsigned int)));
++                if(! (alloc_classes = apc_sma_malloc(sizeof(apc_class_t) * (ep->num_classes + 1)))) {
++                    goto failure;
++                }
++                for(i2=0; i2 < ep->num_classes; i2++) {
++                    if(! (alloc_classes[i2].name = apc_xmemcpy(ep->val.file.classes[i2].name, ep->val.file.classes[i2].name_len+1, apc_sma_malloc))) {
++                        goto failure;
++                    }
++                    alloc_classes[i2].name_len = ep->val.file.classes[i2].name_len;
++                    if(! (alloc_classes[i2].class_entry = apc_copy_class_entry(NULL, ep->val.file.classes[i2].class_entry, &ctxt))) {
++                        goto failure;
++                    }
++                    apc_bin_fixup_class_entry(alloc_classes[i2].class_entry);
++                    if(! (alloc_classes[i2].parent_name = apc_xstrdup(ep->val.file.classes[i2].parent_name, apc_sma_malloc))) {
++                        if(ep->val.file.classes[i2].parent_name != NULL) {
++                            goto failure;
++                        }
++                    }
++                }
++                alloc_classes[i2].name = NULL;
++                alloc_classes[i2].class_entry = NULL;
++
++                if(!(cache_entry = apc_cache_make_file_entry(ep->val.file.filename, alloc_op_array, alloc_functions, alloc_classes, &ctxt))) {
++                    goto failure;
++                }
++
++                if (!apc_cache_make_file_key(&cache_key, ep->val.file.filename, PG(include_path), t TSRMLS_CC)) {
++                    goto failure;
++                }
++
++                if ((ret = apc_cache_insert(apc_cache, cache_key, cache_entry, &ctxt, t)) != 1) {
++                    if(ret==-1) {
++                        goto failure;
++                    }
++                }
++
++#if NONBLOCKING_LOCK_AVAILABLE
++                if(APCG(write_lock)) {
++                    apc_cache_write_unlock(apc_cache);
++                }
++#endif
++                HANDLE_UNBLOCK_INTERRUPTIONS();
 +
-+    for(;iv<e;iv++) {
-+        h += *iv;
-+        h = (h << 7) | (h >> ((8*sizeof(unsigned int)) - 7));
++                break;
++            case APC_CACHE_KEY_USER:
++                ctxt.copy = APC_COPY_IN_USER;
++                _apc_store(ep->val.user.info, ep->val.user.info_len, ep->val.user.val, ep->val.user.ttl, 0 TSRMLS_CC);
++                break;
++            default:
++                break;
++       }
 +    }
-+    s = (const char *)iv;
-+    for(len %= sizeof(unsigned int);len;len--) {
-+        h += *(s++);
++
++    return 0;
++
++failure:
++    apc_pool_destroy(ctxt.pool);
++    apc_wprint("Unable to allocate memory for apc binary load/dump functionality.");
++#if NONBLOCKING_LOCK_AVAILABLE
++    if(APCG(write_lock)) {
++        apc_cache_write_unlock(apc_cache);
 +    }
-+    h ^= (h >> 13);
-+    h ^= (h >> 7);
-+    return h;
-+}
-+/* }}} */
++#endif
++    HANDLE_UNBLOCK_INTERRUPTIONS();
++    return -1;
++} /* }}} */
 +
-+/* {{{ make_slot */
-+slot_t* make_slot(apc_cache_key_t key, apc_cache_entry_t* value, slot_t* next, time_t t)
++
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * End:
++ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
++ * vim<600: expandtab sw=4 ts=4 sts=4
++ */
+diff -Naur php-5.3.1.orig/ext/apc/apc_bin.h php-5.3.1/ext/apc/apc_bin.h
+--- php-5.3.1.orig/ext/apc/apc_bin.h   1970-01-01 01:00:00.000000000 +0100
++++ php-5.3.1/ext/apc/apc_bin.h        1970-01-01 10:13:08.000000000 +0100
+@@ -0,0 +1,63 @@
++/*
++  +----------------------------------------------------------------------+
++  | APC                                                                  |
++  +----------------------------------------------------------------------+
++  | Copyright (c) 2009 The PHP Group                                     |
++  +----------------------------------------------------------------------+
++  | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt                                  |
++  | If you did not receive a copy of the PHP license and are unable to   |
++  | obtain it through the world-wide-web, please send a note to          |
++  | license@php.net so we can mail you a copy immediately.               |
++  +----------------------------------------------------------------------+
++  | Authors: Brian Shire <shire@php.net>                                 |
++  +----------------------------------------------------------------------+
++
++ */
++
++/* $Id: apc_bin.h 274613 2009-01-26 06:57:57Z shire $ */
++
++#ifndef APC_BINDUMP_H
++#define APC_BINDUMP_H
++
++#include "apc.h"
++#include "apc_php.h"
++#include "ext/standard/basic_functions.h"
++
++/* APC binload flags */
++#define APC_BIN_VERIFY_MD5    1 << 0
++#define APC_BIN_VERIFY_CRC32  1 << 1
++
++typedef struct _apc_bd_entry_t {
++    unsigned char type;
++    uint num_functions;
++    uint num_classes;
++    apc_cache_entry_value_t val;
++} apc_bd_entry_t;
++
++typedef struct _apc_bd_t {
++    unsigned int size;
++    int swizzled;
++    unsigned char md5[16];
++    php_uint32 crc;
++    unsigned int num_entries;
++    apc_bd_entry_t *entries;
++    int num_swizzled_ptrs;
++    void ***swizzled_ptrs;
++} apc_bd_t;
++
++apc_bd_t* apc_bin_dump(HashTable *files, HashTable *user_vars TSRMLS_DC);
++int apc_bin_load(apc_bd_t *bd, int flags TSRMLS_DC);
++
++#endif
++
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * End:
++ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
++ * vim<600: expandtab sw=4 ts=4 sts=4
++ */
+diff -Naur php-5.3.1.orig/ext/apc/apc.c php-5.3.1/ext/apc/apc.c
+--- php-5.3.1.orig/ext/apc/apc.c       1970-01-01 01:00:00.000000000 +0100
++++ php-5.3.1/ext/apc/apc.c    1970-01-01 10:13:08.000000000 +0100
+@@ -0,0 +1,635 @@
++/*
++  +----------------------------------------------------------------------+
++  | APC                                                                  |
++  +----------------------------------------------------------------------+
++  | Copyright (c) 2006-2008 The PHP Group                                |
++  +----------------------------------------------------------------------+
++  | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt                                  |
++  | If you did not receive a copy of the PHP license and are unable to   |
++  | obtain it through the world-wide-web, please send a note to          |
++  | license@php.net so we can mail you a copy immediately.               |
++  +----------------------------------------------------------------------+
++  | Authors: Daniel Cowgill <dcowgill@communityconnect.com>              |
++  |          George Schlossnagle <george@omniti.com>                     |
++  |          Rasmus Lerdorf <rasmus@php.net>                             |
++  |          Arun C. Murthy <arunc@yahoo-inc.com>                        |
++  |          Gopal Vijayaraghavan <gopalv@yahoo-inc.com>                 |
++  +----------------------------------------------------------------------+
++
++   This software was contributed to PHP by Community Connect Inc. in 2002
++   and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
++   Future revisions and derivatives of this source code must acknowledge
++   Community Connect Inc. as the original contributor of this module by
++   leaving this note intact in the source code.
++
++   All other licensing and usage conditions are those of the PHP Group.
++
++ */
++
++/* $Id: apc.c 277132 2009-03-14 01:50:57Z shire $ */
++
++#include "apc.h"
++#include "apc_zend.h"
++#include "php.h"
++
++#if HAVE_PCRE || HAVE_BUNDLED_PCRE
++/*  Deal with problem present until php-5.2.2 where php_pcre.h was not installed correctly */
++#   if !HAVE_BUNDLED_PCRE && PHP_MAJOR_VERSION == 5 && (PHP_MINOR_VERSION < 2 || (PHP_MINOR_VERSION == 2 && PHP_RELEASE_VERSION < 2))
++#       include "apc_php_pcre.h"
++#   else
++#       include "ext/pcre/php_pcre.h"
++#   endif
++#   include "ext/standard/php_smart_str.h"
++#endif
++
++#define NELEMS(a) (sizeof(a)/sizeof((a)[0]))
++
++/* {{{ memory allocation wrappers */
++
++void* apc_emalloc(size_t n)
 +{
-+    slot_t* p = apc_sma_malloc(sizeof(slot_t));
-+    if (!p) return NULL;
++    void* p = malloc(n);
++    if (p == NULL) {
++        apc_eprint("apc_emalloc: malloc failed to allocate %u bytes:", n);
++    }
++    return p;
++}
 +
-+    if(value->type == APC_CACHE_ENTRY_USER) {
-+        char *identifier = (char*) apc_xstrdup(key.data.user.identifier, apc_sma_malloc);
-+        if (!identifier) {
-+            apc_sma_free(p);
-+            return NULL;
-+        }
-+        key.data.user.identifier = identifier;
-+    } else if(key.type == APC_CACHE_KEY_FPFILE) {
-+        char *fullpath = (char*) apc_xstrdup(key.data.fpfile.fullpath, apc_sma_malloc);
-+        if (!fullpath) {
-+            apc_sma_free(p);
-+            return NULL;
-+        }
-+        key.data.fpfile.fullpath = fullpath;
++void* apc_erealloc(void* p, size_t n)
++{
++    p = realloc(p, n);
++    if (p == NULL) {
++        apc_eprint("apc_erealloc: realloc failed to allocate %u bytes:", n);
 +    }
-+    p->key = key;
-+    p->value = value;
-+    p->next = next;
-+    p->num_hits = 0;
-+    p->creation_time = t;
-+    p->access_time = t;
-+    p->deletion_time = 0;
 +    return p;
 +}
-+/* }}} */
 +
-+/* {{{ free_slot */
-+static void free_slot(slot_t* slot)
++void apc_efree(void* p)
 +{
-+    if(slot->value->type == APC_CACHE_ENTRY_USER) {
-+        apc_sma_free((char *)slot->key.data.user.identifier);
-+    } else if(slot->key.type == APC_CACHE_KEY_FPFILE) {
-+        apc_sma_free((char *)slot->key.data.fpfile.fullpath);
++    if (p == NULL) {
++        apc_eprint("apc_efree: attempt to free null pointer");
 +    }
-+    apc_cache_free_entry(slot->value);
-+    apc_sma_free(slot);
++    free(p);
 +}
-+/* }}} */
 +
-+/* {{{ remove_slot */
-+static void remove_slot(apc_cache_t* cache, slot_t** slot)
++char* apc_estrdup(const char* s)
 +{
-+    slot_t* dead = *slot;
-+    *slot = (*slot)->next;
++    int len;
++    char* dup;
 +
-+    cache->header->mem_size -= dead->value->mem_size;
-+    cache->header->num_entries--;
-+    if (dead->value->ref_count <= 0) {
-+        free_slot(dead);
++    if (s == NULL) {
++        return NULL;
 +    }
-+    else {
-+        dead->next = cache->header->deleted_list;
-+        dead->deletion_time = time(0);
-+        cache->header->deleted_list = dead;
++    len = strlen(s);
++    dup = (char*) malloc(len+1);
++    if (dup == NULL) {
++        apc_eprint("apc_estrdup: malloc failed to allocate %u bytes:", len+1);
 +    }
++    memcpy(dup, s, len);
++    dup[len] = '\0';
++    return dup;
 +}
-+/* }}} */
 +
-+/* {{{ process_pending_removals */
-+static void process_pending_removals(apc_cache_t* cache)
++void* apc_xstrdup(const char* s, apc_malloc_t f)
 +{
-+    slot_t** slot;
-+    time_t now;
-+
-+    /* This function scans the list of removed cache entries and deletes any
-+     * entry whose reference count is zero (indicating that it is no longer
-+     * being executed) or that has been on the pending list for more than
-+     * cache->gc_ttl seconds (we issue a warning in the latter case).
-+     */
-+
-+    if (!cache->header->deleted_list)
-+        return;
++    return s != NULL ? apc_xmemcpy(s, strlen(s)+1, f) : NULL;
++}
 +
-+    slot = &cache->header->deleted_list;
-+    now = time(0);
++void* apc_xmemcpy(const void* p, size_t n, apc_malloc_t f)
++{
++    void* q;
 +
-+    while (*slot != NULL) {
-+        int gc_sec = cache->gc_ttl ? (now - (*slot)->deletion_time) : 0;
-+
-+        if ((*slot)->value->ref_count <= 0 || gc_sec > cache->gc_ttl) {
-+            slot_t* dead = *slot;
-+
-+            if (dead->value->ref_count > 0) {
-+                switch(dead->value->type) {
-+                    case APC_CACHE_ENTRY_FILE:
-+                        apc_log(APC_WARNING, "GC cache entry '%s' (dev=%d ino=%d) "
-+                            "was on gc-list for %d seconds", dead->value->data.file.filename,
-+                            dead->key.data.file.device, dead->key.data.file.inode, gc_sec);
-+                        break;
-+                    case APC_CACHE_ENTRY_USER:
-+                        apc_log(APC_WARNING, "GC cache entry '%s' "
-+                            "was on gc-list for %d seconds", dead->value->data.user.info, gc_sec);
-+                        break;
-+                }
-+            }
-+            *slot = dead->next;
-+            free_slot(dead);
-+        }
-+        else {
-+            slot = &(*slot)->next;
-+        }
++    if (p != NULL && (q = f(n)) != NULL) {
++        memcpy(q, p, n);
++        return q;
 +    }
++    return NULL;
 +}
++
 +/* }}} */
 +
-+/* {{{ prevent_garbage_collection */
-+static void prevent_garbage_collection(apc_cache_entry_t* entry)
++/* {{{ console display functions */
++
++static void my_log(int level, const char* fmt, va_list args)
 +{
-+    /* set reference counts on zend objects to an arbitrarily high value to
-+     * prevent garbage collection after execution */
++    static const char* level_strings[] = {
++        "apc-debug",
++        "apc-notice",
++        "apc-warning",
++        "apc-error"
++    };
++    static const int num_levels = NELEMS(level_strings);
 +
-+    enum { BIG_VALUE = 1000 };
++    time_t now;
++    char* buf;          /* for ctime */
 +
-+    if(entry->data.file.op_array) {
-+        entry->data.file.op_array->refcount[0] = BIG_VALUE;
++      TSRMLS_FETCH();
++
++    fflush(stdout);
++
++    if (level < 0)
++        level = 0;
++    else if (level >= num_levels)
++        level = num_levels-1;
++
++    now = time(0);
++    buf = ctime(&now);  /* TODO: replace with reentrant impl */
++    buf[24] = '\0';
++
++    fprintf(stderr, "[%s] [%s] ", buf, level_strings[level]);
++    vfprintf(stderr, fmt, args);
++
++    if (fmt[0] != '\0' && fmt[strlen(fmt)-1] == ':') {
++        fprintf(stderr, " %s", strerror(errno));
 +    }
-+    if (entry->data.file.functions) {
-+        int i;
-+        apc_function_t* fns = entry->data.file.functions;
-+        for (i=0; fns[i].function != NULL; i++) {
-+#ifdef ZEND_ENGINE_2            
-+            *(fns[i].function->op_array.refcount) = BIG_VALUE;
-+#else            
-+            fns[i].function->op_array.refcount[0] = BIG_VALUE;
-+#endif            
-+        }
++
++    if (zend_is_compiling(TSRMLS_C)) {
++        fprintf(stderr, " in %s on line %d.", zend_get_compiled_filename(TSRMLS_C), zend_get_compiled_lineno(TSRMLS_C)); 
++    } else if (zend_is_executing(TSRMLS_C)) {
++        fprintf(stderr, " in %s on line %d.", zend_get_executed_filename(TSRMLS_C), zend_get_executed_lineno(TSRMLS_C)); 
 +    }
-+    if (entry->data.file.classes) {
-+        int i;
-+        apc_class_t* classes = entry->data.file.classes;
-+        for (i=0; classes[i].class_entry != NULL; i++) {
-+#ifdef ZEND_ENGINE_2            
-+            classes[i].class_entry->refcount = BIG_VALUE;
-+#else            
-+            classes[i].class_entry->refcount[0] = BIG_VALUE;
-+#endif
-+        }
++    fprintf(stderr, "\n"); 
++
++    if (level == APC_ERROR) {
++        exit(2);
 +    }
 +}
-+/* }}} */
 +
-+/* {{{ apc_cache_create */
-+apc_cache_t* apc_cache_create(int size_hint, int gc_ttl, int ttl)
++void apc_eprint(const char* fmt, ...)
 +{
-+    apc_cache_t* cache;
-+    int cache_size;
-+    int num_slots;
-+    int i;
++    va_list args;
++    va_start(args, fmt);
++    my_log(APC_ERROR, fmt, args);
++    va_end(args);
++}
 +
-+    num_slots = size_hint > 0 ? size_hint*2 : 2000;
++void apc_wprint(const char* fmt, ...)
++{
++    va_list args;
++    va_start(args, fmt);
++    my_log(APC_WARNING, fmt, args);
++    va_end(args);
++}
 +
-+    cache = (apc_cache_t*) apc_emalloc(sizeof(apc_cache_t));
-+    cache_size = sizeof(header_t) + num_slots*sizeof(slot_t*);
++void apc_nprint(const char* fmt, ...)
++{
++    va_list args;
++    va_start(args, fmt);
++    my_log(APC_NOTICE, fmt, args);
++    va_end(args);
++}
 +
-+    cache->shmaddr = apc_sma_malloc(cache_size);
-+    if(!cache->shmaddr) {
-+        apc_eprint("Unable to allocate shared memory for cache structures.  (Perhaps your shared memory size isn't large enough?). ");
-+    }
-+    memset(cache->shmaddr, 0, cache_size);
++void apc_dprint(const char* fmt, ...)
++{
++#ifdef APC_DEBUG
++    va_list args;
++    va_start(args, fmt);
++    my_log(APC_DBG, fmt, args);
++    va_end(args);
++#endif
++}
 +
-+    cache->header = (header_t*) cache->shmaddr;
-+    cache->header->num_hits = 0;
-+    cache->header->num_misses = 0;
-+    cache->header->deleted_list = NULL;
-+    cache->header->start_time = time(NULL);
-+    cache->header->expunges = 0;
-+    cache->header->busy = 0;
++/* }}} */
 +
-+    cache->slots = (slot_t**) (((char*) cache->shmaddr) + sizeof(header_t));
-+    cache->num_slots = num_slots;
-+    cache->gc_ttl = gc_ttl;
-+    cache->ttl = ttl;
-+    CREATE_LOCK(cache->header->lock);
-+#if NONBLOCKING_LOCK_AVAILABLE
-+    CREATE_LOCK(cache->header->wrlock);
-+#endif
-+    for (i = 0; i < num_slots; i++) {
-+        cache->slots[i] = NULL;
-+    }
++/* {{{ string and text manipulation */
 +
-+    return cache;
++char* apc_append(const char* s, const char* t)
++{
++    int slen;
++    int tlen;
++    char* p;
++
++    slen = strlen(s);
++    tlen = strlen(t);
++
++    p = (char*) apc_emalloc((slen + tlen + 1) * sizeof(char));
++    memcpy(p, s, slen);
++    memcpy(p + slen, t, tlen + 1);
++
++    return p;
 +}
-+/* }}} */
 +
-+/* {{{ apc_cache_destroy */
-+void apc_cache_destroy(apc_cache_t* cache)
++char* apc_substr(const char* s, int start, int length)
 +{
-+    DESTROY_LOCK(cache);
-+    apc_efree(cache);
++    char* substr;
++    int src_len = strlen(s);
++
++    /* bring start into range */
++    if (start < 0) {
++        start = 0;
++    }
++    else if (start >= src_len) {
++        start = src_len - 1;
++    }
++
++    /* bring length into range */
++    if (length < 0 || src_len - start < length) {
++        length = src_len - start;
++    }
++
++    /* create the substring */
++    substr = apc_xmemcpy(s + start, length + 1, apc_emalloc);
++    substr[length] = '\0';
++    return substr;
 +}
-+/* }}} */
 +
-+/* {{{ apc_cache_clear */
-+void apc_cache_clear(apc_cache_t* cache)
++char** apc_tokenize(const char* s, char delim)
 +{
-+    int i;
++    char** tokens;      /* array of tokens, NULL terminated */
++    int size;           /* size of tokens array */
++    int n;              /* index of next token in tokens array */
++    int cur;            /* current position in input string */
++    int end;            /* final legal position in input string */
++    int next;           /* position of next delimiter in input */
 +
-+    if(!cache) return;
++    if (!s) {
++        return NULL;
++    }
 +
-+    LOCK(cache);
-+    cache->header->busy = 1;
-+    cache->header->num_hits = 0;
-+    cache->header->num_misses = 0;
-+    cache->header->start_time = time(NULL);
-+    cache->header->expunges = 0;
++    size = 2;
++    n    = 0;
++    cur  = 0;
++    end  = strlen(s) - 1;
 +
-+    for (i = 0; i < cache->num_slots; i++) {
-+        slot_t* p = cache->slots[i];
-+        while (p) {
-+            remove_slot(cache, &p);
++    tokens = (char**) apc_emalloc(size * sizeof(char*));
++    tokens[n] = NULL;
++
++    while (cur <= end) {
++        /* search for the next delimiter */
++        char* p = strchr(s + cur, delim);
++        next = p ? p-s : end+1;
++
++        /* resize token array if necessary */
++        if (n == size-1) {
++            size *= 2;
++            tokens = (char**) apc_erealloc(tokens, size * sizeof(char*));
 +        }
-+        cache->slots[i] = NULL;
++
++        /* save the current token */
++        tokens[n] = apc_substr(s, cur, next-cur);
++
++        tokens[++n] = NULL;
++        cur = next + 1;
 +    }
-+    
-+    cache->header->busy = 0;
-+    UNLOCK(cache);
++
++    return tokens;
 +}
++
 +/* }}} */
 +
-+/* {{{ apc_cache_expunge */
-+void apc_cache_expunge(apc_cache_t* cache, time_t t)
++/* {{{ apc stat */
++/* similar to php_stream_stat_path */
++#define APC_URL_STAT(wrapper, filename, pstatbuf) \
++    ((wrapper)->wops->url_stat((wrapper), (filename), PHP_STREAM_URL_STAT_QUIET, (pstatbuf), NULL TSRMLS_CC))
++int apc_search_paths(const char* filename, const char* path, apc_fileinfo_t* fileinfo)
 +{
++    char** paths;
++    char *exec_fname;
++    int exec_fname_length;
++    int found = 0;
 +    int i;
++    php_stream_wrapper *wrapper = NULL;
++    char *path_for_open = NULL;
 +
-+    if(!cache) return;
++    TSRMLS_FETCH();
 +
-+    if(!cache->ttl) {
-+        /* 
-+         * If cache->ttl is not set, we wipe out the entire cache when
-+         * we run out of space. 
-+         */
-+        LOCK(cache);
-+        cache->header->busy = 1;
-+        cache->header->expunges++;
-+        for (i = 0; i < cache->num_slots; i++) {
-+            slot_t* p = cache->slots[i];
-+            while (p) {
-+                remove_slot(cache, &p);
-+            }
-+            cache->slots[i] = NULL;
-+        }
-+        cache->header->busy = 0;
-+        UNLOCK(cache);
-+    } else {
-+        slot_t **p;
++    assert(filename && fileinfo);
 +
-+        /*
-+         * If the ttl for the cache is set we walk through and delete stale 
-+         * entries.  For the user cache that is slightly confusing since
-+         * we have the individual entry ttl's we can look at, but that would be
-+         * too much work.  So if you want the user cache expunged, set a high
-+         * default apc.user_ttl and still provide a specific ttl for each entry
-+         * on insert
-+         */
 +
-+        LOCK(cache);
-+        cache->header->busy = 1;
-+        cache->header->expunges++;
-+        for (i = 0; i < cache->num_slots; i++) {
-+            p = &cache->slots[i];
-+            while(*p) {
-+                /* 
-+                 * For the user cache we look at the individual entry ttl values
-+                 * and if not set fall back to the default ttl for the user cache
-+                 */
-+                if((*p)->value->type == APC_CACHE_ENTRY_USER) {
-+                    if((*p)->value->data.user.ttl) {
-+                        if((*p)->creation_time + (*p)->value->data.user.ttl < t) {
-+                            remove_slot(cache, p);
-+                            continue;
-+                        }
-+                    } else if(cache->ttl) {
-+                        if((*p)->creation_time + cache->ttl < t) {
-+                            remove_slot(cache, p);
-+                            continue;
-+                        }
-+                    }
-+                } else if((*p)->access_time < (t - cache->ttl)) {
-+                    remove_slot(cache, p);
-+                    continue;
-+                }
-+                p = &(*p)->next;
-+            }
-+        }
-+        cache->header->busy = 0;
-+        UNLOCK(cache);
++    wrapper = php_stream_locate_url_wrapper(filename, &path_for_open, 0 TSRMLS_CC);
++
++    if(!wrapper || !wrapper->wops || !wrapper->wops->url_stat) {
++        return -1;
 +    }
-+}
-+/* }}} */
 +
-+/* {{{ apc_cache_insert */
-+int apc_cache_insert(apc_cache_t* cache,
-+                     apc_cache_key_t key,
-+                     apc_cache_entry_t* value,
-+                     time_t t)
-+{
-+    slot_t** slot;
++    if(wrapper != &php_plain_files_wrapper) {
++        if(APC_URL_STAT(wrapper, path_for_open, &fileinfo->st_buf) == 0) {
++            strncpy(fileinfo->fullpath, path_for_open, MAXPATHLEN);
++            return 0;
++        }
++        return -1; /* cannot stat */
++    }
 +
-+    if (!value) {
++    if (IS_ABSOLUTE_PATH(path_for_open, strlen(path_for_open)) && 
++            APC_URL_STAT(wrapper, path_for_open, &fileinfo->st_buf) == 0) {
++        strncpy(fileinfo->fullpath, path_for_open, MAXPATHLEN);
 +        return 0;
 +    }
 +
-+#ifdef __DEBUG_APC__
-+    fprintf(stderr,"Inserting [%s]\n", value->data.file.filename);
-+#endif
-+
-+    LOCK(cache);
-+    process_pending_removals(cache);
++    paths = apc_tokenize(path, DEFAULT_DIR_SEPARATOR);
++    if (!paths)
++        return -1;
 +
-+    if(key.type == APC_CACHE_KEY_FILE) slot = &cache->slots[hash(key) % cache->num_slots];
-+    else slot = &cache->slots[string_nhash_8(key.data.fpfile.fullpath, key.data.fpfile.fullpath_len) % cache->num_slots];
++    /* for each directory in paths, look for filename inside */
++    for (i = 0; paths[i]; i++) {
++        snprintf(fileinfo->fullpath, sizeof(fileinfo->fullpath), "%s%c%s", paths[i], DEFAULT_SLASH, path_for_open);
++        if (APC_URL_STAT(wrapper, fileinfo->fullpath, &fileinfo->st_buf) == 0) {
++            found = 1;
++            break;
++        }
++    }
 +
-+    while(*slot) {
-+      if(key.type == (*slot)->key.type) {
-+        if(key.type == APC_CACHE_KEY_FILE) {
-+            if(key_equals((*slot)->key.data.file, key.data.file)) {
-+                /* If existing slot for the same device+inode is different, remove it and insert the new version */
-+                if ((*slot)->key.mtime != key.mtime) {
-+                    remove_slot(cache, slot);
-+                    break;
-+                }
-+                UNLOCK(cache);
-+                return 0;
-+            } else if(cache->ttl && (*slot)->access_time < (t - cache->ttl)) {
-+                remove_slot(cache, slot);
-+                continue;
-+            }
-+        } else {   /* APC_CACHE_KEY_FPFILE */
-+                if(!memcmp((*slot)->key.data.fpfile.fullpath, key.data.fpfile.fullpath, key.data.fpfile.fullpath_len+1)) {
-+                /* Hrm.. it's already here, remove it and insert new one */
-+                remove_slot(cache, slot);
-+                break;
-+            } else if(cache->ttl && (*slot)->access_time < (t - cache->ttl)) {
-+                remove_slot(cache, slot);
-+                continue;
++    /* check in path of the calling scripts' current working directory */
++    /* modified from main/streams/plain_wrapper.c */
++    if(!found && zend_is_executing(TSRMLS_C)) {
++        exec_fname = zend_get_executed_filename(TSRMLS_C);
++        exec_fname_length = strlen(exec_fname);
++        while((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length]));
++        if((exec_fname && exec_fname[0] != '[') && exec_fname_length > 0) {
++            /* not: [no active file] or no path */
++            memcpy(fileinfo->fullpath, exec_fname, exec_fname_length);
++            fileinfo->fullpath[exec_fname_length] = DEFAULT_SLASH;
++            strlcpy(fileinfo->fullpath +exec_fname_length +1, path_for_open,sizeof(fileinfo->fullpath)-exec_fname_length-1);
++            /* apc_wprint("filename: %s, exec_fname: %s, fileinfo->fullpath: %s", path_for_open, exec_fname, fileinfo->fullpath); */
++            if (APC_URL_STAT(wrapper, fileinfo->fullpath, &fileinfo->st_buf) == 0) {
++                found = 1;
 +            }
 +        }
-+      }
-+      slot = &(*slot)->next;
 +    }
 +
-+    if ((*slot = make_slot(key, value, *slot, t)) == NULL) {
-+        UNLOCK(cache);
-+        return -1;
++    /* free the value returned by apc_tokenize */
++    for (i = 0; paths[i]; i++) {
++        apc_efree(paths[i]);
 +    }
-+   
-+    cache->header->mem_size += value->mem_size;
-+    cache->header->num_entries++;
-+    cache->header->num_inserts++;
-+    
-+    UNLOCK(cache);
-+    return 1;
++    apc_efree(paths);
++
++    return found ? 0 : -1;
 +}
++
 +/* }}} */
 +
-+/* {{{ apc_cache_user_insert */
-+int apc_cache_user_insert(apc_cache_t* cache, apc_cache_key_t key, apc_cache_entry_t* value, time_t t, int exclusive TSRMLS_DC)
-+{
-+    slot_t** slot;
-+    size_t* mem_size_ptr = NULL;
++/* {{{ regular expression wrapper functions */
 +
-+    if (!value) {
-+        return 0;
-+    }
++#if (HAVE_PCRE || HAVE_BUNDLED_PCRE)
++typedef struct {
++    pcre *preg;
++    pcre *nreg;
++} apc_regex;
 +
-+    LOCK(cache);
-+    process_pending_removals(cache);
++#define APC_ADD_PATTERN(match, pat) do {\
++    if(match.len > 1) {\
++        smart_str_appendc(&match, '|');\
++    }\
++    smart_str_appendc(&match, '(');\
++    while(*pat) {\
++        if(*pat == '/') smart_str_appendc(&match, '\\');\
++        \
++        smart_str_appendc(&match, *(pat++));\
++    }\
++    smart_str_appendc(&match, ')');\
++} while(0)
++
++#define APC_COMPILE_PATTERN(re, match) do {\
++    if(match.len > 2) { /* more than just "//" */\
++        if (((re) = pcre_get_compiled_regex(match.c, NULL, NULL TSRMLS_CC)) == NULL) {\
++            apc_wprint("apc_regex_compile_array: invalid expression '%s'", match.c); \
++            smart_str_free(&match);\
++            return NULL;\
++        }\
++    } else { \
++        (re) = NULL;\
++    }\
++} while(0)
++
++void* apc_regex_compile_array(char* patterns[] TSRMLS_DC)
++{
++    apc_regex* regs;
++    int npat;
++    smart_str pmatch = {0,};
++    smart_str nmatch = {0,};
++    char* pattern;
 +
-+    slot = &cache->slots[string_nhash_8(key.data.user.identifier, key.data.user.identifier_len) % cache->num_slots];
++    if (!patterns)
++        return NULL;
 +
-+    if (APCG(mem_size_ptr) != NULL) {
-+        mem_size_ptr = APCG(mem_size_ptr);
-+        APCG(mem_size_ptr) = NULL;
-+    }
++    regs = (apc_regex*) apc_emalloc(sizeof(apc_regex));
 +
-+    while (*slot) {
-+        if (!memcmp((*slot)->key.data.user.identifier, key.data.user.identifier, key.data.user.identifier_len)) {
-+            /* 
-+             * At this point we have found the user cache entry.  If we are doing 
-+             * an exclusive insert (apc_add) we are going to bail right away if
-+             * the user entry already exists and it has no ttl, or
-+             * there is a ttl and the entry has not timed out yet.
-+             */
-+            if(exclusive && (  !(*slot)->value->data.user.ttl ||
-+                              ( (*slot)->value->data.user.ttl && ((*slot)->creation_time + (*slot)->value->data.user.ttl) >= t ) 
-+                            ) ) {
-+                UNLOCK(cache);
-+                return 0;
-+            }
-+            remove_slot(cache, slot);
-+            break;
-+        } else 
-+        /* 
-+         * This is a bit nasty.  The idea here is to do runtime cleanup of the linked list of
-+         * slot entries so we don't always have to skip past a bunch of stale entries.  We check
-+         * for staleness here and get rid of them by first checking to see if the cache has a global
-+         * access ttl on it and removing entries that haven't been accessed for ttl seconds and secondly
-+         * we see if the entry has a hard ttl on it and remove it if it has been around longer than its ttl
-+         */
-+        if((cache->ttl && (*slot)->access_time < (t - cache->ttl)) || 
-+           ((*slot)->value->data.user.ttl && ((*slot)->creation_time + (*slot)->value->data.user.ttl) < t)) {
-+            remove_slot(cache, slot);
-+            continue;
++    smart_str_appendc(&pmatch, '/');
++    smart_str_appendc(&nmatch, '/');
++
++    for (npat = 0; patterns[npat] != NULL; npat++) {
++        pattern = patterns[npat];
++        if(pattern[0] == '+') {
++            pattern += sizeof(char);
++            APC_ADD_PATTERN(pmatch, pattern);
++        } else {
++            if(pattern[0] == '-') pattern += sizeof(char);
++            APC_ADD_PATTERN(nmatch, pattern);
 +        }
-+        slot = &(*slot)->next;
 +    }
++    smart_str_appendc(&pmatch, '/');
++    smart_str_appendc(&nmatch, '/');
 +
-+    if (mem_size_ptr != NULL) {
-+        APCG(mem_size_ptr) = mem_size_ptr;
-+    }
++    smart_str_0(&nmatch);
++    smart_str_0(&pmatch);
 +
-+    if ((*slot = make_slot(key, value, *slot, t)) == NULL) {
-+        UNLOCK(cache);
-+        return 0;
-+    }
-+    if (APCG(mem_size_ptr) != NULL) {
-+        value->mem_size = *APCG(mem_size_ptr);
-+        cache->header->mem_size += *APCG(mem_size_ptr);
-+    }
-+    cache->header->num_entries++;
-+    cache->header->num_inserts++;
++    APC_COMPILE_PATTERN(regs->preg, pmatch);
++    APC_COMPILE_PATTERN(regs->nreg, nmatch);
 +
-+    UNLOCK(cache);
-+    return 1;
++    smart_str_free(&pmatch);
++    smart_str_free(&nmatch);
++
++    return (void*) regs;
 +}
-+/* }}} */
 +
-+/* {{{ apc_cache_find_slot */
-+slot_t* apc_cache_find_slot(apc_cache_t* cache, apc_cache_key_t key, time_t t)
++void apc_regex_destroy_array(void* p)
 +{
-+    slot_t** slot;
-+    volatile slot_t* retval = NULL;
-+
-+    LOCK(cache);
-+    if(key.type == APC_CACHE_KEY_FILE) slot = &cache->slots[hash(key) % cache->num_slots];
-+    else slot = &cache->slots[string_nhash_8(key.data.fpfile.fullpath, key.data.fpfile.fullpath_len) % cache->num_slots];
-+
-+    while (*slot) {
-+      if(key.type == (*slot)->key.type) {
-+        if(key.type == APC_CACHE_KEY_FILE) {
-+            if(key_equals((*slot)->key.data.file, key.data.file)) {
-+                if((*slot)->key.mtime != key.mtime) {
-+                    remove_slot(cache, slot);
-+                    cache->header->num_misses++;
-+                    UNLOCK(cache);
-+                    return NULL;
-+                }
-+                (*slot)->num_hits++;
-+                (*slot)->value->ref_count++;
-+                (*slot)->access_time = t;
-+                prevent_garbage_collection((*slot)->value);
-+                cache->header->num_hits++;
-+                retval = *slot;
-+                UNLOCK(cache);
-+                return (slot_t*)retval;
-+            }
-+        } else {  /* APC_CACHE_KEY_FPFILE */
-+            if(!memcmp((*slot)->key.data.fpfile.fullpath, key.data.fpfile.fullpath, key.data.fpfile.fullpath_len+1)) {
-+                /* TTL Check ? */
-+                (*slot)->num_hits++;
-+                (*slot)->value->ref_count++;
-+                (*slot)->access_time = t;
-+                prevent_garbage_collection((*slot)->value);
-+                cache->header->num_hits++;
-+                retval = *slot;
-+                UNLOCK(cache);
-+                return (slot_t*)retval;
-+            }
-+        }
-+      }
-+      slot = &(*slot)->next;
++    if (p != NULL) {
++        apc_regex* regs = (apc_regex*) p;
++        apc_efree(regs);
 +    }
-+    cache->header->num_misses++;
-+    UNLOCK(cache);
-+    return NULL;
 +}
-+/* }}} */
 +
-+/* {{{ apc_cache_find */
-+apc_cache_entry_t* apc_cache_find(apc_cache_t* cache, apc_cache_key_t key, time_t t)
-+{
-+    slot_t * slot = apc_cache_find_slot(cache, key, t);
-+    return (slot) ? slot->value : NULL;
-+}
-+/* }}} */
++#define APC_MATCH_PATTERN(re, input, output) do {\
++    if (re && pcre_exec(re, NULL, (input), strlen(input), 0, 0, NULL, 0) >= 0) {\
++        return (output);\
++    }\
++} while(0)
 +
-+/* {{{ apc_cache_user_find */
-+apc_cache_entry_t* apc_cache_user_find(apc_cache_t* cache, char *strkey, int keylen, time_t t)
++
++int apc_regex_match_array(void* p, const char* input)
 +{
-+    slot_t** slot;
-+    volatile apc_cache_entry_t* value = NULL;
++    apc_regex* regs;
 +
-+    LOCK(cache);
++    if (!p)
++        return 0;
 +
-+    slot = &cache->slots[string_nhash_8(strkey, keylen) % cache->num_slots];
++    regs = (apc_regex*) p;
 +
-+    while (*slot) {
-+        if (!memcmp((*slot)->key.data.user.identifier, strkey, keylen)) {
-+            /* Check to make sure this entry isn't expired by a hard TTL */
-+            if((*slot)->value->data.user.ttl && ((*slot)->creation_time + (*slot)->value->data.user.ttl) < t) {
-+                remove_slot(cache, slot);
-+                UNLOCK(cache);
-+                return NULL;
-+            }
-+            /* Otherwise we are fine, increase counters and return the cache entry */
-+            (*slot)->num_hits++;
-+            (*slot)->value->ref_count++;
-+            (*slot)->access_time = t;
++    APC_MATCH_PATTERN(regs->preg, input, APC_POSITIVE_MATCH);
++    APC_MATCH_PATTERN(regs->nreg, input, APC_NEGATIVE_MATCH);
 +
-+            cache->header->num_hits++;
-+            value = (*slot)->value;
-+            UNLOCK(cache);
-+            return (apc_cache_entry_t*)value;
-+        }
-+        slot = &(*slot)->next;
++    return 0;
++}
++#else /* no pcre */
++void* apc_regex_compile_array(char* patterns[] TSRMLS_DC)
++{
++    if(patterns && patterns[0] != NULL) {
++        apc_wprint("pcre missing, disabling filters");
 +    }
-+ 
-+    UNLOCK(cache);
 +    return NULL;
 +}
++void apc_regex_destroy_array(void* p)
++{
++    /* nothing */
++}
++int apc_regex_match_array(void* p, const char* input)
++{
++    return 0;
++}
++#endif
 +/* }}} */
 +
-+/* {{{ apc_cache_user_delete */
-+int apc_cache_user_delete(apc_cache_t* cache, char *strkey, int keylen)
-+{
-+    slot_t** slot;
++/* {{{ crc32 implementation */
 +
-+    LOCK(cache);
++/* this table was generated by crc32gen() */
++static unsigned int crc32tab[] = {
++    /*   0 */  0x00000000, 0x3b83984b, 0x77073096, 0x4c84a8dd,
++    /*   4 */  0xee0e612c, 0xd58df967, 0x990951ba, 0xa28ac9f1,
++    /*   8 */  0x076dc419, 0x3cee5c52, 0x706af48f, 0x4be96cc4,
++    /*  12 */  0xe963a535, 0xd2e03d7e, 0x9e6495a3, 0xa5e70de8,
++    /*  16 */  0x0edb8832, 0x35581079, 0x79dcb8a4, 0x425f20ef,
++    /*  20 */  0xe0d5e91e, 0xdb567155, 0x97d2d988, 0xac5141c3,
++    /*  24 */  0x09b64c2b, 0x3235d460, 0x7eb17cbd, 0x4532e4f6,
++    /*  28 */  0xe7b82d07, 0xdc3bb54c, 0x90bf1d91, 0xab3c85da,
++    /*  32 */  0x1db71064, 0x2634882f, 0x6ab020f2, 0x5133b8b9,
++    /*  36 */  0xf3b97148, 0xc83ae903, 0x84be41de, 0xbf3dd995,
++    /*  40 */  0x1adad47d, 0x21594c36, 0x6ddde4eb, 0x565e7ca0,
++    /*  44 */  0xf4d4b551, 0xcf572d1a, 0x83d385c7, 0xb8501d8c,
++    /*  48 */  0x136c9856, 0x28ef001d, 0x646ba8c0, 0x5fe8308b,
++    /*  52 */  0xfd62f97a, 0xc6e16131, 0x8a65c9ec, 0xb1e651a7,
++    /*  56 */  0x14015c4f, 0x2f82c404, 0x63066cd9, 0x5885f492,
++    /*  60 */  0xfa0f3d63, 0xc18ca528, 0x8d080df5, 0xb68b95be,
++    /*  64 */  0x3b6e20c8, 0x00edb883, 0x4c69105e, 0x77ea8815,
++    /*  68 */  0xd56041e4, 0xeee3d9af, 0xa2677172, 0x99e4e939,
++    /*  72 */  0x3c03e4d1, 0x07807c9a, 0x4b04d447, 0x70874c0c,
++    /*  76 */  0xd20d85fd, 0xe98e1db6, 0xa50ab56b, 0x9e892d20,
++    /*  80 */  0x35b5a8fa, 0x0e3630b1, 0x42b2986c, 0x79310027,
++    /*  84 */  0xdbbbc9d6, 0xe038519d, 0xacbcf940, 0x973f610b,
++    /*  88 */  0x32d86ce3, 0x095bf4a8, 0x45df5c75, 0x7e5cc43e,
++    /*  92 */  0xdcd60dcf, 0xe7559584, 0xabd13d59, 0x9052a512,
++    /*  96 */  0x26d930ac, 0x1d5aa8e7, 0x51de003a, 0x6a5d9871,
++    /* 100 */  0xc8d75180, 0xf354c9cb, 0xbfd06116, 0x8453f95d,
++    /* 104 */  0x21b4f4b5, 0x1a376cfe, 0x56b3c423, 0x6d305c68,
++    /* 108 */  0xcfba9599, 0xf4390dd2, 0xb8bda50f, 0x833e3d44,
++    /* 112 */  0x2802b89e, 0x138120d5, 0x5f058808, 0x64861043,
++    /* 116 */  0xc60cd9b2, 0xfd8f41f9, 0xb10be924, 0x8a88716f,
++    /* 120 */  0x2f6f7c87, 0x14ece4cc, 0x58684c11, 0x63ebd45a,
++    /* 124 */  0xc1611dab, 0xfae285e0, 0xb6662d3d, 0x8de5b576,
++    /* 128 */  0x76dc4190, 0x4d5fd9db, 0x01db7106, 0x3a58e94d,
++    /* 132 */  0x98d220bc, 0xa351b8f7, 0xefd5102a, 0xd4568861,
++    /* 136 */  0x71b18589, 0x4a321dc2, 0x06b6b51f, 0x3d352d54,
++    /* 140 */  0x9fbfe4a5, 0xa43c7cee, 0xe8b8d433, 0xd33b4c78,
++    /* 144 */  0x7807c9a2, 0x438451e9, 0x0f00f934, 0x3483617f,
++    /* 148 */  0x9609a88e, 0xad8a30c5, 0xe10e9818, 0xda8d0053,
++    /* 152 */  0x7f6a0dbb, 0x44e995f0, 0x086d3d2d, 0x33eea566,
++    /* 156 */  0x91646c97, 0xaae7f4dc, 0xe6635c01, 0xdde0c44a,
++    /* 160 */  0x6b6b51f4, 0x50e8c9bf, 0x1c6c6162, 0x27eff929,
++    /* 164 */  0x856530d8, 0xbee6a893, 0xf262004e, 0xc9e19805,
++    /* 168 */  0x6c0695ed, 0x57850da6, 0x1b01a57b, 0x20823d30,
++    /* 172 */  0x8208f4c1, 0xb98b6c8a, 0xf50fc457, 0xce8c5c1c,
++    /* 176 */  0x65b0d9c6, 0x5e33418d, 0x12b7e950, 0x2934711b,
++    /* 180 */  0x8bbeb8ea, 0xb03d20a1, 0xfcb9887c, 0xc73a1037,
++    /* 184 */  0x62dd1ddf, 0x595e8594, 0x15da2d49, 0x2e59b502,
++    /* 188 */  0x8cd37cf3, 0xb750e4b8, 0xfbd44c65, 0xc057d42e,
++    /* 192 */  0x4db26158, 0x7631f913, 0x3ab551ce, 0x0136c985,
++    /* 196 */  0xa3bc0074, 0x983f983f, 0xd4bb30e2, 0xef38a8a9,
++    /* 200 */  0x4adfa541, 0x715c3d0a, 0x3dd895d7, 0x065b0d9c,
++    /* 204 */  0xa4d1c46d, 0x9f525c26, 0xd3d6f4fb, 0xe8556cb0,
++    /* 208 */  0x4369e96a, 0x78ea7121, 0x346ed9fc, 0x0fed41b7,
++    /* 212 */  0xad678846, 0x96e4100d, 0xda60b8d0, 0xe1e3209b,
++    /* 216 */  0x44042d73, 0x7f87b538, 0x33031de5, 0x088085ae,
++    /* 220 */  0xaa0a4c5f, 0x9189d414, 0xdd0d7cc9, 0xe68ee482,
++    /* 224 */  0x5005713c, 0x6b86e977, 0x270241aa, 0x1c81d9e1,
++    /* 228 */  0xbe0b1010, 0x8588885b, 0xc90c2086, 0xf28fb8cd,
++    /* 232 */  0x5768b525, 0x6ceb2d6e, 0x206f85b3, 0x1bec1df8,
++    /* 236 */  0xb966d409, 0x82e54c42, 0xce61e49f, 0xf5e27cd4,
++    /* 240 */  0x5edef90e, 0x655d6145, 0x29d9c998, 0x125a51d3,
++    /* 244 */  0xb0d09822, 0x8b530069, 0xc7d7a8b4, 0xfc5430ff,
++    /* 248 */  0x59b33d17, 0x6230a55c, 0x2eb40d81, 0x153795ca,
++    /* 252 */  0xb7bd5c3b, 0x8c3ec470, 0xc0ba6cad, 0xfb39f4e6,
++};
 +
-+    slot = &cache->slots[string_nhash_8(strkey, keylen) % cache->num_slots];
++unsigned int apc_crc32(const char* buf, int len)
++{
++    int i;
++    int k;
++    unsigned int crc;
 +
-+    while (*slot) {
-+        if (!memcmp((*slot)->key.data.user.identifier, strkey, keylen)) {
-+            remove_slot(cache, slot);
-+            UNLOCK(cache);
-+            return 1;
-+        }
-+        slot = &(*slot)->next;
++    /* preconditioning */
++    crc = 0xFFFFFFFF;
++
++    for (i = 0; i < len; i++) {
++        k = (crc ^ buf[i]) & 0x000000FF;
++        crc = ((crc >> 8) & 0x00FFFFFF) ^ crc32tab[k];
 +    }
 +
-+    UNLOCK(cache);
-+    return 0;
++    /* postconditioning */
++    return ~crc;
 +}
-+/* }}} */
 +
-+/* {{{ apc_cache_release */
-+void apc_cache_release(apc_cache_t* cache, apc_cache_entry_t* entry)
++/* crc32gen: generate the nth (0..255) crc32 table value */
++#if 0
++static unsigned long crc32gen(int n)
 +{
-+    /* local cache refcount-- is done in apc_local_cache_cleanup */
-+    if(entry->local) return;
++    int i;
++    unsigned long crc;
 +
-+    LOCK(cache);
-+    entry->ref_count--;
-+    UNLOCK(cache);
++    crc = n;
++    for (i = 8; i >= 0; i--) {
++        if (crc & 1) {
++            crc = (crc >> 1) ^ 0xEDB88320;
++        }
++        else {
++            crc >>= 1;
++        }
++    }
++    return crc;
 +}
-+/* }}} */
-+
-+/* {{{ apc_cache_make_file_key */
-+int apc_cache_make_file_key(apc_cache_key_t* key,
-+                       const char* filename,
-+                       const char* include_path,
-+                       time_t t
-+                                         TSRMLS_DC)
-+{
-+    struct stat *tmp_buf=NULL;
-+    struct apc_fileinfo_t fileinfo = { {0}, };
-+    int len;
-+
-+    assert(key != NULL);
-+
-+    if (!filename || !SG(request_info).path_translated) {
-+#ifdef __DEBUG_APC__
-+        fprintf(stderr,"No filename and no path_translated - bailing\n");
 +#endif
-+        return 0;
-+      }
 +
-+    len = strlen(filename);
-+    if(APCG(fpstat)==0) {
-+        if(IS_ABSOLUTE_PATH(filename,len)) {
-+            key->data.fpfile.fullpath = filename;
-+            key->data.fpfile.fullpath_len = len;
-+            key->mtime = t;
-+            key->type = APC_CACHE_KEY_FPFILE;
-+        } else {
-+            if (apc_search_paths(filename, include_path, &fileinfo) != 0) {
-+                apc_wprint("apc failed to locate %s - bailing", filename);
-+                return 0;
-+            }
++/* }}} */
 +
-+            if(!realpath(fileinfo.fullpath, APCG(canon_path))) {
-+                apc_wprint("realpath failed to canonicalize %s - bailing", filename);
-+                return 0;
-+            }
 +
-+            key->data.fpfile.fullpath = APCG(canon_path);
-+            key->data.fpfile.fullpath_len = strlen(APCG(canon_path));
-+            key->mtime = t;
-+            key->type = APC_CACHE_KEY_FPFILE;
-+        }
-+        return 1;
-+    } 
++/* {{{ apc_flip_hash() */
++HashTable* apc_flip_hash(HashTable *hash) {
++    zval **entry, *data;
++    HashTable *new_hash;
++    HashPosition pos;
 +
-+    if(!strcmp(SG(request_info).path_translated, filename)) {
-+        tmp_buf = sapi_get_stat(TSRMLS_C);  /* Apache has already done this stat() for us */
-+    }
-+    if(tmp_buf) { 
-+              fileinfo.st_buf = *tmp_buf;
-+    } else {
-+        if (apc_search_paths(filename, include_path, &fileinfo) != 0) {
-+#ifdef __DEBUG_APC__
-+            fprintf(stderr,"Stat failed %s - bailing (%s) (%d)\n",filename,SG(request_info).path_translated);
-+#endif
-+            return 0;
-+        }
-+    }
++    if(hash == NULL) return hash;
 +
-+    if(APCG(max_file_size) < fileinfo.st_buf.st_size) {
-+#ifdef __DEBUG_APC__
-+        fprintf(stderr,"File is too big %s (%d - %ld) - bailing\n",filename,t,fileinfo.st_buf.st_size);
-+#endif
-+        return 0;
-+    }
++    MAKE_STD_ZVAL(data);
++    ZVAL_LONG(data, 1);
++    
++    new_hash = emalloc(sizeof(HashTable));
++    zend_hash_init(new_hash, hash->nTableSize, NULL, ZVAL_PTR_DTOR, 0);
 +
-+    /*
-+     * This is a bit of a hack.
-+     *
-+     * Here I am checking to see if the file is at least 2 seconds old.  
-+     * The idea is that if the file is currently being written to then its
-+     * mtime is going to match or at most be 1 second off of the current
-+     * request time and we want to avoid caching files that have not been
-+     * completely written.  Of course, people should be using atomic 
-+     * mechanisms to push files onto live web servers, but adding this
-+     * tiny safety is easier than educating the world.  This is now
-+     * configurable, but the default is still 2 seconds.
-+     */
-+    if(APCG(file_update_protection) && (t - fileinfo.st_buf.st_mtime < APCG(file_update_protection))) { 
-+#ifdef __DEBUG_APC__
-+        fprintf(stderr,"File is too new %s (%d - %d) - bailing\n",filename,t,fileinfo.st_buf.st_mtime);
-+#endif
-+        return 0;
++    zend_hash_internal_pointer_reset_ex(hash, &pos);
++    while (zend_hash_get_current_data_ex(hash, (void **)&entry, &pos) == SUCCESS) {
++        if(Z_TYPE_PP(entry) == IS_STRING) {
++            zend_hash_update(new_hash, Z_STRVAL_PP(entry), Z_STRLEN_PP(entry) +1, &data, sizeof(data), NULL);
++        } else {
++            zend_hash_index_update(new_hash, Z_LVAL_PP(entry), &data, sizeof(data), NULL);
++        }
++        Z_ADDREF_P(data);
++        zend_hash_move_forward_ex(hash, &pos);
 +    }
++    efree(data);
 +
-+    key->data.file.device = fileinfo.st_buf.st_dev;
-+    key->data.file.inode  = fileinfo.st_buf.st_ino;
-+    /* 
-+     * If working with content management systems that like to munge the mtime, 
-+     * it might be appropriate to key off of the ctime to be immune to systems
-+     * that try to backdate a template.  If the mtime is set to something older
-+     * than the previous mtime of a template we will obviously never see this
-+     * "older" template.  At some point the Smarty templating system did this.
-+     * I generally disagree with using the ctime here because you lose the 
-+     * ability to warm up new content by saving it to a temporary file, hitting
-+     * it once to cache it and then renaming it into its permanent location so
-+     * set the apc.stat_ctime=true to enable this check.
-+     */
-+    if(APCG(stat_ctime)) {
-+        key->mtime  = (fileinfo.st_buf.st_ctime > fileinfo.st_buf.st_mtime) ? fileinfo.st_buf.st_ctime : fileinfo.st_buf.st_mtime; 
-+    } else {
-+        key->mtime = fileinfo.st_buf.st_mtime;
-+    }
-+    key->type = APC_CACHE_KEY_FILE;
-+    return 1;
++    return new_hash;
 +}
 +/* }}} */
 +
-+/* {{{ apc_cache_make_user_key */
-+int apc_cache_make_user_key(apc_cache_key_t* key, char* identifier, int identifier_len, const time_t t)
-+{
-+    assert(key != NULL);
-+
-+    if (!identifier)
-+        return 0;
 +
-+    key->data.user.identifier = identifier;
-+    key->data.user.identifier_len = identifier_len;
-+    key->mtime = t;
-+    key->type = APC_CACHE_KEY_USER;
-+    return 1;
-+}
-+/* }}} */
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * End:
++ * vim>600: expandtab sw=4 ts=4 sts=4 fdm=marker
++ * vim<600: expandtab sw=4 ts=4 sts=4
++ */
+diff -Naur php-5.3.1.orig/ext/apc/apc_cache.c php-5.3.1/ext/apc/apc_cache.c
+--- php-5.3.1.orig/ext/apc/apc_cache.c 1970-01-01 01:00:00.000000000 +0100
++++ php-5.3.1/ext/apc/apc_cache.c      1970-01-01 10:13:08.000000000 +0100
+@@ -0,0 +1,1183 @@
++/*
++  +----------------------------------------------------------------------+
++  | APC                                                                  |
++  +----------------------------------------------------------------------+
++  | Copyright (c) 2006-2008 The PHP Group                                |
++  +----------------------------------------------------------------------+
++  | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt                                  |
++  | If you did not receive a copy of the PHP license and are unable to   |
++  | obtain it through the world-wide-web, please send a note to          |
++  | license@php.net so we can mail you a copy immediately.               |
++  +----------------------------------------------------------------------+
++  | Authors: Daniel Cowgill <dcowgill@communityconnect.com>              |
++  |          Rasmus Lerdorf <rasmus@php.net>                             |
++  |          Arun C. Murthy <arunc@yahoo-inc.com>                        |
++  |          Gopal Vijayaraghavan <gopalv@yahoo-inc.com>                 |
++  +----------------------------------------------------------------------+
 +
-+/* {{{ apc_cache_make_file_entry */
-+apc_cache_entry_t* apc_cache_make_file_entry(const char* filename,
-+                                        zend_op_array* op_array,
-+                                        apc_function_t* functions,
-+                                        apc_class_t* classes)
-+{
-+    apc_cache_entry_t* entry;
++   This software was contributed to PHP by Community Connect Inc. in 2002
++   and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
++   Future revisions and derivatives of this source code must acknowledge
++   Community Connect Inc. as the original contributor of this module by
++   leaving this note intact in the source code.
 +
-+    entry = (apc_cache_entry_t*) apc_sma_malloc(sizeof(apc_cache_entry_t));
-+    if (!entry) return NULL;
++   All other licensing and usage conditions are those of the PHP Group.
 +
-+    entry->data.file.filename  = apc_xstrdup(filename, apc_sma_malloc);
-+    if(!entry->data.file.filename) {
-+#ifdef __DEBUG_APC__
-+        fprintf(stderr,"apc_cache_make_file_entry: entry->data.file.filename is NULL - bailing\n");
-+#endif
-+        apc_sma_free(entry);
-+        return NULL;
-+    }
-+#ifdef __DEBUG_APC__
-+    fprintf(stderr,"apc_cache_make_file_entry: entry->data.file.filename is [%s]\n",entry->data.file.filename);
-+#endif
-+    entry->data.file.op_array  = op_array;
-+    entry->data.file.functions = functions;
-+    entry->data.file.classes   = classes;
-+    entry->type = APC_CACHE_ENTRY_FILE;
-+    entry->ref_count = 0;
-+    entry->mem_size = 0;
-+    entry->local = 0;
-+    return entry;
-+}
-+/* }}} */
++ */
 +
-+/* {{{ apc_cache_store_zval */
-+zval* apc_cache_store_zval(zval* dst, const zval* src, apc_malloc_t allocate, apc_free_t deallocate)
-+{
-+    smart_str buf = {0};
-+    php_serialize_data_t var_hash;
-+    TSRMLS_FETCH();
++/* $Id: apc_cache.c 286717 2009-08-03 05:25:32Z gopalv $ */
 +
-+    if((src->type & ~IS_CONSTANT_INDEX) == IS_OBJECT) {
-+        if(!dst) {
-+            CHECK(dst = (zval*) allocate(sizeof(zval)));
-+        }
-+              
-+        PHP_VAR_SERIALIZE_INIT(var_hash);
-+        php_var_serialize(&buf, (zval**)&src, &var_hash TSRMLS_CC);
-+        PHP_VAR_SERIALIZE_DESTROY(var_hash);
-+              
-+        dst->type = IS_NULL; /* in case we fail */
-+        if(buf.c) {
-+            dst->type = src->type & ~IS_CONSTANT_INDEX;
-+            dst->value.str.len = buf.len;
-+            CHECK(dst->value.str.val = apc_xmemcpy(buf.c, buf.len+1, allocate));
-+            dst->type = src->type;
-+            smart_str_free(&buf);
-+        }
-+        return dst; 
-+    } else {
-+        
-+        /* Maintain a list of zvals we've copied to properly handle recursive structures */
-+        HashTable *old = APCG(copied_zvals);
-+        APCG(copied_zvals) = emalloc(sizeof(HashTable));
-+        zend_hash_init(APCG(copied_zvals), 0, NULL, NULL, 0);
-+        
-+        dst = apc_copy_zval(dst, src, allocate, deallocate);
++#include "apc_cache.h"
++#include "apc_sma.h"
++#include "apc_main.h"
++#include "apc_globals.h"
++#include "SAPI.h"
 +
-+        if(APCG(copied_zvals)) {
-+            zend_hash_destroy(APCG(copied_zvals));
-+            efree(APCG(copied_zvals));
-+        }
++/* TODO: rehash when load factor exceeds threshold */
 +
-+        APCG(copied_zvals) = old;
++#define CHECK(p) { if ((p) == NULL) return NULL; }
 +
-+        return dst;
-+    }
-+}
++/* {{{ key_equals */
++#define key_equals(a, b) (a.inode==b.inode && a.device==b.device)
 +/* }}} */
 +
-+/* {{{ apc_cache_fetch_zval */
-+zval* apc_cache_fetch_zval(zval* dst, const zval* src, apc_malloc_t allocate, apc_free_t deallocate)
-+{
-+    TSRMLS_FETCH();
-+    if((src->type & ~IS_CONSTANT_INDEX) == IS_OBJECT) {
-+        php_unserialize_data_t var_hash;
-+        const unsigned char *p = (unsigned char*)Z_STRVAL_P(src);
-+
-+        PHP_VAR_UNSERIALIZE_INIT(var_hash);
-+        if(!php_var_unserialize(&dst, &p, p + Z_STRLEN_P(src), &var_hash TSRMLS_CC)) {
-+            PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
-+            zval_dtor(dst);
-+            php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Error at offset %ld of %d bytes", (long)((char*)p - Z_STRVAL_P(src)), Z_STRLEN_P(src));
-+            dst->type = IS_NULL;
-+        }
-+        PHP_VAR_UNSERIALIZE_DESTROY(var_hash);                
-+        return dst; 
-+    } else {
-+    
-+        /* Maintain a list of zvals we've copied to properly handle recursive structures */
-+        HashTable *old = APCG(copied_zvals);
-+        APCG(copied_zvals) = emalloc(sizeof(HashTable));
-+        zend_hash_init(APCG(copied_zvals), 0, NULL, NULL, 0);
-+        
-+        dst = apc_copy_zval(dst, src, allocate, deallocate);
-+
-+        if(APCG(copied_zvals)) {
-+            zend_hash_destroy(APCG(copied_zvals));
-+            efree(APCG(copied_zvals));
-+        }
-+
-+        APCG(copied_zvals) = old;
++static void apc_cache_expunge(apc_cache_t* cache, size_t size);
 +
-+        return dst;
-+    }
++/* {{{ hash */
++static unsigned int hash(apc_cache_key_t key)
++{
++    return key.data.file.device + key.data.file.inode;
 +}
 +/* }}} */
 +
-+/* {{{ apc_cache_free_zval */
-+void apc_cache_free_zval(zval* src, apc_free_t deallocate)
-+{
-+    TSRMLS_FETCH();
-+    if ((src->type & ~IS_CONSTANT_INDEX) == IS_OBJECT) {
-+        if (src->value.str.val) {
-+              deallocate(src->value.str.val);
-+        }
-+        deallocate(src);
-+    } else {
-+        /* Maintain a list of zvals we've copied to properly handle recursive structures */
-+        HashTable *old = APCG(copied_zvals);
-+        APCG(copied_zvals) = emalloc(sizeof(HashTable));
-+        zend_hash_init(APCG(copied_zvals), 0, NULL, NULL, 0);
-+        
-+        apc_free_zval(src, deallocate);
++/* {{{ string_nhash_8 */
++#define string_nhash_8(s,len) (unsigned int)(zend_inline_hash_func(s, len))
++/* }}} */
 +
-+        if(APCG(copied_zvals)) {
-+            zend_hash_destroy(APCG(copied_zvals));
-+            efree(APCG(copied_zvals));
-+        }
++/* {{{ make_slot */
++slot_t* make_slot(apc_cache_key_t key, apc_cache_entry_t* value, slot_t* next, time_t t)
++{
++    slot_t* p = apc_pool_alloc(value->pool, sizeof(slot_t));
 +
-+        APCG(copied_zvals) = old;
++    if (!p) return NULL;
++
++    if(value->type == APC_CACHE_ENTRY_USER) {
++        char *identifier = (char*) apc_pstrdup(key.data.user.identifier, value->pool);
++        if (!identifier) {
++            return NULL;
++        }
++        key.data.user.identifier = identifier;
++    } else if(key.type == APC_CACHE_KEY_FPFILE) {
++        char *fullpath = (char*) apc_pstrdup(key.data.fpfile.fullpath, value->pool);
++        if (!fullpath) {
++            return NULL;
++        }
++        key.data.fpfile.fullpath = fullpath;
 +    }
++    p->key = key;
++    p->value = value;
++    p->next = next;
++    p->num_hits = 0;
++    p->creation_time = t;
++    p->access_time = t;
++    p->deletion_time = 0;
++    return p;
 +}
 +/* }}} */
 +
-+/* {{{ apc_cache_make_user_entry */
-+apc_cache_entry_t* apc_cache_make_user_entry(const char* info, int info_len, const zval* val, const unsigned int ttl)
++/* {{{ free_slot */
++static void free_slot(slot_t* slot)
 +{
-+    apc_cache_entry_t* entry;
-+
-+    entry = (apc_cache_entry_t*) apc_sma_malloc(sizeof(apc_cache_entry_t));
-+    if (!entry) return NULL;
-+
-+    entry->data.user.info = apc_xmemcpy(info, info_len, apc_sma_malloc);
-+    entry->data.user.info_len = info_len;
-+    if(!entry->data.user.info) {
-+        apc_sma_free(entry);
-+        return NULL;
-+    }
-+    entry->data.user.val = apc_cache_store_zval(NULL, val, apc_sma_malloc, apc_sma_free);
-+    if(!entry->data.user.val) {
-+        apc_sma_free(entry->data.user.info);
-+        apc_sma_free(entry);
-+        return NULL;
-+    }
-+    INIT_PZVAL(entry->data.user.val);
-+    entry->data.user.ttl = ttl;
-+    entry->type = APC_CACHE_ENTRY_USER;
-+    entry->ref_count = 0;
-+    entry->mem_size = 0;
-+    entry->local = 0;
-+    return entry;
++    apc_pool_destroy(slot->value->pool);
 +}
 +/* }}} */
 +
-+/* {{{ apc_cache_free_entry */
-+void apc_cache_free_entry(apc_cache_entry_t* entry)
++/* {{{ remove_slot */
++static void remove_slot(apc_cache_t* cache, slot_t** slot)
 +{
-+    if (entry != NULL) {
-+        assert(entry->ref_count == 0);
-+        switch(entry->type) {
-+            case APC_CACHE_ENTRY_FILE:
-+                apc_sma_free(entry->data.file.filename);
-+                apc_free_op_array(entry->data.file.op_array, apc_sma_free);
-+                apc_free_functions(entry->data.file.functions, apc_sma_free);
-+                apc_free_classes(entry->data.file.classes, apc_sma_free);
-+                break;
-+            case APC_CACHE_ENTRY_USER:
-+                apc_sma_free(entry->data.user.info);
-+                apc_cache_free_zval(entry->data.user.val, apc_sma_free);
-+                break;
-+        }
-+        apc_sma_free(entry);
++    slot_t* dead = *slot;
++    *slot = (*slot)->next;
++
++    cache->header->mem_size -= dead->value->mem_size;
++    cache->header->num_entries--;
++    if (dead->value->ref_count <= 0) {
++        free_slot(dead);
++    }
++    else {
++        dead->next = cache->header->deleted_list;
++        dead->deletion_time = time(0);
++        cache->header->deleted_list = dead;
 +    }
 +}
 +/* }}} */
 +
-+/* {{{ apc_cache_info */
-+apc_cache_info_t* apc_cache_info(apc_cache_t* cache, zend_bool limited)
++/* {{{ process_pending_removals */
++static void process_pending_removals(apc_cache_t* cache)
 +{
-+    apc_cache_info_t* info;
-+    slot_t* p;
-+    int i;
-+
-+    if(!cache) return NULL;
++    slot_t** slot;
++    time_t now;
 +
-+    LOCK(cache);
++    /* This function scans the list of removed cache entries and deletes any
++     * entry whose reference count is zero (indicating that it is no longer
++     * being executed) or that has been on the pending list for more than
++     * cache->gc_ttl seconds (we issue a warning in the latter case).
++     */
 +
-+    info = (apc_cache_info_t*) apc_emalloc(sizeof(apc_cache_info_t));
-+    if(!info) {
-+        UNLOCK(cache);
-+        return NULL;
-+    }
-+    info->num_slots = cache->num_slots;
-+    info->ttl = cache->ttl;
-+    info->num_hits = cache->header->num_hits;
-+    info->num_misses = cache->header->num_misses;
-+    info->list = NULL;
-+    info->deleted_list = NULL;
-+    info->start_time = cache->header->start_time;
-+    info->expunges = cache->header->expunges;
-+    info->mem_size = cache->header->mem_size;
-+    info->num_entries = cache->header->num_entries;
-+    info->num_inserts = cache->header->num_inserts;
++    if (!cache->header->deleted_list)
++        return;
 +
-+    if(!limited) {
-+        /* For each hashtable slot */
-+        for (i = 0; i < info->num_slots; i++) {
-+            p = cache->slots[i];
-+            for (; p != NULL; p = p->next) {
-+                apc_cache_link_t* link = (apc_cache_link_t*) apc_emalloc(sizeof(apc_cache_link_t));
++    slot = &cache->header->deleted_list;
++    now = time(0);
 +
-+                if(p->value->type == APC_CACHE_ENTRY_FILE) {
-+                    link->data.file.filename = apc_xstrdup(p->value->data.file.filename, apc_emalloc);
-+                    link->data.file.device = p->key.data.file.device;
-+                    link->data.file.inode = p->key.data.file.inode;
-+                    link->type = APC_CACHE_ENTRY_FILE;
-+                } else if(p->value->type == APC_CACHE_ENTRY_USER) {
-+                    link->data.user.info = apc_xmemcpy(p->value->data.user.info, p->value->data.user.info_len, apc_emalloc);
-+                    link->data.user.ttl = p->value->data.user.ttl;
-+                    link->type = APC_CACHE_ENTRY_USER;
-+                }
-+                link->num_hits = p->num_hits;
-+                link->mtime = p->key.mtime;
-+                link->creation_time = p->creation_time;
-+                link->deletion_time = p->deletion_time;
-+                link->access_time = p->access_time;
-+                link->ref_count = p->value->ref_count;
-+                link->mem_size = p->value->mem_size;
-+                link->next = info->list;
-+                info->list = link;
-+            }
-+        }
++    while (*slot != NULL) {
++        int gc_sec = cache->gc_ttl ? (now - (*slot)->deletion_time) : 0;
 +
-+        /* For each slot pending deletion */
-+        for (p = cache->header->deleted_list; p != NULL; p = p->next) {
-+            apc_cache_link_t* link = (apc_cache_link_t*) apc_emalloc(sizeof(apc_cache_link_t));
++        if ((*slot)->value->ref_count <= 0 || gc_sec > cache->gc_ttl) {
++            slot_t* dead = *slot;
 +
-+            if(p->value->type == APC_CACHE_ENTRY_FILE) {
-+                link->data.file.filename = apc_xstrdup(p->value->data.file.filename, apc_emalloc);
-+                if(p->key.type == APC_CACHE_KEY_FILE) {
-+                    link->data.file.device = p->key.data.file.device;
-+                    link->data.file.inode = p->key.data.file.inode;
-+                } else { /* This is a no-stat fullpath file entry */
-+                    link->data.file.device = 0;
-+                    link->data.file.inode = 0;
++            if (dead->value->ref_count > 0) {
++                switch(dead->value->type) {
++                    case APC_CACHE_ENTRY_FILE:
++                        apc_wprint("GC cache entry '%s' (dev=%d ino=%d) was on gc-list for %d seconds", 
++                            dead->value->data.file.filename, dead->key.data.file.device, dead->key.data.file.inode, gc_sec);
++                        break;
++                    case APC_CACHE_ENTRY_USER:
++                        apc_wprint("GC cache entry '%s'was on gc-list for %d seconds", dead->value->data.user.info, gc_sec);
++                        break;
 +                }
-+                link->type = APC_CACHE_ENTRY_FILE;
-+            } else if(p->value->type == APC_CACHE_ENTRY_USER) {
-+                link->data.user.info = apc_xmemcpy(p->value->data.user.info, p->value->data.user.info_len, apc_emalloc);
-+                link->data.user.ttl = p->value->data.user.ttl;
-+                link->type = APC_CACHE_ENTRY_USER;
 +            }
-+            link->num_hits = p->num_hits;
-+            link->mtime = p->key.mtime;
-+            link->creation_time = p->creation_time;
-+            link->deletion_time = p->deletion_time;
-+            link->access_time = p->access_time;
-+            link->ref_count = p->value->ref_count;
-+            link->mem_size = p->value->mem_size;
-+            link->next = info->deleted_list;
-+            info->deleted_list = link;
++            *slot = dead->next;
++            free_slot(dead);
++        }
++        else {
++            slot = &(*slot)->next;
 +        }
 +    }
-+
-+    UNLOCK(cache);
-+    return info;
 +}
 +/* }}} */
 +
-+/* {{{ apc_cache_free_info */
-+void apc_cache_free_info(apc_cache_info_t* info)
++/* {{{ prevent_garbage_collection */
++static void prevent_garbage_collection(apc_cache_entry_t* entry)
 +{
-+    apc_cache_link_t* p = info->list;
-+    apc_cache_link_t* q = NULL;
-+    while (p != NULL) {
-+        q = p;
-+        p = p->next;
-+        if(q->type == APC_CACHE_ENTRY_FILE) apc_efree(q->data.file.filename);
-+        else if(q->type == APC_CACHE_ENTRY_USER) apc_efree(q->data.user.info);
-+        apc_efree(q);
++    /* set reference counts on zend objects to an arbitrarily high value to
++     * prevent garbage collection after execution */
++
++    enum { BIG_VALUE = 1000 };
++
++    if(entry->data.file.op_array) {
++        entry->data.file.op_array->refcount[0] = BIG_VALUE;
 +    }
-+    p = info->deleted_list;
-+    while (p != NULL) {
-+        q = p;
-+        p = p->next;
-+        if(q->type == APC_CACHE_ENTRY_FILE) apc_efree(q->data.file.filename);
-+        else if(q->type == APC_CACHE_ENTRY_USER) apc_efree(q->data.user.info);
-+        apc_efree(q);
++    if (entry->data.file.functions) {
++        int i;
++        apc_function_t* fns = entry->data.file.functions;
++        for (i=0; fns[i].function != NULL; i++) {
++            *(fns[i].function->op_array.refcount) = BIG_VALUE;
++        }
++    }
++    if (entry->data.file.classes) {
++        int i;
++        apc_class_t* classes = entry->data.file.classes;
++        for (i=0; classes[i].class_entry != NULL; i++) {
++            classes[i].class_entry->refcount = BIG_VALUE;
++        }
 +    }
-+    apc_efree(info);
 +}
 +/* }}} */
 +
-+/* {{{ apc_cache_unlock */
-+void apc_cache_unlock(apc_cache_t* cache)
++/* {{{ apc_cache_create */
++apc_cache_t* apc_cache_create(int size_hint, int gc_ttl, int ttl)
 +{
-+    UNLOCK(cache);
-+}
-+/* }}} */
++    apc_cache_t* cache;
++    int cache_size;
++    int num_slots;
++    int i;
 +
-+/* {{{ apc_cache_busy */
-+zend_bool apc_cache_busy(apc_cache_t* cache)
-+{
-+    return cache->header->busy;
-+}
-+/* }}} */
++    num_slots = size_hint > 0 ? size_hint*2 : 2000;
++
++    cache = (apc_cache_t*) apc_emalloc(sizeof(apc_cache_t));
++    cache_size = sizeof(cache_header_t) + num_slots*sizeof(slot_t*);
++
++    cache->shmaddr = apc_sma_malloc(cache_size);
++    if(!cache->shmaddr) {
++        apc_eprint("Unable to allocate shared memory for cache structures.  (Perhaps your shared memory size isn't large enough?). ");
++    }
++    memset(cache->shmaddr, 0, cache_size);
++
++    cache->header = (cache_header_t*) cache->shmaddr;
++    cache->header->num_hits = 0;
++    cache->header->num_misses = 0;
++    cache->header->deleted_list = NULL;
++    cache->header->start_time = time(NULL);
++    cache->header->expunges = 0;
++    cache->header->busy = 0;
 +
++    cache->slots = (slot_t**) (((char*) cache->shmaddr) + sizeof(cache_header_t));
++    cache->num_slots = num_slots;
++    cache->gc_ttl = gc_ttl;
++    cache->ttl = ttl;
++    CREATE_LOCK(cache->header->lock);
 +#if NONBLOCKING_LOCK_AVAILABLE
-+/* {{{ apc_cache_write_lock */
-+zend_bool apc_cache_write_lock(apc_cache_t* cache)
-+{
-+    return apc_lck_nb_lock(cache->header->wrlock);
++    CREATE_LOCK(cache->header->wrlock);
++#endif
++    for (i = 0; i < num_slots; i++) {
++        cache->slots[i] = NULL;
++    }
++    cache->expunge_cb = apc_cache_expunge;
++    cache->has_lock = 0;
++
++    return cache;
 +}
 +/* }}} */
 +
-+/* {{{ apc_cache_write_unlock */
-+void apc_cache_write_unlock(apc_cache_t* cache)
++/* {{{ apc_cache_destroy */
++void apc_cache_destroy(apc_cache_t* cache)
 +{
-+    apc_lck_unlock(cache->header->wrlock);
++    DESTROY_LOCK(cache->header->lock);
++#ifdef NONBLOCKING_LOCK_AVAILABLE
++    DESTROY_LOCK(cache->header->wrlock);
++#endif
++    apc_efree(cache);
 +}
 +/* }}} */
-+#endif
 +
-+/* {{{ make_local_slot */
-+static local_slot_t* make_local_slot(apc_local_cache_t* cache, local_slot_t* lslot, slot_t* slot, time_t t) 
-+{
-+    apc_cache_entry_t* value;
++/* {{{ apc_cache_clear */
++void apc_cache_clear(apc_cache_t* cache)
++{
++    int i;
++
++    if(!cache) return;
++
++    CACHE_LOCK(cache);
++    cache->header->busy = 1;
++    cache->header->num_hits = 0;
++    cache->header->num_misses = 0;
++    cache->header->start_time = time(NULL);
++    cache->header->expunges = 0;
 +
-+    value = apc_emalloc(sizeof(apc_cache_entry_t));
-+    memcpy(value, slot->value, sizeof(apc_cache_entry_t)); /* bitwise copy */
-+    value->local = 1;
++    for (i = 0; i < cache->num_slots; i++) {
++        slot_t* p = cache->slots[i];
++        while (p) {
++            remove_slot(cache, &p);
++        }
++        cache->slots[i] = NULL;
++    }
 +
-+    lslot->original = slot;
-+    lslot->value = value;
-+    lslot->num_hits = 0;
-+    lslot->creation_time = t;
++    memset(&cache->header->lastkey, 0, sizeof(apc_keyid_t));
 +
-+    return lslot; /* for what joy ? ... consistency */
++    cache->header->busy = 0;
++    CACHE_UNLOCK(cache);
 +}
 +/* }}} */
 +
-+/* {{{ free_local_slot */
-+static void free_local_slot(apc_local_cache_t* cache, local_slot_t* lslot) 
++/* {{{ apc_cache_expunge */
++static void apc_cache_expunge(apc_cache_t* cache, size_t size)
 +{
-+    local_slot_t * dead = NULL;
-+    if(!lslot->original) return;
++    int i;
++    time_t t;
++    TSRMLS_FETCH();
 +
-+    /* TODO: Bad design to allocate memory in a free_* - fix when bored (hehe) */
-+    dead = apc_emalloc(sizeof(local_slot_t));
-+    memcpy(dead, lslot, sizeof(local_slot_t)); /* bitwise copy */
++    t = apc_time();
++
++    if(!cache) return;
++
++    if(!cache->ttl) {
++        /*
++         * If cache->ttl is not set, we wipe out the entire cache when
++         * we run out of space.
++         */
++        CACHE_SAFE_LOCK(cache);
++        cache->header->busy = 1;
++        cache->header->expunges++;
++        for (i = 0; i < cache->num_slots; i++) {
++            slot_t* p = cache->slots[i];
++            while (p) {
++                remove_slot(cache, &p);
++            }
++            cache->slots[i] = NULL;
++        }
++        cache->header->busy = 0;
++        CACHE_SAFE_UNLOCK(cache);
++    } else {
++        slot_t **p;
 +
-+    lslot->original = NULL;
-+    lslot->value = NULL;
++        /*
++         * If the ttl for the cache is set we walk through and delete stale 
++         * entries.  For the user cache that is slightly confusing since
++         * we have the individual entry ttl's we can look at, but that would be
++         * too much work.  So if you want the user cache expunged, set a high
++         * default apc.user_ttl and still provide a specific ttl for each entry
++         * on insert
++         */
 +
-+    dead->next = cache->dead_list;
-+    cache->dead_list = dead;
++        CACHE_SAFE_LOCK(cache);
++        cache->header->busy = 1;
++        cache->header->expunges++;
++        for (i = 0; i < cache->num_slots; i++) {
++            p = &cache->slots[i];
++            while(*p) {
++                /*
++                 * For the user cache we look at the individual entry ttl values
++                 * and if not set fall back to the default ttl for the user cache
++                 */
++                if((*p)->value->type == APC_CACHE_ENTRY_USER) {
++                    if((*p)->value->data.user.ttl) {
++                        if((time_t) ((*p)->creation_time + (*p)->value->data.user.ttl) < t) {
++                            remove_slot(cache, p);
++                            continue;
++                        }
++                    } else if(cache->ttl) {
++                        if((*p)->creation_time + cache->ttl < t) {
++                            remove_slot(cache, p);
++                            continue;
++                        }
++                    }
++                } else if((*p)->access_time < (t - cache->ttl)) {
++                    remove_slot(cache, p);
++                    continue;
++                }
++                p = &(*p)->next;
++            }
++        }
++        cache->header->busy = 0;
++        CACHE_SAFE_UNLOCK(cache);
++    }
 +}
 +/* }}} */
 +
-+/* {{{ apc_local_cache_create */
-+apc_local_cache_t* apc_local_cache_create(apc_cache_t *shmcache, int num_slots, int ttl)
++/* {{{ apc_cache_insert */
++static inline int _apc_cache_insert(apc_cache_t* cache,
++                     apc_cache_key_t key,
++                     apc_cache_entry_t* value,
++                     apc_context_t* ctxt,
++                     time_t t)
 +{
-+    apc_local_cache_t* cache = NULL;
++    slot_t** slot;
 +
-+    cache = (apc_local_cache_t*) apc_emalloc(sizeof(apc_local_cache_t));
++    if (!value) {
++        return 0;
++    }
 +
-+    cache->slots = (local_slot_t*) (apc_emalloc(sizeof(local_slot_t) * num_slots));
-+    memset(cache->slots, 0, sizeof(local_slot_t) * num_slots);
++#ifdef __DEBUG_APC__
++    fprintf(stderr,"Inserting [%s]\n", value->data.file.filename);
++#endif
 +
-+    cache->shmcache = shmcache;
-+    cache->num_slots = num_slots;
-+    cache->ttl = ttl;
-+    cache->num_hits = 0;
-+    cache->generation = shmcache->header->expunges;
-+    cache->dead_list = NULL;
++    process_pending_removals(cache);
 +
-+    return cache;
-+}
-+/* }}} */
++    if(key.type == APC_CACHE_KEY_FILE) slot = &cache->slots[hash(key) % cache->num_slots];
++    else slot = &cache->slots[string_nhash_8(key.data.fpfile.fullpath, key.data.fpfile.fullpath_len) % cache->num_slots];
 +
-+/* {{{ apc_local_cache_cleanup */
-+void apc_local_cache_cleanup(apc_local_cache_t* cache) {
-+    local_slot_t * lslot;
-+    time_t t = time(0);
-+    
-+    int i;
-+    for(i = 0; i < cache->num_slots; i++) {
-+        lslot = &cache->slots[i];
-+        /* every slot lives for exactly TTL seconds */
-+        if((lslot->original && lslot->creation_time < (t - cache->ttl)) ||
-+                cache->generation != cache->shmcache->header->expunges) {
-+            free_local_slot(cache, lslot);
++    while(*slot) {
++      if(key.type == (*slot)->key.type) {
++        if(key.type == APC_CACHE_KEY_FILE) {
++            if(key_equals((*slot)->key.data.file, key.data.file)) {
++                /* If existing slot for the same device+inode is different, remove it and insert the new version */
++                if (ctxt->force_update || (*slot)->key.mtime != key.mtime) {
++                    remove_slot(cache, slot);
++                    break;
++                }
++                return 0;
++            } else if(cache->ttl && (*slot)->access_time < (t - cache->ttl)) {
++                remove_slot(cache, slot);
++                continue;
++            }
++        } else {   /* APC_CACHE_KEY_FPFILE */
++            if(!memcmp((*slot)->key.data.fpfile.fullpath, key.data.fpfile.fullpath, key.data.fpfile.fullpath_len+1)) {
++                /* Hrm.. it's already here, remove it and insert new one */
++                remove_slot(cache, slot);
++                break;
++            } else if(cache->ttl && (*slot)->access_time < (t - cache->ttl)) {
++                remove_slot(cache, slot);
++                continue;
++            }
 +        }
++      }
++      slot = &(*slot)->next;
 +    }
 +
-+    LOCK(cache->shmcache);
-+    for(lslot = cache->dead_list; lslot != NULL; lslot = lslot->next) {
-+        lslot->original->num_hits += lslot->num_hits;
-+        lslot->original->value->ref_count--; /* apc_cache_release(cache->shmcache, lslot->original->value); */
-+        apc_efree(lslot->value);
++    if ((*slot = make_slot(key, value, *slot, t)) == NULL) {
++        return -1;
 +    }
-+    UNLOCK(cache->shmcache);
 +
-+    cache->dead_list = NULL;
++    value->mem_size = ctxt->pool->size;
++    cache->header->mem_size += ctxt->pool->size;
++    cache->header->num_entries++;
++    cache->header->num_inserts++;
++
++    return 1;
 +}
 +/* }}} */
 +
-+/* {{{ apc_local_cache_destroy */
-+void apc_local_cache_destroy(apc_local_cache_t* cache)
++/* {{{ apc_cache_insert */
++int apc_cache_insert(apc_cache_t* cache, apc_cache_key_t key, apc_cache_entry_t* value, apc_context_t *ctxt, time_t t)
 +{
-+    int i;
-+    for(i = 0; i < cache->num_slots; i++) {
-+        free_local_slot(cache, &cache->slots[i]);
-+    }
-+
-+    apc_local_cache_cleanup(cache);
-+
-+    LOCK(cache->shmcache);
-+    cache->shmcache->header->num_hits += cache->num_hits;
-+    UNLOCK(cache->shmcache);
-+
-+    apc_efree(cache->slots);
-+    apc_efree(cache);
++    int rval;
++    CACHE_LOCK(cache);
++    rval = _apc_cache_insert(cache, key, value, ctxt, t);
++    CACHE_UNLOCK(cache);
++    return rval;
 +}
 +/* }}} */
 +
-+/* {{{ apc_local_cache_find */
-+apc_cache_entry_t* apc_local_cache_find(apc_local_cache_t* cache, apc_cache_key_t key, time_t t)
++/* {{{ apc_cache_insert */
++int *apc_cache_insert_mult(apc_cache_t* cache, apc_cache_key_t* keys, apc_cache_entry_t** values, apc_context_t *ctxt, time_t t, int num_entries)
 +{
-+    slot_t* slot;
-+    local_slot_t* lslot; 
++    int *rval;
++    int i;
 +
-+    if(key.type == APC_CACHE_KEY_FILE) lslot = &cache->slots[hash(key) % cache->num_slots];
-+    else lslot = &cache->slots[string_nhash_8(key.data.fpfile.fullpath, key.data.fpfile.fullpath_len) % cache->num_slots];
++    rval = emalloc(sizeof(int) * num_entries);
++    CACHE_LOCK(cache);
++    for (i=0; i < num_entries; i++) {
++        if (values[i]) {
++            ctxt->pool = values[i]->pool;
++            rval[i] = _apc_cache_insert(cache, keys[i], values[i], ctxt, t);
++        }
++    }
++    CACHE_UNLOCK(cache);
++    return rval;
++}
++/* }}} */
 +
-+    slot = lslot->original;
 +
-+    if(slot && key.type == slot->key.type) {
-+        if(slot->access_time < (t - cache->ttl)) {
-+            goto not_found;
-+        }
-+        if(key.type == APC_CACHE_KEY_FILE && 
-+           key_equals(slot->key.data.file, key.data.file)) {
-+            if(slot->key.mtime != key.mtime) {
-+                free_local_slot(cache, lslot);
-+                goto not_found;
-+            }
-+            cache->num_hits++;
-+            lslot->num_hits++;
-+            lslot->original->access_time = t; /* unlocked write, but last write wins */
-+            return lslot->value;
-+        } else if(key.type == APC_CACHE_KEY_FPFILE) {
-+            if(!memcmp(slot->key.data.fpfile.fullpath, key.data.fpfile.fullpath, key.data.fpfile.fullpath_len+1)) {
-+                cache->num_hits++;
-+                lslot->num_hits++;
-+                lslot->original->access_time = t; /* unlocked write, but last write wins */
-+                return lslot->value;
-+            }
-+        }
++/* {{{ apc_cache_user_insert */
++int apc_cache_user_insert(apc_cache_t* cache, apc_cache_key_t key, apc_cache_entry_t* value, apc_context_t* ctxt, time_t t, int exclusive TSRMLS_DC)
++{
++    slot_t** slot;
++    unsigned int keylen = key.data.user.identifier_len+1;
++    unsigned int h = string_nhash_8(key.data.user.identifier, keylen);
++    apc_keyid_t *lastkey = &cache->header->lastkey;
++    
++    if (!value) {
++        return 0;
 +    }
-+not_found:
-+    if(apc_cache_busy(cache->shmcache)) {
-+        return NULL;
++    
++    if(apc_cache_busy(cache)) {
++        /* cache cleanup in progress, do not wait */ 
++        return 0;
 +    }
 +
-+    slot = apc_cache_find_slot(cache->shmcache, key, t);
-+
-+    if(!slot) return NULL;
-+   
-+    /* i.e maintain a sort of top list */
-+    if(lslot->original == NULL || (lslot->original->num_hits + lslot->num_hits)  < slot->num_hits) {
-+        free_local_slot(cache, lslot);
-+        make_local_slot(cache, lslot, slot, t); 
-+        return lslot->value;
++    if(apc_cache_is_last_key(cache, &key, t)) {
++        /* potential cache slam */
++        return 0;
 +    }
-+    return slot->value;
-+}
-+/* }}} */
 +
-+/*
-+ * Local variables:
-+ * tab-width: 4
-+ * c-basic-offset: 4
-+ * End:
-+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
-+ * vim<600: expandtab sw=4 ts=4 sts=4
-+ */
-diff -ubrN php-5.2.5-orig/ext/apc/apc_cache.h php-5.2.5/ext/apc/apc_cache.h
---- php-5.2.5-orig/ext/apc/apc_cache.h 1969-12-31 18:00:00.000000000 -0600
-+++ php-5.2.5/ext/apc/apc_cache.h      2007-12-26 16:51:32.000000000 -0600
-@@ -0,0 +1,312 @@
-+/*
-+  +----------------------------------------------------------------------+
-+  | APC                                                                  |
-+  +----------------------------------------------------------------------+
-+  | Copyright (c) 2006 The PHP Group                                     |
-+  +----------------------------------------------------------------------+
-+  | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt.                                 |
-+  | If you did not receive a copy of the PHP license and are unable to   |
-+  | obtain it through the world-wide-web, please send a note to          |
-+  | license@php.net so we can mail you a copy immediately.               |
-+  +----------------------------------------------------------------------+
-+  | Authors: Daniel Cowgill <dcowgill@communityconnect.com>              |
-+  |          Rasmus Lerdorf <rasmus@php.net>                             |
-+  +----------------------------------------------------------------------+
++    CACHE_LOCK(cache);
 +
-+   This software was contributed to PHP by Community Connect Inc. in 2002
-+   and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
-+   Future revisions and derivatives of this source code must acknowledge
-+   Community Connect Inc. as the original contributor of this module by
-+   leaving this note intact in the source code.
++    memset(lastkey, 0, sizeof(apc_keyid_t));
 +
-+   All other licensing and usage conditions are those of the PHP Group.
++    lastkey->h = h;
++    lastkey->keylen = keylen;
++    lastkey->mtime = t;
++    
++    /* we do not reset lastkey after the insert. Whether it is inserted 
++     * or not, another insert in the same second is always a bad idea. 
++     */
 +
-+ */
++    process_pending_removals(cache);
++    
++    slot = &cache->slots[h % cache->num_slots];
 +
-+/* $Id: apc_cache.h,v 3.46 2007/10/05 23:06:56 gopalv Exp $ */
++    while (*slot) {
++        if (!memcmp((*slot)->key.data.user.identifier, key.data.user.identifier, keylen)) {
++            /* 
++             * At this point we have found the user cache entry.  If we are doing 
++             * an exclusive insert (apc_add) we are going to bail right away if
++             * the user entry already exists and it has no ttl, or
++             * there is a ttl and the entry has not timed out yet.
++             */
++            if(exclusive && (  !(*slot)->value->data.user.ttl ||
++                              ( (*slot)->value->data.user.ttl && (time_t) ((*slot)->creation_time + (*slot)->value->data.user.ttl) >= t ) 
++                            ) ) {
++                goto fail;
++            }
++            remove_slot(cache, slot);
++            break;
++        } else 
++        /* 
++         * This is a bit nasty.  The idea here is to do runtime cleanup of the linked list of
++         * slot entries so we don't always have to skip past a bunch of stale entries.  We check
++         * for staleness here and get rid of them by first checking to see if the cache has a global
++         * access ttl on it and removing entries that haven't been accessed for ttl seconds and secondly
++         * we see if the entry has a hard ttl on it and remove it if it has been around longer than its ttl
++         */
++        if((cache->ttl && (*slot)->access_time < (t - cache->ttl)) || 
++           ((*slot)->value->data.user.ttl && (time_t) ((*slot)->creation_time + (*slot)->value->data.user.ttl) < t)) {
++            remove_slot(cache, slot);
++            continue;
++        }
++        slot = &(*slot)->next;
++    }
 +
-+#ifndef APC_CACHE_H
-+#define APC_CACHE_H
++    if ((*slot = make_slot(key, value, *slot, t)) == NULL) {
++        goto fail;
++    } 
++    
++    value->mem_size = ctxt->pool->size;
++    cache->header->mem_size += ctxt->pool->size;
 +
-+/*
-+ * This module defines the shared memory file cache. Basically all of the
-+ * logic for storing and retrieving cache entries lives here.
-+ */
++    cache->header->num_entries++;
++    cache->header->num_inserts++;
 +
-+#include "apc.h"
-+#include "apc_compile.h"
++    CACHE_UNLOCK(cache);
 +
-+#define APC_CACHE_ENTRY_FILE   1
-+#define APC_CACHE_ENTRY_USER   2
++    return 1;
 +
-+#define APC_CACHE_KEY_FILE     1
-+#define APC_CACHE_KEY_USER     2
-+#define APC_CACHE_KEY_FPFILE   3
++fail:
++    CACHE_UNLOCK(cache);
 +
-+/* {{{ struct definition: apc_cache_key_t */
-+#define T apc_cache_t*
-+typedef struct apc_cache_t apc_cache_t; /* opaque cache type */
++    return 0;
++}
++/* }}} */
 +
-+typedef union _apc_cache_key_data_t {
-+    struct {
-+        dev_t device;             /* the filesystem device */
-+        ino_t inode;              /* the filesystem inode */
-+    } file;
-+    struct {
-+        const char *identifier;
-+        int identifier_len;
-+    } user;
-+    struct {
-+        const char *fullpath;
-+        int fullpath_len;
-+    } fpfile;
-+} apc_cache_key_data_t;
-+
-+typedef struct apc_cache_key_t apc_cache_key_t;
-+struct apc_cache_key_t {
-+    apc_cache_key_data_t data;
-+    time_t mtime;                 /* the mtime of this cached entry */
-+    unsigned char type;
-+};
-+/* }}} */
++/* {{{ apc_cache_find_slot */
++slot_t* apc_cache_find_slot(apc_cache_t* cache, apc_cache_key_t key, time_t t)
++{
++    slot_t** slot;
++    volatile slot_t* retval = NULL;
 +
-+/* {{{ struct definition: apc_cache_entry_t */
-+typedef union _apc_cache_entry_value_t {
-+    struct {
-+        char *filename;             /* absolute path to source file */
-+        zend_op_array* op_array;    /* op_array allocated in shared memory */
-+        apc_function_t* functions;  /* array of apc_function_t's */
-+        apc_class_t* classes;       /* array of apc_class_t's */
-+    } file;
-+    struct {
-+        char *info; 
-+        int info_len; 
-+        zval *val;
-+        unsigned int ttl;
-+    } user;
-+} apc_cache_entry_value_t;
++    CACHE_LOCK(cache);
++    if(key.type == APC_CACHE_KEY_FILE) slot = &cache->slots[hash(key) % cache->num_slots];
++    else slot = &cache->slots[string_nhash_8(key.data.fpfile.fullpath, key.data.fpfile.fullpath_len) % cache->num_slots];
 +
-+typedef struct apc_cache_entry_t apc_cache_entry_t;
-+struct apc_cache_entry_t {
-+    apc_cache_entry_value_t data;
-+    unsigned char type;
-+    unsigned char local;
-+    int ref_count;
-+    size_t mem_size;
-+};
++    while (*slot) {
++      if(key.type == (*slot)->key.type) {
++        if(key.type == APC_CACHE_KEY_FILE) {
++            if(key_equals((*slot)->key.data.file, key.data.file)) {
++                if((*slot)->key.mtime != key.mtime) {
++                    remove_slot(cache, slot);
++                    cache->header->num_misses++;
++                    CACHE_UNLOCK(cache);
++                    return NULL;
++                }
++                (*slot)->num_hits++;
++                (*slot)->value->ref_count++;
++                (*slot)->access_time = t;
++                prevent_garbage_collection((*slot)->value);
++                cache->header->num_hits++;
++                retval = *slot;
++                CACHE_UNLOCK(cache);
++                return (slot_t*)retval;
++            }
++        } else {  /* APC_CACHE_KEY_FPFILE */
++            if(!memcmp((*slot)->key.data.fpfile.fullpath, key.data.fpfile.fullpath, key.data.fpfile.fullpath_len+1)) {
++                /* TTL Check ? */
++                (*slot)->num_hits++;
++                (*slot)->value->ref_count++;
++                (*slot)->access_time = t;
++                prevent_garbage_collection((*slot)->value);
++                cache->header->num_hits++;
++                retval = *slot;
++                CACHE_UNLOCK(cache);
++                return (slot_t*)retval;
++            }
++        }
++      }
++      slot = &(*slot)->next;
++    }
++    cache->header->num_misses++;
++    CACHE_UNLOCK(cache);
++    return NULL;
++}
 +/* }}} */
 +
-+/*
-+ * apc_cache_create creates the shared memory compiler cache. This function
-+ * should be called just once (ideally in the web server parent process, e.g.
-+ * in apache), otherwise you will end up with multiple caches (which won't
-+ * necessarily break anything). Returns a pointer to the cache object.
-+ *
-+ * size_hint is a "hint" at the total number of source files that will be
-+ * cached. It determines the physical size of the hash table. Passing 0 for
-+ * this argument will use a reasonable default value.
-+ *
-+ * gc_ttl is the maximum time a cache entry may speed on the garbage
-+ * collection list. This is basically a work around for the inherent
-+ * unreliability of our reference counting mechanism (see apc_cache_release).
-+ *
-+ * ttl is the maximum time a cache entry can idle in a slot in case the slot
-+ * is needed.  This helps in cleaning up the cache and ensuring that entries 
-+ * hit frequently stay cached and ones not hit very often eventually disappear.
-+ */
-+extern T apc_cache_create(int size_hint, int gc_ttl, int ttl);
++/* {{{ apc_cache_find */
++apc_cache_entry_t* apc_cache_find(apc_cache_t* cache, apc_cache_key_t key, time_t t)
++{
++    slot_t * slot = apc_cache_find_slot(cache, key, t);
++    return (slot) ? slot->value : NULL;
++}
++/* }}} */
 +
-+/*
-+ * apc_cache_destroy releases any OS resources associated with a cache object.
-+ * Under apache, this function can be safely called by the child processes
-+ * when they exit.
-+ */
-+extern void apc_cache_destroy(T cache);
++/* {{{ apc_cache_user_find */
++apc_cache_entry_t* apc_cache_user_find(apc_cache_t* cache, char *strkey, int keylen, time_t t)
++{
++    slot_t** slot;
++    volatile apc_cache_entry_t* value = NULL;
 +
-+/*
-+ * apc_cache_clear empties a cache. This can safely be called at any time,
-+ * even while other server processes are executing cached source files.
-+ */
-+extern void apc_cache_clear(T cache);
++    if(apc_cache_busy(cache))
++    {
++        /* cache cleanup in progress */ 
++        return NULL;
++    }
 +
-+/*
-+ * apc_cache_insert adds an entry to the cache, using a filename as a key.
-+ * Internally, the filename is translated to a canonical representation, so
-+ * that relative and absolute filenames will map to a single key. Returns
-+ * non-zero if the file was successfully inserted, 0 otherwise. If 0 is
-+ * returned, the caller must free the cache entry by calling
-+ * apc_cache_free_entry (see below).
-+ *
-+ * key is the value created by apc_cache_make_file_key for file keys.
-+ *
-+ * value is a cache entry returned by apc_cache_make_entry (see below).
-+ */
-+extern int apc_cache_insert(T cache, apc_cache_key_t key,
-+                            apc_cache_entry_t* value, time_t t);
++    CACHE_LOCK(cache);
 +
-+extern int apc_cache_user_insert(T cache, apc_cache_key_t key,
-+                            apc_cache_entry_t* value, time_t t, int exclusive TSRMLS_DC);
++    slot = &cache->slots[string_nhash_8(strkey, keylen) % cache->num_slots];
 +
-+/*
-+ * apc_cache_find searches for a cache entry by filename, and returns a
-+ * pointer to the entry if found, NULL otherwise.
-+ *
-+ * key is a value created by apc_cache_make_file_key for file keys.
-+ */
-+extern apc_cache_entry_t* apc_cache_find(T cache, apc_cache_key_t key, time_t t);
++    while (*slot) {
++        if (!memcmp((*slot)->key.data.user.identifier, strkey, keylen)) {
++            /* Check to make sure this entry isn't expired by a hard TTL */
++            if((*slot)->value->data.user.ttl && (time_t) ((*slot)->creation_time + (*slot)->value->data.user.ttl) < t) {
++                remove_slot(cache, slot);
++                cache->header->num_misses++;
++                CACHE_UNLOCK(cache);
++                return NULL;
++            }
++            /* Otherwise we are fine, increase counters and return the cache entry */
++            (*slot)->num_hits++;
++            (*slot)->value->ref_count++;
++            (*slot)->access_time = t;
 +
-+/*
-+ * apc_cache_user_find searches for a cache entry by its hashed identifier, 
-+ * and returns a pointer to the entry if found, NULL otherwise.
-+ *
-+ */
-+extern apc_cache_entry_t* apc_cache_user_find(T cache, char* strkey, int keylen, time_t t);
++            cache->header->num_hits++;
++            value = (*slot)->value;
++            CACHE_UNLOCK(cache);
++            return (apc_cache_entry_t*)value;
++        }
++        slot = &(*slot)->next;
++    }
++ 
++    cache->header->num_misses++;
++    CACHE_UNLOCK(cache);
++    return NULL;
++}
++/* }}} */
 +
-+/*
-+ * apc_cache_user_delete finds an entry in the user cache and deletes it.
-+ */
-+extern int apc_cache_user_delete(apc_cache_t* cache, char *strkey, int keylen);
++/* {{{ apc_cache_user_update */
++int _apc_cache_user_update(apc_cache_t* cache, char *strkey, int keylen, apc_cache_updater_t updater, void* data TSRMLS_DC)
++{
++    slot_t** slot;
++    int retval;
 +
-+/* apc_cach_fetch_zval takes a zval in the cache and reconstructs a runtime
-+ * zval from it.
-+ *
-+ */
-+zval* apc_cache_fetch_zval(zval* dst, const zval* src, apc_malloc_t allocate, apc_free_t deallocate);
++    if(apc_cache_busy(cache))
++    {
++        /* cache cleanup in progress */ 
++        return 0;
++    }
 +
-+/*
-+ * apc_cache_release decrements the reference count associated with a cache
-+ * entry. Calling apc_cache_find automatically increments the reference count,
-+ * and this function must be called post-execution to return the count to its
-+ * original value. Failing to do so will prevent the entry from being
-+ * garbage-collected.
-+ *
-+ * entry is the cache entry whose ref count you want to decrement.
-+ */
-+extern void apc_cache_release(T cache, apc_cache_entry_t* entry);
++    CACHE_LOCK(cache);
 +
-+/*
-+ * apc_cache_make_file_key creates a key object given a relative or absolute
-+ * filename and an optional list of auxillary paths to search. include_path is
-+ * searched if the filename cannot be found relative to the current working
-+ * directory.
-+ *
-+ * key points to caller-allocated storage (must not be null).
-+ *
-+ * filename is the path to the source file.
-+ *
-+ * include_path is a colon-separated list of directories to search.
-+ *
-+ * and finally we pass in the current request time so we can avoid
-+ * caching files with a current mtime which tends to indicate that
-+ * they are still being written to.
-+ */
-+extern int apc_cache_make_file_key(apc_cache_key_t* key,
-+                                   const char* filename,
-+                                   const char* include_path,
-+                                   time_t t
-+                                                             TSRMLS_DC);
++    slot = &cache->slots[string_nhash_8(strkey, keylen) % cache->num_slots];
 +
-+/*
-+ * apc_cache_make_file_entry creates an apc_cache_entry_t object given a filename
-+ * and the compilation results returned by the PHP compiler.
-+ */
-+extern apc_cache_entry_t* apc_cache_make_file_entry(const char* filename,
-+                                                    zend_op_array* op_array,
-+                                                    apc_function_t* functions,
-+                                                    apc_class_t* classes);
-+/*
-+ * apc_cache_make_user_entry creates an apc_cache_entry_t object given an info string
-+ * and the zval to be stored.
-+ */
-+extern apc_cache_entry_t* apc_cache_make_user_entry(const char* info, int info_len, const zval *val, const unsigned int ttl);
++    while (*slot) {
++        if (!memcmp((*slot)->key.data.user.identifier, strkey, keylen)) {
++            retval = updater(cache, (*slot)->value, data);
++            (*slot)->key.mtime = apc_time();
++            CACHE_UNLOCK(cache);
++            return retval;
++        }
++        slot = &(*slot)->next;
++    }
++    CACHE_UNLOCK(cache);
++    return 0;
++}
++/* }}} */
 +
-+extern int apc_cache_make_user_key(apc_cache_key_t* key, char* identifier, int identifier_len, const time_t t);
++/* {{{ apc_cache_user_delete */
++int apc_cache_user_delete(apc_cache_t* cache, char *strkey, int keylen)
++{
++    slot_t** slot;
 +
-+/*
-+ * Frees all memory associated with an object returned by apc_cache_make_entry
-+ * (see above).
-+ */
-+extern void apc_cache_free_entry(apc_cache_entry_t* entry);
++    CACHE_LOCK(cache);
 +
-+/* {{{ struct definition: apc_cache_link_data_t */
-+typedef union _apc_cache_link_data_t {
-+    struct {
-+        char *filename;
-+        dev_t device;
-+        ino_t inode;
-+    } file;
-+    struct {
-+        char *info;
-+        unsigned int ttl;
-+    } user;
-+} apc_cache_link_data_t;
-+/* }}} */
++    slot = &cache->slots[string_nhash_8(strkey, keylen) % cache->num_slots];
 +
-+/* {{{ struct definition: apc_cache_link_t */
-+typedef struct apc_cache_link_t apc_cache_link_t;
-+struct apc_cache_link_t {
-+    apc_cache_link_data_t data;
-+    unsigned char type;
-+    int num_hits;
-+    time_t mtime;
-+    time_t creation_time;
-+    time_t deletion_time;
-+    time_t access_time;
-+    int ref_count;
-+    size_t mem_size;
-+    apc_cache_link_t* next;
-+};
-+/* }}} */
++    while (*slot) {
++        if (!memcmp((*slot)->key.data.user.identifier, strkey, keylen)) {
++            remove_slot(cache, slot);
++            CACHE_UNLOCK(cache);
++            return 1;
++        }
++        slot = &(*slot)->next;
++    }
 +
-+/* {{{ struct definition: apc_cache_info_t */
-+typedef struct apc_cache_info_t apc_cache_info_t;
-+struct apc_cache_info_t {
-+    int num_slots;
-+    int num_hits;
-+    int num_misses;
-+    int ttl;
-+    apc_cache_link_t* list;
-+    apc_cache_link_t* deleted_list;
-+    time_t start_time;
-+    int expunges;
-+    int num_entries;
-+    int num_inserts;
-+    size_t mem_size;
-+};
++    CACHE_UNLOCK(cache);
++    return 0;
++}
 +/* }}} */
 +
-+extern apc_cache_info_t* apc_cache_info(T cache, zend_bool limited);
-+extern void apc_cache_free_info(apc_cache_info_t* info);
-+extern void apc_cache_expunge(apc_cache_t* cache, time_t t);
-+extern void apc_cache_unlock(apc_cache_t* cache);
-+extern zend_bool apc_cache_busy(apc_cache_t* cache);
-+extern zend_bool apc_cache_write_lock(apc_cache_t* cache);
-+extern void apc_cache_write_unlock(apc_cache_t* cache);
-+
-+/* 
-+ * Process local cache, which keeps a refcount hungry version of the slots
-+ * for quick access without a lock - as long as the entry exists in local
-+ * cache, the refcount of the shm version will be +1 more than required.
-+ * It holds no data, only a shallow copy of apc_cache_entry.
-+ */
-+typedef struct apc_local_cache_t apc_local_cache_t; /* process-local cache */ 
-+
-+extern apc_local_cache_t* apc_local_cache_create(apc_cache_t *shmcache, int num_slots, int ttl);
-+extern apc_cache_entry_t* apc_local_cache_find(apc_local_cache_t* cache, apc_cache_key_t key, time_t t);
-+extern void apc_local_cache_destroy(apc_local_cache_t* cache);
-+extern void apc_local_cache_cleanup(apc_local_cache_t* cache);
-+
-+#undef T
-+#endif
-+
-+/*
-+ * Local variables:
-+ * tab-width: 4
-+ * c-basic-offset: 4
-+ * End:
-+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
-+ * vim<600: expandtab sw=4 ts=4 sts=4
-+ */
-diff -ubrN php-5.2.5-orig/ext/apc/apc_compile.c php-5.2.5/ext/apc/apc_compile.c
---- php-5.2.5-orig/ext/apc/apc_compile.c       1969-12-31 18:00:00.000000000 -0600
-+++ php-5.2.5/ext/apc/apc_compile.c    2007-12-26 16:51:32.000000000 -0600
-@@ -0,0 +1,2529 @@
-+/*
-+  +----------------------------------------------------------------------+
-+  | APC                                                                  |
-+  +----------------------------------------------------------------------+
-+  | Copyright (c) 2006 The PHP Group                                     |
-+  +----------------------------------------------------------------------+
-+  | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt.                                 |
-+  | If you did not receive a copy of the PHP license and are unable to   |
-+  | obtain it through the world-wide-web, please send a note to          |
-+  | license@php.net so we can mail you a copy immediately.               |
-+  +----------------------------------------------------------------------+
-+  | Authors: Daniel Cowgill <dcowgill@communityconnect.com>              |
-+  |          Rasmus Lerdorf <rasmus@php.net>                             |
-+  |          Arun C. Murthy <arunc@yahoo-inc.com>                        |
-+  |          Gopal Vijayaraghavan <gopalv@yahoo-inc.com>                 |
-+  +----------------------------------------------------------------------+
++/* {{{ apc_cache_delete */
++int apc_cache_delete(apc_cache_t* cache, char *filename, int filename_len)
++{
++    slot_t** slot;
++    time_t t;
++    apc_cache_key_t key;
 +
-+   This software was contributed to PHP by Community Connect Inc. in 2002
-+   and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
-+   Future revisions and derivatives of this source code must acknowledge
-+   Community Connect Inc. as the original contributor of this module by
-+   leaving this note intact in the source code.
++    TSRMLS_FETCH();
 +
-+   All other licensing and usage conditions are those of the PHP Group.
++    t = apc_time();
 +
-+ */
++    /* try to create a cache key; if we fail, give up on caching */
++    if (!apc_cache_make_file_key(&key, filename, PG(include_path), t TSRMLS_CC)) {
++        apc_wprint("Could not stat file %s, unable to delete from cache.", filename);
++        return -1;
++    }
 +
-+/* $Id: apc_compile.c,v 3.87 2007/08/25 13:09:13 gopalv Exp $ */
++    CACHE_LOCK(cache);
 +
-+#include "apc_compile.h"
-+#include "apc_globals.h"
-+#include "apc_zend.h"
++    if(key.type == APC_CACHE_KEY_FILE) slot = &cache->slots[hash(key) % cache->num_slots];
++    else slot = &cache->slots[string_nhash_8(key.data.fpfile.fullpath, key.data.fpfile.fullpath_len) % cache->num_slots];
 +
-+typedef void* (*ht_copy_fun_t)(void*, void*, apc_malloc_t, apc_free_t);
-+typedef void  (*ht_free_fun_t)(void*, apc_free_t);
-+typedef int (*ht_check_copy_fun_t)(Bucket*, va_list);
++    while(*slot) {
++      if(key.type == (*slot)->key.type) {
++        if(key.type == APC_CACHE_KEY_FILE) {
++            if(key_equals((*slot)->key.data.file, key.data.file)) {
++                remove_slot(cache, slot);
++                CACHE_UNLOCK(cache);
++                return 1;
++            }
++        } else {   /* APC_CACHE_KEY_FPFILE */
++            if(!memcmp((*slot)->key.data.fpfile.fullpath, key.data.fpfile.fullpath, key.data.fpfile.fullpath_len+1)) {
++                remove_slot(cache, slot);
++                CACHE_UNLOCK(cache);
++                return 1;
++            }
++        }
++      }
++      slot = &(*slot)->next;
++    }
 +
-+#ifdef ZEND_ENGINE_2
-+typedef void (*ht_fixup_fun_t)(Bucket*, zend_class_entry*, zend_class_entry*);
-+#endif
++    CACHE_UNLOCK(cache);
++    return 0;
 +
-+#define CHECK(p) { if ((p) == NULL) return NULL; }
++}
++/* }}} */
 +
-+/* {{{ internal function declarations */
++/* {{{ apc_cache_release */
++void apc_cache_release(apc_cache_t* cache, apc_cache_entry_t* entry)
++{
++    CACHE_LOCK(cache);
++    entry->ref_count--;
++    CACHE_UNLOCK(cache);
++}
++/* }}} */
 +
-+static int is_derived_class(zend_op_array* op_array, const char* key, int key_size);
++/* {{{ apc_cache_make_file_key */
++int apc_cache_make_file_key(apc_cache_key_t* key,
++                       const char* filename,
++                       const char* include_path,
++                       time_t t
++                       TSRMLS_DC)
++{
++    struct stat *tmp_buf=NULL;
++    struct apc_fileinfo_t fileinfo = { {0}, };
++    int len;
 +
-+static zend_function* my_bitwise_copy_function(zend_function*, zend_function*, apc_malloc_t);
++    assert(key != NULL);
 +
-+/*
-+ * The "copy" functions perform deep-copies on a particular data structure
-+ * (passed as the second argument). They also optionally allocate space for
-+ * the destination data structure if the first argument is null.
-+ */
-+static zval** my_copy_zval_ptr(zval**, const zval**, apc_malloc_t, apc_free_t);
-+static zval* my_copy_zval(zval*, const zval*, apc_malloc_t, apc_free_t);
-+static znode* my_copy_znode(znode*, znode*, apc_malloc_t, apc_free_t);
-+static zend_op* my_copy_zend_op(zend_op*, zend_op*, apc_malloc_t, apc_free_t);
-+static zend_function* my_copy_function(zend_function*, zend_function*, apc_malloc_t, apc_free_t);
-+static zend_function_entry* my_copy_function_entry(zend_function_entry*, zend_function_entry*, apc_malloc_t, apc_free_t);
-+static zend_class_entry* my_copy_class_entry(zend_class_entry*, zend_class_entry*, apc_malloc_t, apc_free_t);
-+static HashTable* my_copy_hashtable_ex(HashTable*, HashTable*, ht_copy_fun_t, ht_free_fun_t, int, apc_malloc_t, apc_free_t, ht_check_copy_fun_t, ...);
-+#define my_copy_hashtable( dst, src, copy_fn, free_fn, holds_ptr, allocate, deallocate) \
-+    my_copy_hashtable_ex(dst, src, copy_fn, free_fn, holds_ptr, allocate, deallocate, NULL)
-+static HashTable* my_copy_static_variables(zend_op_array* src, apc_malloc_t allocate, apc_free_t deallocate);
-+#ifdef ZEND_ENGINE_2
-+static zend_property_info* my_copy_property_info(zend_property_info* dst, zend_property_info* src, apc_malloc_t allocate, apc_free_t deallocate);
-+static zend_arg_info* my_copy_arg_info_array(zend_arg_info*, zend_arg_info*, uint, apc_malloc_t, apc_free_t);
-+static zend_arg_info* my_copy_arg_info(zend_arg_info*, zend_arg_info*, apc_malloc_t, apc_free_t);
-+#endif
-+/*
-+ * The "destroy" functions free the memory associated with a particular data
-+ * structure but do not free the pointer to the data structure.
-+ *
-+ * my_destroy_zval() returns SUCCESS or FAILURE, FAILURE means that
-+ * the zval* has other references elsewhere 
-+ */
-+static int  my_destroy_zval(zval*, apc_free_t); 
-+static void my_destroy_zval_ptr(zval**, apc_free_t);
-+static void my_destroy_zend_op(zend_op*, apc_free_t);
-+static void my_destroy_znode(znode*, apc_free_t);
-+static void my_destroy_function(zend_function*, apc_free_t);
-+static void my_destroy_function_entry(zend_function_entry*, apc_free_t);
-+static void my_destroy_class_entry(zend_class_entry*, apc_free_t);
-+static void my_destroy_hashtable(HashTable*, ht_free_fun_t, apc_free_t);
-+static void my_destroy_op_array(zend_op_array*, apc_free_t);
-+#ifdef ZEND_ENGINE_2
-+static void my_destroy_property_info(zend_property_info*, apc_free_t);
-+static void my_destroy_arg_info_array(zend_arg_info* src, uint, apc_free_t);
-+static void my_destroy_arg_info(zend_arg_info*, apc_free_t);
++    if (!filename || !SG(request_info).path_translated) {
++#ifdef __DEBUG_APC__
++        fprintf(stderr,"No filename and no path_translated - bailing\n");
 +#endif
++        return 0;
++    }
 +
-+/*
-+ * The "free" functions work exactly like their "destroy" counterparts (see
-+ * above) but also free the pointer to the data structure.
-+ */
-+static void my_free_zval_ptr(zval**, apc_free_t);
-+static void my_free_function(zend_function*, apc_free_t);
-+static void my_free_hashtable(HashTable*, ht_free_fun_t, apc_free_t);
-+#ifdef ZEND_ENGINE_2
-+static void my_free_property_info(zend_property_info* src, apc_free_t);
-+static void my_free_arg_info_array(zend_arg_info*, uint, apc_free_t);
-+static void my_free_arg_info(zend_arg_info*, apc_free_t);
-+#endif
++    len = strlen(filename);
++    if(APCG(fpstat)==0) {
++        if(IS_ABSOLUTE_PATH(filename,len)) {
++            key->data.fpfile.fullpath = filename;
++            key->data.fpfile.fullpath_len = len;
++            key->mtime = t;
++            key->type = APC_CACHE_KEY_FPFILE;
++            return 1;
++        } else if(APCG(canonicalize)) {
++            if (apc_search_paths(filename, include_path, &fileinfo) != 0) {
++                apc_wprint("apc failed to locate %s - bailing", filename);
++                return 0;
++            }
 +
-+/*
-+ * The "fixup" functions need for ZEND_ENGINE_2
-+ */
-+#ifdef ZEND_ENGINE_2
-+static void my_fixup_function( Bucket *p, zend_class_entry *src, zend_class_entry *dst );
-+static void my_fixup_hashtable( HashTable *ht, ht_fixup_fun_t fixup, zend_class_entry *src, zend_class_entry *dst );
-+/* my_fixup_function_for_execution is the same as my_fixup_function
-+ * but named differently for clarity
-+ */
-+#define my_fixup_function_for_execution my_fixup_function
++            if(!realpath(fileinfo.fullpath, APCG(canon_path))) {
++                apc_wprint("realpath failed to canonicalize %s - bailing", filename);
++                return 0;
++            }
 +
-+#ifdef ZEND_ENGINE_2_2
-+static void my_fixup_property_info( Bucket *p, zend_class_entry *src, zend_class_entry *dst );
-+#define my_fixup_property_info_for_execution my_fixup_property_info
++            key->data.fpfile.fullpath = APCG(canon_path);
++            key->data.fpfile.fullpath_len = strlen(APCG(canon_path));
++            key->mtime = t;
++            key->type = APC_CACHE_KEY_FPFILE;
++            return 1;
++        }
++        /* fall through to stat mode */
++    }
++
++    if(!strcmp(SG(request_info).path_translated, filename)) {
++        tmp_buf = sapi_get_stat(TSRMLS_C);  /* Apache has already done this stat() for us */
++    }
++    if(tmp_buf) {
++        fileinfo.st_buf.sb = *tmp_buf;
++    } else {
++        if (apc_search_paths(filename, include_path, &fileinfo) != 0) {
++#ifdef __DEBUG_APC__
++            fprintf(stderr,"Stat failed %s - bailing (%s) (%d)\n",filename,SG(request_info).path_translated);
 +#endif
++            return 0;
++        }
++    }
 +
++    if(APCG(max_file_size) < fileinfo.st_buf.sb.st_size) {
++#ifdef __DEBUG_APC__
++        fprintf(stderr,"File is too big %s (%d - %ld) - bailing\n",filename,t,fileinfo.st_buf.sb.st_size);
 +#endif
++        return 0;
++    }
 +
-+/*
-+ * These functions return "1" if the member/function is
-+ * defined/overridden in the 'current' class and not inherited.
-+ */
-+static int my_check_copy_function(Bucket* src, va_list args);
-+static int my_check_copy_default_property(Bucket* p, va_list args);
-+#ifdef ZEND_ENGINE_2
-+static int my_check_copy_property_info(Bucket* src, va_list args);
-+static int my_check_copy_static_member(Bucket* src, va_list args);
++    /*
++     * This is a bit of a hack.
++     *
++     * Here I am checking to see if the file is at least 2 seconds old.  
++     * The idea is that if the file is currently being written to then its
++     * mtime is going to match or at most be 1 second off of the current
++     * request time and we want to avoid caching files that have not been
++     * completely written.  Of course, people should be using atomic 
++     * mechanisms to push files onto live web servers, but adding this
++     * tiny safety is easier than educating the world.  This is now
++     * configurable, but the default is still 2 seconds.
++     */
++    if(APCG(file_update_protection) && (t - fileinfo.st_buf.sb.st_mtime < APCG(file_update_protection)) && !APCG(force_file_update)) {
++#ifdef __DEBUG_APC__
++        fprintf(stderr,"File is too new %s (%d - %d) - bailing\n",filename,t,fileinfo.st_buf.sb.st_mtime);
 +#endif
++        return 0;
++    }
 +
++    key->data.file.device = fileinfo.st_buf.sb.st_dev;
++    key->data.file.inode  = fileinfo.st_buf.sb.st_ino;
++    /*
++     * If working with content management systems that like to munge the mtime, 
++     * it might be appropriate to key off of the ctime to be immune to systems
++     * that try to backdate a template.  If the mtime is set to something older
++     * than the previous mtime of a template we will obviously never see this
++     * "older" template.  At some point the Smarty templating system did this.
++     * I generally disagree with using the ctime here because you lose the 
++     * ability to warm up new content by saving it to a temporary file, hitting
++     * it once to cache it and then renaming it into its permanent location so
++     * set the apc.stat_ctime=true to enable this check.
++     */
++    if(APCG(stat_ctime)) {
++        key->mtime  = (fileinfo.st_buf.sb.st_ctime > fileinfo.st_buf.sb.st_mtime) ? fileinfo.st_buf.sb.st_ctime : fileinfo.st_buf.sb.st_mtime; 
++    } else {
++        key->mtime = fileinfo.st_buf.sb.st_mtime;
++    }
++    key->type = APC_CACHE_KEY_FILE;
++    return 1;
++}
 +/* }}} */
 +
-+/* {{{ check_op_array_integrity */
-+#if 0
-+static void check_op_array_integrity(zend_op_array* src)
++/* {{{ apc_cache_make_user_key */
++int apc_cache_make_user_key(apc_cache_key_t* key, char* identifier, int identifier_len, const time_t t)
 +{
-+    int i, j;
-+
-+    /* These sorts of checks really aren't particularly effective, but they
-+     * can provide a welcome sanity check when debugging. Just don't enable
-+     * for production use!  */
++    assert(key != NULL);
 +
-+    assert(src->refcount != NULL);
-+    assert(src->opcodes != NULL);
-+    assert(src->last > 0);
++    if (!identifier)
++        return 0;
 +
-+    for (i = 0; i < src->last; i++) {
-+        zend_op* op = &src->opcodes[i];
-+        znode* nodes[] = { &op->result, &op->op1, &op->op2 };
-+        for (j = 0; j < 3; j++) {
-+            assert(nodes[j]->op_type == IS_CONST ||
-+                   nodes[j]->op_type == IS_VAR ||
-+                   nodes[j]->op_type == IS_TMP_VAR ||
-+                   nodes[j]->op_type == IS_UNUSED);
-+
-+            if (nodes[j]->op_type == IS_CONST) {
-+                int type = nodes[j]->u.constant.type;
-+                assert(type == IS_RESOURCE ||
-+                       type == IS_BOOL ||
-+                       type == IS_LONG ||
-+                       type == IS_DOUBLE ||
-+                       type == IS_NULL ||
-+                       type == IS_CONSTANT ||
-+                       type == IS_STRING ||
-+                       type == FLAG_IS_BC ||
-+                       type == IS_ARRAY ||
-+                       type == IS_CONSTANT_ARRAY ||
-+                       type == IS_OBJECT);
-+            }
-+        }
-+    }
++    key->data.user.identifier = identifier;
++    key->data.user.identifier_len = identifier_len;
++    key->mtime = t;
++    key->type = APC_CACHE_KEY_USER;
++    return 1;
 +}
-+#endif
 +/* }}} */
 +
-+/* {{{ is_derived_class */
-+static int is_derived_class(zend_op_array* op_array, const char* key, int key_size)
++/* {{{ apc_cache_make_file_entry */
++apc_cache_entry_t* apc_cache_make_file_entry(const char* filename,
++                                        zend_op_array* op_array,
++                                        apc_function_t* functions,
++                                        apc_class_t* classes,
++                                        apc_context_t* ctxt)
 +{
-+    int i;
++    apc_cache_entry_t* entry;
++    apc_pool* pool = ctxt->pool;
 +
-+    /*
-+     * Scan the op_array for execution-time class declarations of derived
-+     * classes. If we find one whose key matches our current class key, we
-+     * know the current class is a derived class.
-+     *
-+     * This check is exceedingly inefficient (fortunately it only has to occur
-+     * once, when the source file is first compiled and cached), but the
-+     * compiler should save this information for us -- definitely a candidate
-+     * for a Zend Engine patch.
-+     *
-+     * XXX checking for derived classes provides a minimal (albeit measurable)
-+     * speed up. It may not be worth the added complexity -- considere
-+     * removing this optimization.
-+     */
++    entry = (apc_cache_entry_t*) apc_pool_alloc(pool, sizeof(apc_cache_entry_t));
++    if (!entry) return NULL;
 +
-+    for (i = 0; i < op_array->last; i++) {
-+        zend_op* op = &op_array->opcodes[i];
-+
-+#ifdef ZEND_ENGINE_2        
-+        if (op->opcode == ZEND_DECLARE_CLASS &&
-+            op->extended_value == ZEND_DECLARE_INHERITED_CLASS)
-+#else            
-+        if (op->opcode == ZEND_DECLARE_FUNCTION_OR_CLASS &&
-+            op->extended_value == ZEND_DECLARE_INHERITED_CLASS)
-+#endif            
-+        {
-+            if (op->op1.u.constant.value.str.len == key_size &&
-+                !memcmp(op->op1.u.constant.value.str.val, key, key_size))
-+            {
-+                return 1;
-+            }
-+        }
++    entry->data.file.filename  = apc_pstrdup(filename, pool);
++    if(!entry->data.file.filename) {
++#ifdef __DEBUG_APC__
++        fprintf(stderr,"apc_cache_make_file_entry: entry->data.file.filename is NULL - bailing\n");
++#endif
++        return NULL;
 +    }
++#ifdef __DEBUG_APC__
++    fprintf(stderr,"apc_cache_make_file_entry: entry->data.file.filename is [%s]\n",entry->data.file.filename);
++#endif
++    entry->data.file.op_array  = op_array;
++    entry->data.file.functions = functions;
++    entry->data.file.classes   = classes;
 +
-+    return 0;
++    entry->data.file.halt_offset = apc_file_halt_offset(filename);
++
++    entry->type = APC_CACHE_ENTRY_FILE;
++    entry->ref_count = 0;
++    entry->mem_size = 0;
++    entry->pool = pool;
++    return entry;
 +}
 +/* }}} */
 +
-+/* {{{ my_bitwise_copy_function */
-+static zend_function* my_bitwise_copy_function(zend_function* dst, zend_function* src, apc_malloc_t allocate)
++/* {{{ apc_cache_store_zval */
++zval* apc_cache_store_zval(zval* dst, const zval* src, apc_context_t* ctxt)
 +{
-+    assert(src != NULL);
++    TSRMLS_FETCH();
 +
-+    if (!dst) {
-+        CHECK(dst = (zend_function*) allocate(sizeof(src[0])));
++    if (Z_TYPE_P(src) == IS_ARRAY) {
++        /* Maintain a list of zvals we've copied to properly handle recursive structures */
++        zend_hash_init(&APCG(copied_zvals), 0, NULL, NULL, 0);
++        dst = apc_copy_zval(dst, src, ctxt);
++        zend_hash_destroy(&APCG(copied_zvals));
++        APCG(copied_zvals).nTableSize=0;
++    } else {
++        dst = apc_copy_zval(dst, src, ctxt);
 +    }
 +
-+    /* We only need to do a bitwise copy */
-+    memcpy(dst, src, sizeof(src[0]));
 +
 +    return dst;
 +}
 +/* }}} */
 +
-+/* {{{ my_copy_zval_ptr */
-+static zval** my_copy_zval_ptr(zval** dst, const zval** src, apc_malloc_t allocate, apc_free_t deallocate)
++/* {{{ apc_cache_fetch_zval */
++zval* apc_cache_fetch_zval(zval* dst, const zval* src, apc_context_t* ctxt)
 +{
-+    int local_dst_alloc = 0;
-+    zval* dst_new;
-+    
-+    assert(src != NULL);
++    TSRMLS_FETCH();
 +
-+    if (!dst) {
-+        CHECK(dst = (zval**) allocate(sizeof(zval*)));
-+        local_dst_alloc = 1;
++    if (Z_TYPE_P(src) == IS_ARRAY) {
++        /* Maintain a list of zvals we've copied to properly handle recursive structures */
++        zend_hash_init(&APCG(copied_zvals), 0, NULL, NULL, 0);
++        dst = apc_copy_zval(dst, src, ctxt);
++        zend_hash_destroy(&APCG(copied_zvals));
++        APCG(copied_zvals).nTableSize=0;
++    } else {
++        dst = apc_copy_zval(dst, src, ctxt);
 +    }
 +
-+    if(!(dst[0] = (zval*) allocate(sizeof(zval)))) {
-+        if(local_dst_alloc) deallocate(dst);
-+        return NULL;
-+    }
-+    dst_new = my_copy_zval(*dst, *src, allocate, deallocate);
-+    if(dst_new != *dst) {
-+        deallocate(*dst);
-+        *dst = dst_new;
-+    }
 +
-+    (*dst)->refcount = (*src)->refcount;
-+    (*dst)->is_ref = (*src)->is_ref;
-+    
 +    return dst;
 +}
 +/* }}} */
 +
-+/* {{{ my_copy_zval */
-+static zval* my_copy_zval(zval* dst, const zval* src, apc_malloc_t allocate, apc_free_t deallocate)
++/* {{{ apc_cache_make_user_entry */
++apc_cache_entry_t* apc_cache_make_user_entry(const char* info, int info_len, const zval* val, apc_context_t* ctxt, const unsigned int ttl)
 +{
-+    zval **tmp;
-+    TSRMLS_FETCH();
-+    
-+    assert(dst != NULL);
-+    assert(src != NULL);
-+
-+    memcpy(dst, src, sizeof(src[0]));
++    apc_cache_entry_t* entry;
++    apc_pool* pool = ctxt->pool;
 +
-+    switch (src->type & ~IS_CONSTANT_INDEX) {
-+    case IS_RESOURCE:
-+    case IS_BOOL:
-+    case IS_LONG:
-+    case IS_DOUBLE:
-+    case IS_NULL:
-+        break;
++    entry = (apc_cache_entry_t*) apc_pool_alloc(pool, sizeof(apc_cache_entry_t));
++    if (!entry) return NULL;
 +
-+    case IS_CONSTANT:
-+    case IS_STRING:
-+#ifndef ZEND_ENGINE_2        
-+    case FLAG_IS_BC:
-+#endif        
-+        if (src->value.str.val) {
-+            CHECK(dst->value.str.val = apc_xmemcpy(src->value.str.val,
-+                                                   src->value.str.len+1,
-+                                                   allocate));
-+        }
-+        break;
-+    
-+    case IS_ARRAY:
++    entry->data.user.info = apc_pmemcpy(info, info_len+1, pool);
++    entry->data.user.info_len = info_len;
++    if(!entry->data.user.info) {
++        return NULL;
++    }
++    entry->data.user.val = apc_cache_store_zval(NULL, val, ctxt);
++    if(!entry->data.user.val) {
++        return NULL;
++    }
++    INIT_PZVAL(entry->data.user.val);
++    entry->data.user.ttl = ttl;
++    entry->type = APC_CACHE_ENTRY_USER;
++    entry->ref_count = 0;
++    entry->mem_size = 0;
++    entry->pool = pool;
++    return entry;
++}
++/* }}} */
 +
-+        if(APCG(copied_zvals)) {
-+            if(zend_hash_index_find(APCG(copied_zvals), (ulong)src, (void**)&tmp) == SUCCESS) {
-+                (*tmp)->refcount++;
-+                return *tmp;
-+            }
-+        
-+            zend_hash_index_update(APCG(copied_zvals), (ulong)src, (void**)&dst, sizeof(zval*), NULL);
-+        }
-+        /* fall through */
-+ 
-+    case IS_CONSTANT_ARRAY:
++/* {{{ apc_cache_info */
++apc_cache_info_t* apc_cache_info(apc_cache_t* cache, zend_bool limited)
++{
++    apc_cache_info_t* info;
++    slot_t* p;
++    int i;
 +
-+        CHECK(dst->value.ht =
-+            my_copy_hashtable(NULL,
-+                              src->value.ht,
-+                              (ht_copy_fun_t) my_copy_zval_ptr,
-+                              (ht_free_fun_t) my_free_zval_ptr,
-+                              1,
-+                              allocate, deallocate));
-+        break;
++      TSRMLS_FETCH();
 +
-+    case IS_OBJECT:
-+#ifndef ZEND_ENGINE_2        
-+        CHECK(dst->value.obj.ce =
-+            my_copy_class_entry(NULL, src->value.obj.ce, allocate, deallocate));
++    if(!cache) return NULL;
 +
-+        if(!(dst->value.obj.properties = my_copy_hashtable(NULL,
-+                              src->value.obj.properties,
-+                              (ht_copy_fun_t) my_copy_zval_ptr,
-+                              (ht_free_fun_t) my_free_zval_ptr,
-+                              1,
-+                              allocate, deallocate))) {
-+            my_destroy_class_entry(dst->value.obj.ce, deallocate);
-+            return NULL;
-+        }
-+        break;
-+#else
-+      dst->type = IS_NULL;
-+#endif        
-+        break;
++    CACHE_LOCK(cache);
 +
-+    default:
-+        assert(0);
++    info = (apc_cache_info_t*) apc_emalloc(sizeof(apc_cache_info_t));
++    if(!info) {
++        CACHE_UNLOCK(cache);
++        return NULL;
 +    }
++    info->num_slots = cache->num_slots;
++    info->ttl = cache->ttl;
++    info->num_hits = cache->header->num_hits;
++    info->num_misses = cache->header->num_misses;
++    info->list = NULL;
++    info->deleted_list = NULL;
++    info->start_time = cache->header->start_time;
++    info->expunges = cache->header->expunges;
++    info->mem_size = cache->header->mem_size;
++    info->num_entries = cache->header->num_entries;
++    info->num_inserts = cache->header->num_inserts;
 +
-+    return dst;
-+}
-+/* }}} */
-+
-+/* {{{ my_copy_znode */
-+static znode* my_copy_znode(znode* dst, znode* src, apc_malloc_t allocate, apc_free_t deallocate)
-+{
-+    assert(dst != NULL);
-+    assert(src != NULL);
++    if(!limited) {
++        /* For each hashtable slot */
++        for (i = 0; i < info->num_slots; i++) {
++            p = cache->slots[i];
++            for (; p != NULL; p = p->next) {
++                apc_cache_link_t* link = (apc_cache_link_t*) apc_emalloc(sizeof(apc_cache_link_t));
 +
-+    memcpy(dst, src, sizeof(src[0]));
++                if(p->value->type == APC_CACHE_ENTRY_FILE) {
++                    if(p->key.type == APC_CACHE_KEY_FILE) {
++                        link->data.file.device = p->key.data.file.device;
++                        link->data.file.inode = p->key.data.file.inode;
++                        link->data.file.filename = apc_xstrdup(p->value->data.file.filename, apc_emalloc);
++                    } else { /* This is a no-stat fullpath file entry */
++                        link->data.file.device = 0;
++                        link->data.file.inode = 0;
++                        link->data.file.filename = apc_xstrdup(p->key.data.fpfile.fullpath, apc_emalloc);
++                    }
++                    link->type = APC_CACHE_ENTRY_FILE;
++                    if (APCG(file_md5)) {
++                      link->data.file.md5 = emalloc(sizeof(p->key.md5));
++                      memcpy(link->data.file.md5, p->key.md5, 16);
++                    } else {
++                      link->data.file.md5 = NULL;
++                    }
++                } else if(p->value->type == APC_CACHE_ENTRY_USER) {
++                    link->data.user.info = apc_xmemcpy(p->value->data.user.info, p->value->data.user.info_len+1, apc_emalloc);
++                    link->data.user.ttl = p->value->data.user.ttl;
++                    link->type = APC_CACHE_ENTRY_USER;
++                }
++                link->num_hits = p->num_hits;
++                link->mtime = p->key.mtime;
++                link->creation_time = p->creation_time;
++                link->deletion_time = p->deletion_time;
++                link->access_time = p->access_time;
++                link->ref_count = p->value->ref_count;
++                link->mem_size = p->value->mem_size;
++                link->next = info->list;
++                info->list = link;
++            }
++        }
 +
-+#ifdef IS_CV
-+    assert(dst ->op_type == IS_CONST ||
-+           dst ->op_type == IS_VAR ||
-+           dst ->op_type == IS_CV ||
-+           dst ->op_type == IS_TMP_VAR ||
-+           dst ->op_type == IS_UNUSED);
-+#else
-+    assert(dst ->op_type == IS_CONST ||
-+           dst ->op_type == IS_VAR ||
-+           dst ->op_type == IS_TMP_VAR ||
-+           dst ->op_type == IS_UNUSED);
-+#endif
++        /* For each slot pending deletion */
++        for (p = cache->header->deleted_list; p != NULL; p = p->next) {
++            apc_cache_link_t* link = (apc_cache_link_t*) apc_emalloc(sizeof(apc_cache_link_t));
 +
-+    if (src->op_type == IS_CONST) {
-+        if(!my_copy_zval(&dst->u.constant, &src->u.constant, allocate, deallocate)) {
-+            return NULL;
++            if(p->value->type == APC_CACHE_ENTRY_FILE) {
++                if(p->key.type == APC_CACHE_KEY_FILE) {
++                    link->data.file.device = p->key.data.file.device;
++                    link->data.file.inode = p->key.data.file.inode;
++                    link->data.file.filename = apc_xstrdup(p->value->data.file.filename, apc_emalloc);
++                } else { /* This is a no-stat fullpath file entry */
++                    link->data.file.device = 0;
++                    link->data.file.inode = 0;
++                    link->data.file.filename = apc_xstrdup(p->key.data.fpfile.fullpath, apc_emalloc);
++                }
++                link->type = APC_CACHE_ENTRY_FILE;
++                if (APCG(file_md5)) {
++                  link->data.file.md5 = emalloc(sizeof(p->key.md5));
++                  memcpy(link->data.file.md5, p->key.md5, 16);
++                } else {
++                  link->data.file.md5 = NULL;
++                }
++            } else if(p->value->type == APC_CACHE_ENTRY_USER) {
++                link->data.user.info = apc_xmemcpy(p->value->data.user.info, p->value->data.user.info_len+1, apc_emalloc);
++                link->data.user.ttl = p->value->data.user.ttl;
++                link->type = APC_CACHE_ENTRY_USER;
++            }
++            link->num_hits = p->num_hits;
++            link->mtime = p->key.mtime;
++            link->creation_time = p->creation_time;
++            link->deletion_time = p->deletion_time;
++            link->access_time = p->access_time;
++            link->ref_count = p->value->ref_count;
++            link->mem_size = p->value->mem_size;
++            link->next = info->deleted_list;
++            info->deleted_list = link;
 +        }
 +    }
 +
-+    return dst;
++    CACHE_UNLOCK(cache);
++    return info;
 +}
 +/* }}} */
 +
-+/* {{{ my_copy_zend_op */
-+static zend_op* my_copy_zend_op(zend_op* dst, zend_op* src, apc_malloc_t allocate, apc_free_t deallocate)
++/* {{{ apc_cache_free_info */
++void apc_cache_free_info(apc_cache_info_t* info)
 +{
-+    assert(dst != NULL);
-+    assert(src != NULL);
-+
-+    memcpy(dst, src, sizeof(src[0]));
-+
-+    if( my_copy_znode(&dst->result, &src->result, allocate, deallocate) == NULL 
-+            || my_copy_znode(&dst->op1, &src->op1, allocate, deallocate) == NULL
-+            || my_copy_znode(&dst->op2, &src->op2, allocate, deallocate) == NULL)
-+    {
-+        return NULL;
++    apc_cache_link_t* p = info->list;
++    apc_cache_link_t* q = NULL;
++    while (p != NULL) {
++        q = p;
++        p = p->next;
++        if(q->type == APC_CACHE_ENTRY_FILE) {
++            if(q->data.file.md5) {
++                efree(q->data.file.md5);
++            }
++            apc_efree(q->data.file.filename);
++        }
++        else if(q->type == APC_CACHE_ENTRY_USER) apc_efree(q->data.user.info);
++        apc_efree(q);
 +    }
-+
-+    return dst;
++    p = info->deleted_list;
++    while (p != NULL) {
++        q = p;
++        p = p->next;
++        if(q->type == APC_CACHE_ENTRY_FILE) {
++            if(q->data.file.md5) {
++                efree(q->data.file.md5);
++            }
++            apc_efree(q->data.file.filename);
++        }
++        else if(q->type == APC_CACHE_ENTRY_USER) apc_efree(q->data.user.info);
++        apc_efree(q);
++    }
++    apc_efree(info);
 +}
 +/* }}} */
 +
-+/* {{{ my_copy_function */
-+static zend_function* my_copy_function(zend_function* dst, zend_function* src, apc_malloc_t allocate, apc_free_t deallocate)
++/* {{{ apc_cache_unlock */
++void apc_cache_unlock(apc_cache_t* cache)
 +{
-+    int local_dst_alloc = 0;
-+      TSRMLS_FETCH();
-+
-+    assert(src != NULL);
-+
-+    if(!dst) local_dst_alloc = 1;
-+    CHECK(dst = my_bitwise_copy_function(dst, src, allocate));
-+
-+    switch (src->type) {
-+    case ZEND_INTERNAL_FUNCTION:
-+    case ZEND_OVERLOADED_FUNCTION:
-+        /* shallow copy because op_array is internal */
-+        dst->op_array = src->op_array;
-+        break;
-+        
-+    case ZEND_USER_FUNCTION:
-+    case ZEND_EVAL_CODE:
-+        if(!apc_copy_op_array(&dst->op_array,
-+                                &src->op_array,
-+                                allocate, deallocate TSRMLS_CC)) {
-+            if(local_dst_alloc) deallocate(dst);
-+            return NULL;
-+        }
-+        break;
-+
-+    default:
-+        assert(0);
-+    }
-+#ifdef ZEND_ENGINE_2
-+    /* 
-+     * op_array bitwise copying overwrites what ever you modified
-+     * before apc_copy_op_array - which is why this code is outside 
-+     * my_bitwise_copy_function. 
-+     */
-+
-+    /* zend_do_inheritance will re-look this up, because the pointers
-+     * in prototype are from a function table of another class. It just
-+     * helps if that one is from EG(class_table).
-+     */
-+    dst->common.prototype = NULL; 
-+
-+    /* once a method is marked as ZEND_ACC_IMPLEMENTED_ABSTRACT then you
-+     * have to carry around a prototype. Thankfully zend_do_inheritance
-+     * sets this properly as well
-+     */
-+    dst->common.fn_flags = src->common.fn_flags & (~ZEND_ACC_IMPLEMENTED_ABSTRACT);
-+#endif
-+
-+
-+    return dst;
++    CACHE_UNLOCK(cache);
 +}
 +/* }}} */
 +
-+/* {{{ my_copy_function_entry */
-+static zend_function_entry* my_copy_function_entry(zend_function_entry* dst, zend_function_entry* src, apc_malloc_t allocate, apc_free_t deallocate)
++/* {{{ apc_cache_busy */
++zend_bool apc_cache_busy(apc_cache_t* cache)
 +{
-+    int local_dst_alloc = 0;
-+    assert(src != NULL);
-+
-+    if (!dst) {
-+        CHECK(dst = (zend_function_entry*) allocate(sizeof(src[0])));
-+        local_dst_alloc = 1;
-+    }
-+
-+    /* Start with a bitwise copy */
-+    memcpy(dst, src, sizeof(src[0]));
-+
-+    dst->fname = NULL;
-+#ifdef ZEND_ENGINE_2
-+    dst->arg_info = NULL;
-+#else
-+    dst->func_arg_types = NULL;
-+#endif
-+
-+    if (src->fname) {
-+        if(!(dst->fname = apc_xstrdup(src->fname, allocate))) {
-+            goto cleanup;
-+        }
-+    }
-+
-+#ifdef ZEND_ENGINE_2    
-+    if (src->arg_info) {
-+        if(!(dst->arg_info = my_copy_arg_info_array(NULL,
-+                                                src->arg_info,
-+                                                src->num_args,
-+                                                allocate,
-+                                                deallocate))) {
-+            goto cleanup;
-+        }
-+    }
-+#else    
-+    if (src->func_arg_types) {
-+        if(!(dst->func_arg_types = apc_xmemcpy(src->func_arg_types,
-+                                                src->func_arg_types[0]+1,
-+                                                allocate))) {
-+            goto cleanup;
-+        }
-+    }
-+#endif
-+
-+    return dst;
-+
-+cleanup:
-+    if(dst->fname) deallocate(dst->fname);
-+    if(local_dst_alloc) deallocate(dst);
-+    return NULL;
++    return cache->header->busy;
 +}
 +/* }}} */
 +
-+#ifdef ZEND_ENGINE_2
-+/* {{{ my_copy_property_info */
-+static zend_property_info* my_copy_property_info(zend_property_info* dst, zend_property_info* src, apc_malloc_t allocate, apc_free_t deallocate)
++/* {{{ apc_cache_is_last_key */
++zend_bool apc_cache_is_last_key(apc_cache_t* cache, apc_cache_key_t* key, time_t t)
 +{
-+    int local_dst_alloc = 0;
-+    
-+    assert(src != NULL);
-+
-+    if (!dst) {
-+        CHECK(dst = (zend_property_info*) allocate(sizeof(*src)));
-+        local_dst_alloc = 1;
-+    }
-+
-+    /* Start with a bitwise copy */
-+    memcpy(dst, src, sizeof(*src));
-+
-+    dst->name = NULL;
-+#if defined(ZEND_ENGINE_2) && PHP_MINOR_VERSION > 0
-+    dst->doc_comment = NULL;
-+#endif
-+
-+    if (src->name) {
-+        /* private members are stored inside property_info as a mangled
-+         * string of the form:
-+         *      \0<classname>\0<membername>\0
-+         */
-+        if(!(dst->name = 
-+                    apc_xmemcpy(src->name, src->name_length+1, allocate))) {
-+            goto cleanup;
-+        }
-+    }
-+
-+#if defined(ZEND_ENGINE_2) && PHP_MINOR_VERSION > 0
-+    if (src->doc_comment) {
-+        if( !(dst->doc_comment =
-+                    apc_xmemcpy(src->doc_comment, src->doc_comment_len+1, allocate))) {
-+            goto cleanup;
++    apc_keyid_t *lastkey = &cache->header->lastkey;
++    unsigned int keylen = key->data.user.identifier_len+1;
++    unsigned int h = string_nhash_8(key->data.user.identifier, keylen);
++
++    /* unlocked reads, but we're not shooting for 100% success with this */
++    if(lastkey->h == h && keylen == lastkey->keylen) {
++        if(lastkey->mtime == t) {
++            /* potential cache slam */
++            apc_wprint("Potential cache slam averted for key '%s'", key->data.user.identifier);
++            return 1;
 +        }
 +    }
-+#endif
-+
-+    return dst;
 +
-+cleanup:
-+    if(dst->name) deallocate(dst->name);
-+#if defined(ZEND_ENGINE_2) && PHP_MINOR_VERSION > 0
-+    if(dst->doc_comment) deallocate(dst->doc_comment);
-+#endif
-+    if(local_dst_alloc) deallocate(dst);
-+    return NULL;
++    return 0;
 +}
 +/* }}} */
 +
-+/* {{{ my_copy_property_info_for_execution */
-+static zend_property_info* my_copy_property_info_for_execution(zend_property_info* dst, zend_property_info* src, apc_malloc_t allocate, apc_free_t deallocate)
++#if NONBLOCKING_LOCK_AVAILABLE
++/* {{{ apc_cache_write_lock */
++zend_bool apc_cache_write_lock(apc_cache_t* cache)
 +{
-+    int local_dst_alloc = 0;
-+    
-+    assert(src != NULL);
-+
-+    if (!dst) {
-+        CHECK(dst = (zend_property_info*) allocate(sizeof(*src)));
-+        local_dst_alloc = 1;
-+    }
-+
-+    /* We need only a shallow copy */
-+    memcpy(dst, src, sizeof(*src));
-+
-+    return dst;
++    return apc_lck_nb_lock(cache->header->wrlock);
 +}
 +/* }}} */
 +
-+/* {{{ my_copy_arg_info_array */
-+static zend_arg_info* my_copy_arg_info_array(zend_arg_info* dst, zend_arg_info* src, uint num_args, apc_malloc_t allocate, apc_free_t deallocate)
++/* {{{ apc_cache_write_unlock */
++void apc_cache_write_unlock(apc_cache_t* cache)
 +{
-+    int local_dst_alloc = 0;
-+    int i = 0;
-+
-+    
-+    if (!dst) {
-+        CHECK(dst = (zend_arg_info*) allocate(sizeof(*src)*num_args));
-+        local_dst_alloc = 1;
-+    }
-+
-+    /* Start with a bitwise copy */
-+    memcpy(dst, src, sizeof(*src)*num_args);
-+
-+    for(i=0; i < num_args; i++) {
-+        if(!(my_copy_arg_info( &dst[i], &src[i], allocate, deallocate))) {            
-+            if(i) my_destroy_arg_info_array(dst, i-1, deallocate);
-+            if(local_dst_alloc) deallocate(dst);
-+            return NULL;
-+        }
-+    }
-+
-+    return dst;    
++    apc_lck_unlock(cache->header->wrlock);
 +}
 +/* }}} */
++#endif
 +
-+/* {{{ my_copy_arg_info */
-+static zend_arg_info* my_copy_arg_info(zend_arg_info* dst, zend_arg_info* src, apc_malloc_t allocate, apc_free_t deallocate)
-+{
-+    int local_dst_alloc = 0;
-+    
-+    assert(src != NULL);
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * End:
++ * vim>600: expandtab sw=4 ts=4 sts=4 fdm=marker
++ * vim<600: expandtab sw=4 ts=4 sts=4
++ */
+diff -Naur php-5.3.1.orig/ext/apc/apc_cache.h php-5.3.1/ext/apc/apc_cache.h
+--- php-5.3.1.orig/ext/apc/apc_cache.h 1970-01-01 01:00:00.000000000 +0100
++++ php-5.3.1/ext/apc/apc_cache.h      1970-01-01 10:13:08.000000000 +0100
+@@ -0,0 +1,378 @@
++/*
++  +----------------------------------------------------------------------+
++  | APC                                                                  |
++  +----------------------------------------------------------------------+
++  | Copyright (c) 2006-2008 The PHP Group                                |
++  +----------------------------------------------------------------------+
++  | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt.                                 |
++  | If you did not receive a copy of the PHP license and are unable to   |
++  | obtain it through the world-wide-web, please send a note to          |
++  | license@php.net so we can mail you a copy immediately.               |
++  +----------------------------------------------------------------------+
++  | Authors: Daniel Cowgill <dcowgill@communityconnect.com>              |
++  |          Rasmus Lerdorf <rasmus@php.net>                             |
++  +----------------------------------------------------------------------+
 +
-+    if (!dst) {
-+        CHECK(dst = (zend_arg_info*) allocate(sizeof(*src)));
-+        local_dst_alloc = 1;
-+    }
++   This software was contributed to PHP by Community Connect Inc. in 2002
++   and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
++   Future revisions and derivatives of this source code must acknowledge
++   Community Connect Inc. as the original contributor of this module by
++   leaving this note intact in the source code.
 +
-+    /* Start with a bitwise copy */
-+    memcpy(dst, src, sizeof(*src));
++   All other licensing and usage conditions are those of the PHP Group.
 +
-+    dst->name = NULL;
-+    dst->class_name = NULL;
++ */
 +
-+    if (src->name) {
-+        if(!(dst->name = 
-+                    apc_xmemcpy(src->name, src->name_len+1, allocate))) {
-+            goto cleanup;
-+        }
-+    }
++/* $Id: apc_cache.h 281919 2009-06-10 11:23:55Z gopalv $ */
 +
-+    if (src->class_name) {
-+        if(!(dst->class_name = 
-+                    apc_xmemcpy(src->class_name, src->class_name_len+1, allocate))) {
-+            goto cleanup;
-+        }
-+    }
++#ifndef APC_CACHE_H
++#define APC_CACHE_H
 +
-+    return dst;
++/*
++ * This module defines the shared memory file cache. Basically all of the
++ * logic for storing and retrieving cache entries lives here.
++ */
 +
-+cleanup:
-+    if(dst->name) deallocate(dst->name);
-+    if(dst->class_name) deallocate(dst->name);
-+    if(local_dst_alloc) deallocate(dst);
-+    return NULL;
-+}
-+/* }}} */
-+#endif
++#include "apc.h"
++#include "apc_compile.h"
++#include "apc_lock.h"
++#include "apc_pool.h"
++#include "apc_main.h"
 +
-+/* {{{ my_copy_class_entry */
-+static zend_class_entry* my_copy_class_entry(zend_class_entry* dst, zend_class_entry* src, apc_malloc_t allocate, apc_free_t deallocate)
-+{
-+    int local_dst_alloc = 0;
-+    int i = 0;
++#define APC_CACHE_ENTRY_FILE   1
++#define APC_CACHE_ENTRY_USER   2
 +
-+    assert(src != NULL);
++#define APC_CACHE_KEY_FILE     1
++#define APC_CACHE_KEY_USER     2
++#define APC_CACHE_KEY_FPFILE   3
 +
-+    if (!dst) {
-+        CHECK(dst = (zend_class_entry*) allocate(sizeof(*src)));
-+        local_dst_alloc = 1;
-+    }
++/* {{{ cache locking macros */
++#define CACHE_LOCK(cache)        { LOCK(cache->header->lock);   cache->has_lock = 1; }
++#define CACHE_UNLOCK(cache)      { UNLOCK(cache->header->lock); cache->has_lock = 0; }
++#define CACHE_SAFE_LOCK(cache)   { if ((++cache->has_lock) == 1) LOCK(cache->header->lock); }
++#define CACHE_SAFE_UNLOCK(cache) { if ((--cache->has_lock) == 0) UNLOCK(cache->header->lock); }
++/* }}} */
 +
-+    /* Start with a bitwise copy */
-+    memcpy(dst, src, sizeof(*src));
++/* {{{ struct definition: apc_cache_key_t */
++#define T apc_cache_t*
++typedef struct apc_cache_t apc_cache_t; /* opaque cache type */
 +
-+    dst->name = NULL;
-+    dst->builtin_functions = NULL;
-+    memset(&dst->function_table, 0, sizeof(dst->function_table));
-+    memset(&dst->default_properties, 0, sizeof(dst->default_properties));
-+#ifndef ZEND_ENGINE_2
-+    dst->refcount = NULL;
-+#else
-+    dst->static_members = NULL;
-+    dst->doc_comment = NULL;
-+    dst->filename = NULL;
-+    memset(&dst->properties_info, 0, sizeof(dst->properties_info));
-+    memset(&dst->constants_table, 0, sizeof(dst->constants_table));
-+    memset(&dst->default_static_members, 0, sizeof(dst->default_static_members));
-+#endif
-+
-+    if (src->name) {
-+        if(!(dst->name = apc_xstrdup(src->name, allocate))) {
-+            goto cleanup;
-+        }
-+    }
-+
-+#ifndef ZEND_ENGINE_2    
-+    if(!(dst->refcount = apc_xmemcpy(src->refcount,
-+                                      sizeof(src->refcount[0]),
-+                                      allocate))) {
-+        goto cleanup;
-+    }
-+#endif        
++typedef union _apc_cache_key_data_t {
++    struct {
++        dev_t device;             /* the filesystem device */
++        ino_t inode;              /* the filesystem inode */
++    } file;
++    struct {
++        const char *identifier;
++        int identifier_len;
++    } user;
++    struct {
++        const char *fullpath;
++        int fullpath_len;
++    } fpfile;
++} apc_cache_key_data_t;
 +
-+    if(!(my_copy_hashtable_ex(&dst->function_table,
-+                            &src->function_table,
-+                            (ht_copy_fun_t) my_copy_function,
-+                            (ht_free_fun_t) my_free_function,
-+                            0,
-+                            allocate, deallocate,
-+                            (ht_check_copy_fun_t) my_check_copy_function,
-+                            src))) {
-+        goto cleanup;
-+    }
++typedef struct apc_cache_key_t apc_cache_key_t;
++struct apc_cache_key_t {
++    apc_cache_key_data_t data;
++    time_t mtime;                 /* the mtime of this cached entry */
++    unsigned char type;
++    unsigned char md5[16];        /* md5 hash of the source file */
++};
 +
-+#ifdef ZEND_ENGINE_2
 +
-+    /* the interfaces are populated at runtime using ADD_INTERFACE */
-+    dst->interfaces = NULL; 
++typedef struct apc_keyid_t apc_keyid_t;
 +
-+    /* the current count includes inherited interfaces as well,
-+       the real dynamic ones are the first <n> which are zero'd
-+       out in zend_do_end_class_declaration */
-+    for(i = 0 ; i < src->num_interfaces ; i++) {
-+        if(src->interfaces[i])
-+        {
-+            dst->num_interfaces = i;
-+            break;
-+        }
-+    }
++struct apc_keyid_t {
++    unsigned int h;
++    unsigned int keylen;
++    time_t mtime;
++};
++/* }}} */
 +
-+    /* these will either be set inside my_fixup_hashtable or 
-+     * they will be copied out from parent inside zend_do_inheritance 
-+     */
-+    dst->constructor =  NULL;
-+    dst->destructor = NULL;
-+    dst->clone = NULL;
-+    dst->__get = NULL;
-+    dst->__set = NULL;
-+    dst->__unset = NULL;
-+    dst->__isset = NULL;
-+    dst->__call = NULL;
-+#ifdef ZEND_ENGINE_2_2
-+    dst->__tostring = NULL;
-+#endif
++/* {{{ struct definition: apc_cache_entry_t */
++typedef union _apc_cache_entry_value_t {
++    struct {
++        char *filename;             /* absolute path to source file */
++        zend_op_array* op_array;    /* op_array allocated in shared memory */
++        apc_function_t* functions;  /* array of apc_function_t's */
++        apc_class_t* classes;       /* array of apc_class_t's */
++        long halt_offset;           /* value of __COMPILER_HALT_OFFSET__ for the file */
++    } file;
++    struct {
++        char *info;
++        int info_len;
++        zval *val;
++        unsigned int ttl;
++    } user;
++} apc_cache_entry_value_t;
 +
-+    /* unset function proxies */
-+    dst->serialize_func = NULL;
-+    dst->unserialize_func = NULL;
-+    
-+    my_fixup_hashtable(&dst->function_table, (ht_fixup_fun_t)my_fixup_function, src, dst);
-+#endif
++typedef struct apc_cache_entry_t apc_cache_entry_t;
++struct apc_cache_entry_t {
++    apc_cache_entry_value_t data;
++    unsigned char type;
++    int ref_count;
++    size_t mem_size;
++    apc_pool *pool;
++};
++/* }}} */
 +
-+    if(!(my_copy_hashtable_ex(&dst->default_properties,
-+                            &src->default_properties,
-+                            (ht_copy_fun_t) my_copy_zval_ptr,
-+                            (ht_free_fun_t) my_free_zval_ptr,
-+                            1,
-+                            allocate,deallocate,
-+                            (ht_check_copy_fun_t) my_check_copy_default_property,
-+                            src))) {
-+        goto cleanup;
-+    }
++/*
++ * apc_cache_create creates the shared memory compiler cache. This function
++ * should be called just once (ideally in the web server parent process, e.g.
++ * in apache), otherwise you will end up with multiple caches (which won't
++ * necessarily break anything). Returns a pointer to the cache object.
++ *
++ * size_hint is a "hint" at the total number of source files that will be
++ * cached. It determines the physical size of the hash table. Passing 0 for
++ * this argument will use a reasonable default value.
++ *
++ * gc_ttl is the maximum time a cache entry may speed on the garbage
++ * collection list. This is basically a work around for the inherent
++ * unreliability of our reference counting mechanism (see apc_cache_release).
++ *
++ * ttl is the maximum time a cache entry can idle in a slot in case the slot
++ * is needed.  This helps in cleaning up the cache and ensuring that entries 
++ * hit frequently stay cached and ones not hit very often eventually disappear.
++ */
++extern T apc_cache_create(int size_hint, int gc_ttl, int ttl);
 +
-+#ifdef ZEND_ENGINE_2
-+    
-+    if(!(my_copy_hashtable_ex(&dst->properties_info,
-+                            &src->properties_info,
-+                            (ht_copy_fun_t) my_copy_property_info,
-+                            (ht_free_fun_t) my_free_property_info,
-+                            0,
-+                            allocate, deallocate,
-+                            (ht_check_copy_fun_t) my_check_copy_property_info,
-+                            src))) {
-+        goto cleanup;
-+    }
++/*
++ * apc_cache_destroy releases any OS resources associated with a cache object.
++ * Under apache, this function can be safely called by the child processes
++ * when they exit.
++ */
++extern void apc_cache_destroy(T cache);
 +
-+#ifdef ZEND_ENGINE_2_2
-+    /* php5.2 introduced a scope attribute for property info */
-+    my_fixup_hashtable(&dst->properties_info, (ht_fixup_fun_t)my_fixup_property_info_for_execution, src, dst);
-+#endif
-+    
-+    if(!my_copy_hashtable_ex(&dst->default_static_members,
-+                            &src->default_static_members,
-+                            (ht_copy_fun_t) my_copy_zval_ptr,
-+                            (ht_free_fun_t) my_free_zval_ptr,
-+                            1,
-+                            allocate, deallocate,
-+                            (ht_check_copy_fun_t) my_check_copy_static_member,
-+                            src,
-+                            &src->default_static_members)) {
-+        goto cleanup;
-+    }
-+    if(src->static_members != &src->default_static_members)
-+    {
-+        if(!(dst->static_members = my_copy_hashtable_ex(NULL,
-+                            src->static_members,
-+                            (ht_copy_fun_t) my_copy_zval_ptr,
-+                            (ht_free_fun_t) my_free_zval_ptr,
-+                            1,
-+                            allocate, deallocate,
-+                            (ht_check_copy_fun_t) my_check_copy_static_member,
-+                            src,
-+                            src->static_members))) {
-+            goto cleanup;
-+        }
-+    }
-+    else
-+    {
-+        dst->static_members = &dst->default_static_members;
-+    }
++/*
++ * apc_cache_clear empties a cache. This can safely be called at any time,
++ * even while other server processes are executing cached source files.
++ */
++extern void apc_cache_clear(T cache);
 +
-+    if(!(my_copy_hashtable(&dst->constants_table,
-+                            &src->constants_table,
-+                            (ht_copy_fun_t) my_copy_zval_ptr,
-+                            (ht_free_fun_t) my_free_zval_ptr,
-+                            1,
-+                            allocate, deallocate))) {
-+        goto cleanup;
-+    }
++/*
++ * apc_cache_insert adds an entry to the cache, using a filename as a key.
++ * Internally, the filename is translated to a canonical representation, so
++ * that relative and absolute filenames will map to a single key. Returns
++ * non-zero if the file was successfully inserted, 0 otherwise. If 0 is
++ * returned, the caller must free the cache entry by calling
++ * apc_cache_free_entry (see below).
++ *
++ * key is the value created by apc_cache_make_file_key for file keys.
++ *
++ * value is a cache entry returned by apc_cache_make_entry (see below).
++ */
++extern int apc_cache_insert(T cache, apc_cache_key_t key,
++                            apc_cache_entry_t* value, apc_context_t* ctxt, time_t t);
 +
-+    if (src->doc_comment) {
-+        if(!(dst->doc_comment =
-+                    apc_xmemcpy(src->doc_comment, src->doc_comment_len+1, allocate))) {
-+            goto cleanup;
-+        }
-+    }
-+#endif
-+    
-+    if (src->builtin_functions) {
-+        int i, n;
++extern int apc_cache_user_insert(T cache, apc_cache_key_t key,
++                            apc_cache_entry_t* value, apc_context_t* ctxt, time_t t, int exclusive TSRMLS_DC);
 +
-+        for (n = 0; src->type == ZEND_INTERNAL_CLASS && src->builtin_functions[n].fname != NULL; n++) {}
++extern int *apc_cache_insert_mult(apc_cache_t* cache, apc_cache_key_t* keys,
++                            apc_cache_entry_t** values, apc_context_t *ctxt, time_t t, int num_entries);
 +
-+        if(!(dst->builtin_functions =
-+            (zend_function_entry*)
-+                allocate((n + 1) * sizeof(zend_function_entry)))) {
-+            goto cleanup;
-+        }
++/*
++ * apc_cache_find searches for a cache entry by filename, and returns a
++ * pointer to the entry if found, NULL otherwise.
++ *
++ * key is a value created by apc_cache_make_file_key for file keys.
++ */
++extern apc_cache_entry_t* apc_cache_find(T cache, apc_cache_key_t key, time_t t);
 +
++/*
++ * apc_cache_user_find searches for a cache entry by its hashed identifier,
++ * and returns a pointer to the entry if found, NULL otherwise.
++ *
++ */
++extern apc_cache_entry_t* apc_cache_user_find(T cache, char* strkey, int keylen, time_t t);
 +
-+        for (i = 0; i < n; i++) {
-+            if(!my_copy_function_entry(&dst->builtin_functions[i],
-+                                   &src->builtin_functions[i],
-+                                   allocate, deallocate)) {
-+                int ii;
++/*
++ * apc_cache_delete and apc_cache_user_delete finds an entry in the cache and deletes it.
++ */
++extern int apc_cache_delete(apc_cache_t* cache, char *filename, int filename_len);
++extern int apc_cache_user_delete(apc_cache_t* cache, char *strkey, int keylen);
 +
-+                for(ii=i-1; i>=0; i--) my_destroy_function_entry(&dst->builtin_functions[ii], deallocate);
-+                goto cleanup;
-+            }
-+        }
-+        dst->builtin_functions[n].fname = NULL;
-+    }
++/* apc_cach_fetch_zval takes a zval in the cache and reconstructs a runtime
++ * zval from it.
++ *
++ */
++zval* apc_cache_fetch_zval(zval* dst, const zval* src, apc_context_t* ctxt);
 +
-+#ifdef ZEND_ENGINE_2
-+    if (src->filename) {
-+        if(!(dst->filename = apc_xstrdup(src->filename, allocate))) {
-+            goto cleanup;
-+        }
-+    }
-+#endif
-+   
-+    return dst;
++/*
++ * apc_cache_release decrements the reference count associated with a cache
++ * entry. Calling apc_cache_find automatically increments the reference count,
++ * and this function must be called post-execution to return the count to its
++ * original value. Failing to do so will prevent the entry from being
++ * garbage-collected.
++ *
++ * entry is the cache entry whose ref count you want to decrement.
++ */
++extern void apc_cache_release(T cache, apc_cache_entry_t* entry);
 +
++/*
++ * apc_cache_make_file_key creates a key object given a relative or absolute
++ * filename and an optional list of auxillary paths to search. include_path is
++ * searched if the filename cannot be found relative to the current working
++ * directory.
++ *
++ * key points to caller-allocated storage (must not be null).
++ *
++ * filename is the path to the source file.
++ *
++ * include_path is a colon-separated list of directories to search.
++ *
++ * and finally we pass in the current request time so we can avoid
++ * caching files with a current mtime which tends to indicate that
++ * they are still being written to.
++ */
++extern int apc_cache_make_file_key(apc_cache_key_t* key,
++                                   const char* filename,
++                                   const char* include_path,
++                                   time_t t
++                                   TSRMLS_DC);
 +
-+cleanup:
-+    if(dst->name) deallocate(dst->name);
-+#ifdef ZEND_ENGINE_2
-+    if(dst->doc_comment) deallocate(dst->doc_comment);
-+    if(dst->filename) deallocate(dst->filename);
-+#else
-+    if(dst->refcount) deallocate(dst->refcount);
-+#endif
-+    
-+    if(dst->builtin_functions) deallocate(dst->builtin_functions);
-+    if(dst->function_table.arBuckets) my_destroy_hashtable(&dst->function_table, (ht_free_fun_t) my_free_function, deallocate);
-+    if(dst->default_properties.arBuckets) my_destroy_hashtable(&dst->default_properties, (ht_free_fun_t) my_free_zval_ptr, deallocate);
++/*
++ * apc_cache_make_file_entry creates an apc_cache_entry_t object given a filename
++ * and the compilation results returned by the PHP compiler.
++ */
++extern apc_cache_entry_t* apc_cache_make_file_entry(const char* filename,
++                                                    zend_op_array* op_array,
++                                                    apc_function_t* functions,
++                                                    apc_class_t* classes,
++                                                    apc_context_t* ctxt);
 +
-+#ifdef ZEND_ENGINE_2
-+    if(dst->properties_info.arBuckets) my_destroy_hashtable(&dst->properties_info, (ht_free_fun_t) my_free_property_info, deallocate);
-+    if(dst->default_static_members.arBuckets)
-+    {
-+        my_destroy_hashtable(&dst->default_static_members, (ht_free_fun_t) my_free_zval_ptr, deallocate);
-+    }
-+    if(dst->static_members && dst->static_members != &(dst->default_static_members))
-+    {
-+        my_destroy_hashtable(dst->static_members, (ht_free_fun_t) my_free_zval_ptr, deallocate);
-+        deallocate(dst->static_members);
-+    }
-+    if(dst->constants_table.arBuckets) my_destroy_hashtable(&dst->constants_table, (ht_free_fun_t) my_free_zval_ptr, deallocate);
-+#endif
-+    if(local_dst_alloc) deallocate(dst);
 +
-+    return NULL;
-+}
-+/* }}} */
++zend_bool apc_compile_cache_entry(apc_cache_key_t key, zend_file_handle* h, int type, time_t t, zend_op_array** op_array_pp, apc_cache_entry_t** cache_entry_pp TSRMLS_DC);
 +
-+/* {{{ my_copy_hashtable */
-+static HashTable* my_copy_hashtable_ex(HashTable* dst,
-+                                    HashTable* src,
-+                                    ht_copy_fun_t copy_fn,
-+                                    ht_free_fun_t free_fn,
-+                                    int holds_ptrs,
-+                                    apc_malloc_t allocate, 
-+                                    apc_free_t deallocate,
-+                                    ht_check_copy_fun_t check_fn,
-+                                    ...)
-+{
-+    Bucket* curr = NULL;
-+    Bucket* prev = NULL;
-+    Bucket* newp = NULL;
-+    int first = 1;
-+    int local_dst_alloc = 0;
-+    int index = 0;
++/*
++ * apc_cache_make_user_entry creates an apc_cache_entry_t object given an info string
++ * and the zval to be stored.
++ */
++extern apc_cache_entry_t* apc_cache_make_user_entry(const char* info, int info_len, const zval *val, apc_context_t* ctxt, const unsigned int ttl);
 +
-+    assert(src != NULL);
++extern int apc_cache_make_user_key(apc_cache_key_t* key, char* identifier, int identifier_len, const time_t t);
 +
-+    if (!dst) {
-+        CHECK(dst = (HashTable*) allocate(sizeof(src[0])));
-+        local_dst_alloc = 1;
-+    }
++/* {{{ struct definition: apc_cache_link_data_t */
++typedef union _apc_cache_link_data_t {
++    struct {
++        char *filename;
++        dev_t device;
++        ino_t inode;
++        unsigned char *md5;
++    } file;
++    struct {
++        char *info;
++        unsigned int ttl;
++    } user;
++} apc_cache_link_data_t;
++/* }}} */
 +
-+    memcpy(dst, src, sizeof(src[0]));
++/* {{{ struct definition: apc_cache_link_t */
++typedef struct apc_cache_link_t apc_cache_link_t;
++struct apc_cache_link_t {
++    apc_cache_link_data_t data;
++    unsigned char type;
++    unsigned long num_hits;
++    time_t mtime;
++    time_t creation_time;
++    time_t deletion_time;
++    time_t access_time;
++    int ref_count;
++    size_t mem_size;
++    apc_cache_link_t* next;
++};
++/* }}} */
 +
-+    /* allocate buckets for the new hashtable */
-+    if(!(dst->arBuckets = allocate(dst->nTableSize * sizeof(Bucket*)))) {
-+        if(local_dst_alloc) deallocate(dst);
-+        return NULL;
-+    }
++/* {{{ struct definition: apc_cache_info_t */
++typedef struct apc_cache_info_t apc_cache_info_t;
++struct apc_cache_info_t {
++    int num_slots;
++    unsigned long num_hits;
++    unsigned long num_misses;
++    unsigned long num_inserts;
++    unsigned long expunges;
++    int ttl;
++    apc_cache_link_t* list;
++    apc_cache_link_t* deleted_list;
++    time_t start_time;
++    int num_entries;
++    size_t mem_size;
++};
++/* }}} */
 +
-+    memset(dst->arBuckets, 0, dst->nTableSize * sizeof(Bucket*));
-+    dst->pInternalPointer = NULL;
-+    dst->pListHead = NULL;
-+    
-+    for (curr = src->pListHead; curr != NULL; curr = curr->pListNext) {
-+        int n = curr->h % dst->nTableSize;
++/* {{{ struct definition: slot_t */
++typedef struct slot_t slot_t;
++struct slot_t {
++    apc_cache_key_t key;        /* slot key */
++    apc_cache_entry_t* value;   /* slot value */
++    slot_t* next;               /* next slot in linked list */
++    unsigned long num_hits;     /* number of hits to this bucket */
++    time_t creation_time;       /* time slot was initialized */
++    time_t deletion_time;       /* time slot was removed from cache */
++    time_t access_time;         /* time slot was last accessed */
++};
++/* }}} */
 +
-+        if(check_fn) {
-+            va_list args;
-+            va_start(args, check_fn);
++/* {{{ struct definition: cache_header_t
++   Any values that must be shared among processes should go in here. */
++typedef struct cache_header_t cache_header_t;
++struct cache_header_t {
++    apc_lck_t lock;             /* read/write lock (exclusive blocking cache lock) */
++    apc_lck_t wrlock;           /* write lock (non-blocking used to prevent cache slams) */
++    unsigned long num_hits;     /* total successful hits in cache */
++    unsigned long num_misses;   /* total unsuccessful hits in cache */
++    unsigned long num_inserts;  /* total successful inserts in cache */
++    unsigned long expunges;     /* total number of expunges */
++    slot_t* deleted_list;       /* linked list of to-be-deleted slots */
++    time_t start_time;          /* time the above counters were reset */
++    zend_bool busy;             /* Flag to tell clients when we are busy cleaning the cache */
++    int num_entries;            /* Statistic on the number of entries */
++    size_t mem_size;            /* Statistic on the memory size used by this cache */
++    apc_keyid_t lastkey;        /* the key that is being inserted (user cache) */
++};
++/* }}} */
 +
-+            /* Call the check_fn to see if the current bucket 
-+             * needs to be copied out
-+             */
-+            if(!check_fn(curr, args)) {
-+                dst->nNumOfElements--;
-+                continue;
-+            }
++typedef void (*apc_expunge_cb_t)(T cache, size_t n); 
 +
-+            va_end(args);
-+        }
++/* {{{ struct definition: apc_cache_t */
++struct apc_cache_t {
++    void* shmaddr;                /* process (local) address of shared cache */
++    cache_header_t* header;       /* cache header (stored in SHM) */
++    slot_t** slots;               /* array of cache slots (stored in SHM) */
++    int num_slots;                /* number of slots in cache */
++    int gc_ttl;                   /* maximum time on GC list for a slot */
++    int ttl;                      /* if slot is needed and entry's access time is older than this ttl, remove it */
++    apc_expunge_cb_t expunge_cb;  /* cache specific expunge callback to free up sma memory */
++    uint has_lock;                /* flag for possible recursive locks within the same process */
++};
++/* }}} */
 +
-+        /* create a copy of the bucket 'curr' */
-+        if(!(newp =
-+            (Bucket*) apc_xmemcpy(curr,
-+                                  sizeof(Bucket) + curr->nKeyLength - 1,
-+                                  allocate))) {
-+            goto cleanup;
-+        }
++extern apc_cache_info_t* apc_cache_info(T cache, zend_bool limited);
++extern void apc_cache_free_info(apc_cache_info_t* info);
++extern void apc_cache_unlock(apc_cache_t* cache);
++extern zend_bool apc_cache_busy(apc_cache_t* cache);
++extern zend_bool apc_cache_write_lock(apc_cache_t* cache);
++extern void apc_cache_write_unlock(apc_cache_t* cache);
++extern zend_bool apc_cache_is_last_key(apc_cache_t* cache, apc_cache_key_t* key, time_t t);
 +
-+        /* insert 'newp' into the linked list at its hashed index */
-+        if (dst->arBuckets[n]) {
-+            newp->pNext = dst->arBuckets[n];
-+            newp->pLast = NULL;
-+            newp->pNext->pLast = newp;
-+        }
-+        else {
-+            newp->pNext = newp->pLast = NULL;
-+        }
++/* used by apc_rfc1867 to update data in-place - not to be used elsewhere */
 +
-+        dst->arBuckets[n] = newp;
++typedef int (*apc_cache_updater_t)(apc_cache_t*, apc_cache_entry_t*, void* data);
++extern int _apc_cache_user_update(apc_cache_t* cache, char *strkey, int keylen,
++                                    apc_cache_updater_t updater, void* data TSRMLS_DC);
 +
-+        /* copy the bucket data using our 'copy_fn' callback function */
-+        if(!(newp->pData = copy_fn(NULL, curr->pData, allocate, deallocate))) {
-+            goto cleanup;
-+        }
 +
-+        if (holds_ptrs) {
-+            memcpy(&newp->pDataPtr, newp->pData, sizeof(void*));
-+        }
-+        else {
-+            newp->pDataPtr = NULL;
-+        }
++#undef T
++#endif
 +
-+        /* insert 'newp' into the table-thread linked list */
-+        newp->pListLast = prev;
-+        newp->pListNext = NULL;
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * End:
++ * vim>600: expandtab sw=4 ts=4 sts=4 fdm=marker
++ * vim<600: expandtab sw=4 ts=4 sts=4
++ */
+diff -Naur php-5.3.1.orig/ext/apc/apc_compile.c php-5.3.1/ext/apc/apc_compile.c
+--- php-5.3.1.orig/ext/apc/apc_compile.c       1970-01-01 01:00:00.000000000 +0100
++++ php-5.3.1/ext/apc/apc_compile.c    1970-01-01 10:13:08.000000000 +0100
+@@ -0,0 +1,1775 @@
++/*
++  +----------------------------------------------------------------------+
++  | APC                                                                  |
++  +----------------------------------------------------------------------+
++  | Copyright (c) 2006-2008 The PHP Group                                |
++  +----------------------------------------------------------------------+
++  | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt.                                 |
++  | If you did not receive a copy of the PHP license and are unable to   |
++  | obtain it through the world-wide-web, please send a note to          |
++  | license@php.net so we can mail you a copy immediately.               |
++  +----------------------------------------------------------------------+
++  | Authors: Daniel Cowgill <dcowgill@communityconnect.com>              |
++  |          Rasmus Lerdorf <rasmus@php.net>                             |
++  |          Arun C. Murthy <arunc@yahoo-inc.com>                        |
++  |          Gopal Vijayaraghavan <gopalv@yahoo-inc.com>                 |
++  +----------------------------------------------------------------------+
 +
-+        if (prev) {
-+            prev->pListNext = newp;
-+        }
++   This software was contributed to PHP by Community Connect Inc. in 2002
++   and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
++   Future revisions and derivatives of this source code must acknowledge
++   Community Connect Inc. as the original contributor of this module by
++   leaving this note intact in the source code.
 +
-+        if (first) {
-+            dst->pListHead = newp;
-+            first = 0;
-+        }
++   All other licensing and usage conditions are those of the PHP Group.
 +
-+        prev = newp;
-+    }
++ */
 +
-+    dst->pListTail = newp;
++/* $Id: apc_compile.c 284580 2009-07-22 06:05:31Z kalle $ */
 +
-+    return dst;
-+    
-+    cleanup:
-+    for(index = 0; index < dst->nTableSize; index++)
-+    {
-+        curr = dst->arBuckets[index];
-+        while(curr != NULL)
-+        {
-+            Bucket * tmp = curr;
-+            if(curr->pData && free_fn)
-+            {
-+                free_fn(curr->pData, deallocate);
-+            }
-+            curr = curr->pNext;
-+            deallocate(tmp);
-+        }
-+    }   
-+    deallocate(dst->arBuckets);
-+    if(local_dst_alloc) deallocate(dst);
-+    else dst->arBuckets = NULL;
++#include "apc_compile.h"
++#include "apc_globals.h"
++#include "apc_zend.h"
++#include "ext/standard/php_var.h"
++#include "ext/standard/php_smart_str.h"
 +
-+    return NULL;
-+}
-+/* }}} */
++#ifndef IS_CONSTANT_TYPE_MASK
++#define IS_CONSTANT_TYPE_MASK (~IS_CONSTANT_INDEX)
++#endif
 +
-+/* {{{ my_copy_static_variables */
-+static HashTable* my_copy_static_variables(zend_op_array* src, apc_malloc_t allocate, apc_free_t deallocate)
-+{ 
-+    if (src->static_variables == NULL) {
-+        return NULL;
-+    }
++typedef void* (*ht_copy_fun_t)(void*, void*, apc_context_t*);
++//typedef void  (*ht_free_fun_t)(void*, apc_context_t*);
++typedef int (*ht_check_copy_fun_t)(Bucket*, va_list);
 +
-+    return my_copy_hashtable(NULL,
-+                             src->static_variables,
-+                             (ht_copy_fun_t) my_copy_zval_ptr,
-+                             (ht_free_fun_t) my_free_zval_ptr,
-+                             1,
-+                             allocate, deallocate);
-+}
-+/* }}} */
++typedef void (*ht_fixup_fun_t)(Bucket*, zend_class_entry*, zend_class_entry*);
 +
-+/* {{{ apc_copy_zval */
-+zval* apc_copy_zval(zval* dst, const zval* src, apc_malloc_t allocate, apc_free_t deallocate)
-+{
-+    int local_dst_alloc = 0;
-+    assert(src != NULL);
++#define CHECK(p) { if ((p) == NULL) return NULL; }
 +
-+    if (!dst) {
-+        CHECK(dst = (zval*) allocate(sizeof(zval)));
-+        local_dst_alloc = 1;
-+    }
++/* {{{ internal function declarations */
 +
-+    dst = my_copy_zval(dst, src, allocate, deallocate);
-+    if(!dst) {
-+        if(local_dst_alloc) deallocate(dst);
-+        return NULL;
-+    }
-+    return dst; 
-+}
-+/* }}} */
++static zend_function* my_bitwise_copy_function(zend_function*, zend_function*, apc_context_t*);
 +
-+#ifdef ZEND_ENGINE_2
-+/* {{{ apc_fixup_op_array_jumps */
-+static void apc_fixup_op_array_jumps(zend_op_array *dst, zend_op_array *src )
-+{
-+    int i;
++/*
++ * The "copy" functions perform deep-copies on a particular data structure
++ * (passed as the second argument). They also optionally allocate space for
++ * the destination data structure if the first argument is null.
++ */
++static zval** my_copy_zval_ptr(zval**, const zval**, apc_context_t*);
++static zval* my_copy_zval(zval*, const zval*, apc_context_t*);
++static znode* my_copy_znode(znode*, znode*, apc_context_t*);
++static zend_op* my_copy_zend_op(zend_op*, zend_op*, apc_context_t*);
++static zend_function* my_copy_function(zend_function*, zend_function*, apc_context_t*);
++static zend_function_entry* my_copy_function_entry(zend_function_entry*, const zend_function_entry*, apc_context_t*);
++static zend_class_entry* my_copy_class_entry(zend_class_entry*, zend_class_entry*, apc_context_t*);
++static HashTable* my_copy_hashtable_ex(HashTable*, HashTable*, ht_copy_fun_t, int, apc_context_t*, ht_check_copy_fun_t, ...);
++#define my_copy_hashtable( dst, src, copy_fn, holds_ptr, ctxt) \
++    my_copy_hashtable_ex(dst, src, copy_fn, holds_ptr, ctxt, NULL)
++static HashTable* my_copy_static_variables(zend_op_array* src, apc_context_t*);
++static zend_property_info* my_copy_property_info(zend_property_info* dst, zend_property_info* src, apc_context_t*);
++static zend_arg_info* my_copy_arg_info_array(zend_arg_info*, const zend_arg_info*, uint, apc_context_t*);
++static zend_arg_info* my_copy_arg_info(zend_arg_info*, const zend_arg_info*, apc_context_t*);
 +
-+    for (i=0; i < dst->last; ++i) {
-+        zend_op *zo = &(dst->opcodes[i]);
-+        /*convert opline number to jump address*/
-+        switch (zo->opcode) {
-+            case ZEND_JMP:
-+                /*Note: if src->opcodes != dst->opcodes then we need to the opline according to src*/
-+                zo->op1.u.jmp_addr = dst->opcodes + (zo->op1.u.jmp_addr - src->opcodes);
-+                break;
-+            case ZEND_JMPZ:
-+            case ZEND_JMPNZ:
-+            case ZEND_JMPZ_EX:
-+            case ZEND_JMPNZ_EX:
-+                zo->op2.u.jmp_addr = dst->opcodes + (zo->op2.u.jmp_addr - src->opcodes);
-+                break;
-+            default:
-+                break;
++/*
++ * The "fixup" functions need for ZEND_ENGINE_2
++ */
++static void my_fixup_function( Bucket *p, zend_class_entry *src, zend_class_entry *dst );
++static void my_fixup_hashtable( HashTable *ht, ht_fixup_fun_t fixup, zend_class_entry *src, zend_class_entry *dst );
++/* my_fixup_function_for_execution is the same as my_fixup_function
++ * but named differently for clarity
++ */
++#define my_fixup_function_for_execution my_fixup_function
++
++#ifdef ZEND_ENGINE_2_2
++static void my_fixup_property_info( Bucket *p, zend_class_entry *src, zend_class_entry *dst );
++#define my_fixup_property_info_for_execution my_fixup_property_info
++#endif
++
++/*
++ * These functions return "1" if the member/function is
++ * defined/overridden in the 'current' class and not inherited.
++ */
++static int my_check_copy_function(Bucket* src, va_list args);
++static int my_check_copy_default_property(Bucket* p, va_list args);
++static int my_check_copy_property_info(Bucket* src, va_list args);
++static int my_check_copy_static_member(Bucket* src, va_list args);
++
++/* }}} */
++
++/* {{{ check_op_array_integrity */
++#if 0
++static void check_op_array_integrity(zend_op_array* src)
++{
++    int i, j;
++
++    /* These sorts of checks really aren't particularly effective, but they
++     * can provide a welcome sanity check when debugging. Just don't enable
++     * for production use!  */
++
++    assert(src->refcount != NULL);
++    assert(src->opcodes != NULL);
++    assert(src->last > 0);
++
++    for (i = 0; i < src->last; i++) {
++        zend_op* op = &src->opcodes[i];
++        znode* nodes[] = { &op->result, &op->op1, &op->op2 };
++        for (j = 0; j < 3; j++) {
++            assert(nodes[j]->op_type == IS_CONST ||
++                   nodes[j]->op_type == IS_VAR ||
++                   nodes[j]->op_type == IS_TMP_VAR ||
++                   nodes[j]->op_type == IS_UNUSED);
++
++            if (nodes[j]->op_type == IS_CONST) {
++                int type = nodes[j]->u.constant.type;
++                assert(type == IS_RESOURCE ||
++                       type == IS_BOOL ||
++                       type == IS_LONG ||
++                       type == IS_DOUBLE ||
++                       type == IS_NULL ||
++                       type == IS_CONSTANT ||
++                       type == IS_STRING ||
++                       type == FLAG_IS_BC ||
++                       type == IS_ARRAY ||
++                       type == IS_CONSTANT_ARRAY ||
++                       type == IS_OBJECT);
++            }
 +        }
 +    }
 +}
-+/* }}} */
 +#endif
++/* }}} */
 +
-+/* {{{ apc_copy_op_array */
-+zend_op_array* apc_copy_op_array(zend_op_array* dst, zend_op_array* src, apc_malloc_t allocate, apc_free_t deallocate TSRMLS_DC)
++/* {{{ my_bitwise_copy_function */
++static zend_function* my_bitwise_copy_function(zend_function* dst, zend_function* src, apc_context_t* ctxt)
 +{
-+    int i;
-+    int local_dst_alloc = 0;
-+    apc_fileinfo_t fileinfo;
-+    char canon_path[MAXPATHLEN];
-+    char *fullpath = NULL;
-+#ifdef ZEND_ENGINE_2
-+    apc_opflags_t * flags = NULL;
-+#endif
++    apc_pool* pool = ctxt->pool;
 +
 +    assert(src != NULL);
 +
 +    if (!dst) {
-+        CHECK(dst = (zend_op_array*) allocate(sizeof(src[0])));
-+        local_dst_alloc = 1;
++        CHECK(dst = (zend_function*) apc_pool_alloc(pool, sizeof(src[0])));
 +    }
 +
-+    if(APCG(apc_optimize_function)) {
-+        APCG(apc_optimize_function)(src TSRMLS_CC);
-+    }
-+    
-+    /* start with a bitwise copy of the array */
++    /* We only need to do a bitwise copy */
 +    memcpy(dst, src, sizeof(src[0]));
 +
-+    dst->function_name = NULL;
-+    dst->filename = NULL;
-+    dst->refcount = NULL;
-+    dst->opcodes = NULL;
-+    dst->brk_cont_array = NULL;
-+    dst->static_variables = NULL;
-+#ifdef ZEND_ENGINE_2
-+    dst->try_catch_array = NULL;
-+    dst->arg_info = NULL;
-+    dst->doc_comment = NULL;
-+#else
-+    dst->arg_types = NULL;
-+#endif
-+#ifdef ZEND_ENGINE_2_1
-+    dst->vars = NULL;
-+#endif
++    return dst;
++}
++/* }}} */
 +
-+    /* copy the arg types array (if set) */
-+#ifdef ZEND_ENGINE_2
-+    if (src->arg_info) {
-+        if(!(dst->arg_info = my_copy_arg_info_array(NULL,
-+                                                src->arg_info,
-+                                                src->num_args,
-+                                                allocate,
-+                                                deallocate))) {
-+            goto cleanup;
-+        }
-+    }
-+#else    
-+    if (src->arg_types) {
-+        if(!(dst->arg_types = apc_xmemcpy(src->arg_types,
-+                        sizeof(src->arg_types[0]) * (src->arg_types[0]+1),
-+                        allocate))) {
-+            goto cleanup;
-+        }
++/* {{{ my_copy_zval_ptr */
++static zval** my_copy_zval_ptr(zval** dst, const zval** src, apc_context_t* ctxt)
++{
++    zval* dst_new;
++    apc_pool* pool = ctxt->pool;
++    int usegc = (ctxt->copy == APC_COPY_OUT_OPCODE) || (ctxt->copy == APC_COPY_OUT_USER);
++
++    assert(src != NULL);
++
++    if (!dst) {
++        CHECK(dst = (zval**) apc_pool_alloc(pool, sizeof(zval*)));
 +    }
-+#endif
 +
-+    if (src->function_name) {
-+        if(!(dst->function_name = apc_xstrdup(src->function_name, allocate))) {
-+            goto cleanup;
-+        }
++    if(usegc) {
++        ALLOC_ZVAL(dst[0]);
++        CHECK(dst[0]);
++    } else {
++        CHECK((dst[0] = (zval*) apc_pool_alloc(pool, sizeof(zval))));
 +    }
-+    if (src->filename) {
-+        if(!(dst->filename = apc_xstrdup(src->filename, allocate))) {
-+            goto cleanup;
++
++    CHECK((dst_new = my_copy_zval(*dst, *src, ctxt)));
++
++    if(dst_new != *dst) {
++        if(usegc) {
++            TSRMLS_FETCH();
++            FREE_ZVAL(dst[0]);
 +        }
++        *dst = dst_new;
 +    }
 +
-+    if(!(dst->refcount = apc_xmemcpy(src->refcount,
-+                                      sizeof(src->refcount[0]),
-+                                      allocate))) {
-+        goto cleanup;
-+    }
++    return dst;
++}
++/* }}} */
 +
-+    /* deep-copy the opcodes */
-+    if(!(dst->opcodes = (zend_op*) allocate(sizeof(zend_op) * src->last))) {
-+        goto cleanup;
++/* {{{ my_serialize_object */
++static zval* my_serialize_object(zval* dst, const zval* src, apc_context_t* ctxt)
++{
++    smart_str buf = {0};
++    php_serialize_data_t var_hash;
++    apc_pool* pool = ctxt->pool;
++
++    TSRMLS_FETCH();
++
++    PHP_VAR_SERIALIZE_INIT(var_hash);
++    php_var_serialize(&buf, (zval**)&src, &var_hash TSRMLS_CC);
++    PHP_VAR_SERIALIZE_DESTROY(var_hash);
++
++    if(buf.c) {
++        dst->type = src->type & ~IS_CONSTANT_INDEX;
++        dst->value.str.len = buf.len;
++        CHECK(dst->value.str.val = apc_pmemcpy(buf.c, buf.len+1, pool));
++        dst->type = src->type;
++        smart_str_free(&buf);
 +    }
 +
-+#ifdef ZEND_ENGINE_2
-+    if(APCG(reserved_offset) != -1) {
-+        /* Insanity alert: the void* pointer is cast into an apc_opflags_t 
-+         * struct. apc_zend_init() checks to ensure that it fits in a void* */
-+        flags = (apc_opflags_t*) & (dst->reserved[APCG(reserved_offset)]);
-+        memset(flags, 0, sizeof(apc_opflags_t));
-+        /* assert(sizeof(apc_opflags_t) < sizeof(dst->reserved)); */
++    return dst;
++}
++/* }}} */
++
++/* {{{ my_unserialize_object */
++static zval* my_unserialize_object(zval* dst, const zval* src, apc_context_t* ctxt)
++{
++    php_unserialize_data_t var_hash;
++    const unsigned char *p = (unsigned char*)Z_STRVAL_P(src);
++
++    TSRMLS_FETCH();
++
++    PHP_VAR_UNSERIALIZE_INIT(var_hash);
++    if(!php_var_unserialize(&dst, &p, p + Z_STRLEN_P(src), &var_hash TSRMLS_CC)) {
++        PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
++        zval_dtor(dst);
++        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Error at offset %ld of %d bytes", (long)((char*)p - Z_STRVAL_P(src)), Z_STRLEN_P(src));
++        dst->type = IS_NULL;
 +    }
-+#endif
-+    
-+    for (i = 0; i < src->last; i++) {
-+#ifdef ZEND_ENGINE_2
-+        zend_op *zo = &(src->opcodes[i]);
-+        /* a lot of files are merely constant arrays with no jumps */
-+        switch (zo->opcode) {
-+            case ZEND_JMP:
-+            case ZEND_JMPZ:
-+            case ZEND_JMPNZ:
-+            case ZEND_JMPZ_EX:
-+            case ZEND_JMPNZ_EX:
-+                if(flags != NULL) {
-+                    flags->has_jumps = 1;
-+                }
-+                break;
-+#ifdef ZEND_ENGINE_2
-+            /* auto_globals_jit was not in php-4.3.* */
-+            case ZEND_FETCH_R:
-+            case ZEND_FETCH_W:
-+            case ZEND_FETCH_IS:
-+            case ZEND_FETCH_FUNC_ARG:
-+                if(PG(auto_globals_jit) && flags != NULL)
-+                {
-+                     /* The fetch is only required if auto_globals_jit=1  */
-+                    if(zo->op2.u.EA.type == ZEND_FETCH_GLOBAL &&
-+                            zo->op1.op_type == IS_CONST && 
-+                            zo->op1.u.constant.type == IS_STRING) {
-+                        znode * varname = &zo->op1;
-+                        if (varname->u.constant.value.str.val[0] == '_') {
-+#define SET_IF_AUTOGLOBAL(member) \
-+    if(!strcmp(varname->u.constant.value.str.val, #member)) \
-+        flags->member = 1 /* no ';' here */
-+                            SET_IF_AUTOGLOBAL(_GET);
-+                            else SET_IF_AUTOGLOBAL(_POST);
-+                            else SET_IF_AUTOGLOBAL(_COOKIE);
-+                            else SET_IF_AUTOGLOBAL(_SERVER);
-+                            else SET_IF_AUTOGLOBAL(_ENV);
-+                            else SET_IF_AUTOGLOBAL(_FILES);
-+                            else SET_IF_AUTOGLOBAL(_REQUEST);
-+                            else if(zend_is_auto_global(
-+                                            varname->u.constant.value.str.val,
-+                                            varname->u.constant.value.str.len
-+                                            TSRMLS_CC))
-+                            {
-+                                flags->unknown_global = 1;
-+                            }
-+                        }
-+                    }
-+                }
-+                break;
-+#endif
-+            case ZEND_RECV_INIT:
-+                if(zo->op2.op_type == IS_CONST &&
-+                    zo->op2.u.constant.type == IS_CONSTANT_ARRAY) {
-+                    if(flags != NULL) {
-+                        flags->deep_copy = 1;
-+                    }
-+                }
-+                break;
-+            default:
-+                if((zo->op1.op_type == IS_CONST &&
-+                    zo->op1.u.constant.type == IS_CONSTANT_ARRAY) ||
-+                    (zo->op2.op_type == IS_CONST &&
-+                        zo->op2.u.constant.type == IS_CONSTANT_ARRAY)) {
-+                    if(flags != NULL) {
-+                        flags->deep_copy = 1;
-+                    }
-+                }
-+                break;
-+        }
-+#endif
-+        if(!(my_copy_zend_op(dst->opcodes+i, src->opcodes+i, allocate, deallocate))) {
-+            int ii;
-+            for(ii = i-1; ii>=0; ii--) {
-+                my_destroy_zend_op(dst->opcodes+ii, deallocate);
-+            }
-+            goto  cleanup;
-+        }
-+#ifdef ZEND_ENGINE_2
-+/* This code breaks apc's rule#1 - cache what you compile */
-+        if(APCG(fpstat)==0) {
-+            if((zo->opcode == ZEND_INCLUDE_OR_EVAL) && 
-+                (zo->op1.op_type == IS_CONST && zo->op1.u.constant.type == IS_STRING)) {
-+                /* constant includes */
-+                if(!IS_ABSOLUTE_PATH(Z_STRVAL_P(&zo->op1.u.constant),Z_STRLEN_P(&zo->op1.u.constant))) { 
-+                    if (apc_search_paths(Z_STRVAL_P(&zo->op1.u.constant), PG(include_path), &fileinfo) == 0) {
-+                        if((fullpath = realpath(fileinfo.fullpath, canon_path))) {
-+                            /* everything has to go through a realpath() */
-+                            zend_op *dzo = &(dst->opcodes[i]);
-+                            deallocate(dzo->op1.u.constant.value.str.val);
-+                            dzo->op1.u.constant.value.str.len = strlen(fullpath);
-+                            dzo->op1.u.constant.value.str.val = apc_xstrdup(fullpath, allocate);
-+                        }
-+                    }
-+                }
++    PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
++    return dst;
++}
++/* }}} */
++
++/* {{{ my_copy_zval */
++static zval* my_copy_zval(zval* dst, const zval* src, apc_context_t* ctxt)
++{
++    zval **tmp;
++    apc_pool* pool = ctxt->pool;
++    TSRMLS_FETCH();
++
++    assert(dst != NULL);
++    assert(src != NULL);
++
++    memcpy(dst, src, sizeof(src[0]));
++
++    if(APCG(copied_zvals).nTableSize) {
++        if(zend_hash_index_find(&APCG(copied_zvals), (ulong)src, (void**)&tmp) == SUCCESS) {
++            if(Z_ISREF_P((zval*)src)) {
++                Z_SET_ISREF_PP(tmp);
 +            }
++            Z_ADDREF_PP(tmp);
++            return *tmp;
 +        }
-+#endif 
++
++        zend_hash_index_update(&APCG(copied_zvals), (ulong)src, (void**)&dst, sizeof(zval*), NULL);
 +    }
 +
-+#ifdef ZEND_ENGINE_2
-+    if(flags == NULL || flags->has_jumps) {
-+        apc_fixup_op_array_jumps(dst,src);
-+    }
-+#endif
-+
-+    /* copy the break-continue array */
-+    if (src->brk_cont_array) {
-+        if(!(dst->brk_cont_array =
-+            apc_xmemcpy(src->brk_cont_array,
-+                        sizeof(src->brk_cont_array[0]) * src->last_brk_cont,
-+                        allocate))) {
-+            goto cleanup_opcodes;
-+        }
-+    }
-+
-+    /* copy the table of static variables */
-+    if (src->static_variables) {
-+        if(!(dst->static_variables = my_copy_static_variables(src, allocate, deallocate))) {
-+            goto cleanup_opcodes;
-+        }
-+    }
-+    
-+#ifdef ZEND_ENGINE_2
-+    if (src->try_catch_array) {
-+        if(!(dst->try_catch_array = 
-+                apc_xmemcpy(src->try_catch_array,
-+                        sizeof(src->try_catch_array[0]) * src->last_try_catch,
-+                        allocate))) {
-+            goto cleanup_opcodes;
-+        }
-+    }
-+#endif
-+
-+#ifdef ZEND_ENGINE_2_1 /* PHP 5.1 */
-+    if (src->vars) {
-+        if(!(dst->vars = apc_xmemcpy(src->vars,
-+                            sizeof(src->vars[0]) * src->last_var,
-+                            allocate))) {
-+            goto cleanup_opcodes;
-+        }
-+        
-+        for(i = 0; i <  src->last_var; i++) dst->vars[i].name = NULL;
-+        
-+        for(i = 0; i <  src->last_var; i++) {
-+            if(!(dst->vars[i].name = apc_xmemcpy(src->vars[i].name,
-+                                src->vars[i].name_len + 1,
-+                                allocate))) {
-+                dst->last_var = i;
-+                goto cleanup_opcodes;
-+            }
-+        }
-+    }
-+#endif
-+
-+#ifdef ZEND_ENGINE_2
-+    if (src->doc_comment) {
-+        if (!(dst->doc_comment 
-+                = apc_xmemcpy(src->doc_comment, src->doc_comment_len+1, allocate))) {
-+            goto cleanup_opcodes;
-+        }
-+    }
-+#endif
-+
-+    return dst;
-+
-+cleanup_opcodes:
-+    if(dst->opcodes) {
-+        for(i=0; i < src->last; i++) my_destroy_zend_op(dst->opcodes+i, deallocate);
-+    }
-+cleanup:
-+    if(dst->function_name) deallocate(dst->function_name);
-+    if(dst->refcount) deallocate(dst->refcount);
-+    if(dst->filename) deallocate(dst->filename);
-+#ifdef ZEND_ENGINE_2
-+    if(dst->arg_info) my_free_arg_info_array(dst->arg_info, dst->num_args, deallocate);
-+    if(dst->try_catch_array) deallocate(dst->try_catch_array);
-+    if(dst->doc_comment) deallocate(dst->doc_comment);
-+#else
-+    if(dst->arg_types) deallocate(dst->arg_types);
-+#endif
-+    if(dst->opcodes) deallocate(dst->opcodes);
-+    if(dst->brk_cont_array) deallocate(dst->brk_cont_array);
-+    if(dst->static_variables) my_free_hashtable(dst->static_variables, (ht_free_fun_t)my_free_zval_ptr, (apc_free_t)deallocate);
-+#ifdef ZEND_ENGINE_2_1
-+    if (dst->vars) {
-+      for(i=0; i < dst->last_var; i++) {
-+            if(dst->vars[i].name) deallocate(dst->vars[i].name);    
-+        }
-+        deallocate(dst->vars);
-+    }
-+#endif
-+    if(local_dst_alloc) deallocate(dst);
-+    return NULL;
-+}
-+/* }}} */
-+
-+/* {{{ apc_copy_new_functions */
-+apc_function_t* apc_copy_new_functions(int old_count, apc_malloc_t allocate, apc_free_t deallocate TSRMLS_DC)
-+{
-+    apc_function_t* array;
-+    int new_count;              /* number of new functions in table */
-+    int i;
-+
-+    new_count = zend_hash_num_elements(CG(function_table)) - old_count;
-+    assert(new_count >= 0);
-+
-+    CHECK(array =
-+        (apc_function_t*)
-+            allocate(sizeof(apc_function_t) * (new_count+1)));
-+
-+    if (new_count == 0) {
-+        array[0].function = NULL;
-+        return array;
-+    }
-+    
-+    /* Skip the first `old_count` functions in the table */
-+    zend_hash_internal_pointer_reset(CG(function_table));
-+    for (i = 0; i < old_count; i++) {
-+        zend_hash_move_forward(CG(function_table));
-+    }
-+
-+    /* Add the next `new_count` functions to our array */
-+    for (i = 0; i < new_count; i++) {
-+        char* key;
-+        uint key_size;
-+        zend_function* fun;
-+
-+        zend_hash_get_current_key_ex(CG(function_table),
-+                                     &key,
-+                                     &key_size,
-+                                     NULL,
-+                                     0,
-+                                     NULL);
-+
-+        zend_hash_get_current_data(CG(function_table), (void**) &fun);
-+
-+        if(!(array[i].name = apc_xmemcpy(key, (int) key_size, allocate))) {
-+            int ii;
-+            for(ii=i-1; ii>=0; ii--) {
-+                deallocate(array[ii].name);
-+                my_free_function(array[ii].function, deallocate);
-+            }
-+            deallocate(array);
-+            return NULL;
-+        }
-+        array[i].name_len = (int) key_size-1;
-+        if(!(array[i].function = my_copy_function(NULL, fun, allocate, deallocate))) {
-+            int ii;
-+            deallocate(array[i].name);
-+            for(ii=i-1; ii>=0; ii--) {
-+                deallocate(array[ii].name);
-+                my_free_function(array[ii].function, deallocate);
-+            }
-+            deallocate(array);
-+            return NULL;
-+        }
-+        zend_hash_move_forward(CG(function_table));
-+    }
-+
-+    array[i].function = NULL;
-+    return array;
-+}
-+/* }}} */
-+
-+/* {{{ apc_copy_new_classes */
-+apc_class_t* apc_copy_new_classes(zend_op_array* op_array, int old_count, apc_malloc_t allocate, apc_free_t deallocate TSRMLS_DC)
-+{
-+    apc_class_t* array;
-+    int new_count;              /* number of new classes in table */
-+    int i;
-+    
-+    new_count = zend_hash_num_elements(CG(class_table)) - old_count;
-+    assert(new_count >= 0);
-+
-+    CHECK(array =
-+        (apc_class_t*)
-+            allocate(sizeof(apc_class_t)*(new_count+1)));
-+    
-+    if (new_count == 0) {
-+        array[0].class_entry = NULL;
-+        return array;
-+    }
-+
-+    /* Skip the first `old_count` classes in the table */
-+    zend_hash_internal_pointer_reset(CG(class_table));
-+    for (i = 0; i < old_count; i++) {
-+        zend_hash_move_forward(CG(class_table));
-+    }
-+
-+    /* Add the next `new_count` classes to our array */
-+    for (i = 0; i < new_count; i++) {
-+        char* key;
-+        uint key_size;
-+        zend_class_entry* elem = NULL;
-+
-+        array[i].class_entry = NULL;
-+
-+        zend_hash_get_current_key_ex(CG(class_table),
-+                                     &key,
-+                                     &key_size,
-+                                     NULL,
-+                                     0,
-+                                     NULL);
-+
-+       zend_hash_get_current_data(CG(class_table), (void**) &elem);
-+  
-+        
-+#ifdef ZEND_ENGINE_2
-+              elem = *((zend_class_entry**)elem);
-+#endif
-+        
-+        if(!(array[i].name = apc_xmemcpy(key, (int) key_size, allocate))) {
-+            int ii;
-+
-+            for(ii=i-1; ii>=0; ii--) {
-+                deallocate(array[ii].name);
-+                my_destroy_class_entry(array[ii].class_entry, deallocate);
-+                deallocate(array[ii].class_entry);
-+            }
-+            deallocate(array);
-+            return NULL;
-+        }
-+        array[i].name_len = (int) key_size-1;
-+        if(!(array[i].class_entry = my_copy_class_entry(NULL, elem, allocate, deallocate))) {
-+            int ii;
-+            
-+            deallocate(array[i].name);
-+            for(ii=i-1; ii>=0; ii--) {
-+                deallocate(array[ii].name);
-+                my_destroy_class_entry(array[ii].class_entry, deallocate);
-+                deallocate(array[ii].class_entry);
-+            }
-+            deallocate(array);
-+            return NULL;
-+        }
-+
-+        /*
-+         * If the class has a pointer to its parent class, save the parent
-+         * name so that we can enable compile-time inheritance when we reload
-+         * the child class; otherwise, set the parent name to null and scan
-+         * the op_array to determine if this class inherits from some base
-+         * class at execution-time.
-+         */
-+
-+        if (elem->parent) {
-+            if(!(array[i].parent_name =
-+                apc_xstrdup(elem->parent->name, allocate))) {
-+                int ii;
-+                 
-+                for(ii=i; ii>=0; ii--) {
-+                    deallocate(array[ii].name);
-+                    my_destroy_class_entry(array[ii].class_entry, deallocate);
-+                    deallocate(array[ii].class_entry);
-+                    if(ii==i) continue;
-+                    if(array[ii].parent_name) deallocate(array[ii].parent_name);
-+                }
-+                deallocate(array);
-+                return NULL;
-+            }
-+            array[i].is_derived = 1;
-+        }
-+        else {
-+            array[i].parent_name = NULL;
-+            array[i].is_derived = is_derived_class(op_array, key, key_size);
-+        }
 +
-+        zend_hash_move_forward(CG(class_table));
-+    }
-+
-+    array[i].class_entry = NULL;
-+    return array;
-+}
-+/* }}} */
-+
-+/* {{{ my_destroy_zval_ptr */
-+static void my_destroy_zval_ptr(zval** src, apc_free_t deallocate)
-+{
-+    assert(src != NULL);
-+    if(my_destroy_zval(src[0], deallocate) == SUCCESS) {
-+        deallocate(src[0]);
++    if(ctxt->copy == APC_COPY_OUT_USER || ctxt->copy == APC_COPY_IN_USER) {
++        /* deep copies are refcount(1), but moved up for recursive 
++         * arrays,  which end up being add_ref'd during its copy. */
++        Z_SET_REFCOUNT_P(dst, 1);
++        Z_UNSET_ISREF_P(dst);
++    } else {
++        /* code uses refcount=2 for consts */
++        Z_SET_REFCOUNT_P(dst, Z_REFCOUNT_P((zval*)src));
++        Z_SET_ISREF_TO_P(dst, Z_ISREF_P((zval*)src));
 +    }
-+}
-+/* }}} */
-+
-+/* {{{ my_destroy_zval */
-+static int my_destroy_zval(zval* src, apc_free_t deallocate)
-+{
-+    zval **tmp;
-+    TSRMLS_FETCH();
 +
-+    switch (src->type & ~IS_CONSTANT_INDEX) {
++    switch (src->type & IS_CONSTANT_TYPE_MASK) {
 +    case IS_RESOURCE:
 +    case IS_BOOL:
 +    case IS_LONG:
@@ -3808,1973 +3513,1504 @@ diff -ubrN php-5.2.5-orig/ext/apc/apc_compile.c php-5.2.5/ext/apc/apc_compile.c
 +
 +    case IS_CONSTANT:
 +    case IS_STRING:
-+#ifndef ZEND_ENGINE_2        
-+    case FLAG_IS_BC:
-+#endif        
-+        deallocate(src->value.str.val);
-+        break;
-+    
-+    case IS_ARRAY:
-+    
-+        /* Maintain a list of zvals we've copied to properly handle recursive structures */
-+        if(APCG(copied_zvals)) {
-+            if(zend_hash_index_find(APCG(copied_zvals), (ulong)src, (void**)&tmp) == SUCCESS) {
-+                (*tmp)->refcount--;
-+                return FAILURE;
-+            } 
-+            zend_hash_index_update(APCG(copied_zvals), (ulong)src, (void**)&src, sizeof(zval*), NULL);
++        if (src->value.str.val) {
++            CHECK(dst->value.str.val = apc_pmemcpy(src->value.str.val,
++                                                   src->value.str.len+1,
++                                                   pool));
 +        }
-+        /* fall through */
++        break;
 +
++    case IS_ARRAY:
 +    case IS_CONSTANT_ARRAY:
-+        my_free_hashtable(src->value.ht,
-+                          (ht_free_fun_t) my_free_zval_ptr,
-+                          deallocate);
++
++        CHECK(dst->value.ht =
++            my_copy_hashtable(NULL,
++                              src->value.ht,
++                              (ht_copy_fun_t) my_copy_zval_ptr,
++                              1,
++                              ctxt));
 +        break;
 +
 +    case IS_OBJECT:
-+#ifndef ZEND_ENGINE_2        
-+        my_destroy_class_entry(src->value.obj.ce, deallocate);
-+        deallocate(src->value.obj.ce);
-+        my_free_hashtable(src->value.obj.properties,
-+                          (ht_free_fun_t) my_free_zval_ptr,
-+                          deallocate);
-+#endif        
++    
++        dst->type = IS_NULL;
++        if(ctxt->copy == APC_COPY_IN_USER) {
++            dst = my_serialize_object(dst, src, ctxt);
++        } else if(ctxt->copy == APC_COPY_OUT_USER) {
++            dst = my_unserialize_object(dst, src, ctxt);
++        }
 +        break;
 +
 +    default:
 +        assert(0);
 +    }
 +
-+    return SUCCESS;
++    return dst;
 +}
 +/* }}} */
 +
-+/* {{{ my_destroy_znode */
-+static void my_destroy_znode(znode* src, apc_free_t deallocate)
++/* {{{ my_copy_znode */
++static znode* my_copy_znode(znode* dst, znode* src, apc_context_t* ctxt)
 +{
++    assert(dst != NULL);
++    assert(src != NULL);
++
++    memcpy(dst, src, sizeof(src[0]));
++
++#ifdef IS_CV
++    assert(dst ->op_type == IS_CONST ||
++           dst ->op_type == IS_VAR ||
++           dst ->op_type == IS_CV ||
++           dst ->op_type == IS_TMP_VAR ||
++           dst ->op_type == IS_UNUSED);
++#else
++    assert(dst ->op_type == IS_CONST ||
++           dst ->op_type == IS_VAR ||
++           dst ->op_type == IS_TMP_VAR ||
++           dst ->op_type == IS_UNUSED);
++#endif
++
 +    if (src->op_type == IS_CONST) {
-+        my_destroy_zval(&src->u.constant, deallocate);
++        if(!my_copy_zval(&dst->u.constant, &src->u.constant, ctxt)) {
++            return NULL;
++        }
 +    }
++
++    return dst;
 +}
 +/* }}} */
 +
-+/* {{{ my_destroy_zend_op */
-+static void my_destroy_zend_op(zend_op* src, apc_free_t deallocate)
++/* {{{ my_copy_zend_op */
++static zend_op* my_copy_zend_op(zend_op* dst, zend_op* src, apc_context_t* ctxt)
 +{
-+    my_destroy_znode(&src->result, deallocate);
-+    my_destroy_znode(&src->op1, deallocate);
-+    my_destroy_znode(&src->op2, deallocate);
++    assert(dst != NULL);
++    assert(src != NULL);
++
++    memcpy(dst, src, sizeof(src[0]));
++
++    CHECK(my_copy_znode(&dst->result, &src->result, ctxt));
++    CHECK(my_copy_znode(&dst->op1, &src->op1, ctxt));
++    CHECK(my_copy_znode(&dst->op2, &src->op2, ctxt));
++
++    return dst;
 +}
 +/* }}} */
 +
-+/* {{{ my_destroy_function */
-+static void my_destroy_function(zend_function* src, apc_free_t deallocate)
++/* {{{ my_copy_function */
++static zend_function* my_copy_function(zend_function* dst, zend_function* src, apc_context_t* ctxt)
 +{
++    TSRMLS_FETCH();
++
 +    assert(src != NULL);
 +
++    CHECK(dst = my_bitwise_copy_function(dst, src, ctxt));
++
 +    switch (src->type) {
 +    case ZEND_INTERNAL_FUNCTION:
 +    case ZEND_OVERLOADED_FUNCTION:
++        /* shallow copy because op_array is internal */
++        dst->op_array = src->op_array;
 +        break;
-+        
++
 +    case ZEND_USER_FUNCTION:
 +    case ZEND_EVAL_CODE:
-+        my_destroy_op_array(&src->op_array, deallocate);
++        CHECK(apc_copy_op_array(&dst->op_array,
++                                &src->op_array,
++                                ctxt TSRMLS_CC));
 +        break;
 +
 +    default:
 +        assert(0);
 +    }
-+}
-+/* }}} */
-+
-+/* {{{ my_destroy_function_entry */
-+static void my_destroy_function_entry(zend_function_entry* src, apc_free_t deallocate)
-+{
-+    assert(src != NULL);
++    /*
++     * op_array bitwise copying overwrites what ever you modified
++     * before apc_copy_op_array - which is why this code is outside 
++     * my_bitwise_copy_function.
++     */
 +
-+    deallocate(src->fname);
-+#ifdef ZEND_ENGINE_2    
-+    if (src->arg_info) {
-+            my_free_arg_info_array(src->arg_info, src->num_args, deallocate);
-+    }
-+#else
-+    if (src->func_arg_types) {
-+        deallocate(src->func_arg_types);
-+    }
-+#endif    
-+}
-+/* }}} */
++    /* zend_do_inheritance will re-look this up, because the pointers
++     * in prototype are from a function table of another class. It just
++     * helps if that one is from EG(class_table).
++     */
++    dst->common.prototype = NULL;
 +
-+#ifdef ZEND_ENGINE_2    
-+/* {{{ my_destroy_property_info*/
-+static void my_destroy_property_info(zend_property_info* src, apc_free_t deallocate)
-+{
-+    assert(src != NULL);
++    /* once a method is marked as ZEND_ACC_IMPLEMENTED_ABSTRACT then you
++     * have to carry around a prototype. Thankfully zend_do_inheritance
++     * sets this properly as well
++     */
++    dst->common.fn_flags = src->common.fn_flags & (~ZEND_ACC_IMPLEMENTED_ABSTRACT);
 +
-+    deallocate(src->name);
-+#if defined(ZEND_ENGINE_2) && PHP_MINOR_VERSION > 0
-+    if(src->doc_comment) deallocate(src->doc_comment);
-+#endif
++
++    return dst;
 +}
 +/* }}} */
 +
-+/* {{{ my_destroy_arg_info_array */
-+static void my_destroy_arg_info_array(zend_arg_info* src, uint num_args, apc_free_t deallocate)
++/* {{{ my_copy_function_entry */
++static zend_function_entry* my_copy_function_entry(zend_function_entry* dst, const zend_function_entry* src, apc_context_t* ctxt)
 +{
-+    int i = 0;
-+    
 +    assert(src != NULL);
 +
-+    for(i=0; i < num_args; i++) {
-+        my_destroy_arg_info(&src[i], deallocate);
++    if (!dst) {
++        CHECK(dst = (zend_function_entry*) apc_pool_alloc(ctxt->pool, sizeof(src[0])));
 +    }
-+}
-+/* }}} */
 +
-+/* {{{ my_destroy_arg_info */
-+static void my_destroy_arg_info(zend_arg_info* src, apc_free_t deallocate)
-+{
-+    assert(src != NULL);
++    /* Start with a bitwise copy */
++    memcpy(dst, src, sizeof(src[0]));
++
++    dst->fname = NULL;
++    dst->arg_info = NULL;
++
++    if (src->fname) {
++        CHECK((dst->fname = apc_pstrdup(src->fname, ctxt->pool)));
++    }
++
++    if (src->arg_info) {
++        CHECK((dst->arg_info = my_copy_arg_info_array(NULL,
++                                                src->arg_info,
++                                                src->num_args,
++                                                ctxt)));
++    }
 +
-+    deallocate(src->name);
-+    deallocate(src->class_name);
++    return dst;
 +}
 +/* }}} */
-+#endif    
 +
-+/* {{{ my_destroy_class_entry */
-+static void my_destroy_class_entry(zend_class_entry* src, apc_free_t deallocate)
++/* {{{ my_copy_property_info */
++static zend_property_info* my_copy_property_info(zend_property_info* dst, zend_property_info* src, apc_context_t* ctxt)
 +{
-+    uint i;
++    apc_pool* pool = ctxt->pool;
 +
 +    assert(src != NULL);
 +
-+    deallocate(src->name);
-+#ifndef ZEND_ENGINE_2    
-+    deallocate(src->refcount);
-+#else
-+    if(src->doc_comment) deallocate(src->doc_comment);
-+    if(src->filename) deallocate(src->filename);
-+#endif
++    if (!dst) {
++        CHECK(dst = (zend_property_info*) apc_pool_alloc(pool, sizeof(*src)));
++    }
 +
-+    my_destroy_hashtable(&src->function_table,
-+                         (ht_free_fun_t) my_free_function,
-+                         deallocate);
++    /* Start with a bitwise copy */
++    memcpy(dst, src, sizeof(*src));
 +
-+    my_destroy_hashtable(&src->default_properties,
-+                         (ht_free_fun_t) my_free_zval_ptr,
-+                         deallocate);
++    dst->name = NULL;
++#if defined(ZEND_ENGINE_2) && PHP_MINOR_VERSION > 0
++    dst->doc_comment = NULL;
++#endif
 +
-+#ifdef ZEND_ENGINE_2
-+    my_destroy_hashtable(&src->properties_info, 
-+                            (ht_free_fun_t) my_free_property_info,
-+                            deallocate);
-+    if(src->static_members) 
-+    {
-+        my_destroy_hashtable(src->static_members,
-+                         (ht_free_fun_t) my_free_zval_ptr,
-+                         deallocate);
-+        if(src->static_members != &(src->default_static_members))
-+        {
-+            deallocate(src->static_members);
-+        }
++    if (src->name) {
++        /* private members are stored inside property_info as a mangled
++         * string of the form:
++         *      \0<classname>\0<membername>\0
++         */
++        CHECK((dst->name = apc_pmemcpy(src->name, src->name_length+1, pool)));
 +    }
 +
-+    my_destroy_hashtable(&src->constants_table, 
-+                            (ht_free_fun_t) my_free_zval_ptr,
-+                            deallocate);
++#if defined(ZEND_ENGINE_2) && PHP_MINOR_VERSION > 0
++    if (src->doc_comment) {
++        CHECK((dst->doc_comment = apc_pmemcpy(src->doc_comment, src->doc_comment_len+1, pool)));
++    }
 +#endif
 +
-+    if (src->builtin_functions) {
-+        for (i = 0; src->builtin_functions[i].fname != NULL; i++) {
-+            my_destroy_function_entry(&src->builtin_functions[i], deallocate);
-+        }
-+        deallocate(src->builtin_functions);
-+    }
++    return dst;
 +}
 +/* }}} */
 +
-+/* {{{ my_destroy_hashtable */
-+static void my_destroy_hashtable(HashTable* src, ht_free_fun_t free_fn, apc_free_t deallocate)
++/* {{{ my_copy_property_info_for_execution */
++static zend_property_info* my_copy_property_info_for_execution(zend_property_info* dst, zend_property_info* src, apc_context_t* ctxt)
 +{
-+    int i;
-+
 +    assert(src != NULL);
 +
-+    for (i = 0; i < src->nTableSize; i++) {
-+        Bucket* p = src->arBuckets[i];
-+        while (p != NULL) {
-+            Bucket* q = p;
-+            p = p->pNext;
-+            free_fn(q->pData, deallocate);
-+            deallocate(q);
-+        }
++    if (!dst) {
++        CHECK(dst = (zend_property_info*) apc_pool_alloc(ctxt->pool, (sizeof(*src))));
 +    }
 +
-+    deallocate(src->arBuckets);
++    /* We need only a shallow copy */
++    memcpy(dst, src, sizeof(*src));
++
++    return dst;
 +}
 +/* }}} */
 +
-+/* {{{ my_destroy_op_array */
-+static void my_destroy_op_array(zend_op_array* src, apc_free_t deallocate)
++/* {{{ my_copy_arg_info_array */
++static zend_arg_info* my_copy_arg_info_array(zend_arg_info* dst, const zend_arg_info* src, uint num_args, apc_context_t* ctxt)
 +{
-+    int i;
++    uint i = 0;
 +
-+    assert(src != NULL);
 +
-+#ifdef ZEND_ENGINE_2
-+    if (src->arg_info) {
-+        my_free_arg_info_array(src->arg_info, src->num_args, deallocate);
-+    }
-+#else    
-+    if (src->arg_types) {
-+        deallocate(src->arg_types);
++    if (!dst) {
++        CHECK(dst = (zend_arg_info*) apc_pool_alloc(ctxt->pool, sizeof(*src)*num_args));
 +    }
-+#endif
-+
-+    deallocate(src->function_name);
-+    deallocate(src->filename);
-+    deallocate(src->refcount);
 +
-+    for (i = 0; i < src->last; i++) {
-+        my_destroy_zend_op(src->opcodes + i, deallocate);
-+    }
-+    deallocate(src->opcodes);
++    /* Start with a bitwise copy */
++    memcpy(dst, src, sizeof(*src)*num_args);
 +
-+    if (src->brk_cont_array) {
-+        deallocate(src->brk_cont_array);
++    for(i=0; i < num_args; i++) {
++        CHECK((my_copy_arg_info( &dst[i], &src[i], ctxt)));
 +    }
 +
-+    if (src->static_variables) {
-+        my_free_hashtable(src->static_variables,
-+                          (ht_free_fun_t) my_free_zval_ptr,
-+                          deallocate);
-+    }
-+    
-+#ifdef ZEND_ENGINE_2_1
-+    if (src->vars) {
-+      for(i=0; i < src->last_var; i++) {
-+            if(src->vars[i].name) deallocate(src->vars[i].name);    
-+        }
-+        deallocate(src->vars);
-+    }
-+#endif
-+#ifdef ZEND_ENGINE_2
-+    if(src->try_catch_array) {
-+        deallocate(src->try_catch_array);
-+    }
-+    if (src->doc_comment) {
-+        deallocate(src->doc_comment);
-+    }
-+#endif
++    return dst;
 +}
 +/* }}} */
 +
-+/* {{{ my_free_zval_ptr */
-+static void my_free_zval_ptr(zval** src, apc_free_t deallocate)
++/* {{{ my_copy_arg_info */
++static zend_arg_info* my_copy_arg_info(zend_arg_info* dst, const zend_arg_info* src, apc_context_t* ctxt)
 +{
-+    my_destroy_zval_ptr(src, deallocate);
-+    deallocate(src);
-+}
-+/* }}} */
++    apc_pool* pool = ctxt->pool;
 +
-+#ifdef ZEND_ENGINE_2
-+/* {{{ my_free_property_info */
-+static void my_free_property_info(zend_property_info* src, apc_free_t deallocate)
-+{
-+    my_destroy_property_info(src, deallocate);
-+    deallocate(src);
-+}
-+/* }}} */
++    assert(src != NULL);
 +
-+/* {{{ my_free_arg_info_array */
-+static void my_free_arg_info_array(zend_arg_info* src, uint num_args, apc_free_t deallocate)
-+{
-+    my_destroy_arg_info_array(src, num_args, deallocate);
-+    deallocate(src);
-+}
-+/* }}} */
++    if (!dst) {
++        CHECK(dst = (zend_arg_info*) apc_pool_alloc(pool, sizeof(*src)));
++    }
 +
-+/* {{{ my_free_arg_info */
-+static void my_free_arg_info(zend_arg_info* src, apc_free_t deallocate)
-+{
-+    my_destroy_arg_info(src, deallocate);
-+    deallocate(src);
-+}
-+/* }}} */
-+#endif
++    /* Start with a bitwise copy */
++    memcpy(dst, src, sizeof(*src));
 +
-+/* {{{ my_free_function */
-+static void my_free_function(zend_function* src, apc_free_t deallocate)
-+{
-+    my_destroy_function(src, deallocate);
-+    deallocate(src);
-+}
-+/* }}} */
++    dst->name = NULL;
++    dst->class_name = NULL;
 +
-+/* {{{ my_free_hashtable */
-+static void my_free_hashtable(HashTable* src, ht_free_fun_t free_fn, apc_free_t deallocate)
-+{
-+    my_destroy_hashtable(src, free_fn, deallocate);
-+    deallocate(src);
-+}
-+/* }}} */
++    if (src->name) {
++        CHECK((dst->name = apc_pmemcpy(src->name, src->name_len+1, pool)));
++    }
 +
-+/* {{{ apc_free_op_array */
-+void apc_free_op_array(zend_op_array* src, apc_free_t deallocate)
-+{
-+    if (src != NULL) {
-+        my_destroy_op_array(src, deallocate);
-+        deallocate(src);
++    if (src->class_name) {
++        CHECK((dst->class_name = apc_pmemcpy(src->class_name, src->class_name_len+1, pool)));
 +    }
++
++    return dst;
 +}
 +/* }}} */
 +
-+/* {{{ apc_free_functions */
-+void apc_free_functions(apc_function_t* src, apc_free_t deallocate)
++/* {{{ apc_copy_class_entry */
++zend_class_entry* apc_copy_class_entry(zend_class_entry* dst, zend_class_entry* src, apc_context_t* ctxt)
 +{
-+    int i;
-+
-+    if (src != NULL) {
-+        for (i = 0; src[i].function != NULL; i++) {
-+            deallocate(src[i].name);
-+            my_destroy_function(src[i].function, deallocate);
-+            deallocate(src[i].function);
-+        }   
-+        deallocate(src);
-+    }   
++    return my_copy_class_entry(dst, src, ctxt);
 +}
-+/* }}} */
 +
-+/* {{{ apc_free_classes */
-+void apc_free_classes(apc_class_t* src, apc_free_t deallocate)
++/* {{{ my_copy_class_entry */
++static zend_class_entry* my_copy_class_entry(zend_class_entry* dst, zend_class_entry* src, apc_context_t* ctxt)
 +{
-+    int i;
++    uint i = 0;
++    apc_pool* pool = ctxt->pool;
 +
-+    if (src != NULL) {
-+        for (i = 0; src[i].class_entry != NULL; i++) {
-+            deallocate(src[i].name);
-+            deallocate(src[i].parent_name);
-+            my_destroy_class_entry(src[i].class_entry, deallocate);
-+            deallocate(src[i].class_entry);
-+        }   
-+        deallocate(src);
-+    }   
-+}
-+/* }}} */
++    assert(src != NULL);
 +
-+/* {{{ apc_free_zval */
-+void apc_free_zval(zval* src, apc_free_t deallocate)
-+{
-+    if (src != NULL) {
-+        if(my_destroy_zval(src, deallocate) == SUCCESS) {
-+            deallocate(src);
-+        }
++    if (!dst) {
++        CHECK(dst = (zend_class_entry*) apc_pool_alloc(pool, sizeof(*src)));
 +    }
-+}
-+/* }}} */
 +
++    /* Start with a bitwise copy */
++    memcpy(dst, src, sizeof(*src));
 +
-+/* Used only by my_prepare_op_array_for_execution */
-+#define APC_PREPARE_FETCH_GLOBAL_FOR_EXECUTION()                                                \
-+                         /* The fetch is only required if auto_globals_jit=1  */                \
-+                        if(zo->op2.u.EA.type == ZEND_FETCH_GLOBAL &&                            \
-+                            zo->op1.op_type == IS_CONST &&                                      \
-+                            zo->op1.u.constant.type == IS_STRING &&                             \
-+                            zo->op1.u.constant.value.str.val[0] == '_') {                       \
-+                                                                                                \
-+                            znode* varname = &zo->op1;                                          \
-+                            (void)zend_is_auto_global(varname->u.constant.value.str.val,        \
-+                                                          varname->u.constant.value.str.len     \
-+                                                          TSRMLS_CC);                           \
-+                        }                                                                       \
++    dst->name = NULL;
++    dst->builtin_functions = NULL;
++    memset(&dst->function_table, 0, sizeof(dst->function_table));
++    memset(&dst->default_properties, 0, sizeof(dst->default_properties));
++    dst->static_members = NULL;
++    dst->doc_comment = NULL;
++    dst->filename = NULL;
++    memset(&dst->properties_info, 0, sizeof(dst->properties_info));
++    memset(&dst->constants_table, 0, sizeof(dst->constants_table));
++    memset(&dst->default_static_members, 0, sizeof(dst->default_static_members));
 +
-+/* {{{ my_prepare_op_array_for_execution */
-+static int my_prepare_op_array_for_execution(zend_op_array* dst, zend_op_array* src TSRMLS_DC) 
-+{
-+    /* combine my_fetch_global_vars and my_copy_data_exceptions.
-+     *   - Pre-fetch superglobals which would've been pre-fetched in parse phase.
-+     *   - If the opcode stream contain mutable data, ensure a copy.
-+     *   - Fixup array jumps in the same loop.
-+     */
-+    int i=src->last;
-+    zend_op *zo;
-+    zend_op *dzo;
-+#ifdef ZEND_ENGINE_2
-+    apc_opflags_t * flags = APCG(reserved_offset) != -1 ? 
-+                                (apc_opflags_t*) & (src->reserved[APCG(reserved_offset)]) : NULL;
-+    int needcopy = flags ? flags->deep_copy : 1;
-+    /* auto_globals_jit was not in php4 */
-+    int do_prepare_fetch_global = PG(auto_globals_jit) && (flags == NULL || flags->unknown_global);
++    if (src->name) {
++        CHECK((dst->name = apc_pstrdup(src->name, pool)));
++    }
 +
-+#define FETCH_AUTOGLOBAL(member) do { \
-+    if(flags && flags->member == 1) { \
-+        zend_is_auto_global(#member,\
-+                            (sizeof(#member) - 1)\
-+                            TSRMLS_CC);\
-+    } \
-+}while(0); 
-+            
-+    FETCH_AUTOGLOBAL(_GET);
-+    FETCH_AUTOGLOBAL(_POST);
-+    FETCH_AUTOGLOBAL(_COOKIE);
-+    FETCH_AUTOGLOBAL(_SERVER);
-+    FETCH_AUTOGLOBAL(_ENV);
-+    FETCH_AUTOGLOBAL(_FILES);
-+    FETCH_AUTOGLOBAL(_REQUEST);
++    if(!(my_copy_hashtable_ex(&dst->function_table,
++                            &src->function_table,
++                            (ht_copy_fun_t) my_copy_function,
++                            0,
++                            ctxt,
++                            (ht_check_copy_fun_t) my_check_copy_function,
++                            src))) {
++        return NULL;
++    }
 +
-+#else
-+    int needcopy = 0;
-+    int do_prepare_fetch_global = 0;
-+    int j = 0;
++    /* the interfaces are populated at runtime using ADD_INTERFACE */
++    dst->interfaces = NULL; 
 +
-+    for(j = 0; j < src->last; j++) {
-+        zo = &src->opcodes[j];
-+        
-+        if( ((zo->op1.op_type == IS_CONST &&
-+              zo->op1.u.constant.type == IS_CONSTANT_ARRAY)) ||  
-+            ((zo->op2.op_type == IS_CONST &&
-+              zo->op2.u.constant.type == IS_CONSTANT_ARRAY))) {
-+            needcopy = 1;
++    /* the current count includes inherited interfaces as well,
++       the real dynamic ones are the first <n> which are zero'd
++       out in zend_do_end_class_declaration */
++    for(i = 0 ; i < src->num_interfaces ; i++) {
++        if(src->interfaces[i])
++        {
++            dst->num_interfaces = i;
++            break;
 +        }
 +    }
++
++    /* these will either be set inside my_fixup_hashtable or 
++     * they will be copied out from parent inside zend_do_inheritance 
++     */
++    dst->parent = NULL;
++    dst->constructor =  NULL;
++    dst->destructor = NULL;
++    dst->clone = NULL;
++    dst->__get = NULL;
++    dst->__set = NULL;
++    dst->__unset = NULL;
++    dst->__isset = NULL;
++    dst->__call = NULL;
++#ifdef ZEND_ENGINE_2_2
++    dst->__tostring = NULL;
++#endif
++#ifdef ZEND_ENGINE_2_3
++      dst->__callstatic = NULL;
 +#endif
-+    
-+    if(needcopy) {
 +
-+        dst->opcodes = (zend_op*) apc_xmemcpy(src->opcodes, 
-+                                    sizeof(zend_op) * src->last,
-+                                    apc_php_malloc);
-+        zo = src->opcodes;
-+        dzo = dst->opcodes;
-+        while(i > 0) {
++    /* unset function proxies */
++    dst->serialize_func = NULL;
++    dst->unserialize_func = NULL;
 +
-+            if( ((zo->op1.op_type == IS_CONST &&
-+                  zo->op1.u.constant.type == IS_CONSTANT_ARRAY)) ||  
-+                ((zo->op2.op_type == IS_CONST &&
-+                  zo->op2.u.constant.type == IS_CONSTANT_ARRAY))) {
++    my_fixup_hashtable(&dst->function_table, (ht_fixup_fun_t)my_fixup_function, src, dst);
 +
-+                if(!(my_copy_zend_op(dzo, zo, apc_php_malloc, apc_php_free))) {
-+                    assert(0); /* emalloc failed or a bad constant array */
-+                }
-+            }
-+            
-+#ifdef ZEND_ENGINE_2
-+            switch(zo->opcode) {
-+                case ZEND_JMP:
-+                    dzo->op1.u.jmp_addr = dst->opcodes + 
-+                                            (zo->op1.u.jmp_addr - src->opcodes);
-+                    break;
-+                case ZEND_JMPZ:
-+                case ZEND_JMPNZ:
-+                case ZEND_JMPZ_EX:
-+                case ZEND_JMPNZ_EX:
-+                    dzo->op2.u.jmp_addr = dst->opcodes + 
-+                                            (zo->op2.u.jmp_addr - src->opcodes);
-+                    break;
-+                case ZEND_FETCH_R:
-+                case ZEND_FETCH_W:
-+                case ZEND_FETCH_IS:
-+                case ZEND_FETCH_FUNC_ARG:
-+                    if(do_prepare_fetch_global)
-+                    {
-+                        APC_PREPARE_FETCH_GLOBAL_FOR_EXECUTION();
-+                    }
-+                    break;
-+                default:
-+                    break;
-+            }
-+#endif
-+            i--;
-+            zo++;
-+            dzo++;
-+        }
-+#ifdef ZEND_ENGINE_2
-+    } else {  /* !needcopy */
-+        /* The fetch is only required if auto_globals_jit=1  */
-+        if(do_prepare_fetch_global)
-+        {
-+            zo = src->opcodes;
-+            while(i > 0) {
++    CHECK((my_copy_hashtable_ex(&dst->default_properties,
++                            &src->default_properties,
++                            (ht_copy_fun_t) my_copy_zval_ptr,
++                            1,
++                            ctxt,
++                            (ht_check_copy_fun_t) my_check_copy_default_property,
++                            src)));
 +
-+                if(zo->opcode == ZEND_FETCH_R || 
-+                   zo->opcode == ZEND_FETCH_W ||
-+                   zo->opcode == ZEND_FETCH_IS ||
-+                   zo->opcode == ZEND_FETCH_FUNC_ARG 
-+                  ) {
-+                    APC_PREPARE_FETCH_GLOBAL_FOR_EXECUTION();
-+                }
++    CHECK((my_copy_hashtable_ex(&dst->properties_info,
++                            &src->properties_info,
++                            (ht_copy_fun_t) my_copy_property_info,
++                            0,
++                            ctxt,
++                            (ht_check_copy_fun_t) my_check_copy_property_info,
++                            src)));
 +
-+                i--;
-+                zo++;
-+            }
-+        }
++#ifdef ZEND_ENGINE_2_2
++    /* php5.2 introduced a scope attribute for property info */
++    my_fixup_hashtable(&dst->properties_info, (ht_fixup_fun_t)my_fixup_property_info_for_execution, src, dst);
 +#endif
++
++    CHECK(my_copy_hashtable_ex(&dst->default_static_members,
++                            &src->default_static_members,
++                            (ht_copy_fun_t) my_copy_zval_ptr,
++                            1,
++                            ctxt,
++                            (ht_check_copy_fun_t) my_check_copy_static_member,
++                            src,
++                            &src->default_static_members));
++
++    if(src->static_members != &src->default_static_members)
++    {
++        CHECK((dst->static_members = my_copy_hashtable_ex(NULL,
++                            src->static_members,
++                            (ht_copy_fun_t) my_copy_zval_ptr,
++                            1,
++                            ctxt,
++                            (ht_check_copy_fun_t) my_check_copy_static_member,
++                            src,
++                            src->static_members)));
++    }
++    else
++    {
++        dst->static_members = &dst->default_static_members;
 +    }
-+    return 1;
-+}
-+/* }}} */
 +
-+/* {{{ apc_copy_op_array_for_execution */
-+zend_op_array* apc_copy_op_array_for_execution(zend_op_array* dst, zend_op_array* src TSRMLS_DC)
-+{
-+    if(dst == NULL) {
-+        dst = (zend_op_array*) emalloc(sizeof(src[0]));
++    CHECK((my_copy_hashtable(&dst->constants_table,
++                            &src->constants_table,
++                            (ht_copy_fun_t) my_copy_zval_ptr,
++                            1,
++                            ctxt)));
++
++    if (src->doc_comment) {
++        CHECK(dst->doc_comment =
++                    apc_pmemcpy(src->doc_comment, src->doc_comment_len+1, pool));
 +    }
-+    memcpy(dst, src, sizeof(src[0]));
-+    dst->static_variables = my_copy_static_variables(src, apc_php_malloc, apc_php_free);
 +
-+    dst->refcount = apc_xmemcpy(src->refcount,
-+                                      sizeof(src->refcount[0]),
-+                                      apc_php_malloc);
-+    
-+    my_prepare_op_array_for_execution(dst,src TSRMLS_CC);
++    if (src->builtin_functions) {
++        int i, n;
 +
-+    return dst;
-+}
-+/* }}} */
++        for (n = 0; src->type == ZEND_INTERNAL_CLASS && src->builtin_functions[n].fname != NULL; n++) {}
 +
-+/* {{{ apc_copy_function_for_execution */
-+zend_function* apc_copy_function_for_execution(zend_function* src)
-+{
-+    zend_function* dst;
-+    TSRMLS_FETCH();
++        CHECK((dst->builtin_functions =
++                (zend_function_entry*) apc_pool_alloc(pool, (n + 1) * sizeof(zend_function_entry))));
++
++        for (i = 0; i < n; i++) {
++            CHECK(my_copy_function_entry((zend_function_entry*)(&dst->builtin_functions[i]),
++                                   &src->builtin_functions[i],
++                                   ctxt));
++        }
++        *(char**)&(dst->builtin_functions[n].fname) = NULL;
++    }
++
++    if (src->filename) {
++        CHECK((dst->filename = apc_pstrdup(src->filename, pool)));
++    }
 +
-+    dst = (zend_function*) emalloc(sizeof(src[0]));
-+    memcpy(dst, src, sizeof(src[0]));
-+    apc_copy_op_array_for_execution(&(dst->op_array), &(src->op_array) TSRMLS_CC);
 +    return dst;
 +}
 +/* }}} */
 +
-+/* {{{ apc_copy_function_for_execution_ex */
-+zend_function* apc_copy_function_for_execution_ex(void *dummy, zend_function* src, apc_malloc_t allocate, apc_free_t deallocate)
++/* {{{ my_copy_hashtable */
++static HashTable* my_copy_hashtable_ex(HashTable* dst,
++                                    HashTable* src,
++                                    ht_copy_fun_t copy_fn,
++                                    int holds_ptrs,
++                                    apc_context_t* ctxt,
++                                    ht_check_copy_fun_t check_fn,
++                                    ...)
 +{
-+    if(src->type==ZEND_INTERNAL_FUNCTION || src->type==ZEND_OVERLOADED_FUNCTION) return src;
-+    return apc_copy_function_for_execution(src);
-+}
-+/* }}} */
++    Bucket* curr = NULL;
++    Bucket* prev = NULL;
++    Bucket* newp = NULL;
++    int first = 1;
++    apc_pool* pool = ctxt->pool;
 +
-+/* {{{ apc_copy_class_entry_for_execution */
-+zend_class_entry* apc_copy_class_entry_for_execution(zend_class_entry* src, int is_derived)
-+{
-+    zend_class_entry* dst = (zend_class_entry*) emalloc(sizeof(src[0]));
-+    memcpy(dst, src, sizeof(src[0]));
++    assert(src != NULL);
 +
-+#ifdef ZEND_ENGINE_2
-+    if(src->num_interfaces)
-+    {
-+        /* These are slots to be populated later by ADD_INTERFACE insns */
-+        dst->interfaces = apc_php_malloc(
-+                            sizeof(zend_class_entry*) * src->num_interfaces);
-+        memset(dst->interfaces, 0, 
-+                            sizeof(zend_class_entry*) * src->num_interfaces);
-+    }
-+    else
-+    {
-+        /* assert(dst->interfaces == NULL); */
++    if (!dst) {
++        CHECK(dst = (HashTable*) apc_pool_alloc(pool, sizeof(src[0])));
 +    }
-+#endif
 +
-+#ifndef ZEND_ENGINE_2    
-+    dst->refcount = apc_xmemcpy(src->refcount,
-+                                      sizeof(src->refcount[0]),
-+                                      apc_php_malloc);
-+#endif        
++    memcpy(dst, src, sizeof(src[0]));
 +
-+    /* Deep-copy the class properties, because they will be modified */
++    /* allocate buckets for the new hashtable */
++    CHECK((dst->arBuckets = apc_pool_alloc(pool, dst->nTableSize * sizeof(Bucket*))));
 +
-+    my_copy_hashtable(&dst->default_properties,
-+                      &src->default_properties,
-+                      (ht_copy_fun_t) my_copy_zval_ptr,
-+                      (ht_free_fun_t) my_free_zval_ptr,
-+                      1,
-+                      apc_php_malloc, apc_php_free);
++    memset(dst->arBuckets, 0, dst->nTableSize * sizeof(Bucket*));
++    dst->pInternalPointer = NULL;
++    dst->pListHead = NULL;
 +
-+    /* For derived classes, we must also copy the function hashtable (although
-+     * we can merely bitwise copy the functions it contains) */
++    for (curr = src->pListHead; curr != NULL; curr = curr->pListNext) {
++        int n = curr->h % dst->nTableSize;
 +
-+    my_copy_hashtable(&dst->function_table,
-+                      &src->function_table,
-+                      (ht_copy_fun_t) apc_copy_function_for_execution_ex,
-+                      NULL,
-+                      0,
-+                      apc_php_malloc, apc_php_free);
-+#ifdef ZEND_ENGINE_2
-+    my_fixup_hashtable(&dst->function_table, (ht_fixup_fun_t)my_fixup_function_for_execution, src, dst);
++        if(check_fn) {
++            va_list args;
++            va_start(args, check_fn);
 +
-+    /* zend_do_inheritance merges properties_info.
-+     * Need only shallow copying as it doesn't hold the pointers.
-+     */
-+    my_copy_hashtable(&dst->properties_info,
-+                      &src->properties_info,
-+                      (ht_copy_fun_t) my_copy_property_info_for_execution,
-+                      NULL,
-+                      0,
-+                      apc_php_malloc, apc_php_free);
++            /* Call the check_fn to see if the current bucket
++             * needs to be copied out
++             */
++            if(!check_fn(curr, args)) {
++                dst->nNumOfElements--;
++                continue;
++            }
 +
-+#ifdef ZEND_ENGINE_2_2
-+    /* php5.2 introduced a scope attribute for property info */
-+    my_fixup_hashtable(&dst->properties_info, (ht_fixup_fun_t)my_fixup_property_info_for_execution, src, dst);
-+#endif
++            va_end(args);
++        }
 +
-+    /* if inheritance results in a hash_del, it might result in
-+     * a pefree() of the pointers here. Deep copying required. 
-+     */
++        /* create a copy of the bucket 'curr' */
++        CHECK((newp = (Bucket*) apc_pmemcpy(curr,
++                                  sizeof(Bucket) + curr->nKeyLength - 1,
++                                  pool)));
 +
-+    my_copy_hashtable(&dst->constants_table,
-+                      &src->constants_table,
-+                      (ht_copy_fun_t) my_copy_zval_ptr,
-+                      NULL,
-+                      1,
-+                      apc_php_malloc, apc_php_free);
++        /* insert 'newp' into the linked list at its hashed index */
++        if (dst->arBuckets[n]) {
++            newp->pNext = dst->arBuckets[n];
++            newp->pLast = NULL;
++            newp->pNext->pLast = newp;
++        }
++        else {
++            newp->pNext = newp->pLast = NULL;
++        }
 +
-+    my_copy_hashtable(&dst->default_static_members,
-+                      &src->default_static_members,
-+                      (ht_copy_fun_t) my_copy_zval_ptr,
-+                      (ht_free_fun_t) my_free_zval_ptr,
-+                      1,
-+                      apc_php_malloc, apc_php_free);
++        dst->arBuckets[n] = newp;
 +
-+    if(src->static_members != &(src->default_static_members))
-+    {
-+        dst->static_members = my_copy_hashtable(NULL,
-+                          src->static_members,
-+                          (ht_copy_fun_t) my_copy_zval_ptr,
-+                          (ht_free_fun_t) my_free_zval_ptr,
-+                          1,
-+                          apc_php_malloc, apc_php_free);
-+    }
-+    else 
-+    {
-+        dst->static_members = &(dst->default_static_members);
++        /* copy the bucket data using our 'copy_fn' callback function */
++        CHECK((newp->pData = copy_fn(NULL, curr->pData, ctxt)));
++
++        if (holds_ptrs) {
++            memcpy(&newp->pDataPtr, newp->pData, sizeof(void*));
++        }
++        else {
++            newp->pDataPtr = NULL;
++        }
++
++        /* insert 'newp' into the table-thread linked list */
++        newp->pListLast = prev;
++        newp->pListNext = NULL;
++
++        if (prev) {
++            prev->pListNext = newp;
++        }
++
++        if (first) {
++            dst->pListHead = newp;
++            first = 0;
++        }
++
++        prev = newp;
 +    }
 +
-+#endif
++    dst->pListTail = newp;
 +
 +    return dst;
 +}
 +/* }}} */
 +
-+/* {{{ apc_free_class_entry_after_execution */
-+void apc_free_class_entry_after_execution(zend_class_entry* src)
++/* {{{ my_copy_static_variables */
++static HashTable* my_copy_static_variables(zend_op_array* src, apc_context_t* ctxt)
 +{
-+#ifdef ZEND_ENGINE_2
-+    if(src->num_interfaces > 0 && src->interfaces) {
-+        apc_php_free(src->interfaces);
-+        src->interfaces = NULL;
-+        src->num_interfaces = 0;
-+    }
-+    /* my_destroy_hashtable() does not play nice with refcounts */
-+
-+    zend_hash_clean(&src->default_static_members);
-+    if(src->static_members != &(src->default_static_members))
-+    {
-+        zend_hash_destroy(src->static_members);
-+        apc_php_free(src->static_members);
-+        src->static_members = NULL;
-+    }
-+    else
-+    {
-+        src->static_members = NULL;
++    if (src->static_variables == NULL) {
++        return NULL;
 +    }
-+    zend_hash_clean(&src->default_properties);
-+    zend_hash_clean(&src->constants_table);
-+#endif
 +
-+    /* TODO: more cleanup */
++    return my_copy_hashtable(NULL,
++                             src->static_variables,
++                             (ht_copy_fun_t) my_copy_zval_ptr,
++                             1,
++                             ctxt);
 +}
 +/* }}} */
 +
-+#ifdef ZEND_ENGINE_2
-+
-+/* {{{ my_fixup_function */
-+static void my_fixup_function(Bucket *p, zend_class_entry *src, zend_class_entry *dst)
++/* {{{ apc_copy_zval */
++zval* apc_copy_zval(zval* dst, const zval* src, apc_context_t* ctxt)
 +{
-+    zend_function* zf = p->pData;
++    apc_pool* pool = ctxt->pool;
++    int usegc = (ctxt->copy == APC_COPY_OUT_OPCODE) || (ctxt->copy == APC_COPY_OUT_USER);
 +
-+    #define SET_IF_SAME_NAME(member) \
-+    do { \
-+        if(src->member && !strcmp(zf->common.function_name, src->member->common.function_name)) { \
-+            dst->member = zf; \
-+        } \
-+    } \
-+    while(0)
++    assert(src != NULL);
 +
-+    if(zf->common.scope == src)
-+    {
-+    
-+        /* Fixing up the default functions for objects here since
-+         * we need to compare with the newly allocated functions
-+         *
-+         * caveat: a sub-class method can have the same name as the
-+         * parent's constructor and create problems.
-+         */
-+        
-+        if(zf->common.fn_flags & ZEND_ACC_CTOR) dst->constructor = zf;
-+        else if(zf->common.fn_flags & ZEND_ACC_DTOR) dst->destructor = zf;
-+        else if(zf->common.fn_flags & ZEND_ACC_CLONE) dst->clone = zf;
-+        else
-+        {
-+            SET_IF_SAME_NAME(__get);
-+            SET_IF_SAME_NAME(__set);
-+            SET_IF_SAME_NAME(__unset);
-+            SET_IF_SAME_NAME(__isset);
-+            SET_IF_SAME_NAME(__call);
-+#ifdef ZEND_ENGINE_2_2
-+            SET_IF_SAME_NAME(__tostring);
-+#endif
++    if (!dst) {
++        if(usegc) {
++            ALLOC_ZVAL(dst);
++            CHECK(dst);
++        } else {
++            CHECK(dst = (zval*) apc_pool_alloc(pool, sizeof(zval)));
 +        }
-+        zf->common.scope = dst;
-+    }
-+    else
-+    {
-+        /* no other function should reach here */
-+        assert(0);
 +    }
 +
-+    #undef SET_IF_SAME_NAME
-+}
-+/* }}} */
-+
-+#ifdef ZEND_ENGINE_2_2
-+/* {{{ my_fixup_property_info */
-+static void my_fixup_property_info(Bucket *p, zend_class_entry *src, zend_class_entry *dst)
-+{
-+    zend_property_info* property_info = (zend_property_info*)p->pData;
-+
-+    if(property_info->ce == src)
-+    {
-+        property_info->ce = dst;
-+    }
-+    else
-+    {
-+        assert(0); /* should never happen */
-+    }
++    CHECK(dst = my_copy_zval(dst, src, ctxt));
++    return dst;
 +}
 +/* }}} */
-+#endif
 +
-+/* {{{ my_fixup_hashtable */
-+static void my_fixup_hashtable(HashTable *ht, ht_fixup_fun_t fixup, zend_class_entry *src, zend_class_entry *dst)
++/* {{{ apc_fixup_op_array_jumps */
++static void apc_fixup_op_array_jumps(zend_op_array *dst, zend_op_array *src )
 +{
-+    Bucket *p;
-+    
-+      uint i;
-+    
-+      for (i = 0; i < ht->nTableSize; i++) {
-+              if(!ht->arBuckets) break;
-+        p = ht->arBuckets[i];
-+              while (p != NULL) {
-+            fixup(p, src, dst);
-+                      p = p->pNext;
-+              }
-+      }
-+}
-+/* }}} */
-+
-+#endif
++    uint i;
 +
-+/* {{{ my_check_copy_function */
-+static int my_check_copy_function(Bucket* p, va_list args)
-+{
-+    zend_class_entry* src = va_arg(args, zend_class_entry*);
-+    zend_function* zf = (zend_function*)p->pData;
-+#ifndef ZEND_ENGINE_2
-+    zend_class_entry* parent = src->parent;
-+    zend_function* parent_fn = NULL;
++    for (i=0; i < dst->last; ++i) {
++        zend_op *zo = &(dst->opcodes[i]);
++        /*convert opline number to jump address*/
++        switch (zo->opcode) {
++            case ZEND_JMP:
++                /*Note: if src->opcodes != dst->opcodes then we need to the opline according to src*/
++                zo->op1.u.jmp_addr = dst->opcodes + (zo->op1.u.jmp_addr - src->opcodes);
++                break;
++            case ZEND_JMPZ:
++            case ZEND_JMPNZ:
++            case ZEND_JMPZ_EX:
++            case ZEND_JMPNZ_EX:
++#ifdef ZEND_ENGINE_2_3
++            case ZEND_JMP_SET:
 +#endif
-+
-+#ifdef ZEND_ENGINE_2
-+    return (zf->common.scope == src);
-+#else
-+      if (parent &&
-+        zend_hash_quick_find(&parent->function_table, p->arKey, 
-+            p->nKeyLength, p->h, (void **) &parent_fn)==SUCCESS) {
-+        
-+        if((parent_fn && zf) && 
-+                (parent_fn->op_array.refcount == zf->op_array.refcount))
-+        {
-+            return 0;
++                zo->op2.u.jmp_addr = dst->opcodes + (zo->op2.u.jmp_addr - src->opcodes);
++                break;
++            default:
++                break;
 +        }
 +    }
-+    return 1;
-+#endif 
 +}
 +/* }}} */
 +
-+/* {{{ my_check_copy_default_property */
-+static int my_check_copy_default_property(Bucket* p, va_list args)
++/* {{{ apc_copy_op_array */
++zend_op_array* apc_copy_op_array(zend_op_array* dst, zend_op_array* src, apc_context_t* ctxt TSRMLS_DC)
 +{
-+    zend_class_entry* src = va_arg(args, zend_class_entry*);
-+    zend_class_entry* parent = src->parent;
-+    zval ** child_prop = (zval**)p->pData;
-+    zval ** parent_prop = NULL;
++    int i;
++    apc_fileinfo_t fileinfo;
++    char canon_path[MAXPATHLEN];
++    char *fullpath = NULL;
++    apc_opflags_t * flags = NULL;
++    apc_pool* pool = ctxt->pool;
 +
-+      if (parent &&
-+        zend_hash_quick_find(&parent->default_properties, p->arKey, 
-+            p->nKeyLength, p->h, (void **) &parent_prop)==SUCCESS) {
++    assert(src != NULL);
 +
-+        if((parent_prop && child_prop) && (*parent_prop) == (*child_prop))
-+        {
-+            return 0;
-+        }
++    if (!dst) {
++        CHECK(dst = (zend_op_array*) apc_pool_alloc(pool, sizeof(src[0])));
 +    }
-+    
-+    /* possibly not in the parent */
-+    return 1;
-+}
-+/* }}} */
 +
-+#ifdef ZEND_ENGINE_2
++    if(APCG(apc_optimize_function)) {
++        APCG(apc_optimize_function)(src TSRMLS_CC);
++    }
 +
-+/* {{{ my_check_copy_property_info */
-+static int my_check_copy_property_info(Bucket* p, va_list args)
-+{
-+    zend_class_entry* src = va_arg(args, zend_class_entry*);
-+    zend_class_entry* parent = src->parent;
-+    zend_property_info* child_info = (zend_property_info*)p->pData;
-+    zend_property_info* parent_info = NULL;
++    /* start with a bitwise copy of the array */
++    memcpy(dst, src, sizeof(src[0]));
 +
-+#ifdef ZEND_ENGINE_2_2
-+    /* so much easier */
-+    return (child_info->ce == src);
++    dst->function_name = NULL;
++    dst->filename = NULL;
++    dst->refcount = NULL;
++    dst->opcodes = NULL;
++    dst->brk_cont_array = NULL;
++    dst->static_variables = NULL;
++    dst->try_catch_array = NULL;
++    dst->arg_info = NULL;
++    dst->doc_comment = NULL;
++#ifdef ZEND_ENGINE_2_1
++    dst->vars = NULL;
 +#endif
 +
-+      if (parent &&
-+        zend_hash_quick_find(&parent->properties_info, p->arKey, p->nKeyLength, 
-+            p->h, (void **) &parent_info)==SUCCESS) {
-+        if(parent_info->flags & ZEND_ACC_PRIVATE)
-+        {
-+            return 1;
-+        }
-+        if((parent_info->flags & ZEND_ACC_PPP_MASK) != 
-+            (child_info->flags & ZEND_ACC_PPP_MASK))
-+        {
-+            /* TODO: figure out whether ACC_CHANGED is more appropriate
-+             * here */
-+            return 1;
-+        }
-+        return 0;
++    /* copy the arg types array (if set) */
++    if (src->arg_info) {
++        CHECK(dst->arg_info = my_copy_arg_info_array(NULL,
++                                                src->arg_info,
++                                                src->num_args,
++                                                ctxt));
 +    }
-+    
-+    /* property doesn't exist in parent, copy into cached child */
-+    return 1;
-+}
-+/* }}} */
 +
-+/* {{{ my_check_copy_static_member */
-+static int my_check_copy_static_member(Bucket* p, va_list args)
-+{
-+    zend_class_entry* src = va_arg(args, zend_class_entry*);
-+    HashTable * ht = va_arg(args, HashTable*);
-+    zend_class_entry* parent = src->parent;
-+    HashTable * parent_ht = NULL;
-+    char * member_name;
-+    char * class_name = NULL;
++    if (src->function_name) {
++        CHECK(dst->function_name = apc_pstrdup(src->function_name, pool));
++    }
++    if (src->filename) {
++        CHECK(dst->filename = apc_pstrdup(src->filename, pool));
++    }
 +
-+    zend_property_info *parent_info = NULL;
-+    zend_property_info *child_info = NULL;
-+    zval ** parent_prop = NULL;
-+    zval ** child_prop = (zval**)(p->pData);
++    CHECK(dst->refcount = apc_pmemcpy(src->refcount,
++                                      sizeof(src->refcount[0]),
++                                      pool));
 +
-+    if(!parent) {
-+        return 1;
++    /* deep-copy the opcodes */
++    CHECK(dst->opcodes = (zend_op*) apc_pool_alloc(pool, sizeof(zend_op) * src->last));
++
++    if(apc_reserved_offset != -1) {
++        /* Insanity alert: the void* pointer is cast into an apc_opflags_t 
++         * struct. apc_zend_init() checks to ensure that it fits in a void* */
++        flags = (apc_opflags_t*) & (dst->reserved[apc_reserved_offset]);
++        memset(flags, 0, sizeof(apc_opflags_t));
++        /* assert(sizeof(apc_opflags_t) < sizeof(dst->reserved)); */
 +    }
 +
-+    /* these do not need free'ing */
-+#ifdef ZEND_ENGINE_2_2
-+    zend_unmangle_property_name(p->arKey, p->nKeyLength-1, &class_name, &member_name);
-+#else
-+    zend_unmangle_property_name(p->arKey, &class_name, &member_name);
++    for (i = 0; (uint) i < src->last; i++) {
++        zend_op *zo = &(src->opcodes[i]);
++        /* a lot of files are merely constant arrays with no jumps */
++        switch (zo->opcode) {
++            case ZEND_JMP:
++            case ZEND_JMPZ:
++            case ZEND_JMPNZ:
++            case ZEND_JMPZ_EX:
++            case ZEND_JMPNZ_EX:
++#ifdef ZEND_ENGINE_2_3
++            case ZEND_JMP_SET:
 +#endif
-+
-+    /* please refer do_inherit_property_access_check in zend_compile.c
-+     * to understand why we lookup in properties_info.
-+     */
-+    if((zend_hash_find(&parent->properties_info, member_name, 
-+                        strlen(member_name)+1, (void**)&parent_info) == SUCCESS)
-+        &&
-+        (zend_hash_find(&src->properties_info, member_name,
-+                        strlen(member_name)+1, (void**)&child_info) == SUCCESS))
-+    {
-+        if(child_info->flags & ZEND_ACC_STATIC &&    
-+            (parent_info->flags & ZEND_ACC_PROTECTED &&
-+            child_info->flags & ZEND_ACC_PUBLIC))
-+        {
-+            /* Do not copy into static_members. zend_do_inheritance
-+             * will automatically insert a NULL value.
-+             * TODO: decrement refcount or fixup when copying out for exec ? 
-+             */ 
-+            return 0;
-+        }
-+        if(ht == &(src->default_static_members))
-+        {
-+            parent_ht = &parent->default_static_members;
++                if(flags != NULL) {
++                    flags->has_jumps = 1;
++                }
++                break;
++            /* auto_globals_jit was not in php-4.3.* */
++            case ZEND_FETCH_R:
++            case ZEND_FETCH_W:
++            case ZEND_FETCH_IS:
++            case ZEND_FETCH_FUNC_ARG:
++                if(PG(auto_globals_jit) && flags != NULL)
++                {
++                     /* The fetch is only required if auto_globals_jit=1  */
++                    if(zo->op2.u.EA.type == ZEND_FETCH_GLOBAL &&
++                            zo->op1.op_type == IS_CONST && 
++                            zo->op1.u.constant.type == IS_STRING) {
++                        znode * varname = &zo->op1;
++                        if (varname->u.constant.value.str.val[0] == '_') {
++#define SET_IF_AUTOGLOBAL(member) \
++    if(!strcmp(varname->u.constant.value.str.val, #member)) \
++        flags->member = 1 /* no ';' here */
++                            SET_IF_AUTOGLOBAL(_GET);
++                            else SET_IF_AUTOGLOBAL(_POST);
++                            else SET_IF_AUTOGLOBAL(_COOKIE);
++                            else SET_IF_AUTOGLOBAL(_SERVER);
++                            else SET_IF_AUTOGLOBAL(_ENV);
++                            else SET_IF_AUTOGLOBAL(_FILES);
++                            else SET_IF_AUTOGLOBAL(_REQUEST);
++                            else if(zend_is_auto_global(
++                                            varname->u.constant.value.str.val,
++                                            varname->u.constant.value.str.len
++                                            TSRMLS_CC))
++                            {
++                                flags->unknown_global = 1;
++                            }
++                        }
++                    }
++                }
++                break;
++            case ZEND_RECV_INIT:
++                if(zo->op2.op_type == IS_CONST &&
++                    zo->op2.u.constant.type == IS_CONSTANT_ARRAY) {
++                    if(flags != NULL) {
++                        flags->deep_copy = 1;
++                    }
++                }
++                break;
++            default:
++                if((zo->op1.op_type == IS_CONST &&
++                    zo->op1.u.constant.type == IS_CONSTANT_ARRAY) ||
++                    (zo->op2.op_type == IS_CONST &&
++                        zo->op2.u.constant.type == IS_CONSTANT_ARRAY)) {
++                    if(flags != NULL) {
++                        flags->deep_copy = 1;
++                    }
++                }
++                break;
 +        }
-+        else
-+        {
-+            parent_ht = parent->static_members;
++
++        if(!(my_copy_zend_op(dst->opcodes+i, src->opcodes+i, ctxt))) {
++            return NULL;
 +        }
 +
-+        if(zend_hash_quick_find(parent_ht, p->arKey,
-+                       p->nKeyLength, p->h, (void**)&parent_prop) == SUCCESS)
-+        {
-+            /* they point to the same zval */
-+            if(*parent_prop == *child_prop)
-+            {
-+                return 0;
++/* This code breaks apc's rule#1 - cache what you compile */
++        if((APCG(fpstat)==0) && APCG(canonicalize)) {
++            if((zo->opcode == ZEND_INCLUDE_OR_EVAL) && 
++                (zo->op1.op_type == IS_CONST && zo->op1.u.constant.type == IS_STRING)) {
++                /* constant includes */
++                if(!IS_ABSOLUTE_PATH(Z_STRVAL_P(&zo->op1.u.constant),Z_STRLEN_P(&zo->op1.u.constant))) { 
++                    if (apc_search_paths(Z_STRVAL_P(&zo->op1.u.constant), PG(include_path), &fileinfo) == 0) {
++                        if((fullpath = realpath(fileinfo.fullpath, canon_path))) {
++                            /* everything has to go through a realpath() */
++                            zend_op *dzo = &(dst->opcodes[i]);
++                            dzo->op1.u.constant.value.str.len = strlen(fullpath);
++                            dzo->op1.u.constant.value.str.val = apc_pstrdup(fullpath, pool);
++                        }
++                    }
++                }
 +            }
 +        }
 +    }
-+    
-+    return 1;
-+}
-+/* }}} */
-+#endif
-+
-+/* {{{ apc_register_optimizer(apc_optimize_function_t optimizer)
-+ *      register a optimizer callback function, returns the previous callback
-+ */
-+apc_optimize_function_t apc_register_optimizer(apc_optimize_function_t optimizer TSRMLS_DC) {
-+    apc_optimize_function_t old_optimizer = APCG(apc_optimize_function);
-+    APCG(apc_optimize_function) = optimizer;
-+    return old_optimizer;
-+}
 +
-+/*
-+ * Local variables:
-+ * tab-width: 4
-+ * c-basic-offset: 4
-+ * End:
-+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
-+ * vim<600: expandtab sw=4 ts=4 sts=4
-+ */
-diff -ubrN php-5.2.5-orig/ext/apc/apc_compile.h php-5.2.5/ext/apc/apc_compile.h
---- php-5.2.5-orig/ext/apc/apc_compile.h       1969-12-31 18:00:00.000000000 -0600
-+++ php-5.2.5/ext/apc/apc_compile.h    2007-12-26 16:51:32.000000000 -0600
-@@ -0,0 +1,134 @@
-+/*
-+  +----------------------------------------------------------------------+
-+  | APC                                                                  |
-+  +----------------------------------------------------------------------+
-+  | Copyright (c) 2006 The PHP Group                                     |
-+  +----------------------------------------------------------------------+
-+  | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt                                  |
-+  | If you did not receive a copy of the PHP license and are unable to   |
-+  | obtain it through the world-wide-web, please send a note to          |
-+  | license@php.net so we can mail you a copy immediately.               |
-+  +----------------------------------------------------------------------+
-+  | Authors: Daniel Cowgill <dcowgill@communityconnect.com>              |
-+  |          Arun C. Murthy <arunc@yahoo-inc.com>                        |
-+  |          Gopal Vijayaraghavan <gopalv@yahoo-inc.com>                 |
-+  +----------------------------------------------------------------------+
++    if(flags == NULL || flags->has_jumps) {
++        apc_fixup_op_array_jumps(dst,src);
++    }
 +
-+   This software was contributed to PHP by Community Connect Inc. in 2002
-+   and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
-+   Future revisions and derivatives of this source code must acknowledge
-+   Community Connect Inc. as the original contributor of this module by
-+   leaving this note intact in the source code.
++    /* copy the break-continue array */
++    if (src->brk_cont_array) {
++        CHECK(dst->brk_cont_array = apc_pmemcpy(src->brk_cont_array,
++                                    sizeof(src->brk_cont_array[0]) * src->last_brk_cont,
++                                    pool));
++    }
 +
-+   All other licensing and usage conditions are those of the PHP Group.
++    /* copy the table of static variables */
++    if (src->static_variables) {
++        CHECK(dst->static_variables = my_copy_static_variables(src, ctxt));
++    }
 +
-+ */
++    if (src->try_catch_array) {
++        CHECK(dst->try_catch_array = apc_pmemcpy(src->try_catch_array,
++                                        sizeof(src->try_catch_array[0]) * src->last_try_catch,
++                                        pool));
++    }
 +
-+/* $Id: apc_compile.h,v 3.19 2007/03/08 22:03:35 gopalv Exp $ */
++#ifdef ZEND_ENGINE_2_1 /* PHP 5.1 */
++    if (src->vars) {
++        CHECK(dst->vars = apc_pmemcpy(src->vars,
++                            sizeof(src->vars[0]) * src->last_var,
++                            pool));
 +
-+#ifndef APC_COMPILE_H
-+#define APC_COMPILE_H
++        for(i = 0; i <  src->last_var; i++) dst->vars[i].name = NULL;
 +
-+/*
-+ * This module encapsulates most of the complexity involved in deep-copying
-+ * the Zend compiler data structures. The routines are allocator-agnostic, so
-+ * the same function can be used for copying to and from shared memory.
-+ */
++        for(i = 0; i <  src->last_var; i++) {
++            CHECK(dst->vars[i].name = apc_pmemcpy(src->vars[i].name,
++                                src->vars[i].name_len + 1,
++                                pool));
++        }
++    }
++#endif
 +
-+#include "apc.h"
-+#include "apc_php.h"
++    if (src->doc_comment) {
++        CHECK(dst->doc_comment
++                = apc_pmemcpy(src->doc_comment, src->doc_comment_len+1, pool));
++    }
 +
-+/* {{{ struct definition: apc_function_t */
-+typedef struct apc_function_t apc_function_t;
-+struct apc_function_t {
-+    char* name;                 /* the function name */
-+    int name_len;               /* length of name */
-+    zend_function* function;    /* the zend function data structure */
-+};
++    return dst;
++}
 +/* }}} */
 +
-+/* {{{ struct definition: apc_class_t */
-+typedef struct apc_class_t apc_class_t;
-+struct apc_class_t {
-+    char* name;                     /* the class name */
-+    int name_len;                   /* length of name */
-+    int is_derived;                 /* true if this is a derived class */
-+    char* parent_name;              /* the parent class name */
-+    zend_class_entry* class_entry;  /* the zend class data structure */
-+};
-+/* }}} */
 +
-+/* {{{ struct definition: apc_opflags_t */
-+typedef struct apc_opflags_t apc_opflags_t;
-+struct apc_opflags_t {
-+    unsigned int has_jumps      : 1; /* has jump offsets */
-+    unsigned int deep_copy      : 1; /* needs deep copy */
++/* {{{ apc_copy_new_functions */
++apc_function_t* apc_copy_new_functions(int old_count, apc_context_t* ctxt TSRMLS_DC)
++{
++    apc_function_t* array;
++    int new_count;              /* number of new functions in table */
++    int i;
++    apc_pool* pool = ctxt->pool;
 +
-+    /* autoglobal bits */
-+    unsigned int _POST          : 1;
-+    unsigned int _GET           : 1;
-+    unsigned int _COOKIE        : 1;
-+    unsigned int _SERVER        : 1;
-+    unsigned int _ENV           : 1;
-+    unsigned int _FILES         : 1;
-+    unsigned int _REQUEST       : 1;
-+    unsigned int unknown_global : 1;
-+};
-+/* }}} */
++    new_count = zend_hash_num_elements(CG(function_table)) - old_count;
++    assert(new_count >= 0);
 +
-+/*
-+ * These are the top-level copy functions.
-+ */
++    CHECK(array =
++        (apc_function_t*)
++            apc_pool_alloc(pool, sizeof(apc_function_t) * (new_count+1)));
 +
-+extern zend_op_array* apc_copy_op_array(zend_op_array* dst, zend_op_array* src, apc_malloc_t allocate, apc_free_t deallocate TSRMLS_DC);
-+extern zend_class_entry* apc_copy_class_entry(zend_class_entry* dst, zend_class_entry* src, apc_malloc_t allocate, apc_free_t deallocate);
-+extern apc_function_t* apc_copy_new_functions(int old_count, apc_malloc_t allocate, apc_free_t deallocate TSRMLS_DC);
-+extern apc_class_t* apc_copy_new_classes(zend_op_array* op_array, int old_count, apc_malloc_t allocate, apc_free_t deallocate TSRMLS_DC);
-+extern zval* apc_copy_zval(zval* dst, const zval* src, apc_malloc_t allocate, apc_free_t deallocate);
++    if (new_count == 0) {
++        array[0].function = NULL;
++        return array;
++    }
 +
-+/*
-+ * Deallocation functions corresponding to the copy functions above.
-+ */
++    /* Skip the first `old_count` functions in the table */
++    zend_hash_internal_pointer_reset(CG(function_table));
++    for (i = 0; i < old_count; i++) {
++        zend_hash_move_forward(CG(function_table));
++    }
 +
-+extern void apc_free_op_array(zend_op_array* src, apc_free_t deallocate);
-+extern void apc_free_functions(apc_function_t* src, apc_free_t deallocate);
-+extern void apc_free_classes(apc_class_t* src, apc_free_t deallocate);
-+extern void apc_free_zval(zval* src, apc_free_t deallocate);
++    /* Add the next `new_count` functions to our array */
++    for (i = 0; i < new_count; i++) {
++        char* key;
++        uint key_size;
++        zend_function* fun;
 +
-+/*
-+ * These "copy-for-execution" functions must be called after retrieving an
-+ * object from the shared cache. They do the minimal amount of work necessary
-+ * to allow multiple processes to concurrently execute the same VM data
-+ * structures.
-+ */
++        zend_hash_get_current_key_ex(CG(function_table),
++                                     &key,
++                                     &key_size,
++                                     NULL,
++                                     0,
++                                     NULL);
 +
-+extern zend_op_array* apc_copy_op_array_for_execution(zend_op_array* dst, zend_op_array* src TSRMLS_DC);
-+extern zend_function* apc_copy_function_for_execution(zend_function* src);
-+extern zend_class_entry* apc_copy_class_entry_for_execution(zend_class_entry* src, int is_derived);
++        zend_hash_get_current_data(CG(function_table), (void**) &fun);
 +
-+/*
-+ * The "free-after-execution" function performs a cursory clean up of the class data
-+ * This is required to minimize memory leak warnings and to ensure correct destructor
-+ * ordering of some variables.
-+ */
-+extern void apc_free_class_entry_after_execution(zend_class_entry* src);
-+
-+/*
-+ * Optimization callback definition and registration function. 
-+ */
-+typedef zend_op_array* (*apc_optimize_function_t) (zend_op_array* TSRMLS_DC);
-+extern apc_optimize_function_t apc_register_optimizer(apc_optimize_function_t optimizer TSRMLS_DC);
-+
-+#endif
-+
-+/*
-+ * Local variables:
-+ * tab-width: 4
-+ * c-basic-offset: 4
-+ * End:
-+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
-+ * vim<600: expandtab sw=4 ts=4 sts=4
-+ */
-diff -ubrN php-5.2.5-orig/ext/apc/apc_debug.c php-5.2.5/ext/apc/apc_debug.c
---- php-5.2.5-orig/ext/apc/apc_debug.c 1969-12-31 18:00:00.000000000 -0600
-+++ php-5.2.5/ext/apc/apc_debug.c      2007-12-26 16:51:32.000000000 -0600
-@@ -0,0 +1,57 @@
-+/*
-+  +----------------------------------------------------------------------+
-+  | APC                                                                  |
-+  +----------------------------------------------------------------------+
-+  | Copyright (c) 2006 The PHP Group                                     |
-+  +----------------------------------------------------------------------+
-+  | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt                                  |
-+  | If you did not receive a copy of the PHP license and are unable to   |
-+  | obtain it through the world-wide-web, please send a note to          |
-+  | license@php.net so we can mail you a copy immediately.               |
-+  +----------------------------------------------------------------------+
-+  | Authors: Daniel Cowgill <dcowgill@communityconnect.com>              |
-+  |          Arun C. Murthy <arunc@yahoo-inc.com>                        |
-+  |          Gopal Vijayaraghavan <gopalv@yahoo-inc.com>                 |
-+  +----------------------------------------------------------------------+
++        CHECK(array[i].name = apc_pmemcpy(key, (int) key_size, pool));
++        array[i].name_len = (int) key_size-1;
++        CHECK(array[i].function = my_copy_function(NULL, fun, ctxt));
++        zend_hash_move_forward(CG(function_table));
++    }
 +
-+   This software was contributed to PHP by Community Connect Inc. in 2002
-+   and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
-+   Future revisions and derivatives of this source code must acknowledge
-+   Community Connect Inc. as the original contributor of this module by
-+   leaving this note intact in the source code.
++    array[i].function = NULL;
++    return array;
++}
++/* }}} */
 +
-+   All other licensing and usage conditions are those of the PHP Group.
-+*/
++/* {{{ apc_copy_new_classes */
++apc_class_t* apc_copy_new_classes(zend_op_array* op_array, int old_count, apc_context_t *ctxt TSRMLS_DC)
++{
++    apc_class_t* array;
++    int new_count;              /* number of new classes in table */
++    int i;
++    apc_pool* pool = ctxt->pool;
 +
-+/* $Id: apc_debug.c,v 3.6 2006/12/07 23:51:28 gopalv Exp $ */
-+#include "apc.h"
-+#include <stdio.h>
-+#include "zend_compile.h"
++    new_count = zend_hash_num_elements(CG(class_table)) - old_count;
++    assert(new_count >= 0);
 +
-+#ifdef __DEBUG_APC__
++    CHECK(array =
++        (apc_class_t*)
++            apc_pool_alloc(pool, sizeof(apc_class_t)*(new_count+1)));
 +
-+#include <dlfcn.h>
++    if (new_count == 0) {
++        array[0].class_entry = NULL;
++        return array;
++    }
 +
-+/* keep track of vld_dump_oparray() signature */
-+typedef void (*vld_dump_f) (zend_op_array * TSRMLS_DC);
++    /* Skip the first `old_count` classes in the table */
++    zend_hash_internal_pointer_reset(CG(class_table));
++    for (i = 0; i < old_count; i++) {
++        zend_hash_move_forward(CG(class_table));
++    }
 +
-+#endif
++    /* Add the next `new_count` classes to our array */
++    for (i = 0; i < new_count; i++) {
++        char* key;
++        uint key_size;
++        zend_class_entry* elem = NULL;
 +
-+void dump(zend_op_array *op_array TSRMLS_DC)
-+{
-+#ifdef __DEBUG_APC__
-+      vld_dump_f dump_op_array = dlsym(NULL, "vld_dump_oparray");
++        array[i].class_entry = NULL;
 +
-+      if(dump_op_array)
-+      {
-+              dump_op_array(op_array TSRMLS_CC); 
-+      }
-+      else
-+      {
-+              apc_wprint("vld is not installed or something even worse.");
-+      }
-+#endif
-+}
-diff -ubrN php-5.2.5-orig/ext/apc/apc_debug.h php-5.2.5/ext/apc/apc_debug.h
---- php-5.2.5-orig/ext/apc/apc_debug.h 1969-12-31 18:00:00.000000000 -0600
-+++ php-5.2.5/ext/apc/apc_debug.h      2007-12-26 16:51:32.000000000 -0600
-@@ -0,0 +1 @@
-+void dump(zend_op_array * TSRMLS_DC);
-diff -ubrN php-5.2.5-orig/ext/apc/apc.dsp php-5.2.5/ext/apc/apc.dsp
---- php-5.2.5-orig/ext/apc/apc.dsp     1969-12-31 18:00:00.000000000 -0600
-+++ php-5.2.5/ext/apc/apc.dsp  2007-12-26 16:51:32.000000000 -0600
-@@ -0,0 +1,207 @@
-+# Microsoft Developer Studio Project File - Name="apc" - Package Owner=<4>\r
-+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
-+# ** DO NOT EDIT **\r
-+\r
-+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102\r
-+\r
-+CFG=apc - Win32 Debug_TS\r
-+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
-+!MESSAGE use the Export Makefile command and run\r
-+!MESSAGE \r
-+!MESSAGE NMAKE /f "apc.mak".\r
-+!MESSAGE \r
-+!MESSAGE You can specify a configuration when running NMAKE\r
-+!MESSAGE by defining the macro CFG on the command line. For example:\r
-+!MESSAGE \r
-+!MESSAGE NMAKE /f "apc.mak" CFG="apc - Win32 Debug_TS"\r
-+!MESSAGE \r
-+!MESSAGE Possible choices for configuration are:\r
-+!MESSAGE \r
-+!MESSAGE "apc - Win32 Debug_TS" (based on "Win32 (x86) Dynamic-Link Library")\r
-+!MESSAGE "apc - Win32 Release_TS" (based on "Win32 (x86) Dynamic-Link Library")\r
-+!MESSAGE \r
-+\r
-+# Begin Project\r
-+# PROP AllowPerConfigDependencies 0\r
-+# PROP Scc_ProjName ""\r
-+# PROP Scc_LocalPath ""\r
-+CPP=cl.exe\r
-+MTL=midl.exe\r
-+RSC=rc.exe\r
-+\r
-+!IF  "$(CFG)" == "apc - Win32 Debug_TS"\r
-+\r
-+# PROP BASE Use_MFC 0\r
-+# PROP BASE Use_Debug_Libraries 1\r
-+# PROP BASE Output_Dir "Debug_TS"\r
-+# PROP BASE Intermediate_Dir "Debug_TS"\r
-+# PROP BASE Target_Dir ""\r
-+# PROP Use_MFC 0\r
-+# PROP Use_Debug_Libraries 1\r
-+# PROP Output_Dir "Debug_TS"\r
-+# PROP Intermediate_Dir "Debug_TS"\r
-+# PROP Ignore_Export_Lib 0\r
-+# PROP Target_Dir ""\r
-+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "APC_EXPORTS" /YX /FD /GZ /c\r
-+# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\..\..\php4" /I "..\..\..\php4\main" /I "..\..\..\php4\Zend" /I "..\..\..\php4\TSRM" /I "..\..\..\php4\win32" /I "..\..\..\php4\regex" /D "TSRM_LOCKS" /D HAVE_APC=1 /D "COMPILE_DL_APC" /D ZEND_DEBUG=1 /D ZTS=1 /D "ZEND_WIN32" /D "PHP_WIN32" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "APC_EXPORTS" /YX /FD /GZ /c\r
-+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
-+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
-+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
-+# ADD RSC /l 0x409 /d "_DEBUG"\r
-+BSC32=bscmake.exe\r
-+# ADD BASE BSC32 /nologo\r
-+# ADD BSC32 /nologo\r
-+LINK32=link.exe\r
-+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept\r
-+# ADD LINK32 php4ts_debug.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"Debug_TS/php_apc.dll" /pdbtype:sept /libpath:"..\..\..\php4\Debug_TS"\r
-+\r
-+!ELSEIF  "$(CFG)" == "apc - Win32 Release_TS"\r
-+\r
-+# PROP BASE Use_MFC 0\r
-+# PROP BASE Use_Debug_Libraries 0\r
-+# PROP BASE Output_Dir "Release_TS"\r
-+# PROP BASE Intermediate_Dir "Release_TS"\r
-+# PROP BASE Target_Dir ""\r
-+# PROP Use_MFC 0\r
-+# PROP Use_Debug_Libraries 0\r
-+# PROP Output_Dir "Release_TS"\r
-+# PROP Intermediate_Dir "Release_TS"\r
-+# PROP Ignore_Export_Lib 0\r
-+# PROP Target_Dir ""\r
-+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "APC_EXPORTS" /YX /FD /c\r
-+# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\php4" /I "..\..\..\php4\main" /I "..\..\..\php4\Zend" /I "..\..\..\php4\TSRM" /I "..\..\..\php4\win32" /I "..\..\..\php4\regex" /D "TSRM_LOCKS" /D HAVE_APC=1 /D "COMPILE_DL_APC" /D ZEND_DEBUG=0 /D ZTS=1 /D "ZEND_WIN32" /D "PHP_WIN32" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "APC_EXPORTS" /YX /FD /c\r
-+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
-+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
-+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
-+# ADD RSC /l 0x409 /d "NDEBUG"\r
-+BSC32=bscmake.exe\r
-+# ADD BASE BSC32 /nologo\r
-+# ADD BSC32 /nologo\r
-+LINK32=link.exe\r
-+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386\r
-+# ADD LINK32 php4ts.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"../../Release_TS/php_apc.dll" /libpath:"..\..\..\php4\Release_TS" /libpath:"..\..\..\php4\Release_TS_Inline"\r
-+\r
-+!ENDIF \r
-+\r
-+# Begin Target\r
-+\r
-+# Name "apc - Win32 Debug_TS"\r
-+# Name "apc - Win32 Release_TS"\r
-+# Begin Group "Source Files"\r
-+\r
-+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
-+# Begin Source File\r
-+\r
-+SOURCE=.\apc.c\r
-+# End Source File\r
-+# Begin Source File\r
-+\r
-+SOURCE=.\apc_cache.c\r
-+# End Source File\r
-+# Begin Source File\r
-+\r
-+SOURCE=.\apc_compile.c\r
-+# End Source File\r
-+# Begin Source File\r
-+\r
-+SOURCE=.\apc_debug.c\r
-+# End Source File\r
-+# Begin Source File\r
-+\r
-+SOURCE=.\apc_fcntl_win32.c\r
-+# End Source File\r
-+# Begin Source File\r
-+\r
-+SOURCE=.\apc_main.c\r
-+# End Source File\r
-+# Begin Source File\r
-+\r
-+SOURCE=.\apc_rfc1867.c\r
-+# End Source File\r
-+# Begin Source File\r
-+\r
-+SOURCE=.\apc_shm.c\r
-+# End Source File\r
-+# Begin Source File\r
-+\r
-+SOURCE=.\apc_sma.c\r
-+# End Source File\r
-+# Begin Source File\r
-+\r
-+SOURCE=.\apc_stack.c\r
-+# End Source File\r
-+# Begin Source File\r
-+\r
-+SOURCE=.\apc_zend.c\r
-+# End Source File\r
-+# Begin Source File\r
-+\r
-+SOURCE=.\php_apc.c\r
-+# End Source File\r
-+# End Group\r
-+# Begin Group "Header Files"\r
-+\r
-+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
-+# Begin Source File\r
-+\r
-+SOURCE=.\apc.h\r
-+# End Source File\r
-+# Begin Source File\r
-+\r
-+SOURCE=.\apc_cache.h\r
-+# End Source File\r
-+# Begin Source File\r
-+\r
-+SOURCE=.\apc_compile.h\r
-+# End Source File\r
-+# Begin Source File\r
-+\r
-+SOURCE=.\apc_debug.h\r
-+# End Source File\r
-+# Begin Source File\r
-+\r
-+SOURCE=.\apc_fcntl.h\r
-+# End Source File\r
-+# Begin Source File\r
-+\r
-+SOURCE=.\apc_globals.h\r
-+# End Source File\r
-+# Begin Source File\r
-+\r
-+SOURCE=.\apc_lock.h\r
-+# End Source File\r
-+# Begin Source File\r
-+\r
-+SOURCE=.\apc_main.h\r
-+# End Source File\r
-+# Begin Source File\r
-+\r
-+SOURCE=.\apc_php.h\r
-+# End Source File\r
-+# Begin Source File\r
-+\r
-+SOURCE=.\apc_shm.h\r
-+# End Source File\r
-+# Begin Source File\r
-+\r
-+SOURCE=.\apc_sma.h\r
-+# End Source File\r
-+# Begin Source File\r
-+\r
-+SOURCE=.\apc_stack.h\r
-+# End Source File\r
-+# Begin Source File\r
-+\r
-+SOURCE=.\apc_zend.h\r
-+# End Source File\r
-+# Begin Source File\r
-+\r
-+SOURCE=.\php_apc.h\r
-+# End Source File\r
-+# End Group\r
-+# Begin Group "Resource Files"\r
-+\r
-+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
-+# End Group\r
-+# End Target\r
-+# End Project\r
-diff -ubrN php-5.2.5-orig/ext/apc/apc_fcntl.c php-5.2.5/ext/apc/apc_fcntl.c
---- php-5.2.5-orig/ext/apc/apc_fcntl.c 1969-12-31 18:00:00.000000000 -0600
-+++ php-5.2.5/ext/apc/apc_fcntl.c      2007-12-26 16:51:32.000000000 -0600
-@@ -0,0 +1,118 @@
-+/*
-+  +----------------------------------------------------------------------+
-+  | APC                                                                  |
-+  +----------------------------------------------------------------------+
-+  | Copyright (c) 2006 The PHP Group                                     |
-+  +----------------------------------------------------------------------+
-+  | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt                                  |
-+  | If you did not receive a copy of the PHP license and are unable to   |
-+  | obtain it through the world-wide-web, please send a note to          |
-+  | license@php.net so we can mail you a copy immediately.               |
-+  +----------------------------------------------------------------------+
-+  | Authors: George Schlossnagle <george@omniti.com>                     |
-+  |          Rasmus Lerdorf <rasmus@php.net>                             |
-+  +----------------------------------------------------------------------+
++        zend_hash_get_current_key_ex(CG(class_table),
++                                     &key,
++                                     &key_size,
++                                     NULL,
++                                     0,
++                                     NULL);
 +
-+   This software was contributed to PHP by Community Connect Inc. in 2002
-+   and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
-+   Future revisions and derivatives of this source code must acknowledge
-+   Community Connect Inc. as the original contributor of this module by
-+   leaving this note intact in the source code.
++        zend_hash_get_current_data(CG(class_table), (void**) &elem);
 +
-+   All other licensing and usage conditions are those of the PHP Group.
 +
-+ */
++        elem = *((zend_class_entry**)elem);
 +
-+/* $Id: apc_fcntl.c,v 3.25 2006/06/19 02:52:49 rasmus Exp $ */
++        CHECK(array[i].name = apc_pmemcpy(key, (int) key_size, pool));
++        array[i].name_len = (int) key_size-1;
++        CHECK(array[i].class_entry = my_copy_class_entry(NULL, elem, ctxt));
 +
-+#include "apc_fcntl.h"
-+#include "apc.h"
-+#include <unistd.h>
-+#include <fcntl.h>
++        /*
++         * If the class has a pointer to its parent class, save the parent
++         * name so that we can enable compile-time inheritance when we reload
++         * the child class; otherwise, set the parent name to null and scan
++         * the op_array to determine if this class inherits from some base
++         * class at execution-time.
++         */
 +
-+int apc_fcntl_create(const char* pathname)
-+{
-+    int fd;
-+    if(pathname == NULL) {
-+        char lock_path[] = "/tmp/.apc.XXXXXX";
-+        mktemp(lock_path);
-+        fd = open(lock_path, O_RDWR|O_CREAT, 0666);
-+        if(fd > 0 ) {
-+            unlink(lock_path);
-+            return fd;
-+        } else {
-+            apc_eprint("apc_fcntl_create: open(%s, O_RDWR|O_CREAT, 0666) failed:", lock_path);
-+            return -1;
++        if (elem->parent) {
++            CHECK(array[i].parent_name = apc_pstrdup(elem->parent->name, pool));
 +        }
++        else {
++            array[i].parent_name = NULL;
++        }
++
++        zend_hash_move_forward(CG(class_table));
 +    }
-+    fd = open(pathname, O_RDWR|O_CREAT, 0666);
-+    if(fd > 0 ) {
-+        unlink(pathname);
-+        return fd;
-+    }
-+    apc_eprint("apc_fcntl_create: open(%s, O_RDWR|O_CREAT, 0666) failed:", pathname);
-+    return -1;
-+}
 +
-+void apc_fcntl_destroy(int fd)
-+{
-+    close(fd);
++    array[i].class_entry = NULL;
++    return array;
 +}
++/* }}} */
 +
-+static int lock_reg(int fd, int cmd, int type, off_t offset, int whence, off_t len)
++/* Used only by my_prepare_op_array_for_execution */
++#define APC_PREPARE_FETCH_GLOBAL_FOR_EXECUTION()                                                \
++                         /* The fetch is only required if auto_globals_jit=1  */                \
++                        if(zo->op2.u.EA.type == ZEND_FETCH_GLOBAL &&                            \
++                            zo->op1.op_type == IS_CONST &&                                      \
++                            zo->op1.u.constant.type == IS_STRING &&                             \
++                            zo->op1.u.constant.value.str.val[0] == '_') {                       \
++                                                                                                \
++                            znode* varname = &zo->op1;                                          \
++                            (void)zend_is_auto_global(varname->u.constant.value.str.val,        \
++                                                          varname->u.constant.value.str.len     \
++                                                          TSRMLS_CC);                           \
++                        }                                                                       \
++
++/* {{{ my_prepare_op_array_for_execution */
++static int my_prepare_op_array_for_execution(zend_op_array* dst, zend_op_array* src, apc_context_t* ctxt TSRMLS_DC) 
 +{
-+  int ret;
-+  struct flock lock;
++    /* combine my_fetch_global_vars and my_copy_data_exceptions.
++     *   - Pre-fetch superglobals which would've been pre-fetched in parse phase.
++     *   - If the opcode stream contain mutable data, ensure a copy.
++     *   - Fixup array jumps in the same loop.
++     */
++    int i=src->last;
++    zend_op *zo;
++    zend_op *dzo;
++    apc_opflags_t * flags = apc_reserved_offset  != -1 ? 
++                                (apc_opflags_t*) & (src->reserved[apc_reserved_offset]) : NULL;
++    int needcopy = flags ? flags->deep_copy : 1;
++    /* auto_globals_jit was not in php4 */
++    int do_prepare_fetch_global = PG(auto_globals_jit) && (flags == NULL || flags->unknown_global);
 +
-+  lock.l_type = type;
-+  lock.l_start = offset;
-+  lock.l_whence = whence;
-+  lock.l_len = len;
-+  lock.l_pid = 0;
++#define FETCH_AUTOGLOBAL(member) do { \
++    if(flags && flags->member == 1) { \
++        zend_is_auto_global(#member,\
++                            (sizeof(#member) - 1)\
++                            TSRMLS_CC);\
++    } \
++} while(0);
 +
-+  do { ret = fcntl(fd, cmd, &lock) ; }
-+  while(ret < 0 && errno == EINTR);
-+  return(ret);
-+}
++    FETCH_AUTOGLOBAL(_GET);
++    FETCH_AUTOGLOBAL(_POST);
++    FETCH_AUTOGLOBAL(_COOKIE);
++    FETCH_AUTOGLOBAL(_SERVER);
++    FETCH_AUTOGLOBAL(_ENV);
++    FETCH_AUTOGLOBAL(_FILES);
++    FETCH_AUTOGLOBAL(_REQUEST);
 +
-+void apc_fcntl_lock(int fd)
-+{
-+    if(lock_reg(fd, F_SETLKW, F_WRLCK, 0, SEEK_SET, 0) < 0) {
-+        apc_eprint("apc_fcntl_lock failed:");
-+    }
-+}
++    if(needcopy) {
 +
-+void apc_fcntl_rdlock(int fd)
-+{
-+    if(lock_reg(fd, F_SETLKW, F_RDLCK, 0, SEEK_SET, 0) < 0) {
-+        apc_eprint("apc_fcntl_rdlock failed:");
-+    }
-+}
++        dst->opcodes = (zend_op*) apc_xmemcpy(src->opcodes,
++                                    sizeof(zend_op) * src->last,
++                                    apc_php_malloc);
++        zo = src->opcodes;
++        dzo = dst->opcodes;
++        while(i > 0) {
 +
-+zend_bool apc_fcntl_nonblocking_lock(int fd)
-+{
-+    if(lock_reg(fd, F_SETLK, F_WRLCK, 0, SEEK_SET, 0) < 0) {
-+        if(errno==EACCES||errno==EAGAIN) return 0;
-+        else apc_eprint("apc_fcntl_lock failed:");
-+    }
-+    return 1;
-+}
-+
-+void apc_fcntl_unlock(int fd)
-+{
-+    if(lock_reg(fd, F_SETLKW, F_UNLCK, 0, SEEK_SET, 0) < 0) {
-+        apc_eprint("apc_fcntl_unlock failed:");
-+    }
-+}
-+
-+/*
-+ * Local variables:
-+ * tab-width: 4
-+ * c-basic-offset: 4
-+ * End:
-+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
-+ * vim<600: expandtab sw=4 ts=4 sts=4
-+ */
-diff -ubrN php-5.2.5-orig/ext/apc/apc_fcntl.h php-5.2.5/ext/apc/apc_fcntl.h
---- php-5.2.5-orig/ext/apc/apc_fcntl.h 1969-12-31 18:00:00.000000000 -0600
-+++ php-5.2.5/ext/apc/apc_fcntl.h      2007-12-26 16:51:32.000000000 -0600
-@@ -0,0 +1,50 @@
-+/*
-+  +----------------------------------------------------------------------+
-+  | APC                                                                  |
-+  +----------------------------------------------------------------------+
-+  | Copyright (c) 2006 The PHP Group                                     |
-+  +----------------------------------------------------------------------+
-+  | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt.            &