case ZEND_RECV_INIT:
LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 1);
break;
- case ZEND_DECLARE_FUNCTION:
- LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 2);
- break;
case ZEND_DECLARE_CLASS:
case ZEND_DECLARE_CLASS_DELAYED:
LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 2);
bind_var_slot[opline->op2.constant] = opline->extended_value;
}
break;
- case ZEND_DECLARE_LAMBDA_FUNCTION:
case ZEND_DECLARE_ANON_CLASS:
case ZEND_DECLARE_CLASS_DELAYED:
opline->extended_value = cache_size;
return (type & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) != 0;
}
+static void zend_foreach_op_array_helper(
+ zend_op_array *op_array, zend_op_array_func_t func, void *context) {
+ func(op_array, context);
+ for (uint32_t i = 0; i < op_array->num_dynamic_func_defs; i++) {
+ func(op_array->dynamic_func_defs[i], context);
+ }
+}
+
void zend_foreach_op_array(zend_script *script, zend_op_array_func_t func, void *context)
{
zend_class_entry *ce;
zend_string *key;
zend_op_array *op_array;
- func(&script->main_op_array, context);
+ zend_foreach_op_array_helper(&script->main_op_array, func, context);
ZEND_HASH_FOREACH_PTR(&script->function_table, op_array) {
- func(op_array, context);
+ zend_foreach_op_array_helper(op_array, func, context);
} ZEND_HASH_FOREACH_END();
ZEND_HASH_FOREACH_STR_KEY_PTR(&script->class_table, key, ce) {
if (op_array->scope == ce
&& op_array->type == ZEND_USER_FUNCTION
&& !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
- func(op_array, context);
+ zend_foreach_op_array_helper(op_array, func, context);
}
} ZEND_HASH_FOREACH_END();
} ZEND_HASH_FOREACH_END();
--- /dev/null
+--TEST--
+Static variables in dynamically declared function (first use before dynamic def dtor)
+--FILE--
+<?php
+
+$code = <<<'CODE'
+if (1) {
+ function test() {
+ static $x = 0;
+ var_dump(++$x);
+ }
+ test();
+}
+CODE;
+eval($code);
+test();
+
+?>
+--EXPECT--
+int(1)
+int(2)
--- /dev/null
+--TEST--
+Static variables in dynamically declared function (first use after dynamic def dtor)
+--FILE--
+<?php
+
+$code = <<<'CODE'
+if (1) {
+ function test() {
+ static $x = 0;
+ var_dump(++$x);
+ }
+}
+CODE;
+eval($code);
+test();
+test();
+
+?>
+--EXPECT--
+int(1)
+int(2)
ret = zend_exception_error(EG(exception), E_ERROR);
}
}
+ zend_destroy_static_vars(op_array);
destroy_op_array(op_array);
efree_size(op_array, sizeof(zend_op_array));
} else if (type==ZEND_REQUIRE) {
zend_object_std_dtor(&closure->std);
if (closure->func.type == ZEND_USER_FUNCTION) {
- /* We shared static_variables with the original function.
- * Unshare now so we don't try to destroy them. */
- if (closure->func.op_array.fn_flags & ZEND_ACC_FAKE_CLOSURE) {
- ZEND_MAP_PTR_INIT(closure->func.op_array.static_variables_ptr, NULL);
+ /* We don't own the static variables of fake closures. */
+ if (!(closure->func.op_array.fn_flags & ZEND_ACC_FAKE_CLOSURE)) {
+ zend_destroy_static_vars(&closure->func.op_array);
}
destroy_op_array(&closure->func.op_array);
}
}
}
-ZEND_API zend_result do_bind_function(zval *lcname) /* {{{ */
+ZEND_API zend_result do_bind_function(zend_function *func, zval *lcname) /* {{{ */
{
- zend_function *function;
- zval *rtd_key, *zv;
-
- rtd_key = lcname + 1;
- zv = zend_hash_find_ex(EG(function_table), Z_STR_P(rtd_key), 1);
- if (UNEXPECTED(!zv)) {
- do_bind_function_error(Z_STR_P(lcname), NULL, 0);
+ zend_function *added_func = zend_hash_add_ptr(EG(function_table), Z_STR_P(lcname), func);
+ if (UNEXPECTED(!added_func)) {
+ do_bind_function_error(Z_STR_P(lcname), &func->op_array, 0);
return FAILURE;
}
- function = (zend_function*)Z_PTR_P(zv);
- if (UNEXPECTED(function->common.fn_flags & ZEND_ACC_PRELOADED)
- && !(CG(compiler_options) & ZEND_COMPILE_PRELOAD)) {
- zv = zend_hash_add(EG(function_table), Z_STR_P(lcname), zv);
- } else {
- zv = zend_hash_set_bucket_key(EG(function_table), (Bucket*)zv, Z_STR_P(lcname));
+
+ if (func->op_array.refcount) {
+ ++*func->op_array.refcount;
}
- if (UNEXPECTED(!zv)) {
- do_bind_function_error(Z_STR_P(lcname), &function->op_array, 0);
- return FAILURE;
+ if (func->common.function_name) {
+ zend_string_addref(func->common.function_name);
}
return SUCCESS;
}
}
/* }}} */
+static uint32_t zend_add_dynamic_func_def(zend_op_array *def) {
+ zend_op_array *op_array = CG(active_op_array);
+ uint32_t def_offset = op_array->num_dynamic_func_defs++;
+ op_array->dynamic_func_defs = erealloc(
+ op_array->dynamic_func_defs, op_array->num_dynamic_func_defs * sizeof(zend_op_array *));
+ op_array->dynamic_func_defs[def_offset] = def;
+ return def_offset;
+}
+
static void zend_begin_func_decl(znode *result, zend_op_array *op_array, zend_ast_decl *decl, bool toplevel) /* {{{ */
{
- zend_string *unqualified_name, *name, *lcname, *key;
+ zend_string *unqualified_name, *name, *lcname;
zend_op *opline;
unqualified_name = decl->name;
return;
}
- /* Generate RTD keys until we find one that isn't in use yet. */
- key = NULL;
- do {
- zend_tmp_string_release(key);
- key = zend_build_runtime_definition_key(lcname, decl->start_lineno);
- } while (!zend_hash_add_ptr(CG(function_table), key, op_array));
-
+ uint32_t func_ref = zend_add_dynamic_func_def(op_array);
if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
opline = zend_emit_op_tmp(result, ZEND_DECLARE_LAMBDA_FUNCTION, NULL, NULL);
- opline->extended_value = zend_alloc_cache_slot();
- opline->op1_type = IS_CONST;
- LITERAL_STR(opline->op1, key);
+ opline->op2.num = func_ref;
} else {
opline = get_next_op();
opline->opcode = ZEND_DECLARE_FUNCTION;
opline->op1_type = IS_CONST;
LITERAL_STR(opline->op1, zend_string_copy(lcname));
- /* RTD key is placed after lcname literal in op1 */
- zend_add_literal_string(&key);
+ opline->op2.num = func_ref;
}
zend_string_release_ex(lcname, 0);
}
zend_string *doc_comment;
int last_literal;
+ uint32_t num_dynamic_func_defs;
zval *literals;
+ /* Functions that are declared dynamically are stored here and
+ * referenced by index from opcodes. */
+ zend_op_array **dynamic_func_defs;
+
void *reserved[ZEND_MAX_RESERVED_RESOURCES];
};
/* parser-driven code generators */
void zend_do_free(znode *op1);
-ZEND_API zend_result do_bind_function(zval *lcname);
+ZEND_API zend_result do_bind_function(zend_function *func, zval *lcname);
ZEND_API zend_result do_bind_class(zval *lcname, zend_string *lc_parent_name);
ZEND_API uint32_t zend_build_delayed_early_binding_list(const zend_op_array *op_array);
ZEND_API void zend_do_delayed_early_binding(zend_op_array *op_array, uint32_t first_early_binding_opline);
ZEND_API int open_file_for_scanning(zend_file_handle *file_handle);
ZEND_API void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_size);
ZEND_API void destroy_op_array(zend_op_array *op_array);
+ZEND_API void zend_destroy_static_vars(zend_op_array *op_array);
ZEND_API void zend_destroy_file_handle(zend_file_handle *file_handle);
ZEND_API void zend_cleanup_mutable_class_data(zend_class_entry *ce);
ZEND_API void zend_cleanup_internal_class_data(zend_class_entry *ce);
}
EG(no_extensions)=0;
+ zend_destroy_static_vars(new_op_array);
destroy_op_array(new_op_array);
efree_size(new_op_array, sizeof(zend_op_array));
retval = SUCCESS;
op_array->last_literal = 0;
op_array->literals = NULL;
+ op_array->num_dynamic_func_defs = 0;
+ op_array->dynamic_func_defs = NULL;
+
ZEND_MAP_PTR_INIT(op_array->run_time_cache, NULL);
op_array->cache_size = zend_op_array_extension_handles * sizeof(void*);
}
}
-ZEND_API void destroy_op_array(zend_op_array *op_array)
+ZEND_API void zend_destroy_static_vars(zend_op_array *op_array)
{
- uint32_t i;
-
if (ZEND_MAP_PTR(op_array->static_variables_ptr)) {
HashTable *ht = ZEND_MAP_PTR_GET(op_array->static_variables_ptr);
if (ht) {
zend_array_destroy(ht);
+ ZEND_MAP_PTR_SET(op_array->static_variables_ptr, NULL);
}
}
+}
+
+ZEND_API void destroy_op_array(zend_op_array *op_array)
+{
+ uint32_t i;
if ((op_array->fn_flags & ZEND_ACC_HEAP_RT_CACHE)
&& ZEND_MAP_PTR(op_array->run_time_cache)) {
if (op_array->static_variables) {
zend_array_destroy(op_array->static_variables);
}
+ if (op_array->num_dynamic_func_defs) {
+ for (i = 0; i < op_array->num_dynamic_func_defs; i++) {
+ /* Closures overwrite static_variables in their copy.
+ * Make sure to destroy them when the prototype function is destroyed. */
+ if (op_array->dynamic_func_defs[i]->static_variables
+ && (op_array->dynamic_func_defs[i]->fn_flags & ZEND_ACC_CLOSURE)) {
+ zend_array_destroy(op_array->dynamic_func_defs[i]->static_variables);
+ op_array->dynamic_func_defs[i]->static_variables = NULL;
+ }
+ destroy_op_array(op_array->dynamic_func_defs[i]);
+ }
+ efree(op_array->dynamic_func_defs);
+ }
}
static void zend_update_extended_stmts(zend_op_array *op_array)
ZEND_VM_LEAVE();
} else if (EXPECTED((call_info & ZEND_CALL_TOP) == 0)) {
zend_detach_symbol_table(execute_data);
+ zend_destroy_static_vars(&EX(func)->op_array);
destroy_op_array(&EX(func)->op_array);
efree_size(EX(func), sizeof(zend_op_array));
#ifdef ZEND_PREFER_RELOAD
zend_vm_stack_free_call_frame(call);
}
+ zend_destroy_static_vars(new_op_array);
destroy_op_array(new_op_array);
efree_size(new_op_array, sizeof(zend_op_array));
if (UNEXPECTED(EG(exception) != NULL)) {
ZEND_VM_NEXT_OPCODE();
}
-ZEND_VM_HANDLER(141, ZEND_DECLARE_FUNCTION, ANY, ANY)
+ZEND_VM_HANDLER(141, ZEND_DECLARE_FUNCTION, ANY, NUM)
{
+ zend_function *func;
USE_OPLINE
SAVE_OPLINE();
- do_bind_function(RT_CONSTANT(opline, opline->op1));
+ func = (zend_function *) EX(func)->op_array.dynamic_func_defs[opline->op2.num];
+ do_bind_function(func, RT_CONSTANT(opline, opline->op1));
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
-ZEND_VM_HANDLER(142, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, UNUSED, CACHE_SLOT)
+ZEND_VM_HANDLER(142, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, NUM)
{
USE_OPLINE
zend_function *func;
- zval *zfunc;
zval *object;
zend_class_entry *called_scope;
- func = CACHED_PTR(opline->extended_value);
- if (UNEXPECTED(func == NULL)) {
- zfunc = zend_hash_find_ex(EG(function_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)), 1);
- ZEND_ASSERT(zfunc != NULL);
- func = Z_FUNC_P(zfunc);
- ZEND_ASSERT(func->type == ZEND_USER_FUNCTION);
- CACHE_PTR(opline->extended_value, func);
- }
-
+ func = (zend_function *) EX(func)->op_array.dynamic_func_defs[opline->op2.num];
if (Z_TYPE(EX(This)) == IS_OBJECT) {
called_scope = Z_OBJCE(EX(This));
if (UNEXPECTED((func->common.fn_flags & ZEND_ACC_STATIC) ||
ZEND_VM_LEAVE();
} else if (EXPECTED((call_info & ZEND_CALL_TOP) == 0)) {
zend_detach_symbol_table(execute_data);
+ zend_destroy_static_vars(&EX(func)->op_array);
destroy_op_array(&EX(func)->op_array);
efree_size(EX(func), sizeof(zend_op_array));
#ifdef ZEND_PREFER_RELOAD
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_FUNCTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
+ zend_function *func;
USE_OPLINE
SAVE_OPLINE();
- do_bind_function(RT_CONSTANT(opline, opline->op1));
+ func = (zend_function *) EX(func)->op_array.dynamic_func_defs[opline->op2.num];
+ do_bind_function(func, RT_CONSTANT(opline, opline->op1));
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
zend_vm_stack_free_call_frame(call);
}
+ zend_destroy_static_vars(new_op_array);
destroy_op_array(new_op_array);
efree_size(new_op_array, sizeof(zend_op_array));
if (UNEXPECTED(EG(exception) != NULL)) {
zend_vm_stack_free_call_frame(call);
}
+ zend_destroy_static_vars(new_op_array);
destroy_op_array(new_op_array);
efree_size(new_op_array, sizeof(zend_op_array));
if (UNEXPECTED(EG(exception) != NULL)) {
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
+static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+ USE_OPLINE
+ zend_function *func;
+ zval *object;
+ zend_class_entry *called_scope;
+
+ func = (zend_function *) EX(func)->op_array.dynamic_func_defs[opline->op2.num];
+ if (Z_TYPE(EX(This)) == IS_OBJECT) {
+ called_scope = Z_OBJCE(EX(This));
+ if (UNEXPECTED((func->common.fn_flags & ZEND_ACC_STATIC) ||
+ (EX(func)->common.fn_flags & ZEND_ACC_STATIC))) {
+ object = NULL;
+ } else {
+ object = &EX(This);
+ }
+ } else {
+ called_scope = Z_CE(EX(This));
+ object = NULL;
+ }
+ zend_create_closure(EX_VAR(opline->result.var), func,
+ EX(func)->op_array.scope, called_scope, object);
+
+ ZEND_VM_NEXT_OPCODE();
+}
+
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_FROM_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
}
/* No specialization for op_types (CONST|TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR) */
-static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
-{
- USE_OPLINE
- zend_function *func;
- zval *zfunc;
- zval *object;
- zend_class_entry *called_scope;
-
- func = CACHED_PTR(opline->extended_value);
- if (UNEXPECTED(func == NULL)) {
- zfunc = zend_hash_find_ex(EG(function_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)), 1);
- ZEND_ASSERT(zfunc != NULL);
- func = Z_FUNC_P(zfunc);
- ZEND_ASSERT(func->type == ZEND_USER_FUNCTION);
- CACHE_PTR(opline->extended_value, func);
- }
-
- if (Z_TYPE(EX(This)) == IS_OBJECT) {
- called_scope = Z_OBJCE(EX(This));
- if (UNEXPECTED((func->common.fn_flags & ZEND_ACC_STATIC) ||
- (EX(func)->common.fn_flags & ZEND_ACC_STATIC))) {
- object = NULL;
- } else {
- object = &EX(This);
- }
- } else {
- called_scope = Z_CE(EX(This));
- object = NULL;
- }
- zend_create_closure(EX_VAR(opline->result.var), func,
- EX(func)->op_array.scope, called_scope, object);
-
- ZEND_VM_NEXT_OPCODE();
-}
-
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
zend_vm_stack_free_call_frame(call);
}
+ zend_destroy_static_vars(new_op_array);
destroy_op_array(new_op_array);
efree_size(new_op_array, sizeof(zend_op_array));
if (UNEXPECTED(EG(exception) != NULL)) {
zend_vm_stack_free_call_frame(call);
}
+ zend_destroy_static_vars(new_op_array);
destroy_op_array(new_op_array);
efree_size(new_op_array, sizeof(zend_op_array));
if (UNEXPECTED(EG(exception) != NULL)) {
(void*)&&ZEND_NULL_LABEL,
(void*)&&ZEND_MAKE_REF_SPEC_CV_UNUSED_LABEL,
(void*)&&ZEND_DECLARE_FUNCTION_SPEC_LABEL,
- (void*)&&ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_UNUSED_LABEL,
+ (void*)&&ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_LABEL,
(void*)&&ZEND_DECLARE_CONST_SPEC_CONST_CONST_LABEL,
(void*)&&ZEND_DECLARE_CLASS_SPEC_CONST_LABEL,
(void*)&&ZEND_DECLARE_CLASS_DELAYED_SPEC_CONST_CONST_LABEL,
ZEND_VM_LEAVE();
} else if (EXPECTED((call_info & ZEND_CALL_TOP) == 0)) {
zend_detach_symbol_table(execute_data);
+ zend_destroy_static_vars(&EX(func)->op_array);
destroy_op_array(&EX(func)->op_array);
efree_size(EX(func), sizeof(zend_op_array));
#ifdef ZEND_PREFER_RELOAD
VM_TRACE(ZEND_DECLARE_CLASS_SPEC_CONST)
ZEND_DECLARE_CLASS_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
HYBRID_BREAK();
+ HYBRID_CASE(ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST):
+ VM_TRACE(ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST)
+ ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+ HYBRID_BREAK();
HYBRID_CASE(ZEND_YIELD_FROM_SPEC_CONST):
VM_TRACE(ZEND_YIELD_FROM_SPEC_CONST)
ZEND_YIELD_FROM_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
VM_TRACE(ZEND_ISSET_ISEMPTY_VAR_SPEC_CONST_UNUSED)
ZEND_ISSET_ISEMPTY_VAR_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
HYBRID_BREAK();
- HYBRID_CASE(ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_UNUSED):
- VM_TRACE(ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_UNUSED)
- ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
- HYBRID_BREAK();
HYBRID_CASE(ZEND_YIELD_SPEC_CONST_UNUSED):
VM_TRACE(ZEND_YIELD_SPEC_CONST_UNUSED)
ZEND_YIELD_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
ZEND_NULL_HANDLER,
ZEND_MAKE_REF_SPEC_CV_UNUSED_HANDLER,
ZEND_DECLARE_FUNCTION_SPEC_HANDLER,
- ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_UNUSED_HANDLER,
+ ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_HANDLER,
ZEND_DECLARE_CONST_SPEC_CONST_CONST_HANDLER,
ZEND_DECLARE_CLASS_SPEC_CONST_HANDLER,
ZEND_DECLARE_CLASS_DELAYED_SPEC_CONST_CONST_HANDLER,
_(2286, ZEND_MAKE_REF_SPEC_VAR_UNUSED) \
_(2288, ZEND_MAKE_REF_SPEC_CV_UNUSED) \
_(2289, ZEND_DECLARE_FUNCTION_SPEC) \
- _(2290, ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_UNUSED) \
+ _(2290, ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST) \
_(2291, ZEND_DECLARE_CONST_SPEC_CONST_CONST) \
_(2292, ZEND_DECLARE_CLASS_SPEC_CONST) \
_(2293, ZEND_DECLARE_CLASS_DELAYED_SPEC_CONST_CONST) \
0x00047305,
0x00000000,
0x00000101,
- 0x00000000,
- 0x00040103,
+ 0x00001000,
+ 0x00001003,
0x00000303,
0x00000003,
0x00000303,
ZEND_ASSERT(p->key);
t = zend_hash_find_ex(target, p->key, 1);
if (UNEXPECTED(t != NULL)) {
- if (EXPECTED(ZSTR_LEN(p->key) > 0) && EXPECTED(ZSTR_VAL(p->key)[0] == 0)) {
- /* Runtime definition key. There are two circumstances under which the key can
- * already be defined:
- * 1. The file has been re-included without being changed in the meantime. In
- * this case we can keep the old value, because we know that the definition
- * hasn't changed.
- * 2. The file has been changed in the meantime, but the RTD key ends up colliding.
- * This would be a bug.
- * As we can't distinguish these cases, we assume that it is 1. and keep the old
- * value. */
- continue;
- } else {
- goto failure;
- }
- } else {
- _zend_hash_append_ptr_ex(target, p->key, Z_PTR(p->val), 1);
+ goto failure;
}
+ _zend_hash_append_ptr_ex(target, p->key, Z_PTR(p->val), 1);
}
target->nInternalPointer = 0;
return;
t = zend_hash_find_ex(target, p->key, 1);
if (UNEXPECTED(t != NULL)) {
if (EXPECTED(ZSTR_LEN(p->key) > 0) && EXPECTED(ZSTR_VAL(p->key)[0] == 0)) {
- /* See comment in zend_accel_function_hash_copy(). */
+ /* Runtime definition key. There are two circumstances under which the key can
+ * already be defined:
+ * 1. The file has been re-included without being changed in the meantime. In
+ * this case we can keep the old value, because we know that the definition
+ * hasn't changed.
+ * 2. The file has been changed in the meantime, but the RTD key ends up colliding.
+ * This would be a bug.
+ * As we can't distinguish these cases, we assume that it is 1. and keep the old
+ * value. */
continue;
} else if (UNEXPECTED(!ZCG(accel_directives).ignore_dups)) {
zend_class_entry *ce1 = Z_PTR(p->val);
}
}
+ if (op_array->num_dynamic_func_defs) {
+ zend_op_array **defs;
+ SERIALIZE_PTR(op_array->dynamic_func_defs);
+ defs = op_array->dynamic_func_defs;
+ UNSERIALIZE_PTR(defs);
+ for (uint32_t i = 0; i < op_array->num_dynamic_func_defs; i++) {
+ zend_op_array *def;
+ SERIALIZE_PTR(defs[i]);
+ def = defs[i];
+ UNSERIALIZE_PTR(def);
+ zend_file_cache_serialize_op_array(def, script, info, buf);
+ }
+ }
+
SERIALIZE_STR(op_array->function_name);
SERIALIZE_STR(op_array->filename);
SERIALIZE_PTR(op_array->live_range);
}
}
+ if (op_array->num_dynamic_func_defs) {
+ UNSERIALIZE_PTR(op_array->dynamic_func_defs);
+ for (uint32_t i = 0; i < op_array->num_dynamic_func_defs; i++) {
+ UNSERIALIZE_PTR(op_array->dynamic_func_defs[i]);
+ zend_file_cache_unserialize_op_array(op_array->dynamic_func_defs[i], script, buf);
+ }
+ }
+
UNSERIALIZE_STR(op_array->function_name);
UNSERIALIZE_STR(op_array->filename);
UNSERIALIZE_PTR(op_array->live_range);
typedef void (*zend_persist_func_t)(zval*);
static void zend_persist_zval(zval *z);
+static void zend_persist_op_array(zval *zv);
static const uint32_t uninitialized_bucket[-HT_MIN_MASK] =
{HT_INVALID_IDX, HT_INVALID_IDX};
}
}
+ if (op_array->num_dynamic_func_defs) {
+ op_array->dynamic_func_defs = zend_shared_memdup_put_free(
+ op_array->dynamic_func_defs, sizeof(zend_function *) * op_array->num_dynamic_func_defs);
+ for (uint32_t i = 0; i < op_array->num_dynamic_func_defs; i++) {
+ zval tmp;
+ ZVAL_PTR(&tmp, op_array->dynamic_func_defs[i]);
+ zend_persist_op_array(&tmp);
+ op_array->dynamic_func_defs[i] = Z_PTR(tmp);
+ }
+ }
+
ZCG(mem) = (void*)((char*)ZCG(mem) + ZEND_ALIGNED_SIZE(zend_extensions_op_array_persist(op_array, ZCG(mem))));
#ifdef HAVE_JIT
static void zend_persist_op_array(zval *zv)
{
zend_op_array *op_array = Z_PTR_P(zv);
-
+ zend_op_array *old_op_array;
ZEND_ASSERT(op_array->type == ZEND_USER_FUNCTION);
- op_array = Z_PTR_P(zv) = zend_shared_memdup(Z_PTR_P(zv), sizeof(zend_op_array));
- zend_persist_op_array_ex(op_array, NULL);
- if (!ZCG(current_persistent_script)->corrupted) {
- op_array->fn_flags |= ZEND_ACC_IMMUTABLE;
- ZEND_MAP_PTR_NEW(op_array->run_time_cache);
- if (op_array->static_variables) {
- ZEND_MAP_PTR_NEW(op_array->static_variables_ptr);
+
+ old_op_array = zend_shared_alloc_get_xlat_entry(op_array);
+ if (!old_op_array) {
+ op_array = Z_PTR_P(zv) = zend_shared_memdup_put(Z_PTR_P(zv), sizeof(zend_op_array));
+ zend_persist_op_array_ex(op_array, NULL);
+ if (!ZCG(current_persistent_script)->corrupted) {
+ op_array->fn_flags |= ZEND_ACC_IMMUTABLE;
+ ZEND_MAP_PTR_NEW(op_array->run_time_cache);
+ if (op_array->static_variables) {
+ ZEND_MAP_PTR_NEW(op_array->static_variables_ptr);
+ }
}
+ } else {
+ /* This can happen during preloading, if a dynamic function definition is declared. */
}
}
} while (0)
static void zend_persist_zval_calc(zval *z);
+static void zend_persist_op_array_calc(zval *zv);
static void zend_hash_persist_calc(HashTable *ht)
{
}
}
+ if (op_array->num_dynamic_func_defs) {
+ ADD_SIZE(sizeof(void *) * op_array->num_dynamic_func_defs);
+ for (uint32_t i = 0; i < op_array->num_dynamic_func_defs; i++) {
+ zval tmp;
+ ZVAL_PTR(&tmp, op_array->dynamic_func_defs[i]);
+ zend_persist_op_array_calc(&tmp);
+ }
+ }
+
ADD_SIZE(ZEND_ALIGNED_SIZE(zend_extensions_op_array_persist_calc(op_array)));
}
static void zend_persist_op_array_calc(zval *zv)
{
zend_op_array *op_array = Z_PTR_P(zv);
-
ZEND_ASSERT(op_array->type == ZEND_USER_FUNCTION);
- ADD_SIZE(sizeof(zend_op_array));
- zend_persist_op_array_calc_ex(Z_PTR_P(zv));
+ if (!zend_shared_alloc_get_xlat_entry(op_array)) {
+ zend_shared_alloc_register_xlat_entry(op_array, op_array);
+ ADD_SIZE(sizeof(zend_op_array));
+ zend_persist_op_array_calc_ex(op_array);
+ } else {
+ /* This can happen during preloading, if a dynamic function definition is declared. */
+ }
}
static void zend_persist_class_method_calc(zval *zv)
efree(decode);
opline++;
} while (opcode++ < end);
+
+ for (uint32_t i = 0; i < op_array->num_dynamic_func_defs; i++) {
+ zend_op_array *def = op_array->dynamic_func_defs[i];
+ phpdbg_out("\ndynamic def: %i, function name: %.*s\n",
+ i, (int) ZSTR_LEN(def->function_name), ZSTR_VAL(def->function_name));
+ phpdbg_print_function_helper((zend_function *) def);
+ }
}
} break;