Skip to content

Commit 8b85a9c

Browse files
committed
Preload unlinked classes, remove preload autoload
1 parent f78216f commit 8b85a9c

File tree

8 files changed

+35
-157
lines changed

8 files changed

+35
-157
lines changed

Zend/zend.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ ZEND_API char *(*zend_getenv)(const char *name, size_t name_len);
8585
ZEND_API zend_string *(*zend_resolve_path)(zend_string *filename);
8686
ZEND_API zend_result (*zend_post_startup_cb)(void) = NULL;
8787
ZEND_API void (*zend_post_shutdown_cb)(void) = NULL;
88-
ZEND_API zend_result (*zend_preload_autoload)(zend_string *filename) = NULL;
8988

9089
/* This callback must be signal handler safe! */
9190
void (*zend_on_timeout)(int seconds);

Zend/zend.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -332,9 +332,6 @@ extern ZEND_API zend_string *(*zend_resolve_path)(zend_string *filename);
332332
extern ZEND_API zend_result (*zend_post_startup_cb)(void);
333333
extern ZEND_API void (*zend_post_shutdown_cb)(void);
334334

335-
/* Callback for loading of not preloaded part of the script */
336-
extern ZEND_API zend_result (*zend_preload_autoload)(zend_string *filename);
337-
338335
ZEND_API ZEND_COLD void zend_error(int type, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3);
339336
ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_noreturn(int type, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3);
340337
/* For custom format specifiers like H */

