Merge branch 'master' into scalar_type_hints_v5

This commit is contained in:
Anthony Ferrara 2015-02-20 13:33:35 -05:00
commit dc35868a77
31 changed files with 1573 additions and 179 deletions

1
NEWS
View File

@ -34,6 +34,7 @@
. Implemented FR #55467 (phpinfo: PHP Variables with $ and single quotes). (Kalle)
. Fixed bug #55415 (php_info produces invalid anchor names). (Kalle, Johannes)
. Added ?? operator. (Andrea)
. Added <=> operator. (Andrea)
. Added \u{xxxxx} Unicode Codepoint Escape Syntax. (Andrea)
. Fixed oversight where define() did not support arrays yet const syntax did. (Andrea, Dmitry)
. Use "integer" and "float" instead of "long" and "double" in ZPP, type hint and conversion error messages. (Andrea)

View File

@ -398,6 +398,8 @@ Other
. Added \u{xxxxxx} Unicode Codepoint Escape Syntax for double-quoted strings
and heredocs.
. define() now supports arrays as constant values, fixing an oversight where define() did not support arrays yet const syntax did.
. Added the comparison operator (<=>), aka the spaceship operator.
(RFC: https://wiki.php.net/rfc/combined-comparison-operator)
========================================
3. Changes in SAPI modules

View File

@ -0,0 +1,18 @@
--TEST--
Bug #69092-2 (Declare Encoding Compile Check Wrong) - multibyte off
--INI--
zend.multibyte=0
--FILE--
<?php
echo "Hi";
function foo() {
declare(encoding="UTF-8");
}
echo "Bye"
?>
--EXPECTF--
Warning: declare(encoding=...) ignored because Zend multibyte feature is turned off by settings in %s on line %d
Fatal error: Encoding declaration pragma must be the very first statement in the script in %s on line %d

22
Zend/tests/bug69092.phpt Normal file
View File

@ -0,0 +1,22 @@
--TEST--
Bug #69092 (Declare Encoding Compile Check Wrong)
--SKIPIF--
<?php
if (!extension_loaded("mbstring")) {
die("skip Requires mbstring extension");
}
?>
--INI--
zend.multibyte=On
--FILE--
<?php
echo "Hi";
function foo() {
declare(encoding="utf-8");
}
echo "Bye"
?>
--EXPECTF--
Fatal error: Encoding declaration pragma must be the very first statement in the script in %s on line %d

View File

@ -3938,7 +3938,7 @@ ZEND_API zend_string *zend_resolve_method_name(zend_class_entry *ce, zend_functi
zend_string *name;
if (f->common.type != ZEND_USER_FUNCTION ||
*(f->op_array.refcount) < 2 ||
(f->op_array.refcount && *(f->op_array.refcount) < 2) ||
!f->common.scope ||
!f->common.scope->trait_aliases) {
return f->common.function_name;

File diff suppressed because it is too large Load Diff

View File

@ -203,6 +203,7 @@ ZEND_API zend_ast *zend_ast_create_list(uint32_t init_children, zend_ast_kind ki
ZEND_API zend_ast *zend_ast_list_add(zend_ast *list, zend_ast *op);
ZEND_API void zend_ast_evaluate(zval *result, zend_ast *ast, zend_class_entry *scope);
ZEND_API zend_string *zend_ast_export(const char *prefix, zend_ast *ast, const char *suffix);
ZEND_API zend_ast *zend_ast_copy(zend_ast *ast);
ZEND_API void zend_ast_destroy(zend_ast *ast);

View File

@ -1227,7 +1227,7 @@ ZEND_FUNCTION(get_class_methods)
zend_binary_strcasecmp(key->val, key->len, mptr->common.function_name->val, len) == 0) {
if (mptr->type == ZEND_USER_FUNCTION &&
*mptr->op_array.refcount > 1 &&
(!mptr->op_array.refcount || *mptr->op_array.refcount > 1) &&
!same_name(key, mptr->common.function_name)) {
ZVAL_STR_COPY(&method_name, zend_find_alias_name(mptr->common.scope, key));
zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &method_name);
@ -1936,7 +1936,9 @@ ZEND_FUNCTION(create_function)
zend_error(E_ERROR, "Unexpected inconsistency in create_function()");
RETURN_FALSE;
}
(*func->refcount)++;
if (func->refcount) {
(*func->refcount)++;
}
static_variables = func->static_variables;
func->static_variables = NULL;
zend_hash_str_del(EG(function_table), LAMBDA_TEMP_FUNCNAME, sizeof(LAMBDA_TEMP_FUNCNAME)-1);

View File

@ -499,7 +499,9 @@ ZEND_API void zend_create_closure(zval *res, zend_function *func, zend_class_ent
zend_hash_apply_with_arguments(static_variables, zval_copy_static_var, 1, closure->func.op_array.static_variables);
}
closure->func.op_array.run_time_cache = NULL;
(*closure->func.op_array.refcount)++;
if (closure->func.op_array.refcount) {
(*closure->func.op_array.refcount)++;
}
} else {
/* verify that we aren't binding internal function to a wrong scope */
if(func->common.scope != NULL) {

View File

@ -927,9 +927,13 @@ ZEND_API void function_add_ref(zend_function *function) /* {{{ */
if (function->type == ZEND_USER_FUNCTION) {
zend_op_array *op_array = &function->op_array;
(*op_array->refcount)++;
if (op_array->refcount) {
(*op_array->refcount)++;
}
if (op_array->static_variables) {
op_array->static_variables = zend_array_dup(op_array->static_variables);
if (!(GC_FLAGS(op_array->static_variables) & IS_ARRAY_IMMUTABLE)) {
GC_REFCOUNT(op_array->static_variables)++;
}
}
op_array->run_time_cache = NULL;
} else if (function->type == ZEND_INTERNAL_FUNCTION) {
@ -972,7 +976,9 @@ ZEND_API int do_bind_function(const zend_op_array *op_array, const zend_op *opli
}
return FAILURE;
} else {
(*function->op_array.refcount)++;
if (function->op_array.refcount) {
(*function->op_array.refcount)++;
}
function->op_array.static_variables = NULL; /* NULL out the unbound function */
return SUCCESS;
}
@ -3160,6 +3166,12 @@ static void zend_compile_static_var_common(zend_ast *var_ast, zval *value, zend_
zend_hash_init(CG(active_op_array)->static_variables, 8, NULL, ZVAL_PTR_DTOR, 0);
}
if (GC_REFCOUNT(CG(active_op_array)->static_variables) > 1) {
if (!(GC_FLAGS(CG(active_op_array)->static_variables) & IS_ARRAY_IMMUTABLE)) {
GC_REFCOUNT(CG(active_op_array)->static_variables)--;
}
CG(active_op_array)->static_variables = zend_array_dup(CG(active_op_array)->static_variables);
}
zend_hash_update(CG(active_op_array)->static_variables, Z_STR(var_node.u.constant), value);
opline = zend_emit_op(&result, by_ref ? ZEND_FETCH_W : ZEND_FETCH_R, &var_node, NULL);
@ -3872,16 +3884,26 @@ void zend_compile_declare(zend_ast *ast) /* {{{ */
ZVAL_COPY_VALUE(&CG(declarables).ticks, &value_zv);
zval_dtor(&value_zv);
} else if (zend_string_equals_literal_ci(name, "encoding")) {
uint32_t i = 0;
zend_bool valid = 0;
/* Encoding declaration was already handled during parsing. Here we
* only check that it is the first statement in the file. */
uint32_t num = CG(active_op_array)->last;
while (num > 0 &&
(CG(active_op_array)->opcodes[num-1].opcode == ZEND_EXT_STMT ||
CG(active_op_array)->opcodes[num-1].opcode == ZEND_TICKS)) {
--num;
}
zend_ast_list *file_ast = zend_ast_get_list(CG(ast));
if (num > 0) {
/* Check to see if this declare is preceeded only by declare statements */
while (valid == 0 && i < file_ast->children) {
if (file_ast->child[i] == ast) {
valid = 1;
} else if (file_ast->child[i] == NULL) {
/* Empty statements are not allowed prior to a declare */
break;
} else if (file_ast->child[i]->kind != ZEND_AST_DECLARE) {
/* declares can only be preceeded by other declares */
break;
}
i++;
}
if (valid != 1) {
zend_error_noreturn(E_COMPILE_ERROR, "Encoding declaration pragma must be "
"the very first statement in the script");
}

View File

@ -1230,6 +1230,12 @@ static zend_always_inline HashTable *zend_get_target_symbol_table(zend_execute_d
} else if (EXPECTED(fetch_type == ZEND_FETCH_STATIC)) {
ZEND_ASSERT(EX(func)->op_array.static_variables != NULL);
ht = EX(func)->op_array.static_variables;
if (GC_REFCOUNT(ht) > 1) {
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
GC_REFCOUNT(ht)--;
}
EX(func)->op_array.static_variables = ht = zend_array_dup(ht);
}
} else {
ZEND_ASSERT(fetch_type == ZEND_FETCH_LOCAL);
if (!EX(symbol_table)) {

View File

@ -595,8 +595,9 @@ ZEND_API int zval_update_constant_ex(zval *p, zend_bool inline_change, zend_clas
if (Z_REFCOUNTED_P(p)) Z_SET_REFCOUNT_P(p, refcount);
} else if (Z_TYPE_P(p) == IS_CONSTANT_AST) {
zval tmp;
SEPARATE_ZVAL_NOREF(p);
if (inline_change) {
SEPARATE_ZVAL_NOREF(p);
}
zend_ast_evaluate(&tmp, Z_ASTVAL_P(p), scope);
if (inline_change) {
zend_ast_destroy_and_free(Z_ASTVAL_P(p));

View File

@ -236,7 +236,9 @@ ZEND_API void zend_generator_create_zval(zend_execute_data *call, zend_op_array
zend_op_array *op_array_copy = (zend_op_array*)emalloc(sizeof(zend_op_array));
*op_array_copy = *op_array;
(*op_array->refcount)++;
if (op_array->refcount) {
(*op_array->refcount)++;
}
op_array->run_time_cache = NULL;
if (op_array->static_variables) {
ALLOC_HASHTABLE(op_array_copy->static_variables);

View File

@ -130,7 +130,8 @@ ZEND_API void zend_function_dtor(zval *zv)
ZEND_API void zend_cleanup_op_array_data(zend_op_array *op_array)
{
if (op_array->static_variables) {
if (op_array->static_variables &&
!(GC_FLAGS(op_array->static_variables) & IS_ARRAY_IMMUTABLE)) {
zend_hash_clean(op_array->static_variables);
}
}
@ -317,16 +318,19 @@ ZEND_API void destroy_op_array(zend_op_array *op_array)
zval *end;
uint32_t i;
if (op_array->static_variables) {
zend_hash_destroy(op_array->static_variables);
FREE_HASHTABLE(op_array->static_variables);
if (op_array->static_variables &&
!(GC_FLAGS(op_array->static_variables) & IS_ARRAY_IMMUTABLE)) {
if (--GC_REFCOUNT(op_array->static_variables) == 0) {
zend_array_destroy(op_array->static_variables);
FREE_HASHTABLE(op_array->static_variables);
}
}
if (op_array->run_time_cache && !op_array->function_name) {
efree(op_array->run_time_cache);
}
if (--(*op_array->refcount)>0) {
if (!op_array->refcount || --(*op_array->refcount)>0) {
return;
}

View File

@ -350,6 +350,9 @@ static zend_always_inline zend_uchar zval_get_type(const zval* pz) {
#define IS_STR_CONSTANT (1<<3) /* constant index */
#define IS_STR_CONSTANT_UNQUALIFIED (1<<4) /* the same as IS_CONSTANT_UNQUALIFIED */
/* array flags */
#define IS_ARRAY_IMMUTABLE (1<<1) /* the same as IS_TYPE_IMMUTABLE */
/* object flags (zval.value->gc.u.flags) */
#define IS_OBJ_APPLY_COUNT 0x07
#define IS_OBJ_DESTRUCTOR_CALLED (1<<3)

View File

@ -9,4 +9,4 @@ declare(encoding="ISO-8859-1");
echo "ok\n";
?>
--EXPECTF--
ok
ok

View File

@ -10,4 +10,4 @@ declare(encoding="ISO-8859-15") {
}
?>
--EXPECTF--
ok
Fatal error: Encoding declaration pragma must be the very first statement in the script in %s on line %d

View File

@ -0,0 +1,16 @@
--TEST--
zend multibyte (15)
--INI--
zend.multibyte=1
--FILE--
<?php
declare(encoding="ISO-8859-15") {
echo "ok\n";
}
declare(encoding="UTF-8") {
echo "ok\n";
}
?>
--EXPECTF--
ok
ok

View File

@ -0,0 +1,14 @@
--TEST--
zend multibyte (16)
--INI--
zend.multibyte=1
--FILE--
<?php
declare(encoding="ISO-8859-15") {
echo "ok\n";
}
echo "ok\n";
?>
--EXPECTF--
ok
ok

View File

@ -1163,7 +1163,13 @@ static zend_persistent_script *cache_script_in_shared_memory(zend_persistent_scr
memory_used = zend_accel_script_persist_calc(new_persistent_script, key, key_length);
/* Allocate shared memory */
#ifdef __SSE2__
/* Align to 64-byte boundary */
ZCG(mem) = zend_shared_alloc(memory_used + 64);
ZCG(mem) = (void*)(((zend_uintptr_t)ZCG(mem) + 63L) & ~63L);
#else
ZCG(mem) = zend_shared_alloc(memory_used);
#endif
if (!ZCG(mem)) {
zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM);
zend_shared_alloc_unlock();
@ -1973,7 +1979,11 @@ static int accel_clean_non_persistent_function(zval *zv)
return ZEND_HASH_APPLY_STOP;
} else {
if (function->op_array.static_variables) {
accel_fast_hash_destroy(function->op_array.static_variables);
if (!(GC_FLAGS(function->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) {
if (--GC_REFCOUNT(function->op_array.static_variables) == 0) {
accel_fast_hash_destroy(function->op_array.static_variables);
}
}
function->op_array.static_variables = NULL;
}
return ZEND_HASH_APPLY_REMOVE;
@ -2025,7 +2035,11 @@ static void zend_accel_fast_shutdown(void)
break;
} else {
if (func->op_array.static_variables) {
accel_fast_hash_destroy(func->op_array.static_variables);
if (!(GC_FLAGS(func->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) {
if (--GC_REFCOUNT(func->op_array.static_variables) == 0) {
accel_fast_hash_destroy(func->op_array.static_variables);
}
}
}
zend_accel_fast_del_bucket(EG(function_table), _idx-1, _p);
}
@ -2043,7 +2057,11 @@ static void zend_accel_fast_shutdown(void)
ZEND_HASH_FOREACH_PTR(&ce->function_table, func) {
if (func->type == ZEND_USER_FUNCTION) {
if (func->op_array.static_variables) {
accel_fast_hash_destroy(func->op_array.static_variables);
if (!(GC_FLAGS(func->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) {
if (--GC_REFCOUNT(func->op_array.static_variables) == 0) {
accel_fast_hash_destroy(func->op_array.static_variables);
}
}
func->op_array.static_variables = NULL;
}
}

View File

@ -25,10 +25,6 @@
#include "zend_persist.h"
#include "zend_shared_alloc.h"
#define ZEND_PROTECTED_REFCOUNT (1<<30)
static uint32_t zend_accel_refcount = ZEND_PROTECTED_REFCOUNT;
#if SIZEOF_SIZE_T <= SIZEOF_ZEND_LONG
/* If sizeof(void*) == sizeof(ulong) we can use zend_hash index functions */
# define accel_xlat_set(old, new) zend_hash_index_update_ptr(&ZCG(bind_hash), (zend_ulong)(zend_uintptr_t)(old), (new))
@ -55,8 +51,11 @@ static void zend_accel_destroy_zend_function(zval *zv)
if (function->type == ZEND_USER_FUNCTION) {
if (function->op_array.static_variables) {
FREE_HASHTABLE(function->op_array.static_variables);
if (!(GC_FLAGS(function->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) {
if (--GC_REFCOUNT(function->op_array.static_variables) == 0) {
FREE_HASHTABLE(function->op_array.static_variables);
}
}
function->op_array.static_variables = NULL;
}
}
@ -366,24 +365,6 @@ static void zend_hash_clone_zval(HashTable *ht, HashTable *source, int bind)
}
}
/* protects reference count, creates copy of statics */
static zend_always_inline void zend_prepare_function_for_execution(zend_op_array *op_array)
{
/* protect reference count */
op_array->refcount = &zend_accel_refcount;
(*op_array->refcount) = ZEND_PROTECTED_REFCOUNT;
/* copy statics */
if (UNEXPECTED(op_array->static_variables)) {
HashTable *shared_statics = op_array->static_variables;
ALLOC_HASHTABLE(op_array->static_variables);
GC_REFCOUNT(op_array->static_variables) = 1;
GC_TYPE(op_array->static_variables) = IS_ARRAY;
zend_hash_clone_zval(op_array->static_variables, shared_statics, 0);
}
}
static void zend_hash_clone_methods(HashTable *ht, HashTable *source, zend_class_entry *old_ce, zend_class_entry *ce)
{
uint idx;
@ -432,31 +413,11 @@ static void zend_hash_clone_methods(HashTable *ht, HashTable *source, zend_class
ZVAL_PTR(&q->val, ARENA_REALLOC(Z_PTR(p->val)));
new_entry = (zend_op_array*)Z_PTR(q->val);
/* Copy constructor */
/* we use refcount to show that op_array is referenced from several places */
if (new_entry->refcount != NULL) {
accel_xlat_set(Z_PTR(p->val), new_entry);
}
zend_prepare_function_for_execution(new_entry);
if (old_ce == new_entry->scope) {
new_entry->scope = ce;
} else {
if ((new_ce = accel_xlat_get(new_entry->scope)) != NULL) {
new_entry->scope = new_ce;
} else {
zend_error(E_ERROR, ACCELERATOR_PRODUCT_NAME " class loading error, class %s, function %s", ce->name->val, new_entry->function_name->val);
}
}
new_entry->scope = ARENA_REALLOC(new_entry->scope);
/* update prototype */
if (new_entry->prototype) {
if ((new_prototype = accel_xlat_get(new_entry->prototype)) != NULL) {
new_entry->prototype = new_prototype;
} else {
zend_error(E_ERROR, ACCELERATOR_PRODUCT_NAME " class loading error, class %s, function %s", ce->name->val, new_entry->function_name->val);
}
new_entry->prototype = ARENA_REALLOC(new_entry->prototype);
}
}
}
@ -517,24 +478,14 @@ static void zend_hash_clone_prop_info(HashTable *ht, HashTable *source, zend_cla
prop_info->doc_comment = NULL;
}
}
if (prop_info->ce == old_ce) {
prop_info->ce = ce;
} else if ((new_ce = accel_xlat_get(prop_info->ce)) != NULL) {
prop_info->ce = new_ce;
} else {
zend_error(E_ERROR, ACCELERATOR_PRODUCT_NAME" class loading error, class %s, property %s", ce->name->val, prop_info->name->val);
}
prop_info->ce = ARENA_REALLOC(prop_info->ce);
}
}
#define zend_update_inherited_handler(handler) \
{ \
if (ce->handler != NULL) { \
if ((new_func = accel_xlat_get(ce->handler)) != NULL) { \
ce->handler = new_func; \
} else { \
zend_error(E_ERROR, ACCELERATOR_PRODUCT_NAME " class loading error, class %s", ce->name->val); \
} \
ce->handler = ARENA_REALLOC(ce->handler); \
} \
}
@ -549,11 +500,6 @@ static void zend_class_copy_ctor(zend_class_entry **pce)
*pce = ce = ARENA_REALLOC(old_ce);
ce->refcount = 1;
if (old_ce->refcount != 1) {
/* this class is not used as a parent for any other classes */
accel_xlat_set(old_ce, ce);
}
if (old_ce->default_properties_table) {
int i;
@ -603,11 +549,7 @@ static void zend_class_copy_ctor(zend_class_entry **pce)
}
if (ce->parent) {
if ((new_ce = accel_xlat_get(ce->parent)) != NULL) {
ce->parent = new_ce;
} else {
zend_error(E_ERROR, ACCELERATOR_PRODUCT_NAME" class loading error, class %s", ce->name->val);
}
ce->parent = ARENA_REALLOC(ce->parent);
}
zend_update_inherited_handler(constructor);
@ -718,21 +660,14 @@ static void zend_accel_function_hash_copy(HashTable *target, HashTable *source)
for (idx = 0; idx < source->nNumUsed; idx++) {
p = source->arData + idx;
if (Z_TYPE(p->val) == IS_UNDEF) continue;
if (p->key) {
t = zend_hash_add(target, p->key, &p->val);
if (UNEXPECTED(t == NULL)) {
if (p->key->len > 0 && p->key->val[0] == 0) {
/* Mangled key */
t = zend_hash_update(target, p->key, &p->val);
} else {
t = zend_hash_find(target, p->key);
goto failure;
}
}
} else {
t = zend_hash_index_add(target, p->h, &p->val);
if (UNEXPECTED(t == NULL)) {
t = zend_hash_index_find(target, p->h);
ZEND_ASSERT(p->key);
t = zend_hash_add(target, p->key, &p->val);
if (UNEXPECTED(t == NULL)) {
if (p->key->len > 0 && p->key->val[0] == 0) {
/* Mangled key */
t = zend_hash_update(target, p->key, &p->val);
} else {
t = zend_hash_find(target, p->key);
goto failure;
}
}
@ -767,26 +702,18 @@ static void zend_accel_function_hash_copy_from_shm(HashTable *target, HashTable
for (idx = 0; idx < source->nNumUsed; idx++) {
p = source->arData + idx;
if (Z_TYPE(p->val) == IS_UNDEF) continue;
if (p->key) {
t = zend_hash_add(target, p->key, &p->val);
if (UNEXPECTED(t == NULL)) {
if (p->key->len > 0 && p->key->val[0] == 0) {
/* Mangled key */
t = zend_hash_update(target, p->key, &p->val);
} else {
t = zend_hash_find(target, p->key);
goto failure;
}
}
} else {
t = zend_hash_index_add(target, p->h, &p->val);
if (UNEXPECTED(t == NULL)) {
t = zend_hash_index_find(target, p->h);
ZEND_ASSERT(p->key);
t = zend_hash_add(target, p->key, &p->val);
if (UNEXPECTED(t == NULL)) {
if (p->key->len > 0 && p->key->val[0] == 0) {
/* Mangled key */
t = zend_hash_update(target, p->key, &p->val);
} else {
t = zend_hash_find(target, p->key);
goto failure;
}
}
Z_PTR_P(t) = ARENA_REALLOC(Z_PTR(p->val));
zend_prepare_function_for_execution((zend_op_array*)Z_PTR_P(t));
}
target->nInternalPointer = target->nNumOfElements ? 0 : INVALID_IDX;
return;
@ -818,24 +745,15 @@ static void zend_accel_class_hash_copy(HashTable *target, HashTable *source, uni
for (idx = 0; idx < source->nNumUsed; idx++) {
p = source->arData + idx;
if (Z_TYPE(p->val) == IS_UNDEF) continue;
if (p->key) {
t = zend_hash_add(target, p->key, &p->val);
if (UNEXPECTED(t == NULL)) {
if (p->key->len > 0 && p->key->val[0] == 0) {
/* Mangled key - ignore and wait for runtime */
continue;
} else if (!ZCG(accel_directives).ignore_dups) {
t = zend_hash_find(target, p->key);
goto failure;
}
}
} else {
t = zend_hash_index_add(target, p->h, &p->val);
if (UNEXPECTED(t == NULL)) {
if (!ZCG(accel_directives).ignore_dups) {
t = zend_hash_index_find(target,p->h);
goto failure;
}
ZEND_ASSERT(p->key);
t = zend_hash_add(target, p->key, &p->val);
if (UNEXPECTED(t == NULL)) {
if (p->key->len > 0 && p->key->val[0] == 0) {
/* Mangled key - ignore and wait for runtime */
continue;
} else if (!ZCG(accel_directives).ignore_dups) {
t = zend_hash_find(target, p->key);
goto failure;
}
}
if (pCopyConstructor) {
@ -853,6 +771,34 @@ failure:
zend_error(E_ERROR, "Cannot redeclare class %s", ce1->name->val);
}
#ifdef __SSE2__
#include <mmintrin.h>
#include <emmintrin.h>
static zend_always_inline void fast_memcpy(void *dest, const void *src, size_t size)
{
__m128i *dqdest = (__m128i*)dest;
const __m128i *dqsrc = (const __m128i*)src;
const __m128i *end = (const __m128i*)((const char*)src + size);
do {
_mm_prefetch(dqsrc + 4, _MM_HINT_NTA);
_mm_prefetch(dqsrc + 6, _MM_HINT_NTA);
__m128i xmm0 = _mm_load_si128(dqsrc + 0);
__m128i xmm1 = _mm_load_si128(dqsrc + 1);
__m128i xmm2 = _mm_load_si128(dqsrc + 2);
__m128i xmm3 = _mm_load_si128(dqsrc + 3);
dqsrc += 4;
_mm_stream_si128(dqdest + 0, xmm0);
_mm_stream_si128(dqdest + 1, xmm1);
_mm_stream_si128(dqdest + 2, xmm2);
_mm_stream_si128(dqdest + 3, xmm3);
dqdest += 4;
} while (dqsrc != end);
}
#endif
zend_op_array* zend_accel_load_script(zend_persistent_script *persistent_script, int from_shared_memory)
{
zend_op_array *op_array;
@ -866,8 +812,15 @@ zend_op_array* zend_accel_load_script(zend_persistent_script *persistent_script,
ZCG(current_persistent_script) = persistent_script;
ZCG(arena_mem) = NULL;
if (EXPECTED(persistent_script->arena_size)) {
#ifdef __SSE2__
/* Target address must be aligned to 64-byte boundary */
ZCG(arena_mem) = zend_arena_alloc(&CG(arena), persistent_script->arena_size + 64);
ZCG(arena_mem) = (void*)(((zend_uintptr_t)ZCG(arena_mem) + 63L) & ~63L);
fast_memcpy(ZCG(arena_mem), persistent_script->arena_mem, persistent_script->arena_size);
#else
ZCG(arena_mem) = zend_arena_alloc(&CG(arena), persistent_script->arena_size);
memcpy(ZCG(arena_mem), persistent_script->arena_mem, persistent_script->arena_size);
#endif
}
/* Copy all the necessary stuff from shared memory to regular memory, and protect the shared script */
@ -880,8 +833,6 @@ zend_op_array* zend_accel_load_script(zend_persistent_script *persistent_script,
zend_accel_function_hash_copy_from_shm(CG(function_table), &persistent_script->function_table);
}
zend_prepare_function_for_execution(op_array);
/* Register __COMPILER_HALT_OFFSET__ constant */
if (persistent_script->compiler_halt_offset != 0 &&
persistent_script->full_path) {

View File

@ -204,6 +204,7 @@ static void zend_persist_zval(zval *z)
/* make immutable array */
Z_TYPE_FLAGS_P(z) = IS_TYPE_IMMUTABLE;
GC_REFCOUNT(Z_COUNTED_P(z)) = 2;
GC_FLAGS(Z_COUNTED_P(z)) |= IS_ARRAY_IMMUTABLE;
Z_ARRVAL_P(z)->u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
}
}
@ -229,6 +230,63 @@ static void zend_persist_zval(zval *z)
}
}
static void zend_persist_zval_static(zval *z)
{
zend_uchar flags;
void *new_ptr;
switch (Z_TYPE_P(z)) {
case IS_STRING:
case IS_CONSTANT:
flags = Z_GC_FLAGS_P(z) & ~ (IS_STR_PERSISTENT | IS_STR_INTERNED | IS_STR_PERMANENT);
zend_accel_store_interned_string(Z_STR_P(z));
Z_GC_FLAGS_P(z) |= flags;
Z_TYPE_FLAGS_P(z) &= ~(IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE);
break;
case IS_ARRAY:
new_ptr = zend_shared_alloc_get_xlat_entry(Z_ARR_P(z));
if (new_ptr) {
Z_ARR_P(z) = new_ptr;
Z_TYPE_FLAGS_P(z) = IS_TYPE_IMMUTABLE;
} else {
if (Z_IMMUTABLE_P(z)) {
Z_ARR_P(z) = zend_accel_memdup(Z_ARR_P(z), sizeof(zend_array));
zend_hash_persist_immutable(Z_ARRVAL_P(z));
} else {
GC_REMOVE_FROM_BUFFER(Z_ARR_P(z));
zend_accel_store(Z_ARR_P(z), sizeof(zend_array));
zend_hash_persist(Z_ARRVAL_P(z), zend_persist_zval);
/* make immutable array */
Z_TYPE_FLAGS_P(z) = IS_TYPE_IMMUTABLE;
GC_REFCOUNT(Z_COUNTED_P(z)) = 2;
GC_FLAGS(Z_COUNTED_P(z)) |= IS_ARRAY_IMMUTABLE;
Z_ARRVAL_P(z)->u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
}
}
break;
case IS_REFERENCE:
new_ptr = zend_shared_alloc_get_xlat_entry(Z_REF_P(z));
if (new_ptr) {
Z_REF_P(z) = new_ptr;
} else {
zend_accel_store(Z_REF_P(z), sizeof(zend_reference));
zend_persist_zval(Z_REFVAL_P(z));
}
break;
case IS_CONSTANT_AST:
new_ptr = zend_shared_alloc_get_xlat_entry(Z_AST_P(z));
if (new_ptr) {
Z_AST_P(z) = new_ptr;
} else {
zend_accel_store(Z_AST_P(z), sizeof(zend_ast_ref));
Z_ASTVAL_P(z) = zend_persist_ast(Z_ASTVAL_P(z));
Z_TYPE_FLAGS_P(z) = IS_TYPE_CONSTANT | IS_TYPE_IMMUTABLE;
GC_REFCOUNT(Z_COUNTED_P(z)) = 2;
}
break;
}
}
static void zend_persist_zval_const(zval *z)
{
zend_uchar flags;
@ -258,6 +316,7 @@ static void zend_persist_zval_const(zval *z)
/* make immutable array */
Z_TYPE_FLAGS_P(z) = IS_TYPE_IMMUTABLE;
GC_REFCOUNT(Z_COUNTED_P(z)) = 2;
GC_FLAGS(Z_COUNTED_P(z)) |= IS_ARRAY_IMMUTABLE;
Z_ARRVAL_P(z)->u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
}
}
@ -293,7 +352,7 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc
return;
}
if (--(*op_array->refcount) == 0) {
if (op_array->refcount && --(*op_array->refcount) == 0) {
efree(op_array->refcount);
}
op_array->refcount = NULL;
@ -313,8 +372,18 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc
}
if (op_array->static_variables) {
zend_hash_persist(op_array->static_variables, zend_persist_zval);
zend_accel_store(op_array->static_variables, sizeof(HashTable));
HashTable *stored = zend_shared_alloc_get_xlat_entry(op_array->static_variables);
if (stored) {
op_array->static_variables = stored;
} else {
zend_hash_persist(op_array->static_variables, zend_persist_zval_static);
zend_accel_store(op_array->static_variables, sizeof(HashTable));
/* make immutable array */
GC_REFCOUNT(op_array->static_variables) = 2;
GC_TYPE_INFO(op_array->static_variables) = IS_ARRAY | (IS_ARRAY_IMMUTABLE << 8);
op_array->static_variables->u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
}
}
if (zend_shared_alloc_get_xlat_entry(op_array->opcodes)) {
@ -494,8 +563,6 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc
if (op_array->scope && op_array->prototype) {
if ((persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->prototype))) {
op_array->prototype = (union _zend_function*)persist_ptr;
/* we use refcount to show that op_array is referenced from several places */
op_array->prototype->op_array.refcount++;
}
} else {
op_array->prototype = NULL;
@ -660,63 +727,47 @@ static int zend_update_parent_ce(zval *zv)
if (ce->parent) {
ce->parent = zend_shared_alloc_get_xlat_entry(ce->parent);
/* We use refcount to show if the class is used as a parent */
ce->parent->refcount++;
}
/* update methods */
if (ce->constructor) {
ce->constructor = zend_shared_alloc_get_xlat_entry(ce->constructor);
/* we use refcount to show that op_array is referenced from several places */
ce->constructor->op_array.refcount++;
}
if (ce->destructor) {
ce->destructor = zend_shared_alloc_get_xlat_entry(ce->destructor);
ce->destructor->op_array.refcount++;
}
if (ce->clone) {
ce->clone = zend_shared_alloc_get_xlat_entry(ce->clone);
ce->clone->op_array.refcount++;
}
if (ce->__get) {
ce->__get = zend_shared_alloc_get_xlat_entry(ce->__get);
ce->__get->op_array.refcount++;
}
if (ce->__set) {
ce->__set = zend_shared_alloc_get_xlat_entry(ce->__set);
ce->__set->op_array.refcount++;
}
if (ce->__call) {
ce->__call = zend_shared_alloc_get_xlat_entry(ce->__call);
ce->__call->op_array.refcount++;
}
if (ce->serialize_func) {
ce->serialize_func = zend_shared_alloc_get_xlat_entry(ce->serialize_func);
ce->serialize_func->op_array.refcount++;
}
if (ce->unserialize_func) {
ce->unserialize_func = zend_shared_alloc_get_xlat_entry(ce->unserialize_func);
ce->unserialize_func->op_array.refcount++;
}
if (ce->__isset) {
ce->__isset = zend_shared_alloc_get_xlat_entry(ce->__isset);
ce->__isset->op_array.refcount++;
}
if (ce->__unset) {
ce->__unset = zend_shared_alloc_get_xlat_entry(ce->__unset);
ce->__unset->op_array.refcount++;
}
if (ce->__tostring) {
ce->__tostring = zend_shared_alloc_get_xlat_entry(ce->__tostring);
ce->__tostring->op_array.refcount++;
}
if (ce->__callstatic) {
ce->__callstatic = zend_shared_alloc_get_xlat_entry(ce->__callstatic);
ce->__callstatic->op_array.refcount++;
}
if (ce->__debugInfo) {
ce->__debugInfo = zend_shared_alloc_get_xlat_entry(ce->__debugInfo);
ce->__debugInfo->op_array.refcount++;
}
zend_hash_apply(&ce->properties_info, (apply_func_t) zend_update_property_info_ce);
return 0;
@ -738,6 +789,11 @@ zend_persistent_script *zend_accel_script_persist(zend_persistent_script *script
*key = zend_accel_memdup(*key, key_length + 1);
zend_accel_store_string(script->full_path);
#ifdef __SSE2__
/* Align to 64-byte boundary */
ZCG(mem) = (void*)(((zend_uintptr_t)ZCG(mem) + 63L) & ~63L);
#endif
script->arena_mem = ZCG(arena_mem) = ZCG(mem);
ZCG(mem) = (void*)((char*)ZCG(mem) + script->arena_size);

View File

@ -150,8 +150,13 @@ static void zend_persist_op_array_calc_ex(zend_op_array *op_array)
}
if (op_array->static_variables) {
ADD_DUP_SIZE(op_array->static_variables, sizeof(HashTable));
zend_hash_persist_calc(op_array->static_variables, zend_persist_zval_calc);
if (!zend_shared_alloc_get_xlat_entry(op_array->static_variables)) {
HashTable *old = op_array->static_variables;
ADD_DUP_SIZE(op_array->static_variables, sizeof(HashTable));
zend_hash_persist_calc(op_array->static_variables, zend_persist_zval_calc);
zend_shared_alloc_register_xlat_entry(old, op_array->static_variables);
}
}
if (zend_shared_alloc_get_xlat_entry(op_array->opcodes)) {
@ -356,10 +361,20 @@ uint zend_accel_script_persist_calc(zend_persistent_script *new_persistent_scrip
ADD_DUP_SIZE(key, key_length + 1);
ADD_STRING(new_persistent_script->full_path);
#ifdef __SSE2__
/* Align size to 64-byte boundary */
new_persistent_script->size = (new_persistent_script->size + 63) & ~63;
#endif
zend_accel_persist_class_table_calc(&new_persistent_script->class_table);
zend_hash_persist_calc(&new_persistent_script->function_table, zend_persist_op_array_calc);
zend_persist_op_array_calc_ex(&new_persistent_script->main_op_array);
#ifdef __SSE2__
/* Align size to 64-byte boundary */
new_persistent_script->arena_size = (new_persistent_script->arena_size + 63) & ~63;
#endif
new_persistent_script->size += new_persistent_script->arena_size;
ZCG(current_persistent_script) = NULL;

View File

@ -91,7 +91,7 @@ typedef struct _handler_entry {
typedef struct _zend_shared_memory_state {
int *positions; /* current positions for each segment */
int shared_free; /* amount of free shared memory */
size_t shared_free; /* amount of free shared memory */
} zend_shared_memory_state;
typedef struct _zend_smm_shared_globals {

View File

@ -1852,6 +1852,12 @@ ZEND_METHOD(reflection_function, getStaticVariables)
/* Return an empty array in case no static variables exist */
array_init(return_value);
if (fptr->type == ZEND_USER_FUNCTION && fptr->op_array.static_variables != NULL) {
if (GC_REFCOUNT(fptr->op_array.static_variables) > 1) {
if (!(GC_FLAGS(fptr->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) {
GC_REFCOUNT(fptr->op_array.static_variables)--;
}
fptr->op_array.static_variables = zend_array_dup(fptr->op_array.static_variables);
}
zend_hash_apply_with_argument(fptr->op_array.static_variables, (apply_func_arg_t) zval_update_constant_inline_change, fptr->common.scope);
zend_hash_copy(Z_ARRVAL_P(return_value), fptr->op_array.static_variables, zval_add_ref);
}

View File

@ -192,18 +192,21 @@ static inline void spl_filesystem_object_get_file_name(spl_filesystem_object *in
{
char slash = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_UNIXPATHS) ? '/' : DEFAULT_SLASH;
if (!intern->file_name) {
switch (intern->type) {
switch (intern->type) {
case SPL_FS_INFO:
case SPL_FS_FILE:
php_error_docref(NULL, E_ERROR, "Object not initialized");
if (!intern->file_name) {
php_error_docref(NULL, E_ERROR, "Object not initialized");
}
break;
case SPL_FS_DIR:
if (intern->file_name) {
efree(intern->file_name);
}
intern->file_name_len = (int)spprintf(&intern->file_name, 0, "%s%c%s",
spl_filesystem_object_get_path(intern, NULL),
slash, intern->u.dir.entry.d_name);
break;
}
}
} /* }}} */

View File

@ -0,0 +1,44 @@
--TEST--
Bug #68557 (SplFileInfo::getPathname() may be broken)
--SKIPIF--
<?php
if (substr(PHP_OS, 0, 3) != 'WIN') {
die('skip.. only for Windows');
}
?>
--FILE--
<?php
mkdir(__DIR__ . DIRECTORY_SEPARATOR . 'tmp');
touch(__DIR__ . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR . 'a');
touch(__DIR__ . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR . 'b');
$d = new DirectoryIterator(__DIR__ . DIRECTORY_SEPARATOR . 'tmp');
$d->seek(0);
var_dump($d->current()->getPathname());
$d->seek(1);
var_dump($d->current()->getPathname());
$d->seek(0);
var_dump($d->current()->getPathname());
$d->seek(1);
var_dump($d->current()->getPathname());
$d->seek(2);
var_dump($d->current()->getPathname());
?>
--CLEAN--
<?php
unlink(__DIR__ . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR . 'a');
unlink(__DIR__ . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR . 'b');
rmdir(__DIR__ . DIRECTORY_SEPARATOR . 'tmp');
?>
--EXPECTF--
string(%d) "%s\tmp\."
string(%d) "%s\tmp\.."
string(%d) "%s\tmp\."
string(%d) "%s\tmp\.."
string(%d) "%s\tmp\a"

View File

@ -0,0 +1,44 @@
--TEST--
Bug #68557 (SplFileInfo::getPathname() may be broken)
--SKIPIF--
<?php
if (substr(PHP_OS, 0, 3) == 'WIN') {
die('skip.. Not for Windows');
}
?>
--FILE--
<?php
mkdir(__DIR__ . DIRECTORY_SEPARATOR . 'tmp');
touch(__DIR__ . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR . 'a');
touch(__DIR__ . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR . 'b');
$d = new DirectoryIterator(__DIR__ . DIRECTORY_SEPARATOR . 'tmp');
$d->seek(0);
var_dump($d->current()->getPathname());
$d->seek(1);
var_dump($d->current()->getPathname());
$d->seek(0);
var_dump($d->current()->getPathname());
$d->seek(1);
var_dump($d->current()->getPathname());
$d->seek(2);
var_dump($d->current()->getPathname());
?>
--CLEAN--
<?php
unlink(__DIR__ . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR . 'a');
unlink(__DIR__ . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR . 'b');
rmdir(__DIR__ . DIRECTORY_SEPARATOR . 'tmp');
?>
--EXPECTF--
string(%d) "%s/tmp/b"
string(%d) "%s/tmp/a"
string(%d) "%s/tmp/b"
string(%d) "%s/tmp/a"
string(%d) "%s/tmp/.."

View File

@ -3391,6 +3391,9 @@ static void php_putenv_destructor(zval *zv) /* {{{ */
unsetenv(pe->key);
# elif defined(PHP_WIN32)
SetEnvironmentVariable(pe->key, NULL);
# ifndef ZTS
_putenv_s(pe->key, "");
# endif
# else
char **env;

View File

@ -180,6 +180,7 @@ PHPAPI void php_output_deactivate(void)
php_output_handler **handler = NULL;
if ((OG(flags) & PHP_OUTPUT_ACTIVATED)) {
php_output_header();
OG(flags) ^= PHP_OUTPUT_ACTIVATED;
OG(active) = NULL;

View File

@ -1,5 +0,0 @@
@if exist ..\ZendEngine2\OBJECTS2_HOWTO (
move ..\Zend ..\ZendEngine1
move ..\ZendEngine2 ..\Zend
echo "PLEASE RESTART VISUAL C++ TO RELOAD THE ZEND PROJECT."
exit 1 )