Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

An attempt to implemnt "preloading" ability. #3538

Closed
wants to merge 65 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
9409958
Immutable clases and op_arrays
dstogov Oct 15, 2018
0810ce0
An attempt to implemnt "preloading" ability.
dstogov Oct 15, 2018
f76a955
Fixed incorrect signal handlers overriding
dstogov Oct 16, 2018
c78277a
Preloadsing support for opcache restart
dstogov Oct 16, 2018
a06f0f3
Merge branch 'master' into immutable
dstogov Oct 17, 2018
9ef07c8
typo
dstogov Oct 17, 2018
8dadca8
Hide offset encoding magic in ZEND_MAP_PTR_IS_OFFSET(), ZEND_MAP_PTR_…
dstogov Oct 17, 2018
d5a4108
Removed duplicate code
dstogov Oct 17, 2018
b945548
Removed redundand assertion
dstogov Oct 17, 2018
c63fc5d
Moved static class members initialization into the proper place.
dstogov Oct 17, 2018
0276ea5
Added type cast
dstogov Oct 17, 2018
ad7a78b
Added comment
dstogov Oct 17, 2018
21e0beb
Merge branch 'immutable' into preload
dstogov Oct 17, 2018
4740dab
Reverted back ce->iterator_funcs_ptr. Initialize ce->iterator_funcs_p…
dstogov Oct 17, 2018
d33908a
Merge branch 'immutable' into preload
dstogov Oct 17, 2018
cd0c36c
Merge branch 'master' into immutable
dstogov Oct 17, 2018
632b30b
Merge branch 'immutable' into preload
dstogov Oct 17, 2018
ac8f45f
Merge branch 'master' into preload
dstogov Oct 17, 2018
a609520
Merge branch 'master' into preload
dstogov Oct 17, 2018
b0139dc
Merge branch 'master' into preload
dstogov Oct 19, 2018
b67e283
Don't preload functions declared at run-time.
dstogov Oct 19, 2018
a2ba970
Added test
dstogov Oct 19, 2018
093e8b1
Added warning message
dstogov Oct 19, 2018
811f20a
Added information about preloading to opcache_get_status()
dstogov Oct 22, 2018
e4a7ef0
Merge branch 'master' into preload
dstogov Oct 24, 2018
b5ffba0
Merge branch 'master' into preload
dstogov Oct 24, 2018
d9fc51b
Merge branch 'master' into preload
dstogov Oct 24, 2018
aabe685
Merge branch 'master' into preload
dstogov Oct 25, 2018
d70cb10
cleanup
dstogov Oct 25, 2018
26587a9
eol
dstogov Oct 25, 2018
4f57c1e
Cleanup (move preload_shutdown() call to better place)
dstogov Oct 25, 2018
e3c65db
Merge branch 'master' into preload
dstogov Oct 25, 2018
ab9a40f
Added support for preloaded classes/functions in ZTS build
dstogov Oct 25, 2018
a594a61
Cleanup
dstogov Oct 25, 2018
4531fbf
Disable linking and preloading of classes those parent or one of inte…
dstogov Oct 25, 2018
e6b76ec
Merge branch 'master' into preload
dstogov Oct 25, 2018
3a2d1bc
Support for builds without ZEND_SIGNALS
dstogov Oct 25, 2018
0fe9ea1
Removed dead code
dstogov Oct 26, 2018
d7fbb4d
Restore preload state if it was already loaded in another process.
dstogov Oct 26, 2018
386c9d3
Merge branch 'master' into preload
dstogov Oct 29, 2018
6d4b22c
Override SAPI.ub_write and SAPI.flush for preloading
dstogov Oct 29, 2018
17a3cb4
Execute zend_post_startup() with module_initialized flag set.
dstogov Oct 29, 2018
0a24d7b
Avoid use-after-free in main thread
dstogov Oct 29, 2018
310631c
Stop Apache if PHP wasn't started successful.
dstogov Oct 29, 2018
c559f22
Merge branch 'master' into preload
dstogov Oct 29, 2018
2f697ef
typo
dstogov Oct 29, 2018
e806cb7
Fixed double-free
dstogov Oct 29, 2018
5620495
Merge branch 'master' into preload
dstogov Oct 30, 2018
eb6e2c5
Merge branch 'master' into preload
dstogov Oct 30, 2018
38ab7ef
Merge branch 'master' into preload
dstogov Oct 30, 2018
68c4f99
Added test
dstogov Oct 30, 2018
4a57b5d
Fixed preloading of classes linked with traits
dstogov Oct 30, 2018
7a20781
Added test
dstogov Oct 30, 2018
36b644f
Merge branch 'master' into preload
dstogov Nov 1, 2018
aea85c6
Prevent inlining of method copied from trait
dstogov Nov 1, 2018
3a9d90f
Fexed resolution of method clones
dstogov Nov 1, 2018
b610467
Merge branch 'master' into preload
dstogov Nov 2, 2018
0bd17bd
EG(*) may be not initializd at this point - use CG(*).
dstogov Nov 2, 2018
9b0a53e
We don't need preload_restart() here
dstogov Nov 2, 2018
7ae3a47
Merge branch 'master' into preload
dstogov Nov 6, 2018
8d3429c
Fixed preloading of references to internal classes.
dstogov Nov 6, 2018
08ffc9a
Resolve constants only in linked classes
dstogov Nov 7, 2018
cef0d67
Support for class aliasses
dstogov Nov 7, 2018
34645ae
Don't preload constants defined during preload script excution.
dstogov Nov 8, 2018
45fdd03
Properly resolve magic method of preloaded classes inherited from int…
dstogov Nov 9, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion Zend/zend.c
Original file line number Diff line number Diff line change
Expand Up @@ -566,8 +566,13 @@ static void auto_global_dtor(zval *zv) /* {{{ */
static void function_copy_ctor(zval *zv) /* {{{ */
{
zend_function *old_func = Z_FUNC_P(zv);
zend_function *func = pemalloc(sizeof(zend_internal_function), 1);
zend_function *func;

if (old_func->type == ZEND_USER_FUNCTION) {
ZEND_ASSERT(old_func->op_array.fn_flags & ZEND_ACC_IMMUTABLE);
return;
}
func = pemalloc(sizeof(zend_internal_function), 1);
Z_FUNC_P(zv) = func;
memcpy(func, old_func, sizeof(zend_internal_function));
function_add_ref(func);
Expand Down Expand Up @@ -977,14 +982,17 @@ int zend_post_startup(void) /* {{{ */

zend_destroy_rsrc_list(&EG(persistent_list));
free(compiler_globals->function_table);
compiler_globals->function_table = NULL;
free(compiler_globals->class_table);
compiler_globals->class_table = NULL;
if ((script_encoding_list = (zend_encoding **)compiler_globals->script_encoding_list)) {
compiler_globals_ctor(compiler_globals);
compiler_globals->script_encoding_list = (const zend_encoding **)script_encoding_list;
} else {
compiler_globals_ctor(compiler_globals);
}
free(EG(zend_constants));
EG(zend_constants) = NULL;

executor_globals_ctor(executor_globals);
global_persistent_list = &EG(persistent_list);
Expand Down
5 changes: 4 additions & 1 deletion Zend/zend_compile.h
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ typedef struct _zend_oparray_context {
/* User class has methods with static variables | | | */
#define ZEND_HAS_STATIC_IN_METHODS (1 << 15) /* X | | | */
/* | | | */
/* Function Flags (unused: 26...30) | | | */
/* Function Flags (unused: 27...30) | | | */
/* ============== | | | */
/* | | | */
/* deprecation flag | | | */
Expand Down Expand Up @@ -310,6 +310,9 @@ typedef struct _zend_oparray_context {
/* internal function is allocated at arena (int only) | | | */
#define ZEND_ACC_ARENA_ALLOCATED (1 << 25) /* | X | | */
/* | | | */
/* op_array is a clone of trait method | | | */
#define ZEND_ACC_TRAIT_CLONE (1 << 26) /* | X | | */
/* | | | */
/* op_array uses strict mode types | | | */
#define ZEND_ACC_STRICT_TYPES (1 << 31) /* | X | | */

Expand Down
43 changes: 43 additions & 0 deletions Zend/zend_execute_API.c
Original file line number Diff line number Diff line change
Expand Up @@ -340,13 +340,56 @@ void shutdown_executor(void) /* {{{ */
destroy_op_array(&func->op_array);
zend_string_release_ex(key, 0);
} ZEND_HASH_FOREACH_END_DEL();

/* Cleanup preloaded immutable functions */
ZEND_HASH_REVERSE_FOREACH_VAL(EG(function_table), zv) {
zend_op_array *op_array = Z_PTR_P(zv);
if (op_array->type == ZEND_INTERNAL_FUNCTION) {
break;
}
ZEND_ASSERT(op_array->fn_flags & ZEND_ACC_IMMUTABLE);
if (op_array->static_variables) {
HashTable *ht = ZEND_MAP_PTR_GET(op_array->static_variables_ptr);
if (ht) {
ZEND_ASSERT(GC_REFCOUNT(ht) == 1);
zend_array_destroy(ht);
}
}
} ZEND_HASH_FOREACH_END();

ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL(EG(class_table), key, zv) {
if (_idx == EG(persistent_classes_count)) {
break;
}
destroy_zend_class(zv);
zend_string_release_ex(key, 0);
} ZEND_HASH_FOREACH_END_DEL();

/* Cleanup preloaded immutable classes */
ZEND_HASH_REVERSE_FOREACH_VAL(EG(class_table), zv) {
zend_class_entry *ce = Z_PTR_P(zv);
if (ce->type == ZEND_INTERNAL_CLASS) {
break;
}
ZEND_ASSERT(ce->ce_flags & ZEND_ACC_IMMUTABLE);
if (ce->default_static_members_count) {
zend_cleanup_internal_class_data(ce);
}
if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) {
zend_op_array *op_array;
ZEND_HASH_FOREACH_PTR(&ce->function_table, op_array) {
if (op_array->type == ZEND_USER_FUNCTION) {
if (op_array->static_variables) {
HashTable *ht = ZEND_MAP_PTR_GET(op_array->static_variables_ptr);
if (ht) {
ZEND_ASSERT(GC_REFCOUNT(ht) == 1);
zend_array_destroy(ht);
}
}
}
} ZEND_HASH_FOREACH_END();
}
} ZEND_HASH_FOREACH_END();
}

