Skip to content

Commit f950128

Browse files
committed
Encode parent class name as IS_CONST operand in DECLARE_INHERITED_CLASS and DECLARE_ANON_INHERITED_CLASS opcodes (eliminate FETCH_CLAS
S opcode).
1 parent a5e80b2 commit f950128

File tree

8 files changed

+207
-183
lines changed

8 files changed

+207
-183
lines changed

UPGRADING.INTERNALS

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ PHP 7.3 INTERNALS UPGRADE NOTES
2424
u. GC_G
2525
v. php_add[c]slashes
2626
w. zend_class_entry.iterator_funcs
27+
x. Class declaration opcodes (DECLARE_INHERITED_CLASS ...)
2728

2829
2. Build system changes
2930
a. Unix build system changes
@@ -152,6 +153,13 @@ PHP 7.3 INTERNALS UPGRADE NOTES
152153
You don't have to set its value, setting parent.funcs in the get_iterator
153154
function is enough.
154155

156+
x. Class declaration opcode formats were changed
157+
- DECLARE_INHERITED_CLASS and DECLARE_ANON_INHERITED_CLASS now encode parent
158+
class name in second operand directly (as IS_CONST operand). Previously,
159+
parent class was fetched but previous FETCH_CLASS opcode.
160+
- ADD_INTERFACE and ADD_TRAIT don't use run-time cache to keep interface or
161+
trait. These instructions are executed once, and caching is useless.
162+
155163
========================
156164
2. Build system changes
157165
========================

Zend/zend_compile.c

