Skip to content

Commit 7c89f95

Browse files
committed
Preload unlinked classes, remove preload autoload
1 parent 8834cf0 commit 7c89f95

File tree

8 files changed

+70
-165
lines changed

8 files changed

+70
-165
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 & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1111,29 +1111,23 @@ ZEND_API zend_result do_bind_class(zval *lcname, zend_string *lc_parent_name) /*
11111111

11121112
if (UNEXPECTED(!zv)) {
11131113
ce = zend_hash_find_ptr(EG(class_table), Z_STR_P(lcname));
1114-
if (ce) {
1115-
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));
1116-
return FAILURE;
1117-
} else {
1118-
do {
1119-
ZEND_ASSERT(EG(current_execute_data)->func->op_array.fn_flags & ZEND_ACC_PRELOADED);
1120-
if (zend_preload_autoload
1121-
&& zend_preload_autoload(EG(current_execute_data)->func->op_array.filename) == SUCCESS) {
1122-
zv = zend_hash_find_known_hash(EG(class_table), Z_STR_P(rtd_key));
1123-
if (EXPECTED(zv != NULL)) {
1124-
break;
1125-
}
1126-
}
1127-
zend_error_noreturn(E_ERROR, "Class %s wasn't preloaded", Z_STRVAL_P(lcname));
1128-
return FAILURE;
1129-
} while (0);
1130-
}
1114+
ZEND_ASSERT(ce);
1115+
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));
1116+
return FAILURE;
11311117
}
11321118

11331119
/* Register the derived class */
11341120
ce = (zend_class_entry*)Z_PTR_P(zv);
1135-
zv = zend_hash_set_bucket_key(EG(class_table), (Bucket*)zv, Z_STR_P(lcname));
1136-
if (UNEXPECTED(!zv)) {
1121+
bool is_preloaded =
1122+
(ce->ce_flags & ZEND_ACC_PRELOADED) && !(CG(compiler_options) & ZEND_COMPILE_PRELOAD);
1123+
bool success;
1124+
if (EXPECTED(!is_preloaded)) {
1125+
success = zend_hash_set_bucket_key(EG(class_table), (Bucket*)zv, Z_STR_P(lcname)) != NULL;
1126+
} else {
1127+
/* If preloading is used, don't replace the existing bucket, add a new one. */
1128+
success = zend_hash_add_ptr(EG(class_table), Z_STR_P(lcname), ce) != NULL;
1129+
}
1130+
if (UNEXPECTED(!success)) {
11371131
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));
11381132
return FAILURE;
11391133
}
@@ -1144,9 +1138,13 @@ ZEND_API zend_result do_bind_class(zval *lcname, zend_string *lc_parent_name) /*
11441138

11451139
ce = zend_do_link_class(ce, lc_parent_name, Z_STR_P(lcname));
11461140
if (!ce) {
1147-
/* Reload bucket pointer, the hash table may have been reallocated */
1148-
zv = zend_hash_find(EG(class_table), Z_STR_P(lcname));
1149-
zend_hash_set_bucket_key(EG(class_table), (Bucket *) zv, Z_STR_P(rtd_key));
1141+
if (!is_preloaded) {
1142+
/* Reload bucket pointer, the hash table may have been reallocated */
1143+
zv = zend_hash_find(EG(class_table), Z_STR_P(lcname));
1144+
zend_hash_set_bucket_key(EG(class_table), (Bucket *) zv, Z_STR_P(rtd_key));
1145+
} else {
1146+
zend_hash_del(EG(class_table), Z_STR_P(lcname));
1147+
}
11501148
return FAILURE;
11511149
}
11521150