zend_cleanup_internal_classes();
Expand Down
1 change: 1 addition & 0 deletions Zend/zend_inheritance.c
Original file line number Diff line number Diff line change
Expand Up @@ -1308,6 +1308,7 @@ static void zend_add_trait_method(zend_class_entry *ce, const char *name, zend_s
} else {
new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
memcpy(new_fn, fn, sizeof(zend_op_array));
new_fn->op_array.fn_flags |= ZEND_ACC_TRAIT_CLONE;
new_fn->op_array.fn_flags &= ~ZEND_ACC_IMMUTABLE;
}
function_add_ref(new_fn);
Expand Down
4 changes: 3 additions & 1 deletion Zend/zend_opcode.c
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,9 @@ void zend_class_add_ref(zval *zv)
{
zend_class_entry *ce = Z_PTR_P(zv);

ce->refcount++;
if (!(ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
ce->refcount++;
}
}

ZEND_API void destroy_op_array(zend_op_array *op_array)
Expand Down
7 changes: 5 additions & 2 deletions Zend/zend_signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -322,8 +322,10 @@ void zend_signal_activate(void)

memcpy(&SIGG(handlers), &global_orig_handlers, sizeof(global_orig_handlers));

for (x = 0; x < sizeof(zend_sigs) / sizeof(*zend_sigs); x++) {
zend_signal_register(zend_sigs[x], zend_signal_handler_defer);
if (SIGG(reset)) {
for (x = 0; x < sizeof(zend_sigs) / sizeof(*zend_sigs); x++) {
zend_signal_register(zend_sigs[x], zend_signal_handler_defer);
}
}

SIGG(active) = 1;
Expand Down Expand Up @@ -365,6 +367,7 @@ static void zend_signal_globals_ctor(zend_signal_globals_t *zend_signal_globals)
size_t x;

memset(zend_signal_globals, 0, sizeof(*zend_signal_globals));
zend_signal_globals->reset = 1;

for (x = 0; x < sizeof(zend_signal_globals->pstorage) / sizeof(*zend_signal_globals->pstorage); ++x) {
zend_signal_queue_t *queue = &zend_signal_globals->pstorage[x];
Expand Down
1 change: 1 addition & 0 deletions Zend/zend_signal.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ typedef struct _zend_signal_globals_t {
int running; /* in signal handler execution */
int active; /* internal signal handling is enabled */
zend_bool check; /* check for replaced handlers on shutdown */
zend_bool reset; /* reset signal handlers on each request */
zend_signal_entry_t handlers[NSIG];
zend_signal_queue_t pstorage[ZEND_SIGNAL_QUEUE_SIZE], *phead, *ptail, *pavail; /* pending queue */
} zend_signal_globals_t;
Expand Down
2 changes: 2 additions & 0 deletions ext/opcache/Optimizer/optimize_func_calls.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ static void zend_try_inline_call(zend_op_array *op_array, zend_op *fcall, zend_o
{
if (func->type == ZEND_USER_FUNCTION
&& !(func->op_array.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_HAS_TYPE_HINTS))
/* TODO: function copied from trait may be inconsistent ??? */
&& !(func->op_array.fn_flags & (ZEND_ACC_TRAIT_CLONE))
&& fcall->extended_value >= func->op_array.required_num_args
&& func->op_array.opcodes[func->op_array.num_args].opcode == ZEND_RETURN) {

Expand Down
8 changes: 6 additions & 2 deletions ext/opcache/Optimizer/zend_call_graph.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ static int zend_op_array_collect(zend_call_graph *call_graph, zend_op_array *op_
static int zend_foreach_op_array(zend_call_graph *call_graph, zend_script *script, zend_op_array_func_t func)
{
zend_class_entry *ce;
zend_string *key;
zend_op_array *op_array;

if (func(call_graph, &script->main_op_array) != SUCCESS) {
Expand All @@ -65,9 +66,12 @@ static int zend_foreach_op_array(zend_call_graph *call_graph, zend_script *scrip
}
} ZEND_HASH_FOREACH_END();

ZEND_HASH_FOREACH_PTR(&script->class_table, ce) {
ZEND_HASH_FOREACH_STR_KEY_PTR(&script->class_table, key, ce) {
if (ce->refcount > 1 && !zend_string_equals_ci(key, ce->name)) {
continue;
}
ZEND_HASH_FOREACH_PTR(&ce->function_table, op_array) {
if (op_array->scope == ce) {
if (op_array->scope == ce && !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
if (func(call_graph, op_array) != SUCCESS) {
return FAILURE;
}
Expand Down
24 changes: 18 additions & 6 deletions ext/opcache/Optimizer/zend_optimizer.c
Original file line number Diff line number Diff line change
Expand Up @@ -1421,6 +1421,7 @@ static void zend_adjust_fcall_stack_size_graph(zend_op_array *op_array)
int zend_optimize_script(zend_script *script, zend_long optimization_level, zend_long debug_level)
{
zend_class_entry *ce;
zend_string *key;
zend_op_array *op_array;
zend_string *name;
zend_optimizer_ctx ctx;
Expand All @@ -1440,9 +1441,12 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend
zend_optimize_op_array(op_array, &ctx);
} ZEND_HASH_FOREACH_END();

ZEND_HASH_FOREACH_PTR(&script->class_table, ce) {
ZEND_HASH_FOREACH_STR_KEY_PTR(&script->class_table, key, ce) {
if (ce->refcount > 1 && !zend_string_equals_ci(key, ce->name)) {
continue;
}
ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, name, op_array) {
if (op_array->scope == ce) {
if (op_array->scope == ce && !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
zend_optimize_op_array(op_array, &ctx);
}
} ZEND_HASH_FOREACH_END();
Expand Down Expand Up @@ -1544,27 +1548,35 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend
zend_adjust_fcall_stack_size(op_array, &ctx);
} ZEND_HASH_FOREACH_END();

ZEND_HASH_FOREACH_PTR(&script->class_table, ce) {
ZEND_HASH_FOREACH_STR_KEY_PTR(&script->class_table, key, ce) {
if (ce->refcount > 1 && !zend_string_equals_ci(key, ce->name)) {
continue;
}
ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, name, op_array) {
if (op_array->scope == ce) {
if (op_array->scope == ce && !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
zend_adjust_fcall_stack_size(op_array, &ctx);
}
} ZEND_HASH_FOREACH_END();
} ZEND_HASH_FOREACH_END();
}

ZEND_HASH_FOREACH_PTR(&script->class_table, ce) {
ZEND_HASH_FOREACH_STR_KEY_PTR(&script->class_table, key, ce) {
if (ce->refcount > 1 && !zend_string_equals_ci(key, ce->name)) {
continue;
}
ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, name, op_array) {
if (op_array->scope != ce && op_array->type == ZEND_USER_FUNCTION) {
zend_op_array *orig_op_array =
zend_hash_find_ptr(&op_array->scope->function_table, name);

ZEND_ASSERT(orig_op_array != NULL);
if (orig_op_array != op_array) {
uint32_t fn_flags = op_array->fn_flags;
zend_function *prototype = op_array->prototype;
HashTable *ht = op_array->static_variables;

*op_array = *orig_op_array;
op_array->fn_flags = fn_flags;
op_array->prototype = prototype;
op_array->static_variables = ht;
}
Expand All @@ -1582,7 +1594,7 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend

ZEND_HASH_FOREACH_PTR(&script->class_table, ce) {
ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, name, op_array) {
if (op_array->scope == ce) {
if (op_array->scope == ce && !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
zend_dump_op_array(op_array, ZEND_DUMP_RT_CONSTANTS, "after optimizer", NULL);
}
} ZEND_HASH_FOREACH_END();
Expand Down
Loading