Merge branch 'master' into assert

* master: (59 commits)
  Improved ASSIGN_DIM handler
  Don't inline slow path
  Revert a part committted by mistake
  Fixed compilation warnings
  Fixed a bug that header value is not terminated by '\0' when accessed through getenv().
  better name
  Improve fix for #69038
  Update NEWs
  Fixed bug #69108 ("Segmentation fault" when (de)serializing SplObjectStorage)
  Added specialized versions of DO_FCALL handler:   DO_ICALL - for internal functions   DO_UCALL - for user functions   DO_FCALL_BY_NAME - plain, most probably user, funcstions (not methods)
  Use cache_slot offsets instead of indexes (simplify run-time instructions)
  Split INIT_FCALL_BY_NAME inti INIT_FCALL_BY_NAME(CONST+STRING) and INIT_DYNAMIC_CALL(CONST-STRING|TMPVAR|CV)
  Support list($a, $b) = $a
  Avoid unnecassary check
  Make zend_array_destroy() to free the corresponding zend_array
  Eliminate check on the fast path
  Make current() and key() receive argument by value.
  Use Firebird default home folder, replace Interbase with Firebird
  Updated NEWS
  updated NEWS
  ...

Conflicts:
	Zend/zend_vm_execute.h
	Zend/zend_vm_opcodes.c
	Zend/zend_vm_opcodes.h
This commit is contained in:
Dmitry Stogov 2015-02-26 11:26:03 +03:00
commit 021fd94ed1
70 changed files with 2612 additions and 1567 deletions

1
NEWS
View file

@ -34,6 +34,7 @@
. Implemented FR #55467 (phpinfo: PHP Variables with $ and single quotes). (Kalle) . Implemented FR #55467 (phpinfo: PHP Variables with $ and single quotes). (Kalle)
. Fixed bug #55415 (php_info produces invalid anchor names). (Kalle, Johannes) . Fixed bug #55415 (php_info produces invalid anchor names). (Kalle, Johannes)
. Added ?? operator. (Andrea) . Added ?? operator. (Andrea)
. Added <=> operator. (Andrea)
. Added \u{xxxxx} Unicode Codepoint Escape Syntax. (Andrea) . Added \u{xxxxx} Unicode Codepoint Escape Syntax. (Andrea)
. Fixed oversight where define() did not support arrays yet const syntax did. (Andrea, Dmitry) . 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) . 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 . Added \u{xxxxxx} Unicode Codepoint Escape Syntax for double-quoted strings
and heredocs. and heredocs.
. define() now supports arrays as constant values, fixing an oversight where define() did not support arrays yet const syntax did. . 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 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

11
Zend/tests/gc_034.phpt Normal file
View file

@ -0,0 +1,11 @@
--TEST--
GC 034: GC in request shutdown and resource list destroy
--FILE--
<?php
/* run with valgrind */
$a = array(fopen(__FILE__, 'r'));
$a[] = &$a;
?>
==DONE==
--EXPECT--
==DONE==

View file

@ -0,0 +1,56 @@
--TEST--
Test variable occuring on both LHS and RHS of list()
--FILE--
<?php
$a = [1, 2, 3];
list($a, $b, $c) = $a;
var_dump($a, $b, $c);
$b = [1, 2, 3];
list($a, $b, $c) = $b;
var_dump($a, $b, $c);
$c = [1, 2, 3];
list($a, $b, $c) = $c;
var_dump($a, $b, $c);
$a = [[1, 2], 3];
list(list($a, $b), $c) = $a;
var_dump($a, $b, $c);
$b = [[1, 2], 3];
list(list($a, $b), $c) = $b;
var_dump($a, $b, $c);
$b = [1, [2, 3]];
list($a, list($b, $c)) = $b;
var_dump($a, $b, $c);
$c = [1, [2, 3]];
list($a, list($b, $c)) = $c;
var_dump($a, $b, $c);
?>
--EXPECT--
int(1)
int(2)
int(3)
int(1)
int(2)
int(3)
int(1)
int(2)
int(3)
int(1)
int(2)
int(3)
int(1)
int(2)
int(3)
int(1)
int(2)
int(3)
int(1)
int(2)
int(3)

View file

@ -494,22 +494,28 @@ static void compiler_globals_dtor(zend_compiler_globals *compiler_globals) /* {{
static void executor_globals_ctor(zend_executor_globals *executor_globals) /* {{{ */ static void executor_globals_ctor(zend_executor_globals *executor_globals) /* {{{ */
{ {
ZEND_TSRMLS_CACHE_UPDATE(); ZEND_TSRMLS_CACHE_UPDATE();
zend_startup_constants(); zend_startup_constants();
zend_copy_constants(EG(zend_constants), GLOBAL_CONSTANTS_TABLE); zend_copy_constants(EG(zend_constants), GLOBAL_CONSTANTS_TABLE);
zend_init_rsrc_plist(); zend_init_rsrc_plist();
zend_init_exception_op(); zend_init_exception_op();
EG(lambda_count) = 0; executor_globals->lambda_count = 0;
ZVAL_UNDEF(&EG(user_error_handler)); ZVAL_UNDEF(&executor_globals->user_error_handler);
ZVAL_UNDEF(&EG(user_exception_handler)); ZVAL_UNDEF(&executor_globals->user_exception_handler);
EG(in_autoload) = NULL; executor_globals->in_autoload = NULL;
EG(current_execute_data) = NULL; executor_globals->current_execute_data = NULL;
EG(current_module) = NULL; executor_globals->current_module = NULL;
EG(exit_status) = 0; executor_globals->exit_status = 0;
#if XPFPA_HAVE_CW #if XPFPA_HAVE_CW
EG(saved_fpu_cw) = 0; executor_globals->saved_fpu_cw = 0;
#endif #endif
EG(saved_fpu_cw_ptr) = NULL; executor_globals->saved_fpu_cw_ptr = NULL;
EG(active) = 0; executor_globals->active = 0;
executor_globals->bailout = NULL;
executor_globals->error_handling = EH_NORMAL;
executor_globals->exception_class = NULL;
executor_globals->exception = NULL;
executor_globals->objects_store.object_buckets = NULL;
} }
/* }}} */ /* }}} */
@ -690,9 +696,8 @@ int zend_startup(zend_utility_functions *utility_functions, char **extensions) /
ini_scanner_globals_ctor(&ini_scanner_globals); ini_scanner_globals_ctor(&ini_scanner_globals);
php_scanner_globals_ctor(&language_scanner_globals); php_scanner_globals_ctor(&language_scanner_globals);
zend_set_default_compile_time_values(); zend_set_default_compile_time_values();
ZVAL_UNDEF(&EG(user_error_handler));
ZVAL_UNDEF(&EG(user_exception_handler));
#endif #endif
EG(error_reporting) = E_ALL & ~E_NOTICE;
zend_interned_strings_init(); zend_interned_strings_init();
zend_startup_builtin_functions(); zend_startup_builtin_functions();
@ -921,14 +926,14 @@ ZEND_API void zend_deactivate(void) /* {{{ */
shutdown_compiler(); shutdown_compiler();
} zend_end_try(); } zend_end_try();
zend_destroy_rsrc_list(&EG(regular_list));
#if ZEND_DEBUG #if ZEND_DEBUG
if (GC_G(gc_enabled) && !CG(unclean_shutdown)) { if (GC_G(gc_enabled) && !CG(unclean_shutdown)) {
gc_collect_cycles(); gc_collect_cycles();
} }
#endif #endif
zend_destroy_rsrc_list(&EG(regular_list));
#if GC_BENCH #if GC_BENCH
fprintf(stderr, "GC Statistics\n"); fprintf(stderr, "GC Statistics\n");
fprintf(stderr, "-------------\n"); fprintf(stderr, "-------------\n");

View file

@ -3915,7 +3915,7 @@ ZEND_API zend_string *zend_resolve_method_name(zend_class_entry *ce, zend_functi
zend_string *name; zend_string *name;
if (f->common.type != ZEND_USER_FUNCTION || 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 ||
!f->common.scope->trait_aliases) { !f->common.scope->trait_aliases) {
return f->common.function_name; return f->common.function_name;

View file

@ -890,7 +890,6 @@ static void zend_ast_export_zval(smart_str *str, zval *zv, int priority, int ind
static void zend_ast_export_ex(smart_str *str, zend_ast *ast, int priority, int indent) static void zend_ast_export_ex(smart_str *str, zend_ast *ast, int priority, int indent)
{ {
zval *zv;
zend_ast_decl *decl; zend_ast_decl *decl;
int p, pl, pr; int p, pl, pr;
const char *op; const char *op;

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) { zend_binary_strcasecmp(key->val, key->len, mptr->common.function_name->val, len) == 0) {
if (mptr->type == ZEND_USER_FUNCTION && 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)) { !same_name(key, mptr->common.function_name)) {
ZVAL_STR_COPY(&method_name, zend_find_alias_name(mptr->common.scope, key)); 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); 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()"); zend_error(E_ERROR, "Unexpected inconsistency in create_function()");
RETURN_FALSE; RETURN_FALSE;
} }
(*func->refcount)++; if (func->refcount) {
(*func->refcount)++;
}
static_variables = func->static_variables; static_variables = func->static_variables;
func->static_variables = NULL; func->static_variables = NULL;
zend_hash_str_del(EG(function_table), LAMBDA_TEMP_FUNCNAME, sizeof(LAMBDA_TEMP_FUNCNAME)-1); zend_hash_str_del(EG(function_table), LAMBDA_TEMP_FUNCNAME, sizeof(LAMBDA_TEMP_FUNCNAME)-1);
@ -2256,6 +2258,9 @@ ZEND_FUNCTION(debug_print_backtrace)
skip->prev_execute_data->func && skip->prev_execute_data->func &&
ZEND_USER_CODE(skip->prev_execute_data->func->common.type) && ZEND_USER_CODE(skip->prev_execute_data->func->common.type) &&
skip->prev_execute_data->opline->opcode != ZEND_DO_FCALL && skip->prev_execute_data->opline->opcode != ZEND_DO_FCALL &&
skip->prev_execute_data->opline->opcode != ZEND_DO_ICALL &&
skip->prev_execute_data->opline->opcode != ZEND_DO_UCALL &&
skip->prev_execute_data->opline->opcode != ZEND_DO_FCALL_BY_NAME &&
skip->prev_execute_data->opline->opcode != ZEND_INCLUDE_OR_EVAL) { skip->prev_execute_data->opline->opcode != ZEND_INCLUDE_OR_EVAL) {
skip = skip->prev_execute_data; skip = skip->prev_execute_data;
} }
@ -2451,6 +2456,9 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int
skip->prev_execute_data->func && skip->prev_execute_data->func &&
ZEND_USER_CODE(skip->prev_execute_data->func->common.type) && ZEND_USER_CODE(skip->prev_execute_data->func->common.type) &&
skip->prev_execute_data->opline->opcode != ZEND_DO_FCALL && skip->prev_execute_data->opline->opcode != ZEND_DO_FCALL &&
skip->prev_execute_data->opline->opcode != ZEND_DO_ICALL &&
skip->prev_execute_data->opline->opcode != ZEND_DO_UCALL &&
skip->prev_execute_data->opline->opcode != ZEND_DO_FCALL_BY_NAME &&
skip->prev_execute_data->opline->opcode != ZEND_INCLUDE_OR_EVAL) { skip->prev_execute_data->opline->opcode != ZEND_INCLUDE_OR_EVAL) {
skip = skip->prev_execute_data; skip = skip->prev_execute_data;
} }

View file

@ -63,6 +63,9 @@ ZEND_METHOD(Closure, __invoke) /* {{{ */
/* destruct the function also, then - we have allocated it in get_method */ /* destruct the function also, then - we have allocated it in get_method */
zend_string_release(func->internal_function.function_name); zend_string_release(func->internal_function.function_name);
efree(func); efree(func);
#if ZEND_DEBUG
execute_data->func = NULL;
#endif
} }
/* }}} */ /* }}} */
@ -499,7 +502,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); 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.run_time_cache = NULL;
(*closure->func.op_array.refcount)++; if (closure->func.op_array.refcount) {
(*closure->func.op_array.refcount)++;
}
} else { } else {
/* verify that we aren't binding internal function to a wrong scope */ /* verify that we aren't binding internal function to a wrong scope */
if(func->common.scope != NULL) { if(func->common.scope != NULL) {

View file

@ -52,15 +52,16 @@
static inline void zend_alloc_cache_slot(uint32_t literal) { static inline void zend_alloc_cache_slot(uint32_t literal) {
zend_op_array *op_array = CG(active_op_array); zend_op_array *op_array = CG(active_op_array);
Z_CACHE_SLOT(op_array->literals[literal]) = op_array->last_cache_slot++; Z_CACHE_SLOT(op_array->literals[literal]) = op_array->cache_size;
op_array->cache_size += sizeof(void*);
} }
#define POLYMORPHIC_CACHE_SLOT_SIZE 2 #define POLYMORPHIC_CACHE_SLOT_SIZE 2
static inline void zend_alloc_polymorphic_cache_slot(uint32_t literal) { static inline void zend_alloc_polymorphic_cache_slot(uint32_t literal) {
zend_op_array *op_array = CG(active_op_array); zend_op_array *op_array = CG(active_op_array);
Z_CACHE_SLOT(op_array->literals[literal]) = op_array->last_cache_slot; Z_CACHE_SLOT(op_array->literals[literal]) = op_array->cache_size;
op_array->last_cache_slot += POLYMORPHIC_CACHE_SLOT_SIZE; op_array->cache_size += POLYMORPHIC_CACHE_SLOT_SIZE * sizeof(void*);
} }
ZEND_API zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle, int type); ZEND_API zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle, int type);
@ -863,9 +864,13 @@ ZEND_API void function_add_ref(zend_function *function) /* {{{ */
if (function->type == ZEND_USER_FUNCTION) { if (function->type == ZEND_USER_FUNCTION) {
zend_op_array *op_array = &function->op_array; zend_op_array *op_array = &function->op_array;
(*op_array->refcount)++; if (op_array->refcount) {
(*op_array->refcount)++;
}
if (op_array->static_variables) { 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; op_array->run_time_cache = NULL;
} else if (function->type == ZEND_INTERNAL_FUNCTION) { } else if (function->type == ZEND_INTERNAL_FUNCTION) {
@ -908,7 +913,9 @@ ZEND_API int do_bind_function(const zend_op_array *op_array, const zend_op *opli
} }
return FAILURE; return FAILURE;
} else { } 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 */ function->op_array.static_variables = NULL; /* NULL out the unbound function */
return SUCCESS; return SUCCESS;
} }
@ -2310,6 +2317,50 @@ zend_bool zend_is_assign_to_self(zend_ast *var_ast, zend_ast *expr_ast) /* {{{ *
} }
/* }}} */ /* }}} */
/* Detects if list($a, $b, $c) contains variable with given name */
zend_bool zend_list_has_assign_to(zend_ast *list_ast, zend_string *name) /* {{{ */
{
zend_ast_list *list = zend_ast_get_list(list_ast);
uint32_t i;
for (i = 0; i < list->children; i++) {
zend_ast *var_ast = list->child[i];
if (!var_ast) {
continue;
}
/* Recursively check nested list()s */
if (var_ast->kind == ZEND_AST_LIST && zend_list_has_assign_to(var_ast, name)) {
return 1;
}
if (var_ast->kind == ZEND_AST_VAR && var_ast->child[0]->kind == ZEND_AST_ZVAL) {
zend_string *var_name = zval_get_string(zend_ast_get_zval(var_ast->child[0]));
zend_bool result = zend_string_equals(var_name, name);
zend_string_release(var_name);
if (result) {
return 1;
}
}
}
return 0;
}
/* }}} */
/* Detects patterns like list($a, $b, $c) = $a */
zend_bool zend_list_has_assign_to_self(zend_ast *list_ast, zend_ast *expr_ast) /* {{{ */
{
/* Only check simple variables on the RHS, as only CVs cause issues with this. */
if (expr_ast->kind == ZEND_AST_VAR && expr_ast->child[0]->kind == ZEND_AST_ZVAL) {
zend_string *name = zval_get_string(zend_ast_get_zval(expr_ast->child[0]));
zend_bool result = zend_list_has_assign_to(list_ast, name);
zend_string_release(name);
return result;
}
return 0;
}
/* }}} */
void zend_compile_assign(znode *result, zend_ast *ast) /* {{{ */ void zend_compile_assign(znode *result, zend_ast *ast) /* {{{ */
{ {
zend_ast *var_ast = ast->child[0]; zend_ast *var_ast = ast->child[0];
@ -2359,7 +2410,13 @@ void zend_compile_assign(znode *result, zend_ast *ast) /* {{{ */
zend_emit_op_data(&expr_node); zend_emit_op_data(&expr_node);
return; return;
case ZEND_AST_LIST: case ZEND_AST_LIST:
zend_compile_expr(&expr_node, expr_ast); if (zend_list_has_assign_to_self(var_ast, expr_ast)) {
/* list($a, $b) = $a should evaluate the right $a first */
zend_compile_simple_var_no_cv(&expr_node, expr_ast, BP_VAR_R, 0);
} else {
zend_compile_expr(&expr_node, expr_ast);
}
zend_compile_list_assign(result, var_ast, &expr_node); zend_compile_list_assign(result, var_ast, &expr_node);
return; return;
EMPTY_SWITCH_DEFAULT_CASE(); EMPTY_SWITCH_DEFAULT_CASE();
@ -2560,6 +2617,31 @@ uint32_t zend_compile_args(zend_ast *ast, zend_function *fbc) /* {{{ */
} }
/* }}} */ /* }}} */
ZEND_API zend_uchar zend_get_call_op(zend_uchar init_op, zend_function *fbc) /* {{{ */
{
if (fbc) {
if (fbc->type == ZEND_INTERNAL_FUNCTION) {
if (!zend_execute_internal &&
!fbc->common.scope &&
!(fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED|ZEND_ACC_HAS_TYPE_HINTS))) {
return ZEND_DO_ICALL;
}
} else {
if (zend_execute_ex == execute_ex &&
!(fbc->common.fn_flags & ZEND_ACC_GENERATOR)) {
return ZEND_DO_UCALL;
}
}
} else if (zend_execute_ex == execute_ex &&
!zend_execute_internal &&
(init_op == ZEND_INIT_FCALL_BY_NAME ||
init_op == ZEND_INIT_NS_FCALL_BY_NAME)) {
return ZEND_DO_FCALL_BY_NAME;
}
return ZEND_DO_FCALL;
}
/* }}} */
void zend_compile_call_common(znode *result, zend_ast *args_ast, zend_function *fbc) /* {{{ */ void zend_compile_call_common(znode *result, zend_ast *args_ast, zend_function *fbc) /* {{{ */
{ {
zend_op *opline; zend_op *opline;
@ -2579,7 +2661,7 @@ void zend_compile_call_common(znode *result, zend_ast *args_ast, zend_function *
} }
call_flags = (opline->opcode == ZEND_NEW ? ZEND_CALL_CTOR : 0); call_flags = (opline->opcode == ZEND_NEW ? ZEND_CALL_CTOR : 0);
opline = zend_emit_op(result, ZEND_DO_FCALL, NULL, NULL); opline = zend_emit_op(result, zend_get_call_op(opline->opcode, fbc), NULL, NULL);
opline->op1.num = call_flags; opline->op1.num = call_flags;
zend_do_extended_fcall_end(); zend_do_extended_fcall_end();
@ -2616,16 +2698,17 @@ void zend_compile_ns_call(znode *result, znode *name_node, zend_ast *args_ast) /
void zend_compile_dynamic_call(znode *result, znode *name_node, zend_ast *args_ast) /* {{{ */ void zend_compile_dynamic_call(znode *result, znode *name_node, zend_ast *args_ast) /* {{{ */
{ {
zend_op *opline = get_next_op(CG(active_op_array)); zend_op *opline = get_next_op(CG(active_op_array));
opline->opcode = ZEND_INIT_FCALL_BY_NAME;
SET_UNUSED(opline->op1);
if (name_node->op_type == IS_CONST && Z_TYPE(name_node->u.constant) == IS_STRING) { if (name_node->op_type == IS_CONST && Z_TYPE(name_node->u.constant) == IS_STRING) {
opline->opcode = ZEND_INIT_FCALL_BY_NAME;
opline->op2_type = IS_CONST; opline->op2_type = IS_CONST;
opline->op2.constant = zend_add_func_name_literal(CG(active_op_array), opline->op2.constant = zend_add_func_name_literal(CG(active_op_array),
Z_STR(name_node->u.constant)); Z_STR(name_node->u.constant));
zend_alloc_cache_slot(opline->op2.constant); zend_alloc_cache_slot(opline->op2.constant);
} else { } else {
opline->opcode = ZEND_INIT_DYNAMIC_CALL;
SET_NODE(opline->op2, name_node); SET_NODE(opline->op2, name_node);
} }
SET_UNUSED(opline->op1);
zend_compile_call_common(result, args_ast, NULL); zend_compile_call_common(result, args_ast, NULL);
} }
@ -3146,6 +3229,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); 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); 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); opline = zend_emit_op(&result, by_ref ? ZEND_FETCH_W : ZEND_FETCH_R, &var_node, NULL);
@ -3846,16 +3935,26 @@ void zend_compile_declare(zend_ast *ast) /* {{{ */
ZVAL_COPY_VALUE(&CG(declarables).ticks, &value_zv); ZVAL_COPY_VALUE(&CG(declarables).ticks, &value_zv);
zval_dtor(&value_zv); zval_dtor(&value_zv);
} else if (zend_string_equals_literal_ci(name, "encoding")) { } 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 /* Encoding declaration was already handled during parsing. Here we
* only check that it is the first statement in the file. */ * only check that it is the first statement in the file. */
uint32_t num = CG(active_op_array)->last; zend_ast_list *file_ast = zend_ast_get_list(CG(ast));
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;
}
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 " zend_error_noreturn(E_COMPILE_ERROR, "Encoding declaration pragma must be "
"the very first statement in the script"); "the very first statement in the script");
} }