Lines changed: 23 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1182,11 +1182,10 @@ void zend_do_early_binding(void) /* {{{ */
11821182
break;
11831183
case ZEND_DECLARE_INHERITED_CLASS:
11841184
{
1185-
zend_op *fetch_class_opline = opline-1;
11861185
zval *parent_name;
11871186
zend_class_entry *ce;
11881187

1189-
parent_name = CT_CONSTANT(fetch_class_opline->op2);
1188+
parent_name = CT_CONSTANT(opline->op2);
11901189
if (((ce = zend_lookup_class_ex(Z_STR_P(parent_name), parent_name + 1, 0)) == NULL) ||
11911190
((CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_CLASSES) &&
11921191
(ce->type == ZEND_INTERNAL_CLASS))) {
@@ -1201,9 +1200,8 @@ void zend_do_early_binding(void) /* {{{ */
12011200
if (do_bind_inherited_class(CG(active_op_array), opline, CG(class_table), ce, 1) == NULL) {
12021201
return;
12031202
}
1204-
/* clear unnecessary ZEND_FETCH_CLASS opcode */
1205-
zend_del_literal(CG(active_op_array), fetch_class_opline->op2.constant);
1206-
MAKE_NOP(fetch_class_opline);
1203+
zend_del_literal(CG(active_op_array), opline->op2.constant+1);
1204+
zend_del_literal(CG(active_op_array), opline->op2.constant);
12071205

12081206
table = CG(class_table);
12091207
break;
@@ -1287,7 +1285,7 @@ ZEND_API void zend_do_delayed_early_binding(const zend_op_array *op_array, uint3
12871285

12881286
CG(in_compilation) = 1;
12891287
while (opline_num != (uint32_t)-1) {
1290-
const zend_op *opline = &op_array->opcodes[opline_num-1];
1288+
const zend_op *opline = &op_array->opcodes[opline_num];
12911289
zval *parent_name = RT_CONSTANT(opline, opline->op2);
12921290
if ((ce = zend_lookup_class_ex(Z_STR_P(parent_name), parent_name + 1, 0)) != NULL) {
12931291
do_bind_inherited_class(op_array, &op_array->opcodes[opline_num], EG(class_table), ce, 0);
@@ -2462,46 +2460,6 @@ static inline void zend_set_class_name_op1(zend_op *opline, znode *class_node) /
24622460
}
24632461
/* }}} */
24642462

2465-
static zend_op *zend_compile_class_ref(znode *result, zend_ast *name_ast, int throw_exception) /* {{{ */
2466-
{
2467-
zend_op *opline;
2468-
znode name_node;
2469-
zend_compile_expr(&name_node, name_ast);
2470-
2471-
if (name_node.op_type == IS_CONST) {
2472-
zend_string *name;
2473-
uint32_t fetch_type;
2474-
2475-
if (Z_TYPE(name_node.u.constant) != IS_STRING) {
2476-
zend_error_noreturn(E_COMPILE_ERROR, "Illegal class name");
2477-
}
2478-
2479-
name = Z_STR(name_node.u.constant);
2480-
fetch_type = zend_get_class_fetch_type(name);
2481-
2482-
opline = zend_emit_op(result, ZEND_FETCH_CLASS, NULL, NULL);
2483-
opline->op1.num = fetch_type | (throw_exception ? ZEND_FETCH_CLASS_EXCEPTION : 0);
2484-
2485-
if (fetch_type == ZEND_FETCH_CLASS_DEFAULT) {
2486-
uint32_t type = name_ast->kind == ZEND_AST_ZVAL ? name_ast->attr : ZEND_NAME_FQ;
2487-
opline->op2_type = IS_CONST;
2488-
opline->op2.constant = zend_add_class_name_literal(CG(active_op_array),
2489-
zend_resolve_class_name(name, type));
2490-
opline->extended_value = zend_alloc_cache_slot();
2491-
} else {
2492-
zend_ensure_valid_class_fetch_type(fetch_type);
2493-
}
2494-
2495-
zend_string_release_ex(name, 0);
2496-
} else {
2497-
opline = zend_emit_op(result, ZEND_FETCH_CLASS, NULL, &name_node);
2498-
opline->op1.num = ZEND_FETCH_CLASS_DEFAULT | (throw_exception ? ZEND_FETCH_CLASS_EXCEPTION : 0);
2499-
}
2500-
2501-
return opline;
2502-
}
2503-
/* }}} */
2504-
25052463
static void zend_compile_class_ref_ex(znode *result, zend_ast *name_ast, uint32_t fetch_flags) /* {{{ */
25062464
{
25072465
uint32_t fetch_type;
@@ -6274,7 +6232,6 @@ void zend_compile_use_trait(zend_ast *ast) /* {{{ */
62746232
opline->op2_type = IS_CONST;
62756233
opline->op2.constant = zend_add_class_name_literal(CG(active_op_array),
62766234
zend_resolve_class_name_ast(trait_ast));
6277-
opline->extended_value = zend_alloc_cache_slot();
62786235

62796236
ce->num_traits++;
62806237
}
@@ -6317,7 +6274,6 @@ void zend_compile_implements(znode *class_node, zend_ast *ast) /* {{{ */
63176274
opline->op2_type = IS_CONST;
63186275
opline->op2.constant = zend_add_class_name_literal(CG(active_op_array),
63196276
zend_resolve_class_name_ast(class_ast));
6320-
opline->extended_value = zend_alloc_cache_slot();
63216277

63226278
CG(active_class_entry)->num_interfaces++;
63236279
}
@@ -6347,7 +6303,8 @@ void zend_compile_class_decl(zend_ast *ast) /* {{{ */
63476303
zend_string *name, *lcname;
63486304
zend_class_entry *ce = zend_arena_alloc(&CG(arena), sizeof(zend_class_entry));
63496305
zend_op *opline;
6350-
znode declare_node, extends_node;
6306+
znode declare_node;
6307+
int extends_const;
63516308

63526309
zend_class_entry *original_ce = CG(active_class_entry);
63536310
znode original_implementing_class = FC(implementing_class);
@@ -6400,13 +6357,24 @@ void zend_compile_class_decl(zend_ast *ast) /* {{{ */
64006357
}
64016358

64026359
if (extends_ast) {
6360+
znode extends_node;
6361+
zend_string *extends_name;
6362+
64036363
if (!zend_is_const_default_class_ref(extends_ast)) {
6404-
zend_string *extends_name = zend_ast_get_str(extends_ast);
6364+
extends_name = zend_ast_get_str(extends_ast);
64056365
zend_error_noreturn(E_COMPILE_ERROR,
64066366
"Cannot use '%s' as class name as it is reserved", ZSTR_VAL(extends_name));
64076367
}
64086368

6409-
zend_compile_class_ref(&extends_node, extends_ast, 1);
6369+
zend_compile_expr(&extends_node, extends_ast);
6370+
if (extends_node.op_type != IS_CONST || Z_TYPE(extends_node.u.constant) != IS_STRING) {
6371+
zend_error_noreturn(E_COMPILE_ERROR, "Illegal class name");
6372+
}
6373+
extends_name = Z_STR(extends_node.u.constant);
6374+
extends_const = zend_add_class_name_literal(CG(active_op_array),
6375+
zend_resolve_class_name(extends_name,
6376+
extends_ast->kind == ZEND_AST_ZVAL ? extends_ast->attr : ZEND_NAME_FQ));
6377+
zend_string_release_ex(extends_name, 0);
64106378
ce->ce_flags |= ZEND_ACC_INHERITED;
64116379
}
64126380

@@ -6421,7 +6389,8 @@ void zend_compile_class_decl(zend_ast *ast) /* {{{ */
64216389
if (decl->flags & ZEND_ACC_ANON_CLASS) {
64226390
if (extends_ast) {
64236391
opline->opcode = ZEND_DECLARE_ANON_INHERITED_CLASS;
6424-
SET_NODE(opline->op2, &extends_node);
6392+
opline->op2_type = IS_CONST;
6393+
opline->op2.constant = extends_const;
64256394
} else {
64266395
opline->opcode = ZEND_DECLARE_ANON_CLASS;
64276396
}
@@ -6440,7 +6409,8 @@ void zend_compile_class_decl(zend_ast *ast) /* {{{ */
64406409

64416410
if (extends_ast) {
64426411
opline->opcode = ZEND_DECLARE_INHERITED_CLASS;
6443-
SET_NODE(opline->op2, &extends_node);
6412+
opline->op2_type = IS_CONST;
6413+
opline->op2.constant = extends_const;
64446414
} else {
64456415
opline->opcode = ZEND_DECLARE_CLASS;
64466416
}

Zend/zend_vm_def.h

Lines changed: 43 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6622,7 +6622,7 @@ ZEND_VM_COLD_HANDLER(103, ZEND_EXT_FCALL_END, ANY, ANY)
66226622
ZEND_VM_NEXT_OPCODE();
66236623
}
66246624

6625-
ZEND_VM_HANDLER(139, ZEND_DECLARE_CLASS, ANY, ANY)
6625+
ZEND_VM_HANDLER(139, ZEND_DECLARE_CLASS, CONST, ANY)
66266626
{
66276627
USE_OPLINE
66286628

@@ -6631,25 +6631,41 @@ ZEND_VM_HANDLER(139, ZEND_DECLARE_CLASS, ANY, ANY)
66316631
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
66326632
}
66336633

6634-
ZEND_VM_HANDLER(140, ZEND_DECLARE_INHERITED_CLASS, ANY, VAR)
6634+
ZEND_VM_HANDLER(140, ZEND_DECLARE_INHERITED_CLASS, CONST, CONST)
66356635
{
6636+
zend_class_entry *parent;
66366637
USE_OPLINE
66376638

66386639
SAVE_OPLINE();
6639-
Z_CE_P(EX_VAR(opline->result.var)) = do_bind_inherited_class(&EX(func)->op_array, opline, EG(class_table), Z_CE_P(EX_VAR(opline->op2.var)), 0);
6640+
parent = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op2)),
6641+
RT_CONSTANT(opline, opline->op2) + 1,
6642+
ZEND_FETCH_CLASS_EXCEPTION);
6643+
if (UNEXPECTED(parent == NULL)) {
6644+
ZEND_ASSERT(EG(exception));
6645+
HANDLE_EXCEPTION();
6646+
}
6647+
Z_CE_P(EX_VAR(opline->result.var)) = do_bind_inherited_class(&EX(func)->op_array, opline, EG(class_table), parent, 0);
66406648
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
66416649
}
66426650

