Skip to content

Commit 11f39c6

Browse files
committed
Opcache support
1 parent f384d8a commit 11f39c6

17 files changed

+519
-101
lines changed

Zend/Optimizer/compact_literals.c

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,11 @@
2424
#include "Optimizer/zend_optimizer.h"
2525
#include "Optimizer/zend_optimizer_internal.h"
2626
#include "zend_API.h"
27+
#include "zend_compile.h"
2728
#include "zend_constants.h"
2829
#include "zend_execute.h"
30+
#include "zend_string.h"
31+
#include "zend_types.h"
2932
#include "zend_vm.h"
3033
#include "zend_extensions.h"
3134

@@ -35,6 +38,9 @@
3538
#define LITERAL_STATIC_METHOD 2
3639
#define LITERAL_STATIC_PROPERTY 3
3740

41+
// TODO: temp hack
42+
#define LITERAL_PNR_AND_KEY (1<<7)
43+
3844
typedef struct _literal_info {
3945
uint8_t num_related;
4046
} literal_info;
@@ -245,7 +251,7 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
245251
break;
246252
case ZEND_NEW:
247253
if (opline->op1_type == IS_CONST) {
248-
LITERAL_INFO(opline->op1.constant, 2);
254+
LITERAL_INFO(opline->op1.constant, 2 | LITERAL_PNR_AND_KEY);
249255
}
250256
break;
251257
case ZEND_DECLARE_CLASS:
@@ -312,6 +318,10 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
312318
memset(map, 0, op_array->last_literal * sizeof(int));
313319
for (i = 0; i < op_array->last_literal; i++) {
314320
if (!info[i].num_related) {
321+
// TODO: temp hack
322+
if (Z_TYPE(op_array->literals[i]) == IS_PNR) {
323+
zend_pnr_destroy(Z_PNR(op_array->literals[i]));
324+
}
315325
/* unset literal */
316326
zval_ptr_dtor_nogc(&op_array->literals[i]);
317327
continue;
@@ -443,6 +453,67 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
443453
}
444454
break;
445455
}
456+
case IS_PNR: {
457+
ZEND_ASSERT(info[i].num_related & LITERAL_PNR_AND_KEY);
458+
ZEND_ASSERT(Z_TYPE(op_array->literals[i+1]) == IS_STRING);
459+
460+
uint8_t num_related = info[i].num_related & ~LITERAL_PNR_AND_KEY;
461+
ZEND_ASSERT(num_related == 2);
462+
463+
zend_packed_name_reference pnr = Z_PNR(op_array->literals[i]);
464+
zend_string *base_key = Z_STR(op_array->literals[i+1]);
465+
zend_string *key;
466+
if (ZEND_PNR_IS_COMPLEX(pnr)) {
467+
key = ZEND_PNR_COMPLEX_GET_KEY(pnr);
468+
} else {
469+
key = ZEND_PNR_SIMPLE_GET_NAME(pnr);
470+
}
471+
key = zend_string_concat2(
472+
ZSTR_VAL(key), ZSTR_LEN(key)+1,
473+
ZSTR_VAL(base_key), ZSTR_LEN(base_key));
474+
bias_key(key, 300 + num_related - 1);
475+
476+
if ((pos = zend_hash_find(&hash, key)) != NULL) {
477+
ZEND_ASSERT(Z_TYPE(op_array->literals[Z_LVAL_P(pos)]) == IS_PNR &&
478+
Z_TYPE(op_array->literals[Z_LVAL_P(pos)+1]) == IS_STRING &&
479+
info[i].num_related == info[Z_LVAL_P(pos)].num_related);
480+
zend_string_release_ex(key, 0);
481+
map[i] = Z_LVAL_P(pos);
482+
zend_packed_name_reference pnr2 = Z_PNR(op_array->literals[i]);
483+
if (ZEND_PNR_IS_SIMPLE(pnr2)) {
484+
zend_string_release(ZEND_PNR_SIMPLE_GET_NAME(pnr2));
485+
} else {
486+
zend_name_reference *class_ref = ZEND_PNR_COMPLEX_GET_REF(pnr2);
487+
zend_string_release(class_ref->name);
488+
zend_string_release(class_ref->key);
489+
}
490+
n = num_related;
491+
while (n > 1) {
492+
i++;
493+
zval_ptr_dtor_nogc(&op_array->literals[i]);
494+
n--;
495+
}
496+
} else {
497+
map[i] = j;
498+
ZVAL_LONG(&zv, j);
499+
zend_hash_add_new(&hash, key, &zv);
500+
zend_string_release_ex(key, 0);
501+
if (i != j) {
502+
op_array->literals[j] = op_array->literals[i];
503+
info[j] = info[i];
504+
}
505+
j++;
506+
n = num_related;
507+
while (n > 1) {
508+
i++;
509+
if (i != j) op_array->literals[j] = op_array->literals[i];
510+
j++;
511+
n--;
512+
}
513+
}
514+
515+
break;
516+
}
446517
case IS_ARRAY:
447518
ZEND_ASSERT(info[i].num_related == 1);
448519
if (zend_hash_num_elements(Z_ARRVAL(op_array->literals[i])) == 0) {

Zend/Optimizer/zend_dump.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
#include "zend_func_info.h"
2424
#include "zend_call_graph.h"
2525
#include "zend_dump.h"
26+
#include "zend_smart_str.h"
2627
#include "ext/standard/php_string.h"
28+
#include "zend_types.h"
2729

2830
void zend_dump_ht(HashTable *ht)
2931
{
@@ -76,6 +78,39 @@ void zend_dump_const(const zval *zv)
7678
case IS_ARRAY:
7779
fprintf(stderr, " array(...)");
7880
break;
81+
case IS_PNR: {
82+
zend_packed_name_reference pnr = Z_PNR_P(zv);
83+
zend_string *name;
84+
const zend_type_list *type_args;
85+
ZEND_PNR_UNPACK(pnr, name, type_args);
86+
87+
smart_str str = {0};
88+
smart_str_append(&str, name);
89+
90+
if (type_args != &zend_empty_type_list) {
91+
smart_str_appendc(&str, '<');
92+
zend_type *single_type;
93+
ZEND_TYPE_LIST_FOREACH((zend_type_list*)type_args, single_type) {
94+
if (single_type != type_args->types) {
95+
smart_str_appendc(&str, ',');
96+
}
97+
zend_string *type_str = zend_type_to_string(*single_type, NULL);
98+
smart_str_append(&str, type_str);
99+
zend_string_release(type_str);
100+
} ZEND_TYPE_LIST_FOREACH_END();
101+
smart_str_appendc(&str, '>');
102+
}
103+
104+
name = smart_str_extract(&str);
105+
zend_string *escaped_string = php_addcslashes(name, "\0..\37\"\\\177..\377", 2);
106+
zend_string_release(name);
107+
108+
fprintf(stderr, " pnr(\"%s\")", ZSTR_VAL(escaped_string));
109+
110+
zend_string_release(escaped_string);
111+
112+
break;
113+
}
79114
default:
80115
fprintf(stderr, " zval(type=%d)", Z_TYPE_P(zv));
81116
break;

Zend/Optimizer/zend_inference.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@ END_EXTERN_C()
148148
static zend_always_inline uint32_t _const_op_type(const zval *zv) {
149149
if (Z_TYPE_P(zv) == IS_CONSTANT_AST) {
150150
return MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY;
151+
} else if (Z_TYPE_P(zv) == IS_PNR) {
152+
return MAY_BE_STRING;
151153
} else if (Z_TYPE_P(zv) == IS_ARRAY) {
152154
return zend_array_type_info(zv);
153155
} else {

Zend/Optimizer/zend_optimizer.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "zend_API.h"
2525
#include "zend_constants.h"
2626
#include "zend_execute.h"
27+
#include "zend_types.h"
2728
#include "zend_vm.h"
2829
#include "zend_cfg.h"
2930
#include "zend_func_info.h"
@@ -323,11 +324,13 @@ bool zend_optimizer_update_op1_const(zend_op_array *op_array,
323324
zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
324325
break;
325326
case ZEND_NEW:
326-
REQUIRES_STRING(val);
327-
drop_leading_backslash(val);
327+
if (Z_TYPE_P(val) != IS_PNR) {
328+
return 0;
329+
}
330+
// TODO drop_leading_backslash(val);
328331
opline->op1.constant = zend_optimizer_add_literal(op_array, val);
329332
opline->op2.num = alloc_cache_slots(op_array, 1);
330-
zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
333+
zend_optimizer_add_literal_string(op_array, zend_string_tolower(ZEND_PNR_GET_NAME(Z_PNR_P(val))));
331334
break;
332335
case ZEND_INIT_STATIC_METHOD_CALL:
333336
REQUIRES_STRING(val);
@@ -816,9 +819,9 @@ zend_class_entry *zend_optimizer_get_class_entry_from_op1(
816819
const zend_script *script, const zend_op_array *op_array, const zend_op *opline) {
817820
if (opline->op1_type == IS_CONST) {
818821
zval *op1 = CRT_CONSTANT(opline->op1);
819-
if (Z_TYPE_P(op1) == IS_STRING) {
820-
return zend_optimizer_get_class_entry(script, op_array, Z_STR_P(op1 + 1));
821-
}
822+
ZEND_ASSERT(Z_TYPE_P(op1) == IS_PNR || Z_TYPE_P(op1) == IS_STRING);
823+
ZEND_ASSERT(Z_TYPE_P(op1 + 1) == IS_STRING);
824+
return zend_optimizer_get_class_entry(script, op_array, Z_STR_P(op1 + 1));
822825
} else if (opline->op1_type == IS_UNUSED && op_array->scope
823826
&& !(op_array->scope->ce_flags & ZEND_ACC_TRAIT)
824827
&& (opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF) {

Zend/zend_compile.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1930,6 +1930,16 @@ static zend_packed_name_reference zend_compile_pnr(
19301930
}
19311931
}
19321932

1933+
ZEND_API void zend_pnr_destroy(zend_packed_name_reference pnr) {
1934+
if (ZEND_PNR_IS_SIMPLE(pnr)) {
1935+
zend_string_release(ZEND_PNR_SIMPLE_GET_NAME(pnr));
1936+
} else {
1937+
zend_name_reference *name_ref = ZEND_PNR_COMPLEX_GET_REF(pnr);
1938+
zend_string_release(name_ref->name);
1939+
zend_string_release(name_ref->key);
1940+
}
1941+
}
1942+
19331943
static zend_packed_name_reference zend_compile_default_pnr(
19341944
zend_ast *class_ast, const char *type) {
19351945
zend_ast *name_ast = class_ast->child[0];
@@ -8410,6 +8420,7 @@ zend_class_entry *zend_init_class_entry_header(zend_class_entry_storage *ptr, ze
84108420
zend_class_entry *ce = (zend_class_entry *) ((char *) ptr + ZEND_CLASS_ENTRY_HEADER_SIZE);
84118421
ref->ce = ce;
84128422
ref->key = key;
8423+
zend_string_addref(key);
84138424
ref->args.num_types = 0;
84148425
return ce;
84158426
}

Zend/zend_compile.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -868,6 +868,7 @@ ZEND_API void zend_cleanup_mutable_class_data(zend_class_entry *ce);
868868
ZEND_API void zend_cleanup_internal_class_data(zend_class_entry *ce);
869869
ZEND_API void zend_type_release(zend_type type, bool persistent);
870870
ZEND_API zend_string *zend_create_member_string(zend_string *class_name, zend_string *member_name);
871+
ZEND_API void zend_pnr_destroy(zend_packed_name_reference pnr);
871872

872873
void zend_packed_name_reference_release(zend_packed_name_reference ref, bool persistent);
873874

Zend/zend_execute.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,6 @@ ZEND_API zend_class_entry *zend_fetch_class(zend_string *class_name, uint32_t fe
391391
ZEND_API zend_class_entry *zend_fetch_class_with_scope(zend_string *class_name, uint32_t fetch_type, zend_class_entry *scope);
392392
ZEND_API zend_class_entry *zend_fetch_class_by_name(zend_string *class_name, zend_string *lcname, uint32_t fetch_type);
393393
ZEND_API zend_class_reference *zend_fetch_generic_class_by_ref(zend_name_reference *name_ref, zend_string *base_key, uint32_t fetch_type);
394-
ZEND_API zend_class_reference *zend_register_generic_class(zend_name_reference *name_ref, zend_class_entry *ce);
395394

396395
ZEND_API zend_function * ZEND_FASTCALL zend_fetch_function(zend_string *name);
397396
ZEND_API zend_function * ZEND_FASTCALL zend_fetch_function_str(const char *name, size_t len);

Zend/zend_execute_API.c

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1123,19 +1123,6 @@ ZEND_API bool zend_is_valid_class_name(zend_string *name) {
11231123
return 1;
11241124
}
11251125

1126-
ZEND_API zend_class_reference *zend_register_generic_class(zend_name_reference *name_ref, zend_class_entry *ce)
1127-
{
1128-
zend_class_reference *class_ref = zend_build_class_reference(name_ref, ce);
1129-
if (!UNEXPECTED(class_ref)) {
1130-
return NULL;
1131-
}
1132-
1133-
void *ptr = zend_hash_add_ptr(&EG(generic_class_table), name_ref->key, class_ref);
1134-
ZEND_ASSERT(ptr);
1135-
1136-
return class_ref;
1137-
}
1138-
11391126
ZEND_API zend_class_reference *zend_lookup_generic_class(zend_name_reference *name_ref, zend_string *base_key, uint32_t flags) /* {{{ */
11401127
{
11411128
zend_class_entry *ce = NULL;
@@ -1169,7 +1156,15 @@ ZEND_API zend_class_reference *zend_lookup_generic_class(zend_name_reference *na
11691156
return NULL;
11701157
}
11711158

1172-
return zend_register_generic_class(name_ref, ce);
1159+
zend_class_reference *class_ref = zend_build_class_reference(name_ref, ce);
1160+
if (!UNEXPECTED(class_ref)) {
1161+
return NULL;
1162+
}
1163+
1164+
void *ptr = zend_hash_add_ptr(&EG(generic_class_table), name_ref->key, class_ref);
1165+
ZEND_ASSERT(ptr);
1166+
1167+
return class_ref;
11731168
}
11741169

11751170
ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string *key, uint32_t flags) /* {{{ */

Zend/zend_inheritance.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "zend_attributes.h"
3131
#include "zend_constants.h"
3232
#include "zend_observer.h"
33+
#include "zend_string.h"
3334
#include "zend_types.h"
3435

3536
ZEND_API zend_class_entry* (*zend_inheritance_cache_get)(zend_class_entry *ce, zend_class_entry *parent, zend_class_entry **traits_and_interfaces) = NULL;
@@ -1625,17 +1626,23 @@ static void update_parents(zend_class_entry *ce, zend_class_entry *parent_ce) {
16251626
pemalloc(sizeof(zend_class_reference *) * (parent_ce->num_parents + 1),
16261627
ce->type == ZEND_INTERNAL_CLASS);
16271628
if (ce->parent_name) {
1629+
zend_string *key;
16281630
if (ZEND_PNR_IS_COMPLEX(ce->parent_name)) {
16291631
/* Ownership of the type arguments has been taken by generic arg binding. */
16301632
zend_name_reference *ref = ZEND_PNR_COMPLEX_GET_REF(ce->parent_name);
16311633
zend_string_release(ref->name);
1634+
key = ZEND_PNR_COMPLEX_GET_KEY(ce->parent_name);
1635+
zend_string_addref(key);
16321636
// efree(ref);
16331637
} else {
16341638
zend_string_release(ZEND_PNR_SIMPLE_GET_NAME(ce->parent_name));
1639+
key = ZEND_CE_TO_REF(ce)->key;
1640+
zend_string_addref(key);
16351641
}
16361642

16371643
zend_class_reference *ref = emalloc(ZEND_CLASS_REF_SIZE(parent_ce->num_generic_params));
16381644
ref->ce = parent_ce;
1645+
ref->key = key;
16391646
ref->args.num_types = parent_ce->num_generic_params;
16401647
generic_args -= ref->args.num_types;
16411648
memcpy(ref->args.types, generic_args, sizeof(zend_type) * ref->args.num_types);
@@ -1652,6 +1659,8 @@ static void update_parents(zend_class_entry *ce, zend_class_entry *parent_ce) {
16521659
} else {
16531660
zend_class_reference *new_ref = emalloc(ZEND_CLASS_REF_SIZE(ref->args.num_types));
16541661
new_ref->ce = ref->ce;
1662+
new_ref->key = ref->key;
1663+
zend_string_addref(new_ref->key);
16551664
new_ref->args.num_types = ref->args.num_types;
16561665
generic_args -= ref->args.num_types;
16571666
memcpy(new_ref->args.types, generic_args, sizeof(zend_type) * ref->args.num_types);
@@ -3048,11 +3057,14 @@ static void check_unrecoverable_load_failure(zend_class_entry *ce) {
30483057

30493058
static zend_class_entry *zend_lazy_class_load(zend_class_entry *pce)
30503059
{
3060+
zend_class_reference *class_ref;
30513061
zend_class_entry *ce;
30523062
Bucket *p, *end;
30533063

3054-
ce = zend_arena_alloc(&CG(arena), sizeof(zend_class_entry));
3055-
memcpy(ce, pce, sizeof(zend_class_entry));
3064+
class_ref = zend_arena_alloc(&CG(arena), sizeof(zend_class_entry_storage));
3065+
memcpy(class_ref, ZEND_CE_TO_REF(pce), sizeof(zend_class_entry_storage));
3066+
ce = (zend_class_entry*)((char*)class_ref + ZEND_CLASS_ENTRY_HEADER_SIZE);
3067+
class_ref->ce = ce;
30563068
ce->ce_flags &= ~ZEND_ACC_IMMUTABLE;
30573069
ce->refcount = 1;
30583070
ce->inheritance_cache = NULL;

Zend/zend_opcode.c

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -371,16 +371,6 @@ ZEND_API void destroy_zend_class(zval *zv)
371371
if (ce->num_parents) {
372372
if (!(ce->ce_flags & ZEND_ACC_RESOLVED_PARENT)) {
373373
zend_pnr_release(ce->parent_name, /* uses_arena */ 1, /* persistent */ 0);
374-
} else {
375-
for (uint32_t i = 0; i < ce->num_parents; i++) {
376-
zend_class_reference *ref = ce->parents[i];
377-
if (!ZEND_REF_IS_TRIVIAL(ref)) {
378-
/* The type arguments are owned by bound_generic_args,
379-
* and will be destroyed there. */
380-
efree(ref);
381-
}
382-
}
383-
efree(ce->parents);
384374
}
385375
}
386376

@@ -427,6 +417,19 @@ ZEND_API void destroy_zend_class(zval *zv)
427417
}
428418
}
429419

420+
if (ce->num_parents && (ce->ce_flags & ZEND_ACC_RESOLVED_PARENT)) {
421+
for (uint32_t i = 0; i < ce->num_parents; i++) {
422+
zend_class_reference *ref = ce->parents[i];
423+
if (!ZEND_REF_IS_TRIVIAL(ref)) {
424+
/* The type arguments are owned by bound_generic_args,
425+
* and will be destroyed there. */
426+
zend_string_release(ref->key);
427+
efree(ref);
428+
}
429+
}
430+
efree(ce->parents);
431+
}
432+
430433
if (ce->default_properties_table) {
431434
zval *p = ce->default_properties_table;
432435
zval *end = p + ce->default_properties_count;

0 commit comments

Comments
 (0)