View file

@ -352,7 +352,7 @@ struct _zend_op_array {
int last_literal; int last_literal;
zval *literals; zval *literals;
int last_cache_slot; int cache_size;
void **run_time_cache; void **run_time_cache;
void *reserved[ZEND_MAX_RESERVED_RESOURCES]; void *reserved[ZEND_MAX_RESERVED_RESOURCES];
@ -718,6 +718,7 @@ ZEND_API zend_bool zend_is_compiling(void);
ZEND_API char *zend_make_compiled_string_description(const char *name); ZEND_API char *zend_make_compiled_string_description(const char *name);
ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify_handlers); ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify_handlers);
uint32_t zend_get_class_fetch_type(zend_string *name); uint32_t zend_get_class_fetch_type(zend_string *name);
ZEND_API zend_uchar zend_get_call_op(zend_uchar init_op, zend_function *fbc);
typedef zend_bool (*zend_auto_global_callback)(zend_string *name); typedef zend_bool (*zend_auto_global_callback)(zend_string *name);
typedef struct _zend_auto_global { typedef struct _zend_auto_global {

View file

@ -511,22 +511,19 @@ static inline void zend_assign_to_variable_reference(zval *variable_ptr, zval *v
} }
/* this should modify object only if it's empty */ /* this should modify object only if it's empty */
static inline int make_real_object(zval **object_ptr) static inline int make_real_object(zval *object)
{ {
zval *object = *object_ptr;
ZVAL_DEREF(object);
if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
if (EXPECTED(Z_TYPE_P(object) <= IS_FALSE) if (EXPECTED(Z_TYPE_P(object) <= IS_FALSE)) {
|| (Z_TYPE_P(object) == IS_STRING && Z_STRLEN_P(object) == 0)) { /* nothing to destroy */
} else if (EXPECTED((Z_TYPE_P(object) == IS_STRING && Z_STRLEN_P(object) == 0))) {
zval_ptr_dtor_nogc(object); zval_ptr_dtor_nogc(object);
object_init(object);
zend_error(E_WARNING, "Creating default object from empty value");
} else { } else {
return 0; return 0;
} }
object_init(object);
zend_error(E_WARNING, "Creating default object from empty value");
} }
*object_ptr = object;
return 1; return 1;
} }
@ -933,7 +930,7 @@ static zend_always_inline void zend_assign_to_object(zval *retval, zval *object,
zend_object *zobj = Z_OBJ_P(object); zend_object *zobj = Z_OBJ_P(object);
zval *property; zval *property;
if (EXPECTED(prop_offset != ZEND_DYNAMIC_PROPERTY_OFFSET)) { if (EXPECTED(prop_offset != (uint32_t)ZEND_DYNAMIC_PROPERTY_OFFSET)) {
property = OBJ_PROP(zobj, prop_offset); property = OBJ_PROP(zobj, prop_offset);
if (Z_TYPE_P(property) != IS_UNDEF) { if (Z_TYPE_P(property) != IS_UNDEF) {
fast_assign: fast_assign:
@ -1166,6 +1163,12 @@ static zend_always_inline HashTable *zend_get_target_symbol_table(zend_execute_d
} else if (EXPECTED(fetch_type == ZEND_FETCH_STATIC)) { } else if (EXPECTED(fetch_type == ZEND_FETCH_STATIC)) {
ZEND_ASSERT(EX(func)->op_array.static_variables != NULL); ZEND_ASSERT(EX(func)->op_array.static_variables != NULL);
ht = EX(func)->op_array.static_variables; 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 { } else {
ZEND_ASSERT(fetch_type == ZEND_FETCH_LOCAL); ZEND_ASSERT(fetch_type == ZEND_FETCH_LOCAL);
if (!EX(symbol_table)) { if (!EX(symbol_table)) {
@ -1572,7 +1575,7 @@ static zend_always_inline void zend_fetch_property_address(zval *result, zval *c
zend_object *zobj = Z_OBJ_P(container); zend_object *zobj = Z_OBJ_P(container);
zval *retval; zval *retval;
if (EXPECTED(prop_offset != ZEND_DYNAMIC_PROPERTY_OFFSET)) { if (EXPECTED(prop_offset != (uint32_t)ZEND_DYNAMIC_PROPERTY_OFFSET)) {
retval = OBJ_PROP(zobj, prop_offset); retval = OBJ_PROP(zobj, prop_offset);
if (EXPECTED(Z_TYPE_P(retval) != IS_UNDEF)) { if (EXPECTED(Z_TYPE_P(retval) != IS_UNDEF)) {
ZVAL_INDIRECT(result, retval); ZVAL_INDIRECT(result, retval);
@ -1688,7 +1691,6 @@ ZEND_API void zend_clean_and_cache_symbol_table(zend_array *symbol_table) /* {{{
{ {
if (EG(symtable_cache_ptr) >= EG(symtable_cache_limit)) { if (EG(symtable_cache_ptr) >= EG(symtable_cache_limit)) {
zend_array_destroy(symbol_table); zend_array_destroy(symbol_table);
efree_size(symbol_table, sizeof(zend_array));
} else { } else {
/* clean before putting into the cache, since clean /* clean before putting into the cache, since clean
could call dtors, which could use cached hash */ could call dtors, which could use cached hash */
@ -1737,7 +1739,7 @@ void zend_free_compiled_variables(zend_execute_data *execute_data) /* {{{ */
* +----------------------------------------+ * +----------------------------------------+
*/ */
static zend_always_inline void i_init_func_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value) /* {{{ */ static zend_always_inline void i_init_func_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value, int check_this) /* {{{ */
{ {
uint32_t first_extra_arg, num_args; uint32_t first_extra_arg, num_args;
ZEND_ASSERT(EX(func) == (zend_function*)op_array); ZEND_ASSERT(EX(func) == (zend_function*)op_array);
@ -1793,13 +1795,14 @@ static zend_always_inline void i_init_func_execute_data(zend_execute_data *execu
} while (var != end); } while (var != end);
} }
if (op_array->this_var != (uint32_t)-1 && EXPECTED(Z_OBJ(EX(This)))) { if (check_this && op_array->this_var != (uint32_t)-1 && EXPECTED(Z_OBJ(EX(This)))) {
ZVAL_OBJ(EX_VAR(op_array->this_var), Z_OBJ(EX(This))); ZVAL_OBJ(EX_VAR(op_array->this_var), Z_OBJ(EX(This)));
GC_REFCOUNT(Z_OBJ(EX(This)))++; GC_REFCOUNT(Z_OBJ(EX(This)))++;
} }
if (UNEXPECTED(!op_array->run_time_cache)) { if (UNEXPECTED(!op_array->run_time_cache)) {
op_array->run_time_cache = zend_arena_calloc(&CG(arena), op_array->last_cache_slot, sizeof(void*)); op_array->run_time_cache = zend_arena_alloc(&CG(arena), op_array->cache_size);
memset(op_array->run_time_cache, 0, op_array->cache_size);
} }
EX_LOAD_RUN_TIME_CACHE(op_array); EX_LOAD_RUN_TIME_CACHE(op_array);
EX_LOAD_LITERALS(op_array); EX_LOAD_LITERALS(op_array);
@ -1824,7 +1827,8 @@ static zend_always_inline void i_init_code_execute_data(zend_execute_data *execu
} }
if (!op_array->run_time_cache) { if (!op_array->run_time_cache) {
op_array->run_time_cache = ecalloc(op_array->last_cache_slot, sizeof(void*)); op_array->run_time_cache = emalloc(op_array->cache_size);
memset(op_array->run_time_cache, 0, op_array->cache_size);
} }
EX_LOAD_RUN_TIME_CACHE(op_array); EX_LOAD_RUN_TIME_CACHE(op_array);
EX_LOAD_LITERALS(op_array); EX_LOAD_LITERALS(op_array);
@ -1901,10 +1905,11 @@ static zend_always_inline void i_init_execute_data(zend_execute_data *execute_da
if (!op_array->run_time_cache) { if (!op_array->run_time_cache) {
if (op_array->function_name) { if (op_array->function_name) {
op_array->run_time_cache = zend_arena_calloc(&CG(arena), op_array->last_cache_slot, sizeof(void*)); op_array->run_time_cache = zend_arena_alloc(&CG(arena), op_array->cache_size);
} else { } else {
op_array->run_time_cache = ecalloc(op_array->last_cache_slot, sizeof(void*)); op_array->run_time_cache = emalloc(op_array->cache_size);
} }
memset(op_array->run_time_cache, 0, op_array->cache_size);
} }
EX_LOAD_RUN_TIME_CACHE(op_array); EX_LOAD_RUN_TIME_CACHE(op_array);
EX_LOAD_LITERALS(op_array); EX_LOAD_LITERALS(op_array);
@ -1958,7 +1963,7 @@ ZEND_API zend_execute_data *zend_create_generator_execute_data(zend_execute_data
EX(symbol_table) = NULL; EX(symbol_table) = NULL;
i_init_func_execute_data(execute_data, op_array, return_value); i_init_func_execute_data(execute_data, op_array, return_value, 1);
return execute_data; return execute_data;
} }
@ -2014,7 +2019,7 @@ static zend_execute_data *zend_vm_stack_copy_call_frame(zend_execute_data *call,
static zend_always_inline void zend_vm_stack_extend_call_frame(zend_execute_data **call, uint32_t passed_args, uint32_t additional_args) /* {{{ */ static zend_always_inline void zend_vm_stack_extend_call_frame(zend_execute_data **call, uint32_t passed_args, uint32_t additional_args) /* {{{ */
{ {
if (EXPECTED(EG(vm_stack_end) - EG(vm_stack_top) > additional_args)) { if (EXPECTED((uint32_t)(EG(vm_stack_end) - EG(vm_stack_top)) > additional_args)) {
EG(vm_stack_top) += additional_args; EG(vm_stack_top) += additional_args;
} else { } else {
*call = zend_vm_stack_copy_call_frame(*call, passed_args, additional_args); *call = zend_vm_stack_copy_call_frame(*call, passed_args, additional_args);

View file

@ -256,21 +256,25 @@ ZEND_API int zend_do_fcall(ZEND_OPCODE_HANDLER_ARGS);
ZEND_API void zend_clean_and_cache_symbol_table(zend_array *symbol_table); ZEND_API void zend_clean_and_cache_symbol_table(zend_array *symbol_table);
void zend_free_compiled_variables(zend_execute_data *execute_data); void zend_free_compiled_variables(zend_execute_data *execute_data);
#define CACHE_ADDR(num) \
((void**)((char*)EX_RUN_TIME_CACHE() + (num)))
#define CACHED_PTR(num) \ #define CACHED_PTR(num) \
EX_RUN_TIME_CACHE()[(num)] ((void**)((char*)EX_RUN_TIME_CACHE() + (num)))[0]
#define CACHE_PTR(num, ptr) do { \ #define CACHE_PTR(num, ptr) do { \
EX_RUN_TIME_CACHE()[(num)] = (ptr); \ ((void**)((char*)EX_RUN_TIME_CACHE() + (num)))[0] = (ptr); \
} while (0) } while (0)
#define CACHED_POLYMORPHIC_PTR(num, ce) \ #define CACHED_POLYMORPHIC_PTR(num, ce) \
((EX_RUN_TIME_CACHE()[(num)] == (ce)) ? \ ((((void**)((char*)EX_RUN_TIME_CACHE() + (num)))[0] == (void*)(ce)) ? \
EX_RUN_TIME_CACHE()[(num) + 1] : \ ((void**)((char*)EX_RUN_TIME_CACHE() + (num)))[1] : \
NULL) NULL)
#define CACHE_POLYMORPHIC_PTR(num, ce, ptr) do { \ #define CACHE_POLYMORPHIC_PTR(num, ce, ptr) do { \
EX_RUN_TIME_CACHE()[(num)] = (ce); \ void **slot = (void**)((char*)EX_RUN_TIME_CACHE() + (num)); \
EX_RUN_TIME_CACHE()[(num) + 1] = (ptr); \ slot[0] = (ce); \
slot[1] = (ptr); \
} while (0) } while (0)
#define CACHED_PTR_EX(slot) \ #define CACHED_PTR_EX(slot) \

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); if (Z_REFCOUNTED_P(p)) Z_SET_REFCOUNT_P(p, refcount);
} else if (Z_TYPE_P(p) == IS_CONSTANT_AST) { } else if (Z_TYPE_P(p) == IS_CONSTANT_AST) {
zval tmp; zval tmp;
SEPARATE_ZVAL_NOREF(p); if (inline_change) {
SEPARATE_ZVAL_NOREF(p);
}
zend_ast_evaluate(&tmp, Z_ASTVAL_P(p), scope); zend_ast_evaluate(&tmp, Z_ASTVAL_P(p), scope);
if (inline_change) { if (inline_change) {
zend_ast_destroy_and_free(Z_ASTVAL_P(p)); zend_ast_destroy_and_free(Z_ASTVAL_P(p));
@ -690,7 +691,10 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) /
EG(current_execute_data) = &dummy_execute_data; EG(current_execute_data) = &dummy_execute_data;
} else if (EG(current_execute_data)->func && } else if (EG(current_execute_data)->func &&
ZEND_USER_CODE(EG(current_execute_data)->func->common.type) && ZEND_USER_CODE(EG(current_execute_data)->func->common.type) &&
EG(current_execute_data)->opline->opcode != ZEND_DO_FCALL) { EG(current_execute_data)->opline->opcode != ZEND_DO_FCALL &&
EG(current_execute_data)->opline->opcode != ZEND_DO_ICALL &&
EG(current_execute_data)->opline->opcode != ZEND_DO_UCALL &&
EG(current_execute_data)->opline->opcode != ZEND_DO_FCALL_BY_NAME) {
/* Insert fake frame in case of include or magic calls */ /* Insert fake frame in case of include or magic calls */
dummy_execute_data = *EG(current_execute_data); dummy_execute_data = *EG(current_execute_data);
dummy_execute_data.prev_execute_data = EG(current_execute_data); dummy_execute_data.prev_execute_data = EG(current_execute_data);

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)); zend_op_array *op_array_copy = (zend_op_array*)emalloc(sizeof(zend_op_array));
*op_array_copy = *op_array; *op_array_copy = *op_array;
(*op_array->refcount)++; if (op_array->refcount) {
(*op_array->refcount)++;
}
op_array->run_time_cache = NULL; op_array->run_time_cache = NULL;
if (op_array->static_variables) { if (op_array->static_variables) {
ALLOC_HASHTABLE(op_array_copy->static_variables); ALLOC_HASHTABLE(op_array_copy->static_variables);

View file

@ -1113,7 +1113,7 @@ ZEND_API void zend_array_destroy(HashTable *ht)
/* In some rare cases destructors of regular arrays may be changed */ /* In some rare cases destructors of regular arrays may be changed */
if (UNEXPECTED(ht->pDestructor != ZVAL_PTR_DTOR)) { if (UNEXPECTED(ht->pDestructor != ZVAL_PTR_DTOR)) {
zend_hash_destroy(ht); zend_hash_destroy(ht);
return; goto free_ht;
} }
p = ht->arData; p = ht->arData;
@ -1122,9 +1122,7 @@ ZEND_API void zend_array_destroy(HashTable *ht)
if (ht->u.flags & HASH_FLAG_PACKED) { if (ht->u.flags & HASH_FLAG_PACKED) {
do { do {
if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) { i_zval_ptr_dtor(&p->val ZEND_FILE_LINE_CC);
i_zval_ptr_dtor(&p->val ZEND_FILE_LINE_CC);
}
} while (++p != end); } while (++p != end);
} else { } else {
do { do {
@ -1139,9 +1137,11 @@ ZEND_API void zend_array_destroy(HashTable *ht)
zend_hash_iterators_remove(ht); zend_hash_iterators_remove(ht);
SET_INCONSISTENT(HT_DESTROYED); SET_INCONSISTENT(HT_DESTROYED);
} else if (EXPECTED(!(ht->u.flags & HASH_FLAG_INITIALIZED))) { } else if (EXPECTED(!(ht->u.flags & HASH_FLAG_INITIALIZED))) {
return; goto free_ht;
} }
pefree(ht->arData, ht->u.flags & HASH_FLAG_PERSISTENT); pefree(ht->arData, ht->u.flags & HASH_FLAG_PERSISTENT);
free_ht:
FREE_HASHTABLE(ht);
} }
ZEND_API void zend_hash_clean(HashTable *ht) ZEND_API void zend_hash_clean(HashTable *ht)

View file

@ -934,7 +934,9 @@ ZEND_API void zend_std_call_user_call(INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
/* destruct the function also, then - we have allocated it in get_method */ /* destruct the function also, then - we have allocated it in get_method */
efree_size(func, sizeof(zend_internal_function)); efree_size(func, sizeof(zend_internal_function));
#if ZEND_DEBUG
execute_data->func = NULL; execute_data->func = NULL;
#endif
} }
/* }}} */ /* }}} */
@ -1155,7 +1157,9 @@ ZEND_API void zend_std_callstatic_user_call(INTERNAL_FUNCTION_PARAMETERS) /* {{{
/* destruct the function also, then - we have allocated it in get_method */ /* destruct the function also, then - we have allocated it in get_method */
efree_size(func, sizeof(zend_internal_function)); efree_size(func, sizeof(zend_internal_function));
#if ZEND_DEBUG
execute_data->func = NULL; execute_data->func = NULL;
#endif
} }
/* }}} */ /* }}} */

View file

@ -55,7 +55,6 @@ ZEND_API void zend_object_std_dtor(zend_object *object)
if (object->properties) { if (object->properties) {
zend_array_destroy(object->properties); zend_array_destroy(object->properties);
FREE_HASHTABLE(object->properties);
} }
count = object->ce->default_properties_count; count = object->ce->default_properties_count;
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {

View file

@ -91,7 +91,7 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz
op_array->literals = NULL; op_array->literals = NULL;
op_array->run_time_cache = NULL; op_array->run_time_cache = NULL;
op_array->last_cache_slot = 0; op_array->cache_size = 0;
memset(op_array->reserved, 0, ZEND_MAX_RESERVED_RESOURCES * sizeof(void*)); memset(op_array->reserved, 0, ZEND_MAX_RESERVED_RESOURCES * sizeof(void*));
@ -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) 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); zend_hash_clean(op_array->static_variables);
} }
} }
@ -317,16 +318,18 @@ ZEND_API void destroy_op_array(zend_op_array *op_array)
zval *end; zval *end;
uint32_t i; uint32_t i;
if (op_array->static_variables) { if (op_array->static_variables &&
zend_hash_destroy(op_array->static_variables); !(GC_FLAGS(op_array->static_variables) & IS_ARRAY_IMMUTABLE)) {
FREE_HASHTABLE(op_array->static_variables); if (--GC_REFCOUNT(op_array->static_variables) == 0) {
zend_array_destroy(op_array->static_variables);
}
} }
if (op_array->run_time_cache && !op_array->function_name) { if (op_array->run_time_cache && !op_array->function_name) {
efree(op_array->run_time_cache); efree(op_array->run_time_cache);
} }
if (--(*op_array->refcount)>0) { if (!op_array->refcount || --(*op_array->refcount)>0) {
return; return;
} }

View file

@ -2870,6 +2870,38 @@ ZEND_API const char* zend_memnrstr_ex(const char *haystack, const char *needle,
} }
/* }}} */ /* }}} */
#if !ZEND_DVAL_TO_LVAL_CAST_OK
# if SIZEOF_ZEND_LONG == 4
ZEND_API zend_long zend_dval_to_lval_slow(double d)
{
double two_pow_32 = pow(2., 32.),
dmod;
dmod = fmod(d, two_pow_32);
if (dmod < 0) {
/* we're going to make this number positive; call ceil()
* to simulate rounding towards 0 of the negative number */
dmod = ceil(dmod);// + two_pow_32;
}
return (zend_long)(zend_ulong)dmod;
}
#else
ZEND_API zend_long zend_dval_to_lval_slow(double d)
{
double two_pow_64 = pow(2., 64.),
dmod;
dmod = fmod(d, two_pow_64);
if (dmod < 0) {
/* no need to call ceil; original double must have had no
* fractional part, hence dmod does not have one either */
dmod += two_pow_64;
}
return (zend_long)(zend_ulong)dmod;
}
#endif
#endif
/* /*
* Local variables: * Local variables:
* tab-width: 4 * tab-width: 4

View file

@ -108,41 +108,15 @@ static zend_always_inline zend_long zend_dval_to_lval(double d)
return 0; return 0;
} }
} }
#elif SIZEOF_ZEND_LONG == 4
static zend_always_inline zend_long zend_dval_to_lval(double d)
{
if (UNEXPECTED(!zend_finite(d)) || UNEXPECTED(zend_isnan(d))) {
return 0;
} else if (!ZEND_DOUBLE_FITS_LONG(d)) {
double two_pow_32 = pow(2., 32.),
dmod;
dmod = fmod(d, two_pow_32);
if (dmod < 0) {
/* we're going to make this number positive; call ceil()
* to simulate rounding towards 0 of the negative number */
dmod = ceil(dmod) + two_pow_32;
}
return (zend_long)(zend_ulong)dmod;
}
return (zend_long)d;
}
#else #else
ZEND_API zend_long zend_dval_to_lval_slow(double d);
static zend_always_inline zend_long zend_dval_to_lval(double d) static zend_always_inline zend_long zend_dval_to_lval(double d)
{ {
if (UNEXPECTED(!zend_finite(d)) || UNEXPECTED(zend_isnan(d))) { if (UNEXPECTED(!zend_finite(d)) || UNEXPECTED(zend_isnan(d))) {
return 0; return 0;
} else if (!ZEND_DOUBLE_FITS_LONG(d)) { } else if (!ZEND_DOUBLE_FITS_LONG(d)) {
double two_pow_64 = pow(2., 64.), return zend_dval_to_lval_slow(d);
dmod;
dmod = fmod(d, two_pow_64);
if (dmod < 0) {
/* no need to call ceil; original double must have had no
* fractional part, hence dmod does not have one either */
dmod += two_pow_64;
}
return (zend_long)(zend_ulong)dmod;
} }
return (zend_long)d; return (zend_long)d;
} }