Zend/zend_compile.c

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,9 +1104,16 @@ ZEND_API zend_class_entry *zend_bind_class_in_slot(
11041104
zval *class_table_slot, zval *lcname, zend_string *lc_parent_name)
11051105
{
11061106
zend_class_entry *ce = Z_PTR_P(class_table_slot);
1107-
zval *zv = zend_hash_set_bucket_key(
1108-
EG(class_table), (Bucket *) class_table_slot, Z_STR_P(lcname));
1109-
if (UNEXPECTED(!zv)) {
1107+
bool is_preloaded =
1108+
(ce->ce_flags & ZEND_ACC_PRELOADED) && !(CG(compiler_options) & ZEND_COMPILE_PRELOAD);
1109+
bool success;
1110+
if (EXPECTED(!is_preloaded)) {
1111+
success = zend_hash_set_bucket_key(EG(class_table), (Bucket*) class_table_slot, Z_STR_P(lcname)) != NULL;
1112+
} else {
1113+
/* If preloading is used, don't replace the existing bucket, add a new one. */
1114+
success = zend_hash_add_ptr(EG(class_table), Z_STR_P(lcname), ce) != NULL;
1115+
}
1116+
if (UNEXPECTED(!success)) {
11101117
zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare %s %s, because the name is already in use", zend_get_object_type(ce), ZSTR_VAL(ce->name));
11111118
return NULL;
11121119
}
@@ -1120,9 +1127,13 @@ ZEND_API zend_class_entry *zend_bind_class_in_slot(
11201127
return ce;
11211128
}
11221129

1123-
/* Reload bucket pointer, the hash table may have been reallocated */
1124-
zv = zend_hash_find(EG(class_table), Z_STR_P(lcname));
1125-
zend_hash_set_bucket_key(EG(class_table), (Bucket *) zv, Z_STR_P(lcname + 1));
1130+
if (!is_preloaded) {
1131+
/* Reload bucket pointer, the hash table may have been reallocated */
1132+
zval *zv = zend_hash_find(EG(class_table), Z_STR_P(lcname));
1133+
zend_hash_set_bucket_key(EG(class_table), (Bucket *) zv, Z_STR_P(lcname + 1));
1134+
} else {
1135+
zend_hash_del(EG(class_table), Z_STR_P(lcname));
1136+
}
11261137
return NULL;
11271138
}
11281139

@@ -1137,23 +1148,9 @@ ZEND_API zend_result do_bind_class(zval *lcname, zend_string *lc_parent_name) /*
11371148

11381149
if (UNEXPECTED(!zv)) {
11391150
ce = zend_hash_find_ptr(EG(class_table), Z_STR_P(lcname));
1140-
if (ce) {
1141-
zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare %s %s, because the name is already in use", zend_get_object_type(ce), ZSTR_VAL(ce->name));
1142-
return FAILURE;
1143-
} else {
1144-
do {
1145-
ZEND_ASSERT(EG(current_execute_data)->func->op_array.fn_flags & ZEND_ACC_PRELOADED);
1146-
if (zend_preload_autoload
1147-
&& zend_preload_autoload(EG(current_execute_data)->func->op_array.filename) == SUCCESS) {
1148-
zv = zend_hash_find_known_hash(EG(class_table), Z_STR_P(rtd_key));
1149-
if (EXPECTED(zv != NULL)) {
1150-
break;
1151-
}
1152-
}
1153-
zend_error_noreturn(E_ERROR, "Class %s wasn't preloaded", Z_STRVAL_P(lcname));
1154-
return FAILURE;
1155-
} while (0);
1156-
}
1151+
ZEND_ASSERT(ce);
1152+
zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare %s %s, because the name is already in use", zend_get_object_type(ce), ZSTR_VAL(ce->name));
1153+
return FAILURE;
11571154
}
11581155

11591156
/* Register the derived class */

Zend/zend_inheritance.c

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3017,12 +3017,19 @@ static inheritance_status zend_can_early_bind(zend_class_entry *ce, zend_class_e
30173017

30183018
static zend_always_inline bool register_early_bound_ce(zval *delayed_early_binding, zend_string *lcname, zend_class_entry *ce) {
30193019
if (delayed_early_binding) {
3020-
if (UNEXPECTED(zend_hash_set_bucket_key(EG(class_table), (Bucket *)delayed_early_binding, lcname) == NULL)) {
3021-
zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare %s %s, because the name is already in use", zend_get_object_type(ce), ZSTR_VAL(ce->name));
3022-
return false;
3020+
if (EXPECTED(!(ce->ce_flags & ZEND_ACC_PRELOADED))) {
3021+
if (zend_hash_set_bucket_key(EG(class_table), (Bucket *)delayed_early_binding, lcname) != NULL) {
3022+
Z_CE_P(delayed_early_binding) = ce;
3023+
return true;
3024+
}
3025+
} else {
3026+
/* If preloading is used, don't replace the existing bucket, add a new one. */
3027+
if (zend_hash_add_ptr(EG(class_table), lcname, ce) != NULL) {
3028+
return true;
3029+
}
30233030
}
3024-
Z_CE_P(delayed_early_binding) = ce;
3025-
return true;
3031+
zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare %s %s, because the name is already in use", zend_get_object_type(ce), ZSTR_VAL(ce->name));
3032+
return false;
30263033
}
30273034
return zend_hash_add_ptr(CG(class_table), lcname, ce) != NULL;
30283035
}

Zend/zend_opcode.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ ZEND_API void destroy_zend_class(zval *zv)
277277
zend_class_entry *ce = Z_PTR_P(zv);
278278
zend_function *fn;
279279

280-
if (ce->ce_flags & (ZEND_ACC_IMMUTABLE|ZEND_ACC_PRELOADED)) {
280+
if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
281281
return;
282282
}
283283

Zend/zend_vm_def.h

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7609,20 +7609,6 @@ ZEND_VM_HANDLER(146, ZEND_DECLARE_ANON_CLASS, ANY, ANY, CACHE_SLOT)
76097609
if (UNEXPECTED(ce == NULL)) {
76107610
zend_string *rtd_key = Z_STR_P(RT_CONSTANT(opline, opline->op1));
76117611
zv = zend_hash_find_known_hash(EG(class_table), rtd_key);
7612-
if (UNEXPECTED(zv == NULL)) {
7613-
SAVE_OPLINE();
7614-
do {
7615-
ZEND_ASSERT(EX(func)->op_array.fn_flags & ZEND_ACC_PRELOADED);
7616-
if (zend_preload_autoload
7617-
&& zend_preload_autoload(EX(func)->op_array.filename) == SUCCESS) {
7618-
zv = zend_hash_find_known_hash(EG(class_table), rtd_key);
7619-
if (EXPECTED(zv != NULL)) {
7620-
break;
7621-
}
7622-
}
7623-
zend_error_noreturn(E_ERROR, "Anonymous class wasn't preloaded");
7624-
} while (0);
7625-
}
76267612
ZEND_ASSERT(zv != NULL);
76277613
ce = Z_CE_P(zv);
76287614
if (!(ce->ce_flags & ZEND_ACC_LINKED)) {

Zend/zend_vm_execute.h

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2937,20 +2937,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_ANON_CLASS_SPEC_HANDLE
29372937
if (UNEXPECTED(ce == NULL)) {
29382938
zend_string *rtd_key = Z_STR_P(RT_CONSTANT(opline, opline->op1));
29392939
zv = zend_hash_find_known_hash(EG(class_table), rtd_key);
2940-
if (UNEXPECTED(zv == NULL)) {
2941-
SAVE_OPLINE();
2942-
do {
2943-
ZEND_ASSERT(EX(func)->op_array.fn_flags & ZEND_ACC_PRELOADED);
2944-
if (zend_preload_autoload
2945-
&& zend_preload_autoload(EX(func)->op_array.filename) == SUCCESS) {
2946-
zv = zend_hash_find_known_hash(EG(class_table), rtd_key);
2947-
if (EXPECTED(zv != NULL)) {
2948-
break;
2949-
}
2950-
}
2951-
zend_error_noreturn(E_ERROR, "Anonymous class wasn't preloaded");
2952-
} while (0);
2953-
}
29542940
ZEND_ASSERT(zv != NULL);
29552941
ce = Z_CE_P(zv);
29562942
if (!(ce->ce_flags & ZEND_ACC_LINKED)) {

ext/opcache/ZendAccelerator.c

Lines changed: 2 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -3911,8 +3911,6 @@ static void preload_link(void)
39113911
zend_string *key;
39123912
bool found, changed;
39133913
uint32_t i;
3914-
dtor_func_t orig_dtor;
3915-
zend_function *function;
39163914

39173915
/* Resolve class dependencies */
39183916
do {
@@ -4040,9 +4038,7 @@ static void preload_link(void)
40404038
} ZEND_HASH_FOREACH_END();
40414039
} while (changed);
40424040

4043-
/* Move unlinked clases (and with unresolved constants) back to scripts */
4044-
orig_dtor = EG(class_table)->pDestructor;
4045-
EG(class_table)->pDestructor = NULL;
4041+
/* Warn for classes that could not be linked. */
40464042
ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL(EG(class_table), key, zv) {
40474043
ce = Z_PTR_P(zv);
40484044
if (ce->type == ZEND_INTERNAL_CLASS) {
@@ -4064,25 +4060,8 @@ static void preload_link(void)
40644060
ZSTR_VAL(ce->name), kind, name);
40654061
}
40664062
zend_string_release(key);
4067-
} else {
4068-
continue;
40694063
}
4070-
ce->ce_flags &= ~ZEND_ACC_PRELOADED;
4071-
ZEND_HASH_FOREACH_PTR(&ce->function_table, function) {
4072-
if (EXPECTED(function->type == ZEND_USER_FUNCTION)
4073-
&& function->common.scope == ce) {
4074-
function->common.fn_flags &= ~ZEND_ACC_PRELOADED;
4075-
}
4076-
} ZEND_HASH_FOREACH_END();
4077-
script = zend_hash_find_ptr(preload_scripts, ce->info.user.filename);
4078-
ZEND_ASSERT(script);
4079-
zend_hash_add(&script->script.class_table, key, zv);
4080-
ZVAL_UNDEF(zv);
4081-
zend_string_release(key);
4082-
EG(class_table)->nNumOfElements--;
40834064
} ZEND_HASH_FOREACH_END();
4084-
EG(class_table)->pDestructor = orig_dtor;
4085-
zend_hash_rehash(EG(class_table));
40864065

40874066
/* Remove DECLARE opcodes */
40884067
ZEND_HASH_FOREACH_PTR(preload_scripts, script) {
@@ -4096,7 +4075,7 @@ static void preload_link(void)
40964075
case ZEND_DECLARE_CLASS:
40974076
case ZEND_DECLARE_CLASS_DELAYED:
40984077
key = Z_STR_P(RT_CONSTANT(opline, opline->op1) + 1);
4099-
if (!zend_hash_exists(&script->script.class_table, key)) {
4078+
if (!zend_hash_exists(CG(class_table), key)) {
41004079
MAKE_NOP(opline);
41014080
}
41024081
break;
@@ -4414,8 +4393,6 @@ static zend_persistent_script* preload_script_in_shared_memory(zend_persistent_s
44144393
return new_persistent_script;
44154394
}
44164395

4417-
static zend_result preload_autoload(zend_string *filename);
4418-
44194396
static void preload_load(void)
44204397
{
44214398
/* Load into process tables */
@@ -4459,77 +4436,6 @@ static void preload_load(void)
44594436
memset((void **) ZEND_MAP_PTR_REAL_BASE(CG(map_ptr_base)) + old_map_ptr_last, 0,
44604437
(CG(map_ptr_last) - old_map_ptr_last) * sizeof(void *));
44614438
}
4462-
4463-
zend_preload_autoload = preload_autoload;
4464-
}
4465-
4466-
static zend_result preload_autoload(zend_string *filename)
4467-
{
4468-
zend_persistent_script *persistent_script;
4469-
zend_op_array *op_array;
4470-
zend_execute_data *old_execute_data;
4471-
zend_class_entry *old_fake_scope;
4472-
bool do_bailout = 0;
4473-
int ret = SUCCESS;
4474-
4475-
if (zend_hash_exists(&EG(included_files), filename)) {
4476-
return FAILURE;
4477-
}
4478-
4479-
persistent_script = zend_accel_hash_find(&ZCSG(hash), filename);
4480-
if (!persistent_script) {
4481-
return FAILURE;
4482-
}
4483-
4484-
zend_hash_add_empty_element(&EG(included_files), filename);
4485-
4486-
if (persistent_script->ping_auto_globals_mask & ~ZCG(auto_globals_mask)) {
4487-
zend_accel_set_auto_globals(persistent_script->ping_auto_globals_mask & ~ZCG(auto_globals_mask));
4488-
}
4489-
4490-
op_array = zend_accel_load_script(persistent_script, 1);
4491-
if (!op_array) {
4492-
return FAILURE;
4493-
}
4494-
4495-
/* Execute in global context */
4496-
old_execute_data = EG(current_execute_data);
4497-
EG(current_execute_data) = NULL;
4498-
old_fake_scope = EG(fake_scope);
4499-
EG(fake_scope) = NULL;
4500-
zend_exception_save();
4501-
4502-
zend_try {
4503-
zend_execute(op_array, NULL);
4504-
} zend_catch {
4505-
do_bailout = 1;
4506-
} zend_end_try();
4507-
4508-
if (EG(exception)) {
4509-
ret = FAILURE;
4510-
}
4511-
4512-
zend_exception_restore();
4513-
EG(fake_scope) = old_fake_scope;
4514-
EG(current_execute_data) = old_execute_data;
4515-
while (old_execute_data) {
4516-
if (old_execute_data->func && (ZEND_CALL_INFO(old_execute_data) & ZEND_CALL_HAS_SYMBOL_TABLE)) {
4517-
if (old_execute_data->symbol_table == &EG(symbol_table)) {
4518-
zend_attach_symbol_table(old_execute_data);
4519-
}
4520-
break;
4521-
}
4522-
old_execute_data = old_execute_data->prev_execute_data;
4523-
}
4524-
4525-
destroy_op_array(op_array);
4526-
efree_size(op_array, sizeof(zend_op_array));
4527-
4528-
if (do_bailout) {
4529-
zend_bailout();
4530-
}
4531-
4532-
return ret;
45334439
}
45344440

45354441
static int accel_preload(const char *config, bool in_child)

0 commit comments

Comments
 (0)