6643-
ZEND_VM_HANDLER(145, ZEND_DECLARE_INHERITED_CLASS_DELAYED, ANY, VAR)
6651+
ZEND_VM_HANDLER(145, ZEND_DECLARE_INHERITED_CLASS_DELAYED, CONST, CONST)
66446652
{
66456653
USE_OPLINE
66466654
zval *zce, *orig_zce;
6655+
zend_class_entry *parent;
66476656

66486657
SAVE_OPLINE();
66496658
if ((zce = zend_hash_find_ex(EG(class_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)), 1)) == NULL ||
66506659
((orig_zce = zend_hash_find_ex(EG(class_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)+1), 1)) != NULL &&
66516660
Z_CE_P(zce) != Z_CE_P(orig_zce))) {
6652-
do_bind_inherited_class(&EX(func)->op_array, opline, EG(class_table), Z_CE_P(EX_VAR(opline->op2.var)), 0);
6661+
parent = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op2)),
6662+
RT_CONSTANT(opline, opline->op2) + 1,
6663+
ZEND_FETCH_CLASS_EXCEPTION);
6664+
if (UNEXPECTED(parent == NULL)) {
6665+
ZEND_ASSERT(EG(exception));
6666+
HANDLE_EXCEPTION();
6667+
}
6668+
do_bind_inherited_class(&EX(func)->op_array, opline, EG(class_table), parent, 0);
66536669
}
66546670
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
66556671
}
@@ -6678,10 +6694,10 @@ ZEND_VM_HANDLER(171, ZEND_DECLARE_ANON_CLASS, ANY, ANY, JMP_ADDR)
66786694
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
66796695
}
66806696