View file

@ -345,6 +345,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 (1<<3) /* constant index */
#define IS_STR_CONSTANT_UNQUALIFIED (1<<4) /* the same as IS_CONSTANT_UNQUALIFIED */ #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) */ /* object flags (zval.value->gc.u.flags) */
#define IS_OBJ_APPLY_COUNT 0x07 #define IS_OBJ_APPLY_COUNT 0x07
#define IS_OBJ_DESTRUCTOR_CALLED (1<<3) #define IS_OBJ_DESTRUCTOR_CALLED (1<<3)

View file

@ -46,7 +46,6 @@ ZEND_API void _zval_dtor_func(zend_refcounted *p ZEND_FILE_LINE_DC)
GC_TYPE(arr) = IS_NULL; GC_TYPE(arr) = IS_NULL;
GC_REMOVE_FROM_BUFFER(arr); GC_REMOVE_FROM_BUFFER(arr);
zend_array_destroy(arr); zend_array_destroy(arr);
efree_size(arr, sizeof(zend_array));
break; break;
} }
case IS_CONSTANT_AST: { case IS_CONSTANT_AST: {
@ -102,7 +101,6 @@ ZEND_API void _zval_dtor_func_for_ptr(zend_refcounted *p ZEND_FILE_LINE_DC)
GC_TYPE(arr) = IS_NULL; GC_TYPE(arr) = IS_NULL;
GC_REMOVE_FROM_BUFFER(arr); GC_REMOVE_FROM_BUFFER(arr);
zend_array_destroy(arr); zend_array_destroy(arr);
efree_size(arr, sizeof(zend_array));
break; break;
} }
case IS_CONSTANT_AST: { case IS_CONSTANT_AST: {

View file

@ -366,7 +366,8 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMPVAR|
value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
if (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { if (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
if (UNEXPECTED(!make_real_object(&object))) { ZVAL_DEREF(object);
if (UNEXPECTED(!make_real_object(object))) {
zend_error(E_WARNING, "Attempt to assign property of non-object"); zend_error(E_WARNING, "Attempt to assign property of non-object");
if (UNEXPECTED(RETURN_VALUE_USED(opline))) { if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
ZVAL_NULL(EX_VAR(opline->result.var)); ZVAL_NULL(EX_VAR(opline->result.var));
@ -377,7 +378,7 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMPVAR|
/* here we are sure we are dealing with an object */ /* here we are sure we are dealing with an object */
if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr)
&& EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((OP2_TYPE == IS_CONST) ? (EX_RUN_TIME_CACHE() + Z_CACHE_SLOT_P(property)) : NULL))) != NULL)) { && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(Z_CACHE_SLOT_P(property)) : NULL))) != NULL)) {
ZVAL_DEREF(zptr); ZVAL_DEREF(zptr);
SEPARATE_ZVAL_NOREF(zptr); SEPARATE_ZVAL_NOREF(zptr);
@ -391,7 +392,7 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMPVAR|
zval rv; zval rv;
if (Z_OBJ_HT_P(object)->read_property && if (Z_OBJ_HT_P(object)->read_property &&
(z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((OP2_TYPE == IS_CONST) ? (EX_RUN_TIME_CACHE() + Z_CACHE_SLOT_P(property)) : NULL), &rv)) != NULL) { (z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(Z_CACHE_SLOT_P(property)) : NULL), &rv)) != NULL) {
if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get) { if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get) {
zval rv; zval rv;
zval *value = Z_OBJ_HT_P(z)->get(z, &rv); zval *value = Z_OBJ_HT_P(z)->get(z, &rv);
@ -404,7 +405,7 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMPVAR|
ZVAL_DEREF(z); ZVAL_DEREF(z);
SEPARATE_ZVAL_NOREF(z); SEPARATE_ZVAL_NOREF(z);
binary_op(z, z, value); binary_op(z, z, value);
Z_OBJ_HT_P(object)->write_property(object, property, z, ((OP2_TYPE == IS_CONST) ? (EX_RUN_TIME_CACHE() + Z_CACHE_SLOT_P(property)) : NULL)); Z_OBJ_HT_P(object)->write_property(object, property, z, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(Z_CACHE_SLOT_P(property)) : NULL));
if (UNEXPECTED(RETURN_VALUE_USED(opline))) { if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
ZVAL_COPY(EX_VAR(opline->result.var), z); ZVAL_COPY(EX_VAR(opline->result.var), z);
} }
@ -765,7 +766,8 @@ ZEND_VM_HELPER_EX(zend_pre_incdec_property_helper, VAR|UNUSED|CV, CONST|TMPVAR|C
do { do {
if (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { if (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
if (UNEXPECTED(!make_real_object(&object))) { ZVAL_DEREF(object);
if (UNEXPECTED(!make_real_object(object))) {
zend_error(E_WARNING, "Attempt to increment/decrement property of non-object"); zend_error(E_WARNING, "Attempt to increment/decrement property of non-object");
if (UNEXPECTED(RETURN_VALUE_USED(opline))) { if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
ZVAL_NULL(retval); ZVAL_NULL(retval);
@ -777,7 +779,7 @@ ZEND_VM_HELPER_EX(zend_pre_incdec_property_helper, VAR|UNUSED|CV, CONST|TMPVAR|C
/* here we are sure we are dealing with an object */ /* here we are sure we are dealing with an object */
if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr)
&& EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((OP2_TYPE == IS_CONST) ? (EX_RUN_TIME_CACHE() + Z_CACHE_SLOT_P(property)) : NULL))) != NULL)) { && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(Z_CACHE_SLOT_P(property)) : NULL))) != NULL)) {
ZVAL_DEREF(zptr); ZVAL_DEREF(zptr);
SEPARATE_ZVAL_NOREF(zptr); SEPARATE_ZVAL_NOREF(zptr);
@ -790,7 +792,7 @@ ZEND_VM_HELPER_EX(zend_pre_incdec_property_helper, VAR|UNUSED|CV, CONST|TMPVAR|C
zval rv; zval rv;
if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) { if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) {
zval *z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((OP2_TYPE == IS_CONST) ? (EX_RUN_TIME_CACHE() + Z_CACHE_SLOT_P(property)) : NULL), &rv); zval *z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(Z_CACHE_SLOT_P(property)) : NULL), &rv);
if (UNEXPECTED(Z_TYPE_P(z) == IS_OBJECT) && Z_OBJ_HT_P(z)->get) { if (UNEXPECTED(Z_TYPE_P(z) == IS_OBJECT) && Z_OBJ_HT_P(z)->get) {
zval rv; zval rv;
@ -807,7 +809,7 @@ ZEND_VM_HELPER_EX(zend_pre_incdec_property_helper, VAR|UNUSED|CV, CONST|TMPVAR|C
if (UNEXPECTED(RETURN_VALUE_USED(opline))) { if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
ZVAL_COPY(retval, z); ZVAL_COPY(retval, z);
} }
Z_OBJ_HT_P(object)->write_property(object, property, z, ((OP2_TYPE == IS_CONST) ? (EX_RUN_TIME_CACHE() + Z_CACHE_SLOT_P(property)) : NULL)); Z_OBJ_HT_P(object)->write_property(object, property, z, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(Z_CACHE_SLOT_P(property)) : NULL));
zval_ptr_dtor(z); zval_ptr_dtor(z);
} else { } else {
zend_error(E_WARNING, "Attempt to increment/decrement property of non-object"); zend_error(E_WARNING, "Attempt to increment/decrement property of non-object");
@ -854,7 +856,8 @@ ZEND_VM_HELPER_EX(zend_post_incdec_property_helper, VAR|UNUSED|CV, CONST|TMPVAR|
do { do {
if (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { if (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
if (UNEXPECTED(!make_real_object(&object))) { ZVAL_DEREF(object);
if (UNEXPECTED(!make_real_object(object))) {
zend_error(E_WARNING, "Attempt to increment/decrement property of non-object"); zend_error(E_WARNING, "Attempt to increment/decrement property of non-object");
ZVAL_NULL(retval); ZVAL_NULL(retval);
break; break;
@ -864,7 +867,7 @@ ZEND_VM_HELPER_EX(zend_post_incdec_property_helper, VAR|UNUSED|CV, CONST|TMPVAR|
/* here we are sure we are dealing with an object */ /* here we are sure we are dealing with an object */
if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr)
&& EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((OP2_TYPE == IS_CONST) ? (EX_RUN_TIME_CACHE() + Z_CACHE_SLOT_P(property)) : NULL))) != NULL)) { && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(Z_CACHE_SLOT_P(property)) : NULL))) != NULL)) {
ZVAL_DEREF(zptr); ZVAL_DEREF(zptr);
ZVAL_COPY_VALUE(retval, zptr); ZVAL_COPY_VALUE(retval, zptr);
@ -874,7 +877,7 @@ ZEND_VM_HELPER_EX(zend_post_incdec_property_helper, VAR|UNUSED|CV, CONST|TMPVAR|
} else { } else {
if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) { if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) {
zval rv; zval rv;
zval *z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((OP2_TYPE == IS_CONST) ? (EX_RUN_TIME_CACHE() + Z_CACHE_SLOT_P(property)) : NULL), &rv); zval *z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(Z_CACHE_SLOT_P(property)) : NULL), &rv);
zval z_copy; zval z_copy;
if (UNEXPECTED(Z_TYPE_P(z) == IS_OBJECT) && Z_OBJ_HT_P(z)->get) { if (UNEXPECTED(Z_TYPE_P(z) == IS_OBJECT) && Z_OBJ_HT_P(z)->get) {
@ -890,7 +893,7 @@ ZEND_VM_HELPER_EX(zend_post_incdec_property_helper, VAR|UNUSED|CV, CONST|TMPVAR|
ZVAL_DUP(&z_copy, z); ZVAL_DUP(&z_copy, z);
incdec_op(&z_copy); incdec_op(&z_copy);
if (Z_REFCOUNTED_P(z)) Z_ADDREF_P(z); if (Z_REFCOUNTED_P(z)) Z_ADDREF_P(z);
Z_OBJ_HT_P(object)->write_property(object, property, &z_copy, ((OP2_TYPE == IS_CONST) ? (EX_RUN_TIME_CACHE() + Z_CACHE_SLOT_P(property)) : NULL)); Z_OBJ_HT_P(object)->write_property(object, property, &z_copy, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(Z_CACHE_SLOT_P(property)) : NULL));
zval_ptr_dtor(&z_copy); zval_ptr_dtor(&z_copy);
zval_ptr_dtor(z); zval_ptr_dtor(z);
} else { } else {
@ -1131,7 +1134,7 @@ ZEND_VM_HELPER_EX(zend_fetch_var_address_helper, CONST|TMPVAR|CV, UNUSED|CONST|V
if (OP1_TYPE == IS_CONST && CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)))) { if (OP1_TYPE == IS_CONST && CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)))) {
ce = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1))); ce = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)));
retval = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)) + 1); retval = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)) + sizeof(void*));
/* check if static properties were destoyed */ /* check if static properties were destoyed */
if (UNEXPECTED(CE_STATIC_MEMBERS(ce) == NULL)) { if (UNEXPECTED(CE_STATIC_MEMBERS(ce) == NULL)) {
@ -1438,9 +1441,9 @@ ZEND_VM_HANDLER(82, ZEND_FETCH_OBJ_R, CONST|TMP|VAR|UNUSED|CV, CONST|TMPVAR|CV)
if (OP2_TYPE == IS_CONST && if (OP2_TYPE == IS_CONST &&
EXPECTED(zobj->ce == CACHED_PTR(Z_CACHE_SLOT_P(offset)))) { EXPECTED(zobj->ce == CACHED_PTR(Z_CACHE_SLOT_P(offset)))) {
uint32_t prop_offset = (uint32_t)(intptr_t)CACHED_PTR(Z_CACHE_SLOT_P(offset) + 1); uint32_t prop_offset = (uint32_t)(intptr_t)CACHED_PTR(Z_CACHE_SLOT_P(offset) + sizeof(void*));
if (EXPECTED(prop_offset != ZEND_DYNAMIC_PROPERTY_OFFSET)) { if (EXPECTED(prop_offset != (uint32_t)ZEND_DYNAMIC_PROPERTY_OFFSET)) {
retval = OBJ_PROP(zobj, prop_offset); retval = OBJ_PROP(zobj, prop_offset);
if (EXPECTED(Z_TYPE_P(retval) != IS_UNDEF)) { if (EXPECTED(Z_TYPE_P(retval) != IS_UNDEF)) {
ZVAL_COPY(EX_VAR(opline->result.var), retval); ZVAL_COPY(EX_VAR(opline->result.var), retval);
@ -1460,7 +1463,7 @@ ZEND_VM_C_LABEL(fetch_obj_r_no_object):
zend_error(E_NOTICE, "Trying to get property of non-object"); zend_error(E_NOTICE, "Trying to get property of non-object");
ZVAL_NULL(EX_VAR(opline->result.var)); ZVAL_NULL(EX_VAR(opline->result.var));
} else { } else {
retval = zobj->handlers->read_property(container, offset, BP_VAR_R, ((OP2_TYPE == IS_CONST) ? (EX_RUN_TIME_CACHE() + Z_CACHE_SLOT_P(offset)) : NULL), EX_VAR(opline->result.var)); retval = zobj->handlers->read_property(container, offset, BP_VAR_R, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(Z_CACHE_SLOT_P(offset)) : NULL), EX_VAR(opline->result.var));
if (retval != EX_VAR(opline->result.var)) { if (retval != EX_VAR(opline->result.var)) {
ZVAL_COPY(EX_VAR(opline->result.var), retval); ZVAL_COPY(EX_VAR(opline->result.var), retval);
@ -1489,7 +1492,7 @@ ZEND_VM_HANDLER(85, ZEND_FETCH_OBJ_W, VAR|UNUSED|CV, CONST|TMPVAR|CV)
zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); zend_error_noreturn(E_ERROR, "Cannot use string offset as an object");
} }
zend_fetch_property_address(EX_VAR(opline->result.var), container, OP1_TYPE, property, OP2_TYPE, ((OP2_TYPE == IS_CONST) ? (EX_RUN_TIME_CACHE() + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W); zend_fetch_property_address(EX_VAR(opline->result.var), container, OP1_TYPE, property, OP2_TYPE, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W);
FREE_OP2(); FREE_OP2();
if (OP1_TYPE == IS_VAR && READY_TO_DESTROY(free_op1)) { if (OP1_TYPE == IS_VAR && READY_TO_DESTROY(free_op1)) {
EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var));
@ -1513,7 +1516,7 @@ ZEND_VM_HANDLER(88, ZEND_FETCH_OBJ_RW, VAR|UNUSED|CV, CONST|TMPVAR|CV)
if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) {
zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); zend_error_noreturn(E_ERROR, "Cannot use string offset as an object");
} }
zend_fetch_property_address(EX_VAR(opline->result.var), container, OP1_TYPE, property, OP2_TYPE, ((OP2_TYPE == IS_CONST) ? (EX_RUN_TIME_CACHE() + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_RW); zend_fetch_property_address(EX_VAR(opline->result.var), container, OP1_TYPE, property, OP2_TYPE, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_RW);
FREE_OP2(); FREE_OP2();
if (OP1_TYPE == IS_VAR && READY_TO_DESTROY(free_op1)) { if (OP1_TYPE == IS_VAR && READY_TO_DESTROY(free_op1)) {
EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var));
@ -1553,9 +1556,9 @@ ZEND_VM_HANDLER(91, ZEND_FETCH_OBJ_IS, CONST|TMPVAR|UNUSED|CV, CONST|TMPVAR|CV)
if (OP2_TYPE == IS_CONST && if (OP2_TYPE == IS_CONST &&
EXPECTED(zobj->ce == CACHED_PTR(Z_CACHE_SLOT_P(offset)))) { EXPECTED(zobj->ce == CACHED_PTR(Z_CACHE_SLOT_P(offset)))) {
uint32_t prop_offset = (uint32_t)(intptr_t)CACHED_PTR(Z_CACHE_SLOT_P(offset) + 1); uint32_t prop_offset = (uint32_t)(intptr_t)CACHED_PTR(Z_CACHE_SLOT_P(offset) + sizeof(void*));
if (EXPECTED(prop_offset != ZEND_DYNAMIC_PROPERTY_OFFSET)) { if (EXPECTED(prop_offset != (uint32_t)ZEND_DYNAMIC_PROPERTY_OFFSET)) {
retval = OBJ_PROP(zobj, prop_offset); retval = OBJ_PROP(zobj, prop_offset);
if (EXPECTED(Z_TYPE_P(retval) != IS_UNDEF)) { if (EXPECTED(Z_TYPE_P(retval) != IS_UNDEF)) {
ZVAL_COPY(EX_VAR(opline->result.var), retval); ZVAL_COPY(EX_VAR(opline->result.var), retval);
@ -1575,7 +1578,7 @@ ZEND_VM_C_LABEL(fetch_obj_is_no_object):
ZVAL_NULL(EX_VAR(opline->result.var)); ZVAL_NULL(EX_VAR(opline->result.var));
} else { } else {
retval = zobj->handlers->read_property(container, offset, BP_VAR_IS, ((OP2_TYPE == IS_CONST) ? (EX_RUN_TIME_CACHE() + Z_CACHE_SLOT_P(offset)) : NULL), EX_VAR(opline->result.var)); retval = zobj->handlers->read_property(container, offset, BP_VAR_IS, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(Z_CACHE_SLOT_P(offset)) : NULL), EX_VAR(opline->result.var));
if (retval != EX_VAR(opline->result.var)) { if (retval != EX_VAR(opline->result.var)) {
ZVAL_COPY(EX_VAR(opline->result.var), retval); ZVAL_COPY(EX_VAR(opline->result.var), retval);
@ -1609,7 +1612,7 @@ ZEND_VM_HANDLER(94, ZEND_FETCH_OBJ_FUNC_ARG, CONST|TMP|VAR|UNUSED|CV, CONST|TMPV
if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) {
zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); zend_error_noreturn(E_ERROR, "Cannot use string offset as an object");
} }
zend_fetch_property_address(EX_VAR(opline->result.var), container, OP1_TYPE, property, OP2_TYPE, ((OP2_TYPE == IS_CONST) ? (EX_RUN_TIME_CACHE() + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W); zend_fetch_property_address(EX_VAR(opline->result.var), container, OP1_TYPE, property, OP2_TYPE, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W);
FREE_OP2(); FREE_OP2();
if (OP1_TYPE == IS_VAR && READY_TO_DESTROY(free_op1)) { if (OP1_TYPE == IS_VAR && READY_TO_DESTROY(free_op1)) {
EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var));
@ -1635,7 +1638,7 @@ ZEND_VM_HANDLER(97, ZEND_FETCH_OBJ_UNSET, VAR|UNUSED|CV, CONST|TMPVAR|CV)
if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) {
zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); zend_error_noreturn(E_ERROR, "Cannot use string offset as an object");
} }
zend_fetch_property_address(EX_VAR(opline->result.var), container, OP1_TYPE, property, OP2_TYPE, ((OP2_TYPE == IS_CONST) ? (EX_RUN_TIME_CACHE() + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_UNSET); zend_fetch_property_address(EX_VAR(opline->result.var), container, OP1_TYPE, property, OP2_TYPE, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_UNSET);
FREE_OP2(); FREE_OP2();
if (OP1_TYPE == IS_VAR && READY_TO_DESTROY(free_op1)) { if (OP1_TYPE == IS_VAR && READY_TO_DESTROY(free_op1)) {
EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var));
@ -1696,7 +1699,7 @@ ZEND_VM_HANDLER(136, ZEND_ASSIGN_OBJ, VAR|UNUSED|CV, CONST|TMPVAR|CV)
if (OP1_TYPE == IS_VAR && UNEXPECTED(object == NULL)) { if (OP1_TYPE == IS_VAR && UNEXPECTED(object == NULL)) {
zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); zend_error_noreturn(E_ERROR, "Cannot use string offset as an array");
} }
zend_assign_to_object(UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL, object, OP1_TYPE, property_name, OP2_TYPE, (opline+1)->op1_type, (opline+1)->op1, execute_data, ((OP2_TYPE == IS_CONST) ? (EX_RUN_TIME_CACHE() + Z_CACHE_SLOT_P(property_name)) : NULL)); zend_assign_to_object(UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL, object, OP1_TYPE, property_name, OP2_TYPE, (opline+1)->op1_type, (opline+1)->op1, execute_data, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(Z_CACHE_SLOT_P(property_name)) : NULL));
FREE_OP2(); FREE_OP2();
FREE_OP1_VAR_PTR(); FREE_OP1_VAR_PTR();
/* assign_obj has two opcodes! */ /* assign_obj has two opcodes! */
@ -1711,7 +1714,6 @@ ZEND_VM_HANDLER(147, ZEND_ASSIGN_DIM, VAR|CV, CONST|TMPVAR|UNUSED|CV)
zend_free_op free_op1; zend_free_op free_op1;
zval *object_ptr; zval *object_ptr;
zend_free_op free_op2, free_op_data1; zend_free_op free_op2, free_op_data1;
zval rv;
zval *value; zval *value;
zval *variable_ptr; zval *variable_ptr;
zval *dim; zval *dim;
@ -1726,12 +1728,20 @@ ZEND_VM_HANDLER(147, ZEND_ASSIGN_DIM, VAR|CV, CONST|TMPVAR|UNUSED|CV)
ZEND_VM_C_LABEL(try_assign_dim): ZEND_VM_C_LABEL(try_assign_dim):
if (EXPECTED(Z_TYPE_P(object_ptr) == IS_ARRAY)) { if (EXPECTED(Z_TYPE_P(object_ptr) == IS_ARRAY)) {
ZEND_VM_C_LABEL(try_assign_dim_array): ZEND_VM_C_LABEL(try_assign_dim_array):
dim = GET_OP2_ZVAL_PTR(BP_VAR_R); if (OP2_TYPE == IS_UNUSED) {
zend_fetch_dimension_address_W(&rv, object_ptr, dim, OP2_TYPE); SEPARATE_ARRAY(object_ptr);
FREE_OP2(); variable_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(object_ptr), &EG(uninitialized_zval));
if (UNEXPECTED(variable_ptr == NULL)) {
zend_error(E_WARNING, "Cannot add element to the array as the next element is already occupied");
variable_ptr = &EG(error_zval);
}
} else {
dim = GET_OP2_ZVAL_PTR(BP_VAR_R);
SEPARATE_ARRAY(object_ptr);
variable_ptr = zend_fetch_dimension_address_inner(Z_ARRVAL_P(object_ptr), dim, OP2_TYPE, BP_VAR_W);
FREE_OP2();
}
value = get_zval_ptr_deref((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); value = get_zval_ptr_deref((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT);
variable_ptr = Z_INDIRECT(rv);
if (UNEXPECTED(variable_ptr == &EG(error_zval))) { if (UNEXPECTED(variable_ptr == &EG(error_zval))) {
FREE_OP(free_op_data1); FREE_OP(free_op_data1);
if (UNEXPECTED(RETURN_VALUE_USED(opline))) { if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
@ -1752,21 +1762,41 @@ ZEND_VM_C_LABEL(try_assign_dim_array):
zend_assign_to_object_dim(UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL, object_ptr, property_name, (opline+1)->op1_type, (opline+1)->op1, execute_data); zend_assign_to_object_dim(UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL, object_ptr, property_name, (opline+1)->op1_type, (opline+1)->op1, execute_data);
FREE_OP2(); FREE_OP2();
} else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING) && } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) {
EXPECTED(Z_STRLEN_P(object_ptr) != 0)) { if (EXPECTED(Z_STRLEN_P(object_ptr) != 0)) {
zend_long offset; zend_long offset;
dim = GET_OP2_ZVAL_PTR(BP_VAR_R); dim = GET_OP2_ZVAL_PTR(BP_VAR_R);
offset = zend_fetch_string_offset(object_ptr, dim, BP_VAR_W); offset = zend_fetch_string_offset(object_ptr, dim, BP_VAR_W);
FREE_OP2(); FREE_OP2();
value = get_zval_ptr_deref((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); value = get_zval_ptr_deref((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
zend_assign_to_string_offset(object_ptr, offset, value, (UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL)); zend_assign_to_string_offset(object_ptr, offset, value, (UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL));
FREE_OP(free_op_data1); FREE_OP(free_op_data1);
} else {
zval_ptr_dtor_nogc(object_ptr);
ZEND_VM_C_LABEL(assign_dim_convert_to_array):
ZVAL_NEW_ARR(object_ptr);
zend_hash_init(Z_ARRVAL_P(object_ptr), 8, NULL, ZVAL_PTR_DTOR, 0);
ZEND_VM_C_GOTO(try_assign_dim_array);
}
} else if (EXPECTED(Z_ISREF_P(object_ptr))) { } else if (EXPECTED(Z_ISREF_P(object_ptr))) {
object_ptr = Z_REFVAL_P(object_ptr); object_ptr = Z_REFVAL_P(object_ptr);
ZEND_VM_C_GOTO(try_assign_dim); ZEND_VM_C_GOTO(try_assign_dim);
} else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) {
if (UNEXPECTED(object_ptr == &EG(error_zval))) {
ZEND_VM_C_GOTO(assign_dim_clean);
}
ZEND_VM_C_GOTO(assign_dim_convert_to_array);
} else { } else {
ZEND_VM_C_GOTO(try_assign_dim_array); zend_error(E_WARNING, "Cannot use a scalar value as an array");
ZEND_VM_C_LABEL(assign_dim_clean):
dim = GET_OP2_ZVAL_PTR(BP_VAR_R);
FREE_OP2();
value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
FREE_OP(free_op_data1);
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
ZVAL_NULL(EX_VAR(opline->result.var));
}
} }
FREE_OP1_VAR_PTR(); FREE_OP1_VAR_PTR();
/* assign_dim has two opcodes! */ /* assign_dim has two opcodes! */
@ -2347,13 +2377,17 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMPVAR|UNUSED|CV, CONST|TMPVAR|CV)
if (opline->opcode == ZEND_INIT_FCALL || if (opline->opcode == ZEND_INIT_FCALL ||
opline->opcode == ZEND_INIT_FCALL_BY_NAME || opline->opcode == ZEND_INIT_FCALL_BY_NAME ||
opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME || opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME ||
opline->opcode == ZEND_INIT_DYNAMIC_CALL ||
opline->opcode == ZEND_INIT_METHOD_CALL || opline->opcode == ZEND_INIT_METHOD_CALL ||
opline->opcode == ZEND_INIT_STATIC_METHOD_CALL || opline->opcode == ZEND_INIT_STATIC_METHOD_CALL ||
opline->opcode == ZEND_INIT_USER_CALL || opline->opcode == ZEND_INIT_USER_CALL ||
opline->opcode == ZEND_NEW opline->opcode == ZEND_NEW
) { ) {
nesting++; nesting++;
} else if (opline->opcode == ZEND_DO_FCALL) { } else if (opline->opcode == ZEND_DO_FCALL ||
opline->opcode == ZEND_DO_ICALL ||
opline->opcode == ZEND_DO_UCALL ||
opline->opcode == ZEND_DO_FCALL_BY_NAME) {
nesting--; nesting--;
} }
} while (nesting); } while (nesting);
@ -2534,150 +2568,154 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMPVAR|UNUSE
ZEND_VM_NEXT_OPCODE(); ZEND_VM_NEXT_OPCODE();
} }
ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMPVAR|CV) ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST)
{ {
USE_OPLINE USE_OPLINE
zend_function *fbc; zend_function *fbc;
zval *function_name, *func; zval *function_name, *func;
if (OP2_TYPE == IS_CONST && Z_TYPE_P(EX_CONSTANT(opline->op2)) == IS_STRING) { if (EXPECTED(CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2))))) {
fbc = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)));
} else {
function_name = (zval*)(EX_CONSTANT(opline->op2)+1); function_name = (zval*)(EX_CONSTANT(opline->op2)+1);
if (CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)))) { if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(function_name))) == NULL)) {
fbc = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)));
} else if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(function_name))) == NULL)) {
SAVE_OPLINE(); SAVE_OPLINE();
zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(EX_CONSTANT(opline->op2))); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(EX_CONSTANT(opline->op2)));
} else { } else {
fbc = Z_FUNC_P(func); fbc = Z_FUNC_P(func);
CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), fbc); CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), fbc);
} }
}
EX(call) = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION,
fbc, opline->extended_value, NULL, NULL, EX(call));
EX(call) = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, /*CHECK_EXCEPTION();*/
fbc, opline->extended_value, NULL, NULL, EX(call)); ZEND_VM_NEXT_OPCODE();
}
/*CHECK_EXCEPTION();*/ ZEND_VM_HANDLER(128, ZEND_INIT_DYNAMIC_CALL, ANY, CONST|TMPVAR|CV)
ZEND_VM_NEXT_OPCODE(); {
} else { USE_OPLINE
zend_string *lcname; zend_function *fbc;
zend_free_op free_op2; zval *function_name, *func;
zend_class_entry *called_scope; zend_string *lcname;
zend_object *object; zend_free_op free_op2;
zend_class_entry *called_scope;
zend_object *object;
SAVE_OPLINE(); SAVE_OPLINE();
function_name = GET_OP2_ZVAL_PTR(BP_VAR_R); function_name = GET_OP2_ZVAL_PTR(BP_VAR_R);
ZEND_VM_C_LABEL(try_function_name): ZEND_VM_C_LABEL(try_function_name):
if (OP2_TYPE != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_STRING)) { if (OP2_TYPE != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_STRING)) {
if (Z_STRVAL_P(function_name)[0] == '\\') { if (Z_STRVAL_P(function_name)[0] == '\\') {
lcname = zend_string_alloc(Z_STRLEN_P(function_name) - 1, 0); lcname = zend_string_alloc(Z_STRLEN_P(function_name) - 1, 0);
zend_str_tolower_copy(lcname->val, Z_STRVAL_P(function_name) + 1, Z_STRLEN_P(function_name) - 1); zend_str_tolower_copy(lcname->val, Z_STRVAL_P(function_name) + 1, Z_STRLEN_P(function_name) - 1);
} else { } else {
lcname = zend_string_tolower(Z_STR_P(function_name)); lcname = zend_string_tolower(Z_STR_P(function_name));
} }
if (UNEXPECTED((func = zend_hash_find(EG(function_table), lcname)) == NULL)) { if (UNEXPECTED((func = zend_hash_find(EG(function_table), lcname)) == NULL)) {
zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(function_name)); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(function_name));
} }
zend_string_release(lcname); zend_string_release(lcname);
FREE_OP2();
fbc = Z_FUNC_P(func);
called_scope = NULL;
object = NULL;
} else if (OP2_TYPE != IS_CONST &&
EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) &&
Z_OBJ_HANDLER_P(function_name, get_closure) &&
Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &called_scope, &fbc, &object) == SUCCESS) {
if (object) {
GC_REFCOUNT(object)++;
}
if (OP2_TYPE == IS_VAR && (fbc->common.fn_flags & ZEND_ACC_CLOSURE)) {
/* Delay closure destruction until its invocation */
fbc->common.prototype = (zend_function*)Z_OBJ_P(free_op2);
} else if (OP2_TYPE == IS_CV) {
FREE_OP2(); FREE_OP2();
}
} else if (EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) &&
zend_hash_num_elements(Z_ARRVAL_P(function_name)) == 2) {
zval *obj;
zval *method;
obj = zend_hash_index_find(Z_ARRVAL_P(function_name), 0);
method = zend_hash_index_find(Z_ARRVAL_P(function_name), 1);
fbc = Z_FUNC_P(func); if (!obj || !method) {
called_scope = NULL; zend_error_noreturn(E_ERROR, "Array callback has to contain indices 0 and 1");
}
ZVAL_DEREF(obj);
if (Z_TYPE_P(obj) != IS_STRING && Z_TYPE_P(obj) != IS_OBJECT) {
zend_error_noreturn(E_ERROR, "First array member is not a valid class name or object");
}
ZVAL_DEREF(method);
if (Z_TYPE_P(method) != IS_STRING) {
zend_error_noreturn(E_ERROR, "Second array member is not a valid method");
}
if (Z_TYPE_P(obj) == IS_STRING) {
object = NULL; object = NULL;
} else if (OP2_TYPE != IS_CONST && called_scope = zend_fetch_class_by_name(Z_STR_P(obj), NULL, 0);
EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) && if (UNEXPECTED(called_scope == NULL)) {
Z_OBJ_HANDLER_P(function_name, get_closure) && CHECK_EXCEPTION();
Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &called_scope, &fbc, &object) == SUCCESS) { ZEND_VM_NEXT_OPCODE();
if (object) {
GC_REFCOUNT(object)++;
}
if (OP2_TYPE == IS_VAR && (fbc->common.fn_flags & ZEND_ACC_CLOSURE)) {
/* Delay closure destruction until its invocation */
fbc->common.prototype = (zend_function*)Z_OBJ_P(free_op2);
} else if (OP2_TYPE == IS_CV) {
FREE_OP2();
}
} else if (EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) &&
zend_hash_num_elements(Z_ARRVAL_P(function_name)) == 2) {
zval *obj;
zval *method;
obj = zend_hash_index_find(Z_ARRVAL_P(function_name), 0);
method = zend_hash_index_find(Z_ARRVAL_P(function_name), 1);
if (!obj || !method) {
zend_error_noreturn(E_ERROR, "Array callback has to contain indices 0 and 1");
} }
ZVAL_DEREF(obj); if (called_scope->get_static_method) {
if (Z_TYPE_P(obj) != IS_STRING && Z_TYPE_P(obj) != IS_OBJECT) { fbc = called_scope->get_static_method(called_scope, Z_STR_P(method));
zend_error_noreturn(E_ERROR, "First array member is not a valid class name or object"); } else {
fbc = zend_std_get_static_method(called_scope, Z_STR_P(method), NULL);
} }
if (UNEXPECTED(fbc == NULL)) {
ZVAL_DEREF(method); zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", called_scope->name->val, Z_STRVAL_P(method));
if (Z_TYPE_P(method) != IS_STRING) {
zend_error_noreturn(E_ERROR, "Second array member is not a valid method");
} }
if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) {
if (Z_TYPE_P(obj) == IS_STRING) { if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
object = NULL; zend_error(E_STRICT,
called_scope = zend_fetch_class_by_name(Z_STR_P(obj), NULL, 0);
if (UNEXPECTED(called_scope == NULL)) {
CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
}
if (called_scope->get_static_method) {
fbc = called_scope->get_static_method(called_scope, Z_STR_P(method));
} else {
fbc = zend_std_get_static_method(called_scope, Z_STR_P(method), NULL);
}
if (UNEXPECTED(fbc == NULL)) {
zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", called_scope->name->val, Z_STRVAL_P(method));
}
if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) {
if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
zend_error(E_STRICT,
"Non-static method %s::%s() should not be called statically", "Non-static method %s::%s() should not be called statically",
fbc->common.scope->name->val, fbc->common.function_name->val); fbc->common.scope->name->val, fbc->common.function_name->val);
} else {
zend_error_noreturn(
E_ERROR,
"Non-static method %s::%s() cannot be called statically",
fbc->common.scope->name->val, fbc->common.function_name->val);
}
}
} else {
called_scope = Z_OBJCE_P(obj);
object = Z_OBJ_P(obj);
fbc = Z_OBJ_HT_P(obj)->get_method(&object, Z_STR_P(method), NULL);
if (UNEXPECTED(fbc == NULL)) {
zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", object->ce->name->val, Z_STRVAL_P(method));
}
if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) {
object = NULL;
} else { } else {
GC_REFCOUNT(object)++; /* For $this pointer */ zend_error_noreturn(
E_ERROR,
"Non-static method %s::%s() cannot be called statically",
fbc->common.scope->name->val, fbc->common.function_name->val);
} }
} }
FREE_OP2();
} else if ((OP2_TYPE & (IS_VAR|IS_CV)) && Z_TYPE_P(function_name) == IS_REFERENCE) {
function_name = Z_REFVAL_P(function_name);
ZEND_VM_C_GOTO(try_function_name);
} else { } else {
if (UNEXPECTED(EG(exception) != NULL)) { called_scope = Z_OBJCE_P(obj);
HANDLE_EXCEPTION(); object = Z_OBJ_P(obj);
}
zend_error_noreturn(E_ERROR, "Function name must be a string");
ZEND_VM_CONTINUE(); /* Never reached */
}
EX(call) = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION,
fbc, opline->extended_value, called_scope, object, EX(call));
CHECK_EXCEPTION(); fbc = Z_OBJ_HT_P(obj)->get_method(&object, Z_STR_P(method), NULL);
ZEND_VM_NEXT_OPCODE(); if (UNEXPECTED(fbc == NULL)) {
zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", object->ce->name->val, Z_STRVAL_P(method));
}
if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) {
object = NULL;
} else {
GC_REFCOUNT(object)++; /* For $this pointer */
}
}
FREE_OP2();
} else if ((OP2_TYPE & (IS_VAR|IS_CV)) && Z_TYPE_P(function_name) == IS_REFERENCE) {
function_name = Z_REFVAL_P(function_name);
ZEND_VM_C_GOTO(try_function_name);
} else {
if (UNEXPECTED(EG(exception) != NULL)) {
HANDLE_EXCEPTION();
}
zend_error_noreturn(E_ERROR, "Function name must be a string");
ZEND_VM_CONTINUE(); /* Never reached */
} }
EX(call) = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION,
fbc, opline->extended_value, called_scope, object, EX(call));
CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
} }
ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV) ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV)
@ -2791,6 +2829,185 @@ ZEND_VM_HANDLER(61, ZEND_INIT_FCALL, ANY, CONST)
ZEND_VM_NEXT_OPCODE(); ZEND_VM_NEXT_OPCODE();
} }
ZEND_VM_HANDLER(129, ZEND_DO_ICALL, ANY, ANY)
{
USE_OPLINE
zend_execute_data *call = EX(call);
zend_function *fbc = call->func;
zval *ret;
SAVE_OPLINE();
EX(call) = call->prev_execute_data;
LOAD_OPLINE();
call->called_scope = EX(called_scope);
Z_OBJ(call->This) = Z_OBJ(EX(This));
call->prev_execute_data = execute_data;
EG(current_execute_data) = call;
ret = EX_VAR(opline->result.var);
ZVAL_NULL(ret);
Z_VAR_FLAGS_P(ret) = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0 ? IS_VAR_RET_REF : 0;
fbc->internal_function.handler(call, ret);
ZEND_ASSERT(
!call->func ||
!(call->func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) ||
zend_verify_internal_return_type(call->func, EX_VAR(opline->result.var)));
EG(current_execute_data) = call->prev_execute_data;
zend_vm_stack_free_args(call);
zend_vm_stack_free_call_frame(call);
if (!RETURN_VALUE_USED(opline)) {
zval_ptr_dtor(EX_VAR(opline->result.var));
}
if (UNEXPECTED(EG(exception) != NULL)) {
zend_throw_exception_internal(NULL);
if (RETURN_VALUE_USED(opline)) {
zval_ptr_dtor(EX_VAR(opline->result.var));
}
HANDLE_EXCEPTION();
}
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_HANDLER(130, ZEND_DO_UCALL, ANY, ANY)
{
USE_OPLINE
zend_execute_data *call = EX(call);
zend_function *fbc = call->func;
zval *ret;
SAVE_OPLINE();
EX(call) = call->prev_execute_data;
LOAD_OPLINE();
EG(scope) = NULL;
ret = NULL;
call->symbol_table = NULL;
if (RETURN_VALUE_USED(opline)) {
ret = EX_VAR(opline->result.var);
ZVAL_NULL(ret);
Z_VAR_FLAGS_P(ret) = 0;
}
call->prev_execute_data = execute_data;
i_init_func_execute_data(call, &fbc->op_array, ret, 0);
ZEND_VM_ENTER();
}
ZEND_VM_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY)
{
USE_OPLINE
zend_execute_data *call = EX(call);
zend_function *fbc = call->func;
zval *ret;
SAVE_OPLINE();
EX(call) = call->prev_execute_data;
LOAD_OPLINE();
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) {
EG(scope) = NULL;
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_GENERATOR) != 0)) {
if (RETURN_VALUE_USED(opline)) {
zend_generator_create_zval(call, &fbc->op_array, EX_VAR(opline->result.var));
} else {
zend_vm_stack_free_args(call);
}
zend_vm_stack_free_call_frame(call);
} else {
ret = NULL;
call->symbol_table = NULL;
if (RETURN_VALUE_USED(opline)) {
ret = EX_VAR(opline->result.var);
ZVAL_NULL(ret);
Z_VAR_FLAGS_P(ret) = 0;
}
call->prev_execute_data = execute_data;
i_init_func_execute_data(call, &fbc->op_array, ret, 0);
ZEND_VM_ENTER();
}
EG(scope) = EX(func)->op_array.scope;
} else {
ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION);
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
zend_error(E_DEPRECATED, "Function %s%s%s() is deprecated",
fbc->common.scope ? fbc->common.scope->name->val : "",
fbc->common.scope ? "::" : "",
fbc->common.function_name->val);
if (UNEXPECTED(EG(exception) != NULL)) {
HANDLE_EXCEPTION();
}
}
call->called_scope = EX(called_scope);
Z_OBJ(call->This) = Z_OBJ(EX(This));
call->prev_execute_data = execute_data;
EG(current_execute_data) = call;
if (fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
uint32_t i;
uint32_t num_args = ZEND_CALL_NUM_ARGS(call);
zval *p = ZEND_CALL_ARG(call, 1);
for (i = 0; i < num_args; ++i) {
zend_verify_internal_arg_type(fbc, i + 1, p);
p++;
}
if (UNEXPECTED(EG(exception) != NULL)) {
EG(current_execute_data) = call->prev_execute_data;
zend_vm_stack_free_args(call);
zend_vm_stack_free_call_frame(call);
zend_throw_exception_internal(NULL);
HANDLE_EXCEPTION();
}
}
ret = EX_VAR(opline->result.var);
ZVAL_NULL(ret);
Z_VAR_FLAGS_P(ret) = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0 ? IS_VAR_RET_REF : 0;
fbc->internal_function.handler(call, ret);
ZEND_ASSERT(
!call->func ||
!(call->func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) ||
zend_verify_internal_return_type(call->func, EX_VAR(opline->result.var)));
EG(current_execute_data) = call->prev_execute_data;
zend_vm_stack_free_args(call);
zend_vm_stack_free_call_frame(call);
if (!RETURN_VALUE_USED(opline)) {
zval_ptr_dtor(EX_VAR(opline->result.var));
}
}
if (UNEXPECTED(EG(exception) != NULL)) {
zend_throw_exception_internal(NULL);
if (RETURN_VALUE_USED(opline)) {
zval_ptr_dtor(EX_VAR(opline->result.var));
}
HANDLE_EXCEPTION();
}
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY)
{ {
USE_OPLINE USE_OPLINE
@ -2838,7 +3055,7 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY)
} }
call->prev_execute_data = execute_data; call->prev_execute_data = execute_data;
i_init_func_execute_data(call, &fbc->op_array, ret); i_init_func_execute_data(call, &fbc->op_array, ret, 1);
if (EXPECTED(zend_execute_ex == execute_ex)) { if (EXPECTED(zend_execute_ex == execute_ex)) {
ZEND_VM_ENTER(); ZEND_VM_ENTER();
@ -2849,7 +3066,6 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY)
} }
} else if (EXPECTED(fbc->type < ZEND_USER_FUNCTION)) { } else if (EXPECTED(fbc->type < ZEND_USER_FUNCTION)) {
int should_change_scope = 0; int should_change_scope = 0;
zval *ret;
if (fbc->common.scope) { if (fbc->common.scope) {
should_change_scope = 1; should_change_scope = 1;
@ -4654,7 +4870,7 @@ ZEND_VM_HANDLER(76, ZEND_UNSET_OBJ, VAR|UNUSED|CV, CONST|TMPVAR|CV)
} }
} }
if (Z_OBJ_HT_P(container)->unset_property) { if (Z_OBJ_HT_P(container)->unset_property) {
Z_OBJ_HT_P(container)->unset_property(container, offset, ((OP2_TYPE == IS_CONST) ? (EX_RUN_TIME_CACHE() + Z_CACHE_SLOT_P(offset)) : NULL)); Z_OBJ_HT_P(container)->unset_property(container, offset, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(Z_CACHE_SLOT_P(offset)) : NULL));
} else { } else {
zend_error(E_NOTICE, "Trying to unset property of non-object"); zend_error(E_NOTICE, "Trying to unset property of non-object");
} }
@ -5316,7 +5532,7 @@ ZEND_VM_HANDLER(114, ZEND_ISSET_ISEMPTY_VAR, CONST|TMPVAR|CV, UNUSED|CONST|VAR)
if (OP1_TYPE == IS_CONST && CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)))) { if (OP1_TYPE == IS_CONST && CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)))) {
ce = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1))); ce = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)));
value = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)) + 1); value = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)) + sizeof(void*));
/* check if static properties were destoyed */ /* check if static properties were destoyed */
if (UNEXPECTED(CE_STATIC_MEMBERS(ce) == NULL)) { if (UNEXPECTED(CE_STATIC_MEMBERS(ce) == NULL)) {
@ -5523,7 +5739,7 @@ ZEND_VM_HANDLER(148, ZEND_ISSET_ISEMPTY_PROP_OBJ, CONST|TMPVAR|UNUSED|CV, CONST|
ZEND_VM_C_LABEL(isset_no_object): ZEND_VM_C_LABEL(isset_no_object):
result = ((opline->extended_value & ZEND_ISSET) == 0); result = ((opline->extended_value & ZEND_ISSET) == 0);
} else { } else {
result = Z_OBJ_HT_P(container)->has_property(container, offset, (opline->extended_value & ZEND_ISSET) == 0, ((OP2_TYPE == IS_CONST) ? (EX_RUN_TIME_CACHE() + Z_CACHE_SLOT_P(offset)) : NULL)); result = Z_OBJ_HT_P(container)->has_property(container, offset, (opline->extended_value & ZEND_ISSET) == 0, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(Z_CACHE_SLOT_P(offset)) : NULL));
if ((opline->extended_value & ZEND_ISSET) == 0) { if ((opline->extended_value & ZEND_ISSET) == 0) {
result = !result; result = !result;
} }
@ -5960,11 +6176,15 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
do { do {
switch (opline->opcode) { switch (opline->opcode) {
case ZEND_DO_FCALL: case ZEND_DO_FCALL:
case ZEND_DO_ICALL:
case ZEND_DO_UCALL:
case ZEND_DO_FCALL_BY_NAME:
level++; level++;
break; break;
case ZEND_INIT_FCALL: case ZEND_INIT_FCALL:
case ZEND_INIT_FCALL_BY_NAME: case ZEND_INIT_FCALL_BY_NAME:
case ZEND_INIT_NS_FCALL_BY_NAME: case ZEND_INIT_NS_FCALL_BY_NAME:
case ZEND_INIT_DYNAMIC_CALL:
case ZEND_INIT_USER_CALL: case ZEND_INIT_USER_CALL:
case ZEND_INIT_METHOD_CALL: case ZEND_INIT_METHOD_CALL:
case ZEND_INIT_STATIC_METHOD_CALL: case ZEND_INIT_STATIC_METHOD_CALL:
@ -6005,11 +6225,15 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
do { do {
switch (opline->opcode) { switch (opline->opcode) {
case ZEND_DO_FCALL: case ZEND_DO_FCALL:
case ZEND_DO_ICALL:
case ZEND_DO_UCALL:
case ZEND_DO_FCALL_BY_NAME:
level++; level++;
break; break;
case ZEND_INIT_FCALL: case ZEND_INIT_FCALL:
case ZEND_INIT_FCALL_BY_NAME: case ZEND_INIT_FCALL_BY_NAME:
case ZEND_INIT_NS_FCALL_BY_NAME: case ZEND_INIT_NS_FCALL_BY_NAME:
case ZEND_INIT_DYNAMIC_CALL:
case ZEND_INIT_USER_CALL: case ZEND_INIT_USER_CALL:
case ZEND_INIT_METHOD_CALL: case ZEND_INIT_METHOD_CALL:
case ZEND_INIT_STATIC_METHOD_CALL: case ZEND_INIT_STATIC_METHOD_CALL:
@ -6609,7 +6833,7 @@ ZEND_VM_HANDLER(122, ZEND_DEFINED, CONST, ANY)
ZEND_VM_NEXT_OPCODE(); ZEND_VM_NEXT_OPCODE();
} }
ZEND_VM_HANDLER(128, ZEND_ASSERT_CHECK, ANY, ANY) ZEND_VM_HANDLER(137, ZEND_ASSERT_CHECK, ANY, ANY)
{ {
USE_OPLINE USE_OPLINE

File diff suppressed because it is too large Load diff

View file

@ -967,7 +967,7 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name,
out($f,"#undef LOAD_OPLINE\n"); out($f,"#undef LOAD_OPLINE\n");
out($f,"#undef SAVE_OPLINE\n"); out($f,"#undef SAVE_OPLINE\n");
out($f,"#define OPLINE opline\n"); out($f,"#define OPLINE opline\n");
out($f,"#define DCL_OPLINE zend_op *opline;\n"); out($f,"#define DCL_OPLINE const zend_op *opline;\n");
out($f,"#define USE_OPLINE\n"); out($f,"#define USE_OPLINE\n");
out($f,"#define LOAD_OPLINE() opline = EX(opline)\n"); out($f,"#define LOAD_OPLINE() opline = EX(opline)\n");
out($f,"#define SAVE_OPLINE() EX(opline) = opline\n"); out($f,"#define SAVE_OPLINE() EX(opline) = opline\n");
@ -993,7 +993,7 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name,
out($f,"#undef LOAD_OPLINE\n"); out($f,"#undef LOAD_OPLINE\n");
out($f,"#undef SAVE_OPLINE\n"); out($f,"#undef SAVE_OPLINE\n");
out($f,"#define OPLINE opline\n"); out($f,"#define OPLINE opline\n");
out($f,"#define DCL_OPLINE zend_op *opline;\n"); out($f,"#define DCL_OPLINE const zend_op *opline;\n");
out($f,"#define USE_OPLINE\n"); out($f,"#define USE_OPLINE\n");
out($f,"#define LOAD_OPLINE() opline = EX(opline)\n"); out($f,"#define LOAD_OPLINE() opline = EX(opline)\n");
out($f,"#define SAVE_OPLINE() EX(opline) = opline\n"); out($f,"#define SAVE_OPLINE() EX(opline) = opline\n");

View file

@ -150,16 +150,16 @@ const char *zend_vm_opcodes_map[171] = {
"ZEND_FE_RESET_RW", "ZEND_FE_RESET_RW",
"ZEND_FE_FETCH_RW", "ZEND_FE_FETCH_RW",
"ZEND_FE_FREE", "ZEND_FE_FREE",
"ZEND_ASSERT_CHECK", "ZEND_INIT_DYNAMIC_CALL",
NULL, "ZEND_DO_ICALL",
NULL, "ZEND_DO_UCALL",
NULL, "ZEND_DO_FCALL_BY_NAME",
"ZEND_PRE_INC_OBJ", "ZEND_PRE_INC_OBJ",
"ZEND_PRE_DEC_OBJ", "ZEND_PRE_DEC_OBJ",
"ZEND_POST_INC_OBJ", "ZEND_POST_INC_OBJ",
"ZEND_POST_DEC_OBJ", "ZEND_POST_DEC_OBJ",
"ZEND_ASSIGN_OBJ", "ZEND_ASSIGN_OBJ",
NULL, "ZEND_ASSERT_CHECK",
"ZEND_INSTANCEOF", "ZEND_INSTANCEOF",
"ZEND_DECLARE_CLASS", "ZEND_DECLARE_CLASS",
"ZEND_DECLARE_INHERITED_CLASS", "ZEND_DECLARE_INHERITED_CLASS",

View file

@ -152,12 +152,16 @@ END_EXTERN_C()
#define ZEND_FE_RESET_RW 125 #define ZEND_FE_RESET_RW 125
#define ZEND_FE_FETCH_RW 126 #define ZEND_FE_FETCH_RW 126
#define ZEND_FE_FREE 127 #define ZEND_FE_FREE 127
#define ZEND_ASSERT_CHECK 128 #define ZEND_INIT_DYNAMIC_CALL 128
#define ZEND_DO_ICALL 129
#define ZEND_DO_UCALL 130
#define ZEND_DO_FCALL_BY_NAME 131
#define ZEND_PRE_INC_OBJ 132 #define ZEND_PRE_INC_OBJ 132
#define ZEND_PRE_DEC_OBJ 133 #define ZEND_PRE_DEC_OBJ 133
#define ZEND_POST_INC_OBJ 134 #define ZEND_POST_INC_OBJ 134
#define ZEND_POST_DEC_OBJ 135 #define ZEND_POST_DEC_OBJ 135
#define ZEND_ASSIGN_OBJ 136 #define ZEND_ASSIGN_OBJ 136
#define ZEND_ASSERT_CHECK 137
#define ZEND_INSTANCEOF 138 #define ZEND_INSTANCEOF 138
#define ZEND_DECLARE_CLASS 139 #define ZEND_DECLARE_CLASS 139
#define ZEND_DECLARE_INHERITED_CLASS 140 #define ZEND_DECLARE_INHERITED_CLASS 140

View file

@ -844,6 +844,11 @@ PHP_MINIT_FUNCTION(curl)
REGISTER_CURL_CONSTANT(CURLPROXY_SOCKS4); REGISTER_CURL_CONSTANT(CURLPROXY_SOCKS4);
REGISTER_CURL_CONSTANT(CURLPROXY_SOCKS5); REGISTER_CURL_CONSTANT(CURLPROXY_SOCKS5);
#if LIBCURL_VERSION_NUM >= 0x071200 /* Available since 7.18.0 */
REGISTER_CURL_CONSTANT(CURLPROXY_SOCKS4A);
REGISTER_CURL_CONSTANT(CURLPROXY_SOCKS5_HOSTNAME);
#endif
/* Curl Share constants */ /* Curl Share constants */
REGISTER_CURL_CONSTANT(CURLSHOPT_NONE); REGISTER_CURL_CONSTANT(CURLSHOPT_NONE);
REGISTER_CURL_CONSTANT(CURLSHOPT_SHARE); REGISTER_CURL_CONSTANT(CURLSHOPT_SHARE);
@ -1239,7 +1244,7 @@ PHP_MINIT_FUNCTION(curl)
gcry_control(GCRYCTL_SET_THREAD_CBS, &php_curl_gnutls_tsl); gcry_control(GCRYCTL_SET_THREAD_CBS, &php_curl_gnutls_tsl);
#endif #endif
if (curl_global_init(CURL_GLOBAL_SSL) != CURLE_OK) { if (curl_global_init(CURL_GLOBAL_DEFAULT) != CURLE_OK) {
return FAILURE; return FAILURE;
} }

View file

@ -809,6 +809,16 @@ PHP_RSHUTDOWN_FUNCTION(date)
#define DATE_FORMAT_ISO8601 "Y-m-d\\TH:i:sO" #define DATE_FORMAT_ISO8601 "Y-m-d\\TH:i:sO"
/*
* RFC3339, Appendix A: http://www.ietf.org/rfc/rfc3339.txt
* ISO 8601 also requires (in section 5.3.1.3) that a decimal fraction
* be proceeded by a "0" if less than unity. Annex B.2 of ISO 8601
* gives examples where the decimal fractions are not preceded by a "0".
* This grammar assumes section 5.3.1.3 is correct and that Annex B.2 is
* in error.
*/
#define DATE_FORMAT_RFC3339_EXTENDED "Y-m-d\\TH:i:s.vP"
/* /*
* This comes from various sources that like to contradict. I'm going with the * This comes from various sources that like to contradict. I'm going with the
* format here because of: * format here because of:
@ -849,12 +859,15 @@ PHP_MINIT_FUNCTION(date)
*/ */
REGISTER_STRING_CONSTANT("DATE_COOKIE", DATE_FORMAT_COOKIE, CONST_CS | CONST_PERSISTENT); REGISTER_STRING_CONSTANT("DATE_COOKIE", DATE_FORMAT_COOKIE, CONST_CS | CONST_PERSISTENT);
REGISTER_STRING_CONSTANT("DATE_ISO8601", DATE_FORMAT_ISO8601, CONST_CS | CONST_PERSISTENT); REGISTER_STRING_CONSTANT("DATE_ISO8601", DATE_FORMAT_ISO8601, CONST_CS | CONST_PERSISTENT);
REGISTER_STRING_CONSTANT("DATE_RFC822", DATE_FORMAT_RFC822, CONST_CS | CONST_PERSISTENT); REGISTER_STRING_CONSTANT("DATE_RFC822", DATE_FORMAT_RFC822, CONST_CS | CONST_PERSISTENT);
REGISTER_STRING_CONSTANT("DATE_RFC850", DATE_FORMAT_RFC850, CONST_CS | CONST_PERSISTENT); REGISTER_STRING_CONSTANT("DATE_RFC850", DATE_FORMAT_RFC850, CONST_CS | CONST_PERSISTENT);
REGISTER_STRING_CONSTANT("DATE_RFC1036", DATE_FORMAT_RFC1036, CONST_CS | CONST_PERSISTENT); REGISTER_STRING_CONSTANT("DATE_RFC1036", DATE_FORMAT_RFC1036, CONST_CS | CONST_PERSISTENT);
REGISTER_STRING_CONSTANT("DATE_RFC1123", DATE_FORMAT_RFC1123, CONST_CS | CONST_PERSISTENT); REGISTER_STRING_CONSTANT("DATE_RFC1123", DATE_FORMAT_RFC1123, CONST_CS | CONST_PERSISTENT);
REGISTER_STRING_CONSTANT("DATE_RFC2822", DATE_FORMAT_RFC2822, CONST_CS | CONST_PERSISTENT); REGISTER_STRING_CONSTANT("DATE_RFC2822", DATE_FORMAT_RFC2822, CONST_CS | CONST_PERSISTENT);
REGISTER_STRING_CONSTANT("DATE_RFC3339", DATE_FORMAT_RFC3339, CONST_CS | CONST_PERSISTENT); REGISTER_STRING_CONSTANT("DATE_RFC3339", DATE_FORMAT_RFC3339, CONST_CS | CONST_PERSISTENT);
REGISTER_STRING_CONSTANT("DATE_RFC3339_EXTENDED", DATE_FORMAT_RFC3339_EXTENDED, CONST_CS | CONST_PERSISTENT);
/* /*
* RSS 2.0 Specification: http://blogs.law.harvard.edu/tech/rss * RSS 2.0 Specification: http://blogs.law.harvard.edu/tech/rss
* "All date-times in RSS conform to the Date and Time Specification of RFC 822, * "All date-times in RSS conform to the Date and Time Specification of RFC 822,
@ -1145,6 +1158,7 @@ static zend_string *date_format(char *format, size_t format_len, timelib_time *t
case 'i': length = slprintf(buffer, 32, "%02d", (int) t->i); break; case 'i': length = slprintf(buffer, 32, "%02d", (int) t->i); break;
case 's': length = slprintf(buffer, 32, "%02d", (int) t->s); break; case 's': length = slprintf(buffer, 32, "%02d", (int) t->s); break;
case 'u': length = slprintf(buffer, 32, "%06d", (int) floor(t->f * 1000000 + 0.5)); break; case 'u': length = slprintf(buffer, 32, "%06d", (int) floor(t->f * 1000000 + 0.5)); break;
case 'v': length = slprintf(buffer, 32, "%03d", (int) floor(t->f * 1000 + 0.5)); break;
/* timezone */ /* timezone */
case 'I': length = slprintf(buffer, 32, "%d", localtime ? offset->is_dst : 0); break; case 'I': length = slprintf(buffer, 32, "%d", localtime ? offset->is_dst : 0); break;
@ -1981,17 +1995,18 @@ static void date_register_classes(void) /* {{{ */
#define REGISTER_DATE_CLASS_CONST_STRING(const_name, value) \ #define REGISTER_DATE_CLASS_CONST_STRING(const_name, value) \
zend_declare_class_constant_stringl(date_ce_date, const_name, sizeof(const_name)-1, value, sizeof(value)-1); zend_declare_class_constant_stringl(date_ce_date, const_name, sizeof(const_name)-1, value, sizeof(value)-1);
REGISTER_DATE_CLASS_CONST_STRING("ATOM", DATE_FORMAT_RFC3339); REGISTER_DATE_CLASS_CONST_STRING("ATOM", DATE_FORMAT_RFC3339);
REGISTER_DATE_CLASS_CONST_STRING("COOKIE", DATE_FORMAT_COOKIE); REGISTER_DATE_CLASS_CONST_STRING("COOKIE", DATE_FORMAT_COOKIE);
REGISTER_DATE_CLASS_CONST_STRING("ISO8601", DATE_FORMAT_ISO8601); REGISTER_DATE_CLASS_CONST_STRING("ISO8601", DATE_FORMAT_ISO8601);
REGISTER_DATE_CLASS_CONST_STRING("RFC822", DATE_FORMAT_RFC822); REGISTER_DATE_CLASS_CONST_STRING("RFC822", DATE_FORMAT_RFC822);
REGISTER_DATE_CLASS_CONST_STRING("RFC850", DATE_FORMAT_RFC850); REGISTER_DATE_CLASS_CONST_STRING("RFC850", DATE_FORMAT_RFC850);
REGISTER_DATE_CLASS_CONST_STRING("RFC1036", DATE_FORMAT_RFC1036); REGISTER_DATE_CLASS_CONST_STRING("RFC1036", DATE_FORMAT_RFC1036);
REGISTER_DATE_CLASS_CONST_STRING("RFC1123", DATE_FORMAT_RFC1123); REGISTER_DATE_CLASS_CONST_STRING("RFC1123", DATE_FORMAT_RFC1123);
REGISTER_DATE_CLASS_CONST_STRING("RFC2822", DATE_FORMAT_RFC2822); REGISTER_DATE_CLASS_CONST_STRING("RFC2822", DATE_FORMAT_RFC2822);
REGISTER_DATE_CLASS_CONST_STRING("RFC3339", DATE_FORMAT_RFC3339); REGISTER_DATE_CLASS_CONST_STRING("RFC3339", DATE_FORMAT_RFC3339);
REGISTER_DATE_CLASS_CONST_STRING("RSS", DATE_FORMAT_RFC1123); REGISTER_DATE_CLASS_CONST_STRING("RFC3339_EXTENDED", DATE_FORMAT_RFC3339_EXTENDED);
REGISTER_DATE_CLASS_CONST_STRING("W3C", DATE_FORMAT_RFC3339); REGISTER_DATE_CLASS_CONST_STRING("RSS", DATE_FORMAT_RFC1123);
REGISTER_DATE_CLASS_CONST_STRING("W3C", DATE_FORMAT_RFC3339);
INIT_CLASS_ENTRY(ce_immutable, "DateTimeImmutable", date_funcs_immutable); INIT_CLASS_ENTRY(ce_immutable, "DateTimeImmutable", date_funcs_immutable);
ce_immutable.create_object = date_object_new_date; ce_immutable.create_object = date_object_new_date;

View file

@ -156,7 +156,7 @@ array(18) {
} }
} }
..and get names of all its class constants ..and get names of all its class constants
array(11) { array(12) {
["ATOM"]=> ["ATOM"]=>
string(13) "Y-m-d\TH:i:sP" string(13) "Y-m-d\TH:i:sP"
["COOKIE"]=> ["COOKIE"]=>
@ -175,6 +175,8 @@ array(11) {
string(16) "D, d M Y H:i:s O" string(16) "D, d M Y H:i:s O"
["RFC3339"]=> ["RFC3339"]=>
string(13) "Y-m-d\TH:i:sP" string(13) "Y-m-d\TH:i:sP"
["RFC3339_EXTENDED"]=>
string(15) "Y-m-d\TH:i:s.vP"
["RSS"]=> ["RSS"]=>
string(16) "D, d M Y H:i:s O" string(16) "D, d M Y H:i:s O"
["W3C"]=> ["W3C"]=>

View file

@ -0,0 +1,17 @@
--TEST--
Bug #69089 (Add support for RFC3339 extended to DateTime::format)
--CREDITS--
Mariano Iglesias <mariano@cricava.com>
--FILE--
<?php
date_default_timezone_set('America/Buenos_Aires');
$date = new DateTime('2009-09-28 09:45:31.918312');
var_dump($date->format(DateTime::RFC3339_EXTENDED));
var_dump($date->format('u'));
var_dump($date->format('v'));
--EXPECT--
string(29) "2009-09-28T09:45:31.918-03:00"
string(6) "918312"
string(3) "918"

View file

@ -1,11 +1,11 @@
PHP_ARG_WITH(interbase,for InterBase support, PHP_ARG_WITH(interbase,for Firebird support,
[ --with-interbase[=DIR] Include InterBase support. DIR is the InterBase base [ --with-interbase[=DIR] Include Firebird support. DIR is the Firebird base
install directory [/usr/interbase]]) install directory [/opt/firebird]])
if test "$PHP_INTERBASE" != "no"; then if test "$PHP_INTERBASE" != "no"; then
if test "$PHP_INTERBASE" = "yes"; then if test "$PHP_INTERBASE" = "yes"; then
IBASE_INCDIR=/usr/interbase/include IBASE_INCDIR=/opt/firebird/include
IBASE_LIBDIR=/usr/interbase/lib IBASE_LIBDIR=/opt/firebird/lib
else else
IBASE_INCDIR=$PHP_INTERBASE/include IBASE_INCDIR=$PHP_INTERBASE/include
IBASE_LIBDIR=$PHP_INTERBASE/$PHP_LIBDIR IBASE_LIBDIR=$PHP_INTERBASE/$PHP_LIBDIR
@ -23,7 +23,7 @@ if test "$PHP_INTERBASE" != "no"; then
[ [
IBASE_LIBNAME=ib_util IBASE_LIBNAME=ib_util
], [ ], [
AC_MSG_ERROR([libgds, libib_util or libfbclient not found! Check config.log for more information.]) AC_MSG_ERROR([libfbclient, libgds or libib_util not found! Check config.log for more information.])
], [ ], [
-L$IBASE_LIBDIR -L$IBASE_LIBDIR
]) ])

View file

@ -94,23 +94,24 @@ static inline void php_json_pretty_print_indent(smart_str *buf, int options) /*
/* }}} */ /* }}} */
static inline int php_json_is_valid_double(double d) /* {{{ */
{
return !zend_isinf(d) && !zend_isnan(d);
}
/* }}} */
static inline void php_json_encode_double(smart_str *buf, double d, int options) /* {{{ */ static inline void php_json_encode_double(smart_str *buf, double d, int options) /* {{{ */
{ {
if (!zend_isinf(d) && !zend_isnan(d)) { size_t len;
size_t len; char num[PHP_JSON_DOUBLE_MAX_LENGTH];
char num[PHP_JSON_DOUBLE_MAX_LENGTH]; php_gcvt(d, EG(precision), '.', 'e', &num[0]);
php_gcvt(d, EG(precision), '.', 'e', &num[0]); len = strlen(num);
len = strlen(num); if (options & PHP_JSON_PRESERVE_ZERO_FRACTION && strchr(num, '.') == NULL && len < PHP_JSON_DOUBLE_MAX_LENGTH - 2) {
if (options & PHP_JSON_PRESERVE_ZERO_FRACTION && strchr(num, '.') == NULL && len < PHP_JSON_DOUBLE_MAX_LENGTH - 2) { num[len++] = '.';
num[len++] = '.'; num[len++] = '0';
num[len++] = '0'; num[len] = '\0';
num[len] = '\0';
}
smart_str_appendl(buf, num, len);
} else {
JSON_G(error_code) = PHP_JSON_ERROR_INF_OR_NAN;
smart_str_appendc(buf, '0');
} }
smart_str_appendl(buf, num, len);
} }
/* }}} */ /* }}} */
@ -293,10 +294,11 @@ static void php_json_escape_string(smart_str *buf, char *s, size_t len, int opti
if ((type = is_numeric_string(s, len, &p, &d, 0)) != 0) { if ((type = is_numeric_string(s, len, &p, &d, 0)) != 0) {
if (type == IS_LONG) { if (type == IS_LONG) {
smart_str_append_long(buf, p); smart_str_append_long(buf, p);
} else if (type == IS_DOUBLE) { return;
} else if (type == IS_DOUBLE && php_json_is_valid_double(d)) {
php_json_encode_double(buf, d, options); php_json_encode_double(buf, d, options);
return;
} }
return;
} }
} }
@ -506,7 +508,12 @@ again:
break; break;
case IS_DOUBLE: case IS_DOUBLE:
php_json_encode_double(buf, Z_DVAL_P(val), options); if (php_json_is_valid_double(Z_DVAL_P(val))) {
php_json_encode_double(buf, Z_DVAL_P(val), options);
} else {
JSON_G(error_code) = PHP_JSON_ERROR_INF_OR_NAN;
smart_str_appendc(buf, '0');
}
break; break;
case IS_STRING: case IS_STRING:

View file

@ -0,0 +1,14 @@
--TEST--
Bug #64695 JSON_NUMERIC_CHECK has issues with strings that are numbers plus the letter e
--SKIPIF--
<?php if (!extension_loaded("json")) print "skip"; ?>
--FILE--
<?php
$t = array('test' => '123343e871700');
var_dump(json_encode($t, JSON_NUMERIC_CHECK));
echo "Done\n";
?>
--EXPECT--
string(24) "{"test":"123343e871700"}"
Done

View file

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

View file

@ -10,4 +10,4 @@ declare(encoding="ISO-8859-15") {
} }
?> ?>
--EXPECTF-- --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

@ -1830,6 +1830,9 @@ static void zend_t_usage(zend_code_block *block, zend_op_array *op_array, char *
case ZEND_ASSIGN: case ZEND_ASSIGN:
case ZEND_ASSIGN_REF: case ZEND_ASSIGN_REF:
case ZEND_DO_FCALL: case ZEND_DO_FCALL:
case ZEND_DO_ICALL:
case ZEND_DO_UCALL:
case ZEND_DO_FCALL_BY_NAME:
if (ZEND_RESULT_TYPE(opline) == IS_VAR) { if (ZEND_RESULT_TYPE(opline) == IS_VAR) {
ZEND_RESULT_TYPE(opline) |= EXT_TYPE_UNUSED; ZEND_RESULT_TYPE(opline) |= EXT_TYPE_UNUSED;
} }

View file

@ -117,7 +117,7 @@ static void optimizer_literal_class_info(literal_info *info,
void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx *ctx) void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx *ctx)
{ {
zend_op *opline, *end; zend_op *opline, *end;
int i, j, n, *map, cache_slots; int i, j, n, *map, cache_size;
zval zv, *pos; zval zv, *pos;
literal_info *info; literal_info *info;
int l_null = -1; int l_null = -1;
@ -139,9 +139,7 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 1, 1, 1); LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 1, 1, 1);
break; break;
case ZEND_INIT_FCALL_BY_NAME: case ZEND_INIT_FCALL_BY_NAME:
if (ZEND_OP2_TYPE(opline) == IS_CONST) { LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 1, 1, 2);
LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 1, 1, 2);
}
break; break;
case ZEND_INIT_NS_FCALL_BY_NAME: case ZEND_INIT_NS_FCALL_BY_NAME:
LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 1, 1, 3); LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 1, 1, 3);
@ -320,7 +318,7 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
#endif #endif
/* Merge equal constants */ /* Merge equal constants */
j = 0; cache_slots = 0; j = 0; cache_size = 0;
zend_hash_init(&hash, op_array->last_literal, NULL, NULL, 0); zend_hash_init(&hash, op_array->last_literal, NULL, NULL, 0);
map = (int*)zend_arena_alloc(&ctx->arena, op_array->last_literal * sizeof(int)); map = (int*)zend_arena_alloc(&ctx->arena, op_array->last_literal * sizeof(int));
memset(map, 0, op_array->last_literal * sizeof(int)); memset(map, 0, op_array->last_literal * sizeof(int));
@ -441,8 +439,8 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
info[j] = info[i]; info[j] = info[i];
} }
if (LITERAL_NUM_SLOTS(info[i].flags)) { if (LITERAL_NUM_SLOTS(info[i].flags)) {
Z_CACHE_SLOT(op_array->literals[j]) = cache_slots; Z_CACHE_SLOT(op_array->literals[j]) = cache_size;
cache_slots += LITERAL_NUM_SLOTS(info[i].flags); cache_size += LITERAL_NUM_SLOTS(info[i].flags) * sizeof(void*);
} }
j++; j++;
n = LITERAL_NUM_RELATED(info[i].flags); n = LITERAL_NUM_RELATED(info[i].flags);
@ -467,7 +465,7 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
} }
zend_hash_destroy(&hash); zend_hash_destroy(&hash);
op_array->last_literal = j; op_array->last_literal = j;
op_array->last_cache_slot = cache_slots; op_array->cache_size = cache_size;
/* Update opcodes to use new literals table */ /* Update opcodes to use new literals table */
opline = op_array->opcodes; opline = op_array->opcodes;