Zend/zend_inheritance.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3021,18 +3021,24 @@ zend_class_entry *zend_try_early_bind(zend_class_entry *ce, zend_class_entry *pa
30213021
zend_class_entry *proto = NULL;
30223022
zend_class_entry *orig_linking_class;
30233023
uint32_t is_cacheable = ce->ce_flags & ZEND_ACC_IMMUTABLE;
3024+
bool is_preloaded = ce->ce_flags & ZEND_ACC_PRELOADED;
30243025

30253026
UPDATE_IS_CACHEABLE(parent_ce);
30263027
if (is_cacheable) {
30273028
if (zend_inheritance_cache_get && zend_inheritance_cache_add) {
30283029
zend_class_entry *ret = zend_inheritance_cache_get(ce, parent_ce, NULL);
30293030
if (ret) {
30303031
if (delayed_early_binding) {
3031-
if (UNEXPECTED(zend_hash_set_bucket_key(EG(class_table), (Bucket*)delayed_early_binding, lcname) == NULL)) {
3032+
bool success = is_preloaded
3033+
? zend_hash_add_ptr(EG(class_table), lcname, ce) != NULL
3034+
: zend_hash_set_bucket_key(EG(class_table), (Bucket*)delayed_early_binding, lcname) != NULL;
3035+
if (UNEXPECTED(!success)) {
30323036
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));
30333037
return NULL;
30343038
}
3035-
Z_CE_P(delayed_early_binding) = ret;
3039+
if (!is_preloaded) {
3040+
Z_CE_P(delayed_early_binding) = ret;
3041+
}
30363042
} else {
30373043
if (UNEXPECTED(zend_hash_add_ptr(CG(class_table), lcname, ret) == NULL)) {
30383044
return NULL;
@@ -3064,11 +3070,16 @@ zend_class_entry *zend_try_early_bind(zend_class_entry *ce, zend_class_entry *pa
30643070
}
30653071

30663072
if (delayed_early_binding) {
3067-
if (UNEXPECTED(zend_hash_set_bucket_key(EG(class_table), (Bucket*)delayed_early_binding, lcname) == NULL)) {
3073+
bool success = is_preloaded
3074+
? zend_hash_add_ptr(EG(class_table), lcname, ce) != NULL
3075+
: zend_hash_set_bucket_key(EG(class_table), (Bucket*)delayed_early_binding, lcname) != NULL;
3076+
if (UNEXPECTED(!success)) {
30683077
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));
30693078
return NULL;
30703079
}
3071-
Z_CE_P(delayed_early_binding) = ce;
3080+
if (!is_preloaded) {
3081+
Z_CE_P(delayed_early_binding) = ce;
3082+
}
30723083
} else {
30733084
if (UNEXPECTED(zend_hash_add_ptr(CG(class_table), lcname, ce) == NULL)) {
30743085
return NULL;

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: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7592,15 +7592,26 @@ ZEND_VM_HANDLER(145, ZEND_DECLARE_CLASS_DELAYED, CONST, CONST)
75927592
if (zv) {
75937593
SAVE_OPLINE();
75947594
ce = Z_CE_P(zv);
7595-
zv = zend_hash_set_bucket_key(EG(class_table), (Bucket*)zv, Z_STR_P(lcname));
7596-
if (UNEXPECTED(!zv)) {
7595+
bool is_preloaded = ce->ce_flags & ZEND_ACC_PRELOADED;
7596+
bool success;
7597+
if (EXPECTED(!is_preloaded)) {
7598+
success = zend_hash_set_bucket_key(EG(class_table), (Bucket*)zv, Z_STR_P(lcname)) != NULL;
7599+
} else {
7600+
/* If preloading is used, don't replace the existing bucket, add a new one. */
7601+
success = zend_hash_add_ptr(EG(class_table), Z_STR_P(lcname), ce);
7602+
}
7603+
if (UNEXPECTED(!success)) {
75977604
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));
75987605
} else {
75997606
ce = zend_do_link_class(ce, Z_STR_P(RT_CONSTANT(opline, opline->op2)), Z_STR_P(lcname));
76007607
if (!ce) {
7601-
/* Reload bucket pointer, the hash table may have been reallocated */
7602-
zv = zend_hash_find(EG(class_table), Z_STR_P(lcname));
7603-
zend_hash_set_bucket_key(EG(class_table), (Bucket *) zv, Z_STR_P(lcname + 1));
7608+
if (!is_preloaded) {
7609+
/* Reload bucket pointer, the hash table may have been reallocated */
7610+
zv = zend_hash_find(EG(class_table), Z_STR_P(lcname));
7611+
zend_hash_set_bucket_key(EG(class_table), (Bucket *) zv, Z_STR_P(lcname + 1));
7612+
} else {
7613+
zend_hash_del(EG(class_table), Z_STR_P(lcname));
7614+
}
76047615
HANDLE_EXCEPTION();
76057616
}
76067617
}
@@ -7620,20 +7631,6 @@ ZEND_VM_HANDLER(146, ZEND_DECLARE_ANON_CLASS, ANY, ANY, CACHE_SLOT)
76207631
if (UNEXPECTED(ce == NULL)) {
76217632
zend_string *rtd_key = Z_STR_P(RT_CONSTANT(opline, opline->op1));
76227633
zv = zend_hash_find_known_hash(EG(class_table), rtd_key);
7623-
if (UNEXPECTED(zv == NULL)) {
7624-
SAVE_OPLINE();
7625-
do {
7626-
ZEND_ASSERT(EX(func)->op_array.fn_flags & ZEND_ACC_PRELOADED);
7627-
if (zend_preload_autoload
7628-
&& zend_preload_autoload(EX(func)->op_array.filename) == SUCCESS) {
7629-
zv = zend_hash_find_known_hash(EG(class_table), rtd_key);
7630-
if (EXPECTED(zv != NULL)) {
7631-
break;
7632-
}
7633-
}
7634-
zend_error_noreturn(E_ERROR, "Anonymous class wasn't preloaded");
7635-
} while (0);
7636-
}
76377634
ZEND_ASSERT(zv != NULL);
76387635
ce = Z_CE_P(zv);
76397636
if (!(ce->ce_flags & ZEND_ACC_LINKED)) {

Zend/zend_vm_execute.h

Lines changed: 16 additions & 19 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)) {
@@ -7365,15 +7351,26 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_CLASS_DELAYED_SPEC_CON
73657351
if (zv) {
73667352
SAVE_OPLINE();
73677353
ce = Z_CE_P(zv);
7368-
zv = zend_hash_set_bucket_key(EG(class_table), (Bucket*)zv, Z_STR_P(lcname));
7369-
if (UNEXPECTED(!zv)) {
7354+
bool is_preloaded = ce->ce_flags & ZEND_ACC_PRELOADED;
7355+
bool success;
7356+
if (EXPECTED(!is_preloaded)) {
7357+
success = zend_hash_set_bucket_key(EG(class_table), (Bucket*)zv, Z_STR_P(lcname)) != NULL;
7358+
} else {
7359+
/* If preloading is used, don't replace the existing bucket, add a new one. */
7360+
success = zend_hash_add_ptr(EG(class_table), Z_STR_P(lcname), ce);
7361+
}
7362+
if (UNEXPECTED(!success)) {
73707363
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));
73717364
} else {
73727365
ce = zend_do_link_class(ce, Z_STR_P(RT_CONSTANT(opline, opline->op2)), Z_STR_P(lcname));
73737366
if (!ce) {
7374-
/* Reload bucket pointer, the hash table may have been reallocated */
7375-
zv = zend_hash_find(EG(class_table), Z_STR_P(lcname));
7376-
zend_hash_set_bucket_key(EG(class_table), (Bucket *) zv, Z_STR_P(lcname + 1));
7367+
if (!is_preloaded) {
7368+
/* Reload bucket pointer, the hash table may have been reallocated */
7369+
zv = zend_hash_find(EG(class_table), Z_STR_P(lcname));
7370+
zend_hash_set_bucket_key(EG(class_table), (Bucket *) zv, Z_STR_P(lcname + 1));
7371+
} else {
7372+
zend_hash_del(EG(class_table), Z_STR_P(lcname));
7373+
}
73777374
HANDLE_EXCEPTION();
73787375
}
73797376
}

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)