6681-
ZEND_VM_HANDLER(172, ZEND_DECLARE_ANON_INHERITED_CLASS, ANY, VAR, JMP_ADDR)
6697+
ZEND_VM_HANDLER(172, ZEND_DECLARE_ANON_INHERITED_CLASS, CONST, CONST, JMP_ADDR)
66826698
{
66836699
zval *zv;
6684-
zend_class_entry *ce;
6700+
zend_class_entry *ce, *parent;
66856701
USE_OPLINE
66866702

66876703
SAVE_OPLINE();
@@ -6695,7 +6711,15 @@ ZEND_VM_HANDLER(172, ZEND_DECLARE_ANON_INHERITED_CLASS, ANY, VAR, JMP_ADDR)
66956711
ZEND_VM_CONTINUE();
66966712
}
66976713

6698-
zend_do_inheritance(ce, Z_CE_P(EX_VAR(opline->op2.var)));
6714+
parent = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op2)),
6715+
RT_CONSTANT(opline, opline->op2) + 1,
6716+
ZEND_FETCH_CLASS_EXCEPTION);
6717+
if (UNEXPECTED(parent == NULL)) {
6718+
ZEND_ASSERT(EG(exception));
6719+
HANDLE_EXCEPTION();
6720+
}
6721+
6722+
zend_do_inheritance(ce, parent);
66996723
ce->ce_flags |= ZEND_ACC_ANON_BOUND;
67006724
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
67016725
}
@@ -6794,13 +6818,10 @@ ZEND_VM_HANDLER(144, ZEND_ADD_INTERFACE, ANY, CONST, CACHE_SLOT)
67946818
zend_class_entry *iface;
67956819

67966820
SAVE_OPLINE();
6797-
iface = CACHED_PTR(opline->extended_value);
6821+
iface = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op2)), RT_CONSTANT(opline, opline->op2) + 1, ZEND_FETCH_CLASS_INTERFACE);
67986822
if (UNEXPECTED(iface == NULL)) {
6799-
iface = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op2)), RT_CONSTANT(opline, opline->op2) + 1, ZEND_FETCH_CLASS_INTERFACE);
6800-
if (UNEXPECTED(iface == NULL)) {
6801-
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
6802-
}
6803-
CACHE_PTR(opline->extended_value, iface);
6823+
ZEND_ASSERT(EG(exception));
6824+
HANDLE_EXCEPTION();
68046825
}
68056826

68066827
if (UNEXPECTED((iface->ce_flags & ZEND_ACC_INTERFACE) == 0)) {
@@ -6818,18 +6839,15 @@ ZEND_VM_HANDLER(154, ZEND_ADD_TRAIT, ANY, ANY, CACHE_SLOT)
68186839
zend_class_entry *trait;
68196840

68206841
SAVE_OPLINE();
6821-
trait = CACHED_PTR(opline->extended_value);
6842+
trait = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op2)),
6843+
RT_CONSTANT(opline, opline->op2) + 1,
6844+
ZEND_FETCH_CLASS_TRAIT);
68226845
if (UNEXPECTED(trait == NULL)) {
6823-
trait = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op2)),
6824-
RT_CONSTANT(opline, opline->op2) + 1,
6825-
ZEND_FETCH_CLASS_TRAIT);
6826-
if (UNEXPECTED(trait == NULL)) {
6827-
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
6828-
}
6829-
if (!(trait->ce_flags & ZEND_ACC_TRAIT)) {
6830-
zend_error_noreturn(E_ERROR, "%s cannot use %s - it is not a trait", ZSTR_VAL(ce->name), ZSTR_VAL(trait->name));
6831-
}
6832-
CACHE_PTR(opline->extended_value, trait);
6846+
ZEND_ASSERT(EG(exception));
6847+
HANDLE_EXCEPTION();
6848+
}
6849+
if (!(trait->ce_flags & ZEND_ACC_TRAIT)) {
6850+
zend_error_noreturn(E_ERROR, "%s cannot use %s - it is not a trait", ZSTR_VAL(ce->name), ZSTR_VAL(trait->name));
68336851
}
68346852

68356853
zend_do_implement_trait(ce, trait);

0 commit comments

Comments
 (0)