View file

@ -66,6 +66,7 @@ void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx)
} }
/* break missing intentionally */ /* break missing intentionally */
case ZEND_NEW: case ZEND_NEW:
case ZEND_INIT_DYNAMIC_CALL:
case ZEND_INIT_METHOD_CALL: case ZEND_INIT_METHOD_CALL:
case ZEND_INIT_STATIC_METHOD_CALL: case ZEND_INIT_STATIC_METHOD_CALL:
case ZEND_INIT_FCALL: case ZEND_INIT_FCALL:
@ -74,6 +75,9 @@ void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx)
call++; call++;
break; break;
case ZEND_DO_FCALL: case ZEND_DO_FCALL:
case ZEND_DO_ICALL:
case ZEND_DO_UCALL:
case ZEND_DO_FCALL_BY_NAME:
call--; call--;
if (call_stack[call].func && call_stack[call].opline) { if (call_stack[call].func && call_stack[call].opline) {
zend_op *fcall = call_stack[call].opline; zend_op *fcall = call_stack[call].opline;
@ -84,6 +88,7 @@ void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx)
Z_CACHE_SLOT(op_array->literals[fcall->op2.constant + 1]) = Z_CACHE_SLOT(op_array->literals[fcall->op2.constant]); Z_CACHE_SLOT(op_array->literals[fcall->op2.constant + 1]) = Z_CACHE_SLOT(op_array->literals[fcall->op2.constant]);
literal_dtor(&ZEND_OP2_LITERAL(fcall)); literal_dtor(&ZEND_OP2_LITERAL(fcall));
fcall->op2.constant = fcall->op2.constant + 1; fcall->op2.constant = fcall->op2.constant + 1;
opline->opcode = zend_get_call_op(ZEND_INIT_FCALL, call_stack[call].func);
} else if (fcall->opcode == ZEND_INIT_NS_FCALL_BY_NAME) { } else if (fcall->opcode == ZEND_INIT_NS_FCALL_BY_NAME) {
fcall->opcode = ZEND_INIT_FCALL; fcall->opcode = ZEND_INIT_FCALL;
fcall->op1.num = zend_vm_calc_used_stack(fcall->extended_value, call_stack[call].func); fcall->op1.num = zend_vm_calc_used_stack(fcall->extended_value, call_stack[call].func);
@ -91,6 +96,7 @@ void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx)
literal_dtor(&op_array->literals[fcall->op2.constant]); literal_dtor(&op_array->literals[fcall->op2.constant]);
literal_dtor(&op_array->literals[fcall->op2.constant + 2]); literal_dtor(&op_array->literals[fcall->op2.constant + 2]);
fcall->op2.constant = fcall->op2.constant + 1; fcall->op2.constant = fcall->op2.constant + 1;
opline->opcode = zend_get_call_op(ZEND_INIT_FCALL, call_stack[call].func);
} else { } else {
ZEND_ASSERT(0); ZEND_ASSERT(0);
} }

View file

@ -341,7 +341,7 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
} }
break; break;
case ZEND_DO_FCALL: { case ZEND_DO_ICALL: {
zend_op *send1_opline = opline - 1; zend_op *send1_opline = opline - 1;
zend_op *send2_opline = NULL; zend_op *send2_opline = NULL;
zend_op *init_opline = NULL; zend_op *init_opline = NULL;

View file

@ -129,7 +129,8 @@ void zend_optimizer_update_op1_const(zend_op_array *op_array,
case ZEND_NEW: case ZEND_NEW:
opline->op1.constant = zend_optimizer_add_literal(op_array, val); opline->op1.constant = zend_optimizer_add_literal(op_array, val);
zend_string_hash_val(Z_STR(ZEND_OP1_LITERAL(opline))); zend_string_hash_val(Z_STR(ZEND_OP1_LITERAL(opline)));
Z_CACHE_SLOT(op_array->literals[opline->op1.constant]) = op_array->last_cache_slot++; Z_CACHE_SLOT(op_array->literals[opline->op1.constant]) = op_array->cache_size;
op_array->cache_size += sizeof(void*);
zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val)); zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));
zend_optimizer_add_literal(op_array, val); zend_optimizer_add_literal(op_array, val);
zend_string_hash_val(Z_STR(op_array->literals[opline->op1.constant+1])); zend_string_hash_val(Z_STR(op_array->literals[opline->op1.constant+1]));
@ -154,7 +155,8 @@ void zend_optimizer_update_op2_const(zend_op_array *op_array,
zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val)); zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));
opline->op2.constant = zend_optimizer_add_literal(op_array, val); opline->op2.constant = zend_optimizer_add_literal(op_array, val);
zend_string_hash_val(Z_STR(ZEND_OP2_LITERAL(opline))); zend_string_hash_val(Z_STR(ZEND_OP2_LITERAL(opline)));
Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = op_array->last_cache_slot++; Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = op_array->cache_size;
op_array->cache_size += sizeof(void*);
return; return;
} }
opline->op2.constant = zend_optimizer_add_literal(op_array, val); opline->op2.constant = zend_optimizer_add_literal(op_array, val);
@ -175,7 +177,16 @@ void zend_optimizer_update_op2_const(zend_op_array *op_array,
case ZEND_ADD_INTERFACE: case ZEND_ADD_INTERFACE:
case ZEND_ADD_TRAIT: case ZEND_ADD_TRAIT:
case ZEND_INSTANCEOF: case ZEND_INSTANCEOF:
Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = op_array->last_cache_slot++; Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = op_array->cache_size;
op_array->cache_size += sizeof(void*);
zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));
zend_optimizer_add_literal(op_array, val);
zend_string_hash_val(Z_STR(op_array->literals[opline->op2.constant+1]));
break;
case ZEND_INIT_DYNAMIC_CALL:
opline->opcode = ZEND_INIT_FCALL_BY_NAME;
Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = op_array->cache_size;
op_array->cache_size += sizeof(void*);
zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val)); zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));
zend_optimizer_add_literal(op_array, val); zend_optimizer_add_literal(op_array, val);
zend_string_hash_val(Z_STR(op_array->literals[opline->op2.constant+1])); zend_string_hash_val(Z_STR(op_array->literals[opline->op2.constant+1]));
@ -200,8 +211,8 @@ void zend_optimizer_update_op2_const(zend_op_array *op_array,
case ZEND_POST_INC_OBJ: case ZEND_POST_INC_OBJ:
case ZEND_POST_DEC_OBJ: case ZEND_POST_DEC_OBJ:
case ZEND_ISSET_ISEMPTY_PROP_OBJ: case ZEND_ISSET_ISEMPTY_PROP_OBJ:
Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = op_array->last_cache_slot; Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = op_array->cache_size;
op_array->last_cache_slot += 2; op_array->cache_size += 2 * sizeof(void*);
break; break;
case ZEND_ASSIGN_ADD: case ZEND_ASSIGN_ADD:
case ZEND_ASSIGN_SUB: case ZEND_ASSIGN_SUB:
@ -215,8 +226,8 @@ void zend_optimizer_update_op2_const(zend_op_array *op_array,
case ZEND_ASSIGN_BW_AND: case ZEND_ASSIGN_BW_AND:
case ZEND_ASSIGN_BW_XOR: case ZEND_ASSIGN_BW_XOR:
if (opline->extended_value == ZEND_ASSIGN_OBJ) { if (opline->extended_value == ZEND_ASSIGN_OBJ) {
Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = op_array->last_cache_slot; Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = op_array->cache_size;
op_array->last_cache_slot += 2; op_array->cache_size += 2 * sizeof(void*);
} }
break; break;
case ZEND_OP_DATA: case ZEND_OP_DATA:
@ -309,15 +320,26 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array,
* and allows its reuse. The number of ZEND_CASE instructions * and allows its reuse. The number of ZEND_CASE instructions
* usually terminated by ZEND_FREE that finally kills the value. * usually terminated by ZEND_FREE that finally kills the value.
*/ */
case ZEND_FREE:
case ZEND_CASE: { case ZEND_CASE: {
zend_op *m, *n; zend_op *m, *n;
int brk = op_array->last_brk_cont; int brk = op_array->last_brk_cont;
zend_bool in_switch = 0;
while (brk--) { while (brk--) {
if (op_array->brk_cont_array[brk].start <= (opline - op_array->opcodes) && if (op_array->brk_cont_array[brk].start <= (opline - op_array->opcodes) &&
op_array->brk_cont_array[brk].brk > (opline - op_array->opcodes)) { op_array->brk_cont_array[brk].brk > (opline - op_array->opcodes)) {
in_switch = 1;
break; break;
} }
} }
if (!in_switch) {
ZEND_ASSERT(opline->opcode == ZEND_FREE);
MAKE_NOP(opline);
zval_dtor(val);
return 1;
}
m = opline; m = opline;
n = op_array->opcodes + op_array->brk_cont_array[brk].brk + 1; n = op_array->opcodes + op_array->brk_cont_array[brk].brk + 1;
while (m < n) { while (m < n) {
@ -340,10 +362,6 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array,
zval_dtor(val); zval_dtor(val);
return 1; return 1;
} }
case ZEND_FREE:
MAKE_NOP(opline);
zval_dtor(val);
return 1;
default: default:
break; break;
} }

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); memory_used = zend_accel_script_persist_calc(new_persistent_script, key, key_length);
/* Allocate shared memory */ /* 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); ZCG(mem) = zend_shared_alloc(memory_used);
#endif
if (!ZCG(mem)) { if (!ZCG(mem)) {
zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM); zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM);
zend_shared_alloc_unlock(); zend_shared_alloc_unlock();
@ -1830,6 +1836,11 @@ static void accel_activate(void)
return; return;
} }
if (!ZCG(function_table).nTableSize) {
zend_hash_init(&ZCG(function_table), zend_hash_num_elements(CG(function_table)), NULL, ZEND_FUNCTION_DTOR, 1);
zend_accel_copy_internal_functions();
}
SHM_UNPROTECT(); SHM_UNPROTECT();
/* PHP-5.4 and above return "double", but we use 1 sec precision */ /* PHP-5.4 and above return "double", but we use 1 sec precision */
ZCG(auto_globals_mask) = 0; ZCG(auto_globals_mask) = 0;
@ -1973,7 +1984,11 @@ static int accel_clean_non_persistent_function(zval *zv)
return ZEND_HASH_APPLY_STOP; return ZEND_HASH_APPLY_STOP;
} else { } else {
if (function->op_array.static_variables) { 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; function->op_array.static_variables = NULL;
} }
return ZEND_HASH_APPLY_REMOVE; return ZEND_HASH_APPLY_REMOVE;
@ -2025,7 +2040,11 @@ static void zend_accel_fast_shutdown(void)
break; break;
} else { } else {
if (func->op_array.static_variables) { 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); zend_accel_fast_del_bucket(EG(function_table), _idx-1, _p);
} }
@ -2043,7 +2062,11 @@ static void zend_accel_fast_shutdown(void)
ZEND_HASH_FOREACH_PTR(&ce->function_table, func) { ZEND_HASH_FOREACH_PTR(&ce->function_table, func) {
if (func->type == ZEND_USER_FUNCTION) { if (func->type == ZEND_USER_FUNCTION) {
if (func->op_array.static_variables) { 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; func->op_array.static_variables = NULL;
} }
} }
@ -2239,8 +2262,6 @@ static void accel_globals_ctor(zend_accel_globals *accel_globals)
ZEND_TSRMLS_CACHE_UPDATE(); ZEND_TSRMLS_CACHE_UPDATE();
#endif #endif
memset(accel_globals, 0, sizeof(zend_accel_globals)); memset(accel_globals, 0, sizeof(zend_accel_globals));
zend_hash_init(&accel_globals->function_table, zend_hash_num_elements(CG(function_table)), NULL, ZEND_FUNCTION_DTOR, 1);
zend_accel_copy_internal_functions();
} }
static void accel_globals_internal_func_dtor(zval *zv) static void accel_globals_internal_func_dtor(zval *zv)
@ -2250,8 +2271,10 @@ static void accel_globals_internal_func_dtor(zval *zv)
static void accel_globals_dtor(zend_accel_globals *accel_globals) static void accel_globals_dtor(zend_accel_globals *accel_globals)
{ {
accel_globals->function_table.pDestructor = accel_globals_internal_func_dtor; if (accel_globals->function_table.nTableSize) {
zend_hash_destroy(&accel_globals->function_table); accel_globals->function_table.pDestructor = accel_globals_internal_func_dtor;
zend_hash_destroy(&accel_globals->function_table);
}
} }
static int accel_startup(zend_extension *extension) static int accel_startup(zend_extension *extension)
@ -2404,11 +2427,6 @@ static int accel_startup(zend_extension *extension)
zend_accel_blacklist_load(&accel_blacklist, ZCG(accel_directives.user_blacklist_filename)); zend_accel_blacklist_load(&accel_blacklist, ZCG(accel_directives.user_blacklist_filename));
} }
#if 0
/* FIXME: We probably don't need it here */
zend_accel_copy_internal_functions();
#endif
return SUCCESS; return SUCCESS;
} }

View file

@ -49,8 +49,17 @@ function c($b = "bad") {
} }
var_dump(c()); var_dump(c());
function d() {
switch (PHP_OS) {
default: return "bad";
case PHP_OS: return "okey";
}
}
var_dump(d());
?> ?>
--EXPECT-- --EXPECT--
string(4) "okey" string(4) "okey"
string(4) "okey" string(4) "okey"
string(4) "okey" string(4) "okey"
string(4) "okey"

View file

@ -25,10 +25,6 @@
#include "zend_persist.h" #include "zend_persist.h"
#include "zend_shared_alloc.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_SIZE_T <= SIZEOF_ZEND_LONG
/* If sizeof(void*) == sizeof(ulong) we can use zend_hash index functions */ /* 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)) # 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->type == ZEND_USER_FUNCTION) {
if (function->op_array.static_variables) { if (function->op_array.static_variables) {
if (!(GC_FLAGS(function->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) {
FREE_HASHTABLE(function->op_array.static_variables); if (--GC_REFCOUNT(function->op_array.static_variables) == 0) {
FREE_HASHTABLE(function->op_array.static_variables);
}
}
function->op_array.static_variables = NULL; function->op_array.static_variables = NULL;
} }
} }
@ -366,31 +365,11 @@ 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) static void zend_hash_clone_methods(HashTable *ht, HashTable *source, zend_class_entry *old_ce, zend_class_entry *ce)
{ {
uint idx; uint idx;
Bucket *p, *q; Bucket *p, *q;
zend_ulong nIndex; zend_ulong nIndex;
zend_class_entry *new_ce;
zend_function *new_prototype;
zend_op_array *new_entry; zend_op_array *new_entry;
ht->nTableSize = source->nTableSize; ht->nTableSize = source->nTableSize;
@ -432,31 +411,11 @@ static void zend_hash_clone_methods(HashTable *ht, HashTable *source, zend_class
ZVAL_PTR(&q->val, ARENA_REALLOC(Z_PTR(p->val))); ZVAL_PTR(&q->val, ARENA_REALLOC(Z_PTR(p->val)));
new_entry = (zend_op_array*)Z_PTR(q->val); new_entry = (zend_op_array*)Z_PTR(q->val);
/* Copy constructor */ new_entry->scope = ARENA_REALLOC(new_entry->scope);
/* 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);
}
}
/* update prototype */ /* update prototype */
if (new_entry->prototype) { if (new_entry->prototype) {
if ((new_prototype = accel_xlat_get(new_entry->prototype)) != NULL) { new_entry->prototype = ARENA_REALLOC(new_entry->prototype);
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);
}
} }
} }
} }
@ -466,7 +425,6 @@ static void zend_hash_clone_prop_info(HashTable *ht, HashTable *source, zend_cla
uint idx; uint idx;
Bucket *p, *q; Bucket *p, *q;
zend_ulong nIndex; zend_ulong nIndex;
zend_class_entry *new_ce;
zend_property_info *prop_info; zend_property_info *prop_info;
ht->nTableSize = source->nTableSize; ht->nTableSize = source->nTableSize;
@ -517,24 +475,14 @@ static void zend_hash_clone_prop_info(HashTable *ht, HashTable *source, zend_cla
prop_info->doc_comment = NULL; prop_info->doc_comment = NULL;
} }
} }
if (prop_info->ce == old_ce) { prop_info->ce = ARENA_REALLOC(prop_info->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);
}
} }
} }
#define zend_update_inherited_handler(handler) \ #define zend_update_inherited_handler(handler) \
{ \ { \
if (ce->handler != NULL) { \ if (ce->handler != NULL) { \
if ((new_func = accel_xlat_get(ce->handler)) != NULL) { \ ce->handler = ARENA_REALLOC(ce->handler); \
ce->handler = new_func; \
} else { \
zend_error(E_ERROR, ACCELERATOR_PRODUCT_NAME " class loading error, class %s", ce->name->val); \
} \
} \ } \
} }
@ -543,17 +491,10 @@ static void zend_class_copy_ctor(zend_class_entry **pce)
{ {
zend_class_entry *ce = *pce; zend_class_entry *ce = *pce;
zend_class_entry *old_ce = ce; zend_class_entry *old_ce = ce;
zend_class_entry *new_ce;
zend_function *new_func;
*pce = ce = ARENA_REALLOC(old_ce); *pce = ce = ARENA_REALLOC(old_ce);
ce->refcount = 1; 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) { if (old_ce->default_properties_table) {
int i; int i;
@ -603,11 +544,7 @@ static void zend_class_copy_ctor(zend_class_entry **pce)
} }
if (ce->parent) { if (ce->parent) {
if ((new_ce = accel_xlat_get(ce->parent)) != NULL) { ce->parent = ARENA_REALLOC(ce->parent);
ce->parent = new_ce;
} else {
zend_error(E_ERROR, ACCELERATOR_PRODUCT_NAME" class loading error, class %s", ce->name->val);
}
} }
zend_update_inherited_handler(constructor); zend_update_inherited_handler(constructor);
@ -718,21 +655,14 @@ static void zend_accel_function_hash_copy(HashTable *target, HashTable *source)
for (idx = 0; idx < source->nNumUsed; idx++) { for (idx = 0; idx < source->nNumUsed; idx++) {
p = source->arData + idx; p = source->arData + idx;
if (Z_TYPE(p->val) == IS_UNDEF) continue; if (Z_TYPE(p->val) == IS_UNDEF) continue;
if (p->key) { ZEND_ASSERT(p->key);
t = zend_hash_add(target, p->key, &p->val); t = zend_hash_add(target, p->key, &p->val);
if (UNEXPECTED(t == NULL)) { if (UNEXPECTED(t == NULL)) {
if (p->key->len > 0 && p->key->val[0] == 0) { if (p->key->len > 0 && p->key->val[0] == 0) {
/* Mangled key */ /* Mangled key */
t = zend_hash_update(target, p->key, &p->val); t = zend_hash_update(target, p->key, &p->val);
} else { } else {
t = zend_hash_find(target, p->key); 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);
goto failure; goto failure;
} }
} }
@ -767,26 +697,18 @@ static void zend_accel_function_hash_copy_from_shm(HashTable *target, HashTable
for (idx = 0; idx < source->nNumUsed; idx++) { for (idx = 0; idx < source->nNumUsed; idx++) {
p = source->arData + idx; p = source->arData + idx;
if (Z_TYPE(p->val) == IS_UNDEF) continue; if (Z_TYPE(p->val) == IS_UNDEF) continue;
if (p->key) { ZEND_ASSERT(p->key);
t = zend_hash_add(target, p->key, &p->val); t = zend_hash_add(target, p->key, &p->val);
if (UNEXPECTED(t == NULL)) { if (UNEXPECTED(t == NULL)) {
if (p->key->len > 0 && p->key->val[0] == 0) { if (p->key->len > 0 && p->key->val[0] == 0) {
/* Mangled key */ /* Mangled key */
t = zend_hash_update(target, p->key, &p->val); t = zend_hash_update(target, p->key, &p->val);
} else { } else {
t = zend_hash_find(target, p->key); 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);
goto failure; goto failure;
} }
} }
Z_PTR_P(t) = ARENA_REALLOC(Z_PTR(p->val)); 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; target->nInternalPointer = target->nNumOfElements ? 0 : INVALID_IDX;
return; return;
@ -818,24 +740,15 @@ static void zend_accel_class_hash_copy(HashTable *target, HashTable *source, uni
for (idx = 0; idx < source->nNumUsed; idx++) { for (idx = 0; idx < source->nNumUsed; idx++) {
p = source->arData + idx; p = source->arData + idx;
if (Z_TYPE(p->val) == IS_UNDEF) continue; if (Z_TYPE(p->val) == IS_UNDEF) continue;
if (p->key) { ZEND_ASSERT(p->key);
t = zend_hash_add(target, p->key, &p->val); t = zend_hash_add(target, p->key, &p->val);
if (UNEXPECTED(t == NULL)) { if (UNEXPECTED(t == NULL)) {
if (p->key->len > 0 && p->key->val[0] == 0) { if (p->key->len > 0 && p->key->val[0] == 0) {
/* Mangled key - ignore and wait for runtime */ /* Mangled key - ignore and wait for runtime */
continue; continue;
} else if (!ZCG(accel_directives).ignore_dups) { } else if (!ZCG(accel_directives).ignore_dups) {
t = zend_hash_find(target, p->key); t = zend_hash_find(target, p->key);
goto failure; 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;
}
} }
} }
if (pCopyConstructor) { if (pCopyConstructor) {
@ -853,6 +766,34 @@ failure:
zend_error(E_ERROR, "Cannot redeclare class %s", ce1->name->val); 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* zend_accel_load_script(zend_persistent_script *persistent_script, int from_shared_memory)
{ {
zend_op_array *op_array; zend_op_array *op_array;
@ -866,8 +807,15 @@ zend_op_array* zend_accel_load_script(zend_persistent_script *persistent_script,
ZCG(current_persistent_script) = persistent_script; ZCG(current_persistent_script) = persistent_script;
ZCG(arena_mem) = NULL; ZCG(arena_mem) = NULL;
if (EXPECTED(persistent_script->arena_size)) { 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); ZCG(arena_mem) = zend_arena_alloc(&CG(arena), persistent_script->arena_size);
memcpy(ZCG(arena_mem), persistent_script->arena_mem, 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 */ /* Copy all the necessary stuff from shared memory to regular memory, and protect the shared script */
@ -880,8 +828,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_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 */ /* Register __COMPILER_HALT_OFFSET__ constant */
if (persistent_script->compiler_halt_offset != 0 && if (persistent_script->compiler_halt_offset != 0 &&
persistent_script->full_path) { persistent_script->full_path) {

View file

@ -204,6 +204,7 @@ static void zend_persist_zval(zval *z)
/* make immutable array */ /* make immutable array */
Z_TYPE_FLAGS_P(z) = IS_TYPE_IMMUTABLE; Z_TYPE_FLAGS_P(z) = IS_TYPE_IMMUTABLE;
GC_REFCOUNT(Z_COUNTED_P(z)) = 2; 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; 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) static void zend_persist_zval_const(zval *z)
{ {
zend_uchar flags; zend_uchar flags;
@ -258,6 +316,7 @@ static void zend_persist_zval_const(zval *z)
/* make immutable array */ /* make immutable array */
Z_TYPE_FLAGS_P(z) = IS_TYPE_IMMUTABLE; Z_TYPE_FLAGS_P(z) = IS_TYPE_IMMUTABLE;
GC_REFCOUNT(Z_COUNTED_P(z)) = 2; 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; 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; return;
} }
if (--(*op_array->refcount) == 0) { if (op_array->refcount && --(*op_array->refcount) == 0) {
efree(op_array->refcount); efree(op_array->refcount);
} }
op_array->refcount = NULL; 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) { if (op_array->static_variables) {
zend_hash_persist(op_array->static_variables, zend_persist_zval); HashTable *stored = zend_shared_alloc_get_xlat_entry(op_array->static_variables);
zend_accel_store(op_array->static_variables, sizeof(HashTable));
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)) { if (zend_shared_alloc_get_xlat_entry(op_array->opcodes)) {
@ -495,8 +564,6 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc
if (op_array->scope && op_array->prototype) { if (op_array->scope && op_array->prototype) {
if ((persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->prototype))) { if ((persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->prototype))) {
op_array->prototype = (union _zend_function*)persist_ptr; 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 { } else {
op_array->prototype = NULL; op_array->prototype = NULL;
@ -661,63 +728,47 @@ static int zend_update_parent_ce(zval *zv)
if (ce->parent) { if (ce->parent) {
ce->parent = zend_shared_alloc_get_xlat_entry(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 */ /* update methods */
if (ce->constructor) { if (ce->constructor) {
ce->constructor = zend_shared_alloc_get_xlat_entry(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) { if (ce->destructor) {
ce->destructor = zend_shared_alloc_get_xlat_entry(ce->destructor); ce->destructor = zend_shared_alloc_get_xlat_entry(ce->destructor);
ce->destructor->op_array.refcount++;
} }
if (ce->clone) { if (ce->clone) {
ce->clone = zend_shared_alloc_get_xlat_entry(ce->clone); ce->clone = zend_shared_alloc_get_xlat_entry(ce->clone);
ce->clone->op_array.refcount++;
} }
if (ce->__get) { if (ce->__get) {
ce->__get = zend_shared_alloc_get_xlat_entry(ce->__get); ce->__get = zend_shared_alloc_get_xlat_entry(ce->__get);
ce->__get->op_array.refcount++;
} }
if (ce->__set) { if (ce->__set) {
ce->__set = zend_shared_alloc_get_xlat_entry(ce->__set); ce->__set = zend_shared_alloc_get_xlat_entry(ce->__set);
ce->__set->op_array.refcount++;
} }
if (ce->__call) { if (ce->__call) {
ce->__call = zend_shared_alloc_get_xlat_entry(ce->__call); ce->__call = zend_shared_alloc_get_xlat_entry(ce->__call);
ce->__call->op_array.refcount++;
} }
if (ce->serialize_func) { if (ce->serialize_func) {
ce->serialize_func = zend_shared_alloc_get_xlat_entry(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) { if (ce->unserialize_func) {
ce->unserialize_func = zend_shared_alloc_get_xlat_entry(ce->unserialize_func); ce->unserialize_func = zend_shared_alloc_get_xlat_entry(ce->unserialize_func);
ce->unserialize_func->op_array.refcount++;
} }
if (ce->__isset) { if (ce->__isset) {
ce->__isset = zend_shared_alloc_get_xlat_entry(ce->__isset); ce->__isset = zend_shared_alloc_get_xlat_entry(ce->__isset);
ce->__isset->op_array.refcount++;
} }
if (ce->__unset) { if (ce->__unset) {
ce->__unset = zend_shared_alloc_get_xlat_entry(ce->__unset); ce->__unset = zend_shared_alloc_get_xlat_entry(ce->__unset);
ce->__unset->op_array.refcount++;
} }
if (ce->__tostring) { if (ce->__tostring) {
ce->__tostring = zend_shared_alloc_get_xlat_entry(ce->__tostring); ce->__tostring = zend_shared_alloc_get_xlat_entry(ce->__tostring);
ce->__tostring->op_array.refcount++;
} }
if (ce->__callstatic) { if (ce->__callstatic) {
ce->__callstatic = zend_shared_alloc_get_xlat_entry(ce->__callstatic); ce->__callstatic = zend_shared_alloc_get_xlat_entry(ce->__callstatic);
ce->__callstatic->op_array.refcount++;
} }
if (ce->__debugInfo) { if (ce->__debugInfo) {
ce->__debugInfo = zend_shared_alloc_get_xlat_entry(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); zend_hash_apply(&ce->properties_info, (apply_func_t) zend_update_property_info_ce);
return 0; return 0;
@ -739,6 +790,11 @@ zend_persistent_script *zend_accel_script_persist(zend_persistent_script *script
*key = zend_accel_memdup(*key, key_length + 1); *key = zend_accel_memdup(*key, key_length + 1);
zend_accel_store_string(script->full_path); 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); script->arena_mem = ZCG(arena_mem) = ZCG(mem);
ZCG(mem) = (void*)((char*)ZCG(mem) + script->arena_size); 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) { if (op_array->static_variables) {
ADD_DUP_SIZE(op_array->static_variables, sizeof(HashTable)); if (!zend_shared_alloc_get_xlat_entry(op_array->static_variables)) {
zend_hash_persist_calc(op_array->static_variables, zend_persist_zval_calc); 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)) { 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_DUP_SIZE(key, key_length + 1);
ADD_STRING(new_persistent_script->full_path); 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_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_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); 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; new_persistent_script->size += new_persistent_script->arena_size;
ZCG(current_persistent_script) = NULL; ZCG(current_persistent_script) = NULL;

View file

@ -91,7 +91,7 @@ typedef struct _handler_entry {
typedef struct _zend_shared_memory_state { typedef struct _zend_shared_memory_state {
int *positions; /* current positions for each segment */ 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; } zend_shared_memory_state;
typedef struct _zend_smm_shared_globals { 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 */ /* Return an empty array in case no static variables exist */
array_init(return_value); array_init(return_value);
if (fptr->type == ZEND_USER_FUNCTION && fptr->op_array.static_variables != NULL) { 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_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); 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; 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_INFO:
case SPL_FS_FILE: 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; break;
case SPL_FS_DIR: 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", intern->file_name_len = (int)spprintf(&intern->file_name, 0, "%s%c%s",
spl_filesystem_object_get_path(intern, NULL), spl_filesystem_object_get_path(intern, NULL),
slash, intern->u.dir.entry.d_name); slash, intern->u.dir.entry.d_name);
break; break;
}
} }
} /* }}} */ } /* }}} */

View file

@ -770,6 +770,7 @@ SPL_METHOD(SplObjectStorage, serialize)
/* members */ /* members */
smart_str_appendl(&buf, "m:", 2); smart_str_appendl(&buf, "m:", 2);
ZVAL_ARR(&members, zend_array_dup(zend_std_get_properties(getThis()))); ZVAL_ARR(&members, zend_array_dup(zend_std_get_properties(getThis())));
zend_hash_str_del(Z_ARRVAL(members), "\x00gcdata", sizeof("\x00gcdata") - 1);
php_var_serialize(&buf, &members, &var_hash); /* finishes the string */ php_var_serialize(&buf, &members, &var_hash); /* finishes the string */
zval_ptr_dtor(&members); zval_ptr_dtor(&members);

View file

@ -0,0 +1,42 @@
--TEST--
Bug #68557 (SplFileInfo::getPathname() may be broken)
--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);
$path0 = $d->current()->getPathname();
$d->seek(1);
$path1 = $d->current()->getPathname();
$d->seek(2);
$path2 = $d->current()->getPathname();
$d->seek(0);
var_dump($path0 === $d->current()->getPathname());
$d->seek(1);
var_dump($path1 === $d->current()->getPathname());
$d->seek(2);
var_dump($path2 === $d->current()->getPathname());
$d->seek(0);
var_dump($path0 === $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--
bool(true)
bool(true)
bool(true)
bool(true)

View file

@ -0,0 +1,22 @@
--TEST--
Bug #69108 ("Segmentation fault" when (de)serializing SplObjectStorage)
--INI--
zend.enable_gc=1
--FILE--
<?php
$a = array();
$b = new SplObjectStorage();
for ($i = 10000; $i > 0; $i--) {
$object = new StdClass();
$a[] = $object;
$b->attach($object);
}
$c = serialize(array($a, $b));
$d = unserialize($c);
unset($d);
echo "ok";
?>
--EXPECT--
ok

View file

@ -925,12 +925,12 @@ PHP_FUNCTION(current)
zval *entry; zval *entry;
#ifndef FAST_ZPP #ifndef FAST_ZPP
if (zend_parse_parameters(ZEND_NUM_ARGS(), "H/", &array) == FAILURE) { if (zend_parse_parameters(ZEND_NUM_ARGS(), "H", &array) == FAILURE) {
return; return;
} }
#else #else
ZEND_PARSE_PARAMETERS_START(1, 1) ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ARRAY_OR_OBJECT_HT_EX(array, 0, 1) Z_PARAM_ARRAY_OR_OBJECT_HT(array)
ZEND_PARSE_PARAMETERS_END(); ZEND_PARSE_PARAMETERS_END();
#endif #endif
@ -953,12 +953,12 @@ PHP_FUNCTION(key)
HashTable *array; HashTable *array;
#ifndef FAST_ZPP #ifndef FAST_ZPP
if (zend_parse_parameters(ZEND_NUM_ARGS(), "H/", &array) == FAILURE) { if (zend_parse_parameters(ZEND_NUM_ARGS(), "H", &array) == FAILURE) {
return; return;
} }
#else #else
ZEND_PARSE_PARAMETERS_START(1, 1) ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ARRAY_OR_OBJECT_HT_EX(array, 0, 1) Z_PARAM_ARRAY_OR_OBJECT_HT(array)
ZEND_PARSE_PARAMETERS_END(); ZEND_PARSE_PARAMETERS_END();
#endif #endif

View file

@ -289,11 +289,11 @@ ZEND_BEGIN_ARG_INFO(arginfo_reset, 0)
ZEND_END_ARG_INFO() ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_current, 0) ZEND_BEGIN_ARG_INFO(arginfo_current, 0)
ZEND_ARG_INFO(ZEND_SEND_PREFER_REF, arg) ZEND_ARG_INFO(0, arg)
ZEND_END_ARG_INFO() ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_key, 0) ZEND_BEGIN_ARG_INFO(arginfo_key, 0)
ZEND_ARG_INFO(ZEND_SEND_PREFER_REF, arg) ZEND_ARG_INFO(0, arg)
ZEND_END_ARG_INFO() ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_min, 0, 0, 1) ZEND_BEGIN_ARG_INFO_EX(arginfo_min, 0, 0, 1)

View file

@ -311,8 +311,7 @@ PHP_MINIT_FUNCTION(browscap) /* {{{ */
char *browscap = INI_STR("browscap"); char *browscap = INI_STR("browscap");
#ifdef ZTS #ifdef ZTS
ts_allocate_id(&browscap_globals_id, sizeof(browser_data), ts_allocate_id(&browscap_globals_id, sizeof(browser_data), (ts_allocate_ctor) browscap_globals_ctor, NULL);
(ts_allocate_ctor) browscap_globals_ctor, NULL);
#endif #endif
/* ctor call not really needed for non-ZTS */ /* ctor call not really needed for non-ZTS */

View file

@ -359,11 +359,7 @@ PHP_FUNCTION(flock)
/* flock_values contains all possible actions if (operation & 4) we won't block on the lock */ /* flock_values contains all possible actions if (operation & 4) we won't block on the lock */
act = flock_values[act - 1] | (operation & PHP_LOCK_NB ? LOCK_NB : 0); act = flock_values[act - 1] | (operation & PHP_LOCK_NB ? LOCK_NB : 0);
if (php_stream_lock(stream, act)) { if (php_stream_lock(stream, act)) {
#ifdef PHP_WIN32
if (operation && errno == ERROR_INVALID_BLOCK && wouldblock) {
#else
if (operation && errno == EWOULDBLOCK && wouldblock) { if (operation && errno == EWOULDBLOCK && wouldblock) {
#endif
ZVAL_LONG(wouldblock, 1); ZVAL_LONG(wouldblock, 1);
} }
RETURN_FALSE; RETURN_FALSE;

View file

@ -125,8 +125,12 @@ PHPAPI int php_flock(int fd, int operation)
DWORD low = 1, high = 0; DWORD low = 1, high = 0;
OVERLAPPED offset = OVERLAPPED offset =
{0, 0, 0, 0, NULL}; {0, 0, 0, 0, NULL};
if (hdl < 0) DWORD err;
if (hdl < 0) {
_set_errno(EBADF);
return -1; /* error in file descriptor */ return -1; /* error in file descriptor */
}
/* bug for bug compatible with Unix */ /* bug for bug compatible with Unix */
UnlockFileEx(hdl, 0, low, high, &offset); UnlockFileEx(hdl, 0, low, high, &offset);
switch (operation & ~LOCK_NB) { /* translate to LockFileEx() op */ switch (operation & ~LOCK_NB) { /* translate to LockFileEx() op */
@ -146,12 +150,14 @@ PHPAPI int php_flock(int fd, int operation)
default: /* default */ default: /* default */
break; break;
} }
/* Under Win32 MT library, errno is not a variable but a function call,
* which cannot be assigned to. err = GetLastError();
*/ if (ERROR_LOCK_VIOLATION == err || ERROR_SHARING_VIOLATION == err) {
#if !defined(PHP_WIN32) _set_errno(EWOULDBLOCK);
errno = EINVAL; /* bad call */ } else {
#endif _set_errno(EINVAL); /* bad call */
}
return -1; return -1;
} }
/* }}} */ /* }}} */

View file

@ -459,9 +459,13 @@ array(5) {
-- Testing variation: when array is unset -- -- Testing variation: when array is unset --
Notice: Undefined variable: unset_array in %s on line %d
Warning: current() expects parameter 1 to be array, null given in %s on line %d Warning: current() expects parameter 1 to be array, null given in %s on line %d
NULL NULL
Notice: Undefined variable: unset_array in %s on line %d
Warning: key() expects parameter 1 to be array, null given in %s on line %d Warning: key() expects parameter 1 to be array, null given in %s on line %d
NULL NULL

View file

@ -1919,8 +1919,6 @@ static size_t php_output_wrapper(const char *str, size_t str_length)
static void core_globals_ctor(php_core_globals *core_globals) static void core_globals_ctor(php_core_globals *core_globals)
{ {
memset(core_globals, 0, sizeof(*core_globals)); memset(core_globals, 0, sizeof(*core_globals));
php_startup_ticks();
} }
/* }}} */ /* }}} */
#endif #endif
@ -2034,11 +2032,6 @@ int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_mod
int retval = SUCCESS, module_number=0; /* for REGISTER_INI_ENTRIES() */ int retval = SUCCESS, module_number=0; /* for REGISTER_INI_ENTRIES() */
char *php_os; char *php_os;
zend_module_entry *module; zend_module_entry *module;
#ifdef ZTS
zend_executor_globals *executor_globals;
void ***tsrm_ls;
php_core_globals *core_globals;
#endif
#if defined(PHP_WIN32) || (defined(NETWARE) && defined(USE_WINSOCK)) #if defined(PHP_WIN32) || (defined(NETWARE) && defined(USE_WINSOCK))
WORD wVersionRequested = MAKEWORD(2, 0); WORD wVersionRequested = MAKEWORD(2, 0);
@ -2057,11 +2050,11 @@ int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_mod
_CrtSetReportMode(_CRT_ASSERT, 0); _CrtSetReportMode(_CRT_ASSERT, 0);
#endif #endif
#else #else
php_os=PHP_OS; php_os = PHP_OS;
#endif #endif
#ifdef ZTS #ifdef ZTS
tsrm_ls = ts_resource(0); (void)ts_resource(0);
#endif #endif
#ifdef PHP_WIN32 #ifdef PHP_WIN32
@ -2081,6 +2074,17 @@ int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_mod
php_output_startup(); php_output_startup();
#ifdef ZTS
ts_allocate_id(&core_globals_id, sizeof(php_core_globals), (ts_allocate_ctor) core_globals_ctor, (ts_allocate_dtor) core_globals_dtor);
php_startup_ticks();
#ifdef PHP_WIN32
ts_allocate_id(&php_win32_core_globals_id, sizeof(php_win32_core_globals), (ts_allocate_ctor) php_win32_core_globals_ctor, (ts_allocate_dtor) php_win32_core_globals_dtor);
#endif
#else
php_startup_ticks();
#endif
gc_globals_ctor();
zuf.error_function = php_error_cb; zuf.error_function = php_error_cb;
zuf.printf_function = php_printf; zuf.printf_function = php_printf;
zuf.write_function = php_output_wrapper; zuf.write_function = php_output_wrapper;
@ -2098,18 +2102,6 @@ int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_mod
zuf.resolve_path_function = php_resolve_path_for_zend; zuf.resolve_path_function = php_resolve_path_for_zend;
zend_startup(&zuf, NULL); zend_startup(&zuf, NULL);
#ifdef ZTS
executor_globals = ts_resource(executor_globals_id);
ts_allocate_id(&core_globals_id, sizeof(php_core_globals), (ts_allocate_ctor) core_globals_ctor, (ts_allocate_dtor) core_globals_dtor);
core_globals = ts_resource(core_globals_id);
#ifdef PHP_WIN32
ts_allocate_id(&php_win32_core_globals_id, sizeof(php_win32_core_globals), (ts_allocate_ctor) php_win32_core_globals_ctor, (ts_allocate_dtor) php_win32_core_globals_dtor);
#endif
#else
php_startup_ticks();
#endif
gc_globals_ctor();
#ifdef PHP_WIN32 #ifdef PHP_WIN32
{ {
OSVERSIONINFOEX *osvi = &EG(windows_version_info); OSVERSIONINFOEX *osvi = &EG(windows_version_info);
@ -2122,24 +2114,6 @@ int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_mod
} }
} }
#endif #endif
EG(bailout) = NULL;
EG(error_reporting) = E_ALL & ~E_NOTICE;
PG(header_is_being_sent) = 0;
SG(request_info).headers_only = 0;
SG(request_info).argv0 = NULL;
SG(request_info).argc=0;
SG(request_info).argv=(char **)NULL;
PG(connection_status) = PHP_CONNECTION_NORMAL;
PG(during_request_startup) = 0;
PG(last_error_message) = NULL;
PG(last_error_file) = NULL;
PG(last_error_lineno) = 0;
EG(error_handling) = EH_NORMAL;
EG(exception_class) = NULL;
PG(disable_functions) = NULL;
PG(disable_classes) = NULL;
EG(exception) = NULL;
EG(objects_store).object_buckets = NULL;
#if HAVE_SETLOCALE #if HAVE_SETLOCALE
setlocale(LC_CTYPE, ""); setlocale(LC_CTYPE, "");

View file

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

View file

@ -1390,10 +1390,12 @@ char * LSAPI_GetHeader_r( LSAPI_Request * pReq, int headerIndex )
off = pReq->m_pHeaderIndex->m_headerOff[ headerIndex ]; off = pReq->m_pHeaderIndex->m_headerOff[ headerIndex ];
if ( !off ) if ( !off )
return NULL; return NULL;
if ( *(pReq->m_pHttpHeader + off + if ( *(pReq->m_pHttpHeader + off
pReq->m_pHeaderIndex->m_headerLen[ headerIndex ]) ) + pReq->m_pHeaderIndex->m_headerLen[ headerIndex ]) )
*( pReq->m_pHttpHeader + off + {
pReq->m_pHeaderIndex->m_headerLen[ headerIndex ]) = 0; *( pReq->m_pHttpHeader + off
+ pReq->m_pHeaderIndex->m_headerLen[ headerIndex ]) = 0;
}
return pReq->m_pHttpHeader + off; return pReq->m_pHttpHeader + off;
} }
@ -1830,12 +1832,21 @@ ssize_t LSAPI_Write_Stderr_r( LSAPI_Request * pReq, const char * pBuf, size_t le
static char * GetHeaderVar( LSAPI_Request * pReq, const char * name ) static char * GetHeaderVar( LSAPI_Request * pReq, const char * name )
{ {
int i; int i;
char * pValue;
for( i = 0; i < H_TRANSFER_ENCODING; ++i ) for( i = 0; i < H_TRANSFER_ENCODING; ++i )
{ {
if ( pReq->m_pHeaderIndex->m_headerOff[i] ) if ( pReq->m_pHeaderIndex->m_headerOff[i] )
{ {
if ( strcmp( name, CGI_HEADERS[i] ) == 0 ) if ( strcmp( name, CGI_HEADERS[i] ) == 0 )
return pReq->m_pHttpHeader + pReq->m_pHeaderIndex->m_headerOff[i]; {
pValue = pReq->m_pHttpHeader
+ pReq->m_pHeaderIndex->m_headerOff[i];
if ( *(pValue + pReq->m_pHeaderIndex->m_headerLen[i]) != '\0')
{
*(pValue + pReq->m_pHeaderIndex->m_headerLen[i]) = '\0';
}
return pValue;
}
} }
} }
if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 ) if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 )
@ -1862,7 +1873,15 @@ static char * GetHeaderVar( LSAPI_Request * pReq, const char * name )
++p; ++pKey; ++p; ++pKey;
} }
if (( pKey == pKeyEnd )&& (!*p )) if (( pKey == pKeyEnd )&& (!*p ))
return pReq->m_pHttpHeader + pCur->valueOff; {
pValue = pReq->m_pHttpHeader + pCur->valueOff;
if ( *(pValue + pCur->valueLen) != '\0')
{
*(pValue + pCur->valueLen) = '\0';
}
return pValue;
}
++pCur; ++pCur;
} }
} }

View file

@ -1454,7 +1454,10 @@ next:
PHPDBG_G(last_line) = execute_data->opline->lineno; PHPDBG_G(last_line) = execute_data->opline->lineno;
/* stupid hack to make zend_do_fcall_common_helper return ZEND_VM_ENTER() instead of recursively calling zend_execute() and eventually segfaulting */ /* stupid hack to make zend_do_fcall_common_helper return ZEND_VM_ENTER() instead of recursively calling zend_execute() and eventually segfaulting */
if (execute_data->opline->opcode == ZEND_DO_FCALL && execute_data->func->type == ZEND_USER_FUNCTION) { if ((execute_data->opline->opcode == ZEND_DO_FCALL ||
execute_data->opline->opcode == ZEND_DO_UCALL ||
execute_data->opline->opcode == ZEND_DO_FCALL_BY_NAME) &&
execute_data->func->type == ZEND_USER_FUNCTION) {
zend_execute_ex = execute_ex; zend_execute_ex = execute_ex;
} }
PHPDBG_G(vmret) = execute_data->opline->handler(execute_data); PHPDBG_G(vmret) = execute_data->opline->handler(execute_data);

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 )

View file

@ -1,84 +0,0 @@
/*
* Program: Unix compatibility routines
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 14 September 1996
* Last Edited: 14 August 1997
*
* Copyright 1997 by the University of Washington
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted, provided
* that the above copyright notice appears in all copies and that both the
* above copyright notice and this permission notice appear in supporting
* documentation, and that the name of the University of Washington not be
* used in advertising or publicity pertaining to distribution of the software
* without specific, written prior permission. This software is made available
* "as is", and
* THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
* WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
* NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
* (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
/* DEDICATION
* This file is dedicated to my dog, Unix, also known as Yun-chan and
* Unix J. Terwilliker Jehosophat Aloysius Monstrosity Animal Beast. Unix
* passed away at the age of 11 1/2 on September 14, 1996, 12:18 PM PDT, after
* a two-month bout with cirrhosis of the liver.
*
* He was a dear friend, and I miss him terribly.
*
* Lift a leg, Yunie. Luv ya forever!!!!
*/
#include "php.h"
#include <windows.h>
#include <io.h>
#include <errno.h>
#include "flock.h"
PHPAPI int flock(int fd, int op)
{
HANDLE hdl = (HANDLE) _get_osfhandle(fd);
DWORD low = 1, high = 0;
OVERLAPPED offset =
{0, 0, 0, 0, NULL};
if (hdl < 0)
return -1; /* error in file descriptor */
/* bug for bug compatible with Unix */
UnlockFileEx(hdl, 0, low, high, &offset);
switch (op & ~LOCK_NB) { /* translate to LockFileEx() op */
case LOCK_EX: /* exclusive */
if (LockFileEx(hdl, LOCKFILE_EXCLUSIVE_LOCK +
((op & LOCK_NB) ? LOCKFILE_FAIL_IMMEDIATELY : 0),
0, low, high, &offset))
return 0;
break;
case LOCK_SH: /* shared */
if (LockFileEx(hdl, ((op & LOCK_NB) ? LOCKFILE_FAIL_IMMEDIATELY : 0),
0, low, high, &offset))
return 0;
break;
case LOCK_UN: /* unlock */
return 0; /* always succeeds */
default: /* default */
break;
}
errno = EINVAL; /* bad call */
return -1;
}

View file

@ -1,11 +0,0 @@
#define fsync _commit
#define ftruncate chsize
/* For flock() emulation */
#define LOCK_SH 1
#define LOCK_EX 2
#define LOCK_NB 4
#define LOCK_UN 8
PHPAPI int flock(int fd, int op);