php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
compact_literals.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | Zend OPcache |
4 +----------------------------------------------------------------------+
5 | Copyright (c) The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | https://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Dmitry Stogov <dmitry@php.net> |
16 | Xinchen Hui <laruence@php.net> |
17 +----------------------------------------------------------------------+
18*/
19
20/* pass 11
21 * - compact literals table
22 */
23
26#include "zend_API.h"
27#include "zend_constants.h"
28#include "zend_execute.h"
29#include "zend_vm.h"
30#include "zend_extensions.h"
31
32#define DEBUG_COMPACT_LITERALS 0
33
34#define LITERAL_CLASS_CONST 1
35#define LITERAL_STATIC_METHOD 2
36#define LITERAL_STATIC_PROPERTY 3
37
38typedef struct _literal_info {
39 uint8_t num_related;
41
42#define LITERAL_INFO(n, related) do { \
43 info[n].num_related = (related); \
44 } while (0)
45
46static size_t type_num_classes(const zend_op_array *op_array, uint32_t arg_num)
47{
48 zend_arg_info *arg_info;
49 if (arg_num > 0) {
50 if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
51 return 0;
52 }
54 arg_info = &op_array->arg_info[arg_num-1];
55 } else if (UNEXPECTED(op_array->fn_flags & ZEND_ACC_VARIADIC)) {
56 arg_info = &op_array->arg_info[op_array->num_args];
57 } else {
58 return 0;
59 }
60 } else {
61 arg_info = op_array->arg_info - 1;
62 }
63
64 if (ZEND_TYPE_IS_COMPLEX(arg_info->type)) {
65 if (ZEND_TYPE_HAS_LIST(arg_info->type)) {
66 /* Intersection types cannot have nested list types */
67 if (ZEND_TYPE_IS_INTERSECTION(arg_info->type)) {
68 return ZEND_TYPE_LIST(arg_info->type)->num_types;
69 }
71 size_t count = 0;
72 zend_type *list_type;
73
74 ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(arg_info->type), list_type) {
75 if (ZEND_TYPE_IS_INTERSECTION(*list_type)) {
76 count += ZEND_TYPE_LIST(*list_type)->num_types;
77 } else {
78 ZEND_ASSERT(!ZEND_TYPE_HAS_LIST(*list_type));
79 count += 1;
80 }
82 return count;
83 }
84 return 1;
85 }
86
87 return 0;
88}
89
90static uint32_t add_static_slot(HashTable *hash,
91 zend_op_array *op_array,
92 uint32_t op1,
93 uint32_t op2,
94 uint32_t kind,
95 uint32_t *cache_size)
96{
97 uint32_t ret;
98 zval *class_name = &op_array->literals[op1];
99 zval *prop_name = &op_array->literals[op2];
100 zval *pos, tmp;
101
102 zend_string *key = zend_create_member_string(Z_STR_P(class_name), Z_STR_P(prop_name));
104 ZSTR_H(key) += kind;
105
107 if (pos) {
108 ret = Z_LVAL_P(pos);
109 } else {
110 ret = *cache_size;
111 *cache_size += (kind == LITERAL_STATIC_PROPERTY ? 3 : 2) * sizeof(void *);
112 ZVAL_LONG(&tmp, ret);
113 zend_hash_add(hash, key, &tmp);
114 }
116 return ret;
117}
118
119static inline void bias_key(zend_string *key, uint32_t bias)
120{
121 /* Add a bias to the hash so we can distinguish string keys
122 * that would otherwise be the same. */
123 ZSTR_H(key) = zend_string_hash_val(key) + bias;
124}
125
126static zend_string *create_str_cache_key(zval *literal, uint8_t num_related)
127{
128 ZEND_ASSERT(Z_TYPE_P(literal) == IS_STRING);
129 if (num_related == 1) {
130 return zend_string_copy(Z_STR_P(literal));
131 }
132
133 /* Concatenate all the related literals for the cache key. */
135 if (num_related == 2) {
136 ZEND_ASSERT(Z_TYPE_P(literal + 1) == IS_STRING);
138 Z_STRVAL_P(literal), Z_STRLEN_P(literal),
139 Z_STRVAL_P(literal + 1), Z_STRLEN_P(literal + 1));
140 } else if (num_related == 3) {
141 ZEND_ASSERT(Z_TYPE_P(literal + 1) == IS_STRING && Z_TYPE_P(literal + 2) == IS_STRING);
143 Z_STRVAL_P(literal), Z_STRLEN_P(literal),
144 Z_STRVAL_P(literal + 1), Z_STRLEN_P(literal + 1),
145 Z_STRVAL_P(literal + 2), Z_STRLEN_P(literal + 2));
146 } else {
147 ZEND_ASSERT(0 && "Currently not needed");
148 }
149
150 bias_key(key, num_related - 1);
151 return key;
152}
153
155{
156 zend_op *opline, *end;
157 int i, j, n, *map;
158 uint32_t cache_size;
159 zval zv, *pos;
160 literal_info *info;
161 int l_null = -1;
162 int l_false = -1;
163 int l_true = -1;
164 int l_empty_arr = -1;
167 void *checkpoint = zend_arena_checkpoint(ctx->arena);
168 int *const_slot, *class_slot, *func_slot, *bind_var_slot, *property_slot, *method_slot;
169
170 if (op_array->last_literal) {
171 info = (literal_info*)zend_arena_calloc(&ctx->arena, op_array->last_literal, sizeof(literal_info));
172
173 /* Mark literals of specific types */
174 opline = op_array->opcodes;
175 end = opline + op_array->last;
176 while (opline < end) {
177 switch (opline->opcode) {
179 LITERAL_INFO(opline->op2.constant, 2);
180 break;
182 LITERAL_INFO(opline->op2.constant, 3);
183 break;
185 if (opline->op1_type == IS_CONST) {
186 LITERAL_INFO(opline->op1.constant, 1);
187 }
188 if (opline->op2_type == IS_CONST) {
189 LITERAL_INFO(opline->op2.constant, 2);
190 }
191 break;
193 if (opline->op1_type == IS_CONST) {
194 LITERAL_INFO(opline->op1.constant, 2);
195 }
196 if (opline->op2_type == IS_CONST) {
197 LITERAL_INFO(opline->op2.constant, 2);
198 }
199 break;
201 LITERAL_INFO(opline->op1.constant, 1);
202 break;
203 case ZEND_CATCH:
204 LITERAL_INFO(opline->op1.constant, 2);
205 break;
208 LITERAL_INFO(opline->op2.constant, 3);
209 } else {
210 LITERAL_INFO(opline->op2.constant, 2);
211 }
212 break;
214 if (opline->op1_type == IS_CONST) {
215 LITERAL_INFO(opline->op1.constant, 2);
216 }
217 if (opline->op2_type == IS_CONST) {
218 LITERAL_INFO(opline->op2.constant, 1);
219 }
220 break;
236 if (opline->op2_type == IS_CONST) {
237 LITERAL_INFO(opline->op2.constant, 2);
238 }
239 if (opline->op1_type == IS_CONST) {
240 LITERAL_INFO(opline->op1.constant, 1);
241 }
242 break;
243 case ZEND_FETCH_CLASS:
244 case ZEND_INSTANCEOF:
245 if (opline->op2_type == IS_CONST) {
246 LITERAL_INFO(opline->op2.constant, 2);
247 }
248 break;
249 case ZEND_NEW:
250 if (opline->op1_type == IS_CONST) {
251 LITERAL_INFO(opline->op1.constant, 2);
252 }
253 break;
256 LITERAL_INFO(opline->op1.constant, 2);
257 if (opline->op2_type == IS_CONST) {
258 LITERAL_INFO(opline->op2.constant, 1);
259 }
260 break;
262 case ZEND_ASSIGN_DIM:
263 case ZEND_UNSET_DIM:
264 case ZEND_FETCH_DIM_R:
265 case ZEND_FETCH_DIM_W:
273 if (opline->op1_type == IS_CONST) {
274 LITERAL_INFO(opline->op1.constant, 1);
275 }
276 if (opline->op2_type == IS_CONST) {
277 if (Z_EXTRA(op_array->literals[opline->op2.constant]) == ZEND_EXTRA_VALUE) {
278 LITERAL_INFO(opline->op2.constant, 2);
279 } else {
280 LITERAL_INFO(opline->op2.constant, 1);
281 }
282 }
283 break;
284 default:
285 if (opline->op1_type == IS_CONST) {
286 LITERAL_INFO(opline->op1.constant, 1);
287 }
288 if (opline->op2_type == IS_CONST) {
289 LITERAL_INFO(opline->op2.constant, 1);
290 }
291 break;
292 }
293 opline++;
294 }
295
296#if DEBUG_COMPACT_LITERALS
297 {
298 fprintf(stderr, "File %s func %s\n", op_array->filename->val,
299 op_array->function_name ? op_array->function_name->val : "main");
300 fprintf(stderr, "Literals table size %d\n", op_array->last_literal);
301
302 for (int i = 0; i < op_array->last_literal; i++) {
303 zend_string *str = zval_get_string(op_array->literals + i);
304 fprintf(stderr, "Literal %d, val (%zu):%s\n", i, ZSTR_LEN(str), ZSTR_VAL(str));
305 zend_string_release(str);
306 }
307 fflush(stderr);
308 }
309#endif
310
311 /* Merge equal constants */
312 j = 0;
313 zend_hash_init(&hash, op_array->last_literal, NULL, NULL, 0);
314 map = (int*)zend_arena_alloc(&ctx->arena, op_array->last_literal * sizeof(int));
315 memset(map, 0, op_array->last_literal * sizeof(int));
316 for (i = 0; i < op_array->last_literal; i++) {
317 if (!info[i].num_related) {
318 /* unset literal */
319 zval_ptr_dtor_nogc(&op_array->literals[i]);
320 continue;
321 }
322 switch (Z_TYPE(op_array->literals[i])) {
323 case IS_NULL:
324 ZEND_ASSERT(info[i].num_related == 1);
325 if (l_null < 0) {
326 l_null = j;
327 if (i != j) {
328 op_array->literals[j] = op_array->literals[i];
329 info[j] = info[i];
330 }
331 j++;
332 }
333 map[i] = l_null;
334 break;
335 case IS_FALSE:
336 ZEND_ASSERT(info[i].num_related == 1);
337 if (l_false < 0) {
338 l_false = j;
339 if (i != j) {
340 op_array->literals[j] = op_array->literals[i];
341 info[j] = info[i];
342 }
343 j++;
344 }
345 map[i] = l_false;
346 break;
347 case IS_TRUE:
348 ZEND_ASSERT(info[i].num_related == 1);
349 if (l_true < 0) {
350 l_true = j;
351 if (i != j) {
352 op_array->literals[j] = op_array->literals[i];
353 info[j] = info[i];
354 }
355 j++;
356 }
357 map[i] = l_true;
358 break;
359 case IS_LONG:
360 if (info[i].num_related == 1) {
361 if ((pos = zend_hash_index_find(&hash, Z_LVAL(op_array->literals[i]))) != NULL) {
362 map[i] = Z_LVAL_P(pos);
363 } else {
364 map[i] = j;
365 ZVAL_LONG(&zv, j);
366 zend_hash_index_add_new(&hash, Z_LVAL(op_array->literals[i]), &zv);
367 if (i != j) {
368 op_array->literals[j] = op_array->literals[i];
369 info[j] = info[i];
370 }
371 j++;
372 }
373 } else {
374 ZEND_ASSERT(info[i].num_related == 2);
375 key = zend_string_init(Z_STRVAL(op_array->literals[i+1]), Z_STRLEN(op_array->literals[i+1]), 0);
376 bias_key(key, 100 + info[i].num_related - 1);
377 if ((pos = zend_hash_find(&hash, key)) != NULL) {
378 ZEND_ASSERT(info[Z_LVAL_P(pos)].num_related == 2);
379 map[i] = Z_LVAL_P(pos);
380 zval_ptr_dtor_nogc(&op_array->literals[i+1]);
381 } else {
382 map[i] = j;
383 ZVAL_LONG(&zv, j);
385 if (i != j) {
386 op_array->literals[j] = op_array->literals[i];
387 info[j] = info[i];
388 op_array->literals[j+1] = op_array->literals[i+1];
389 info[j+1] = info[i+1];
390 }
391 j += 2;
392 }
394 i++;
395 }
396 break;
397 case IS_DOUBLE:
398 ZEND_ASSERT(info[i].num_related == 1);
399 key = zend_string_init((char*)&Z_DVAL(op_array->literals[i]), sizeof(double), 0);
400 bias_key(key, 200);
401 if ((pos = zend_hash_find(&hash, key))) {
402 map[i] = Z_LVAL_P(pos);
403 } else {
404 map[i] = j;
405 ZVAL_LONG(&zv, j);
407 if (i != j) {
408 op_array->literals[j] = op_array->literals[i];
409 info[j] = info[i];
410 }
411 j++;
412 }
414 break;
415 case IS_STRING: {
416 key = create_str_cache_key(&op_array->literals[i], info[i].num_related);
417 if ((pos = zend_hash_find(&hash, key)) != NULL) {
419 info[i].num_related == info[Z_LVAL_P(pos)].num_related);
421 map[i] = Z_LVAL_P(pos);
422 zval_ptr_dtor_nogc(&op_array->literals[i]);
423 n = info[i].num_related;
424 while (n > 1) {
425 i++;
426 zval_ptr_dtor_nogc(&op_array->literals[i]);
427 n--;
428 }
429 } else {
430 map[i] = j;
431 ZVAL_LONG(&zv, j);
434 if (i != j) {
435 op_array->literals[j] = op_array->literals[i];
436 info[j] = info[i];
437 }
438 j++;
439 n = info[i].num_related;
440 while (n > 1) {
441 i++;
442 if (i != j) op_array->literals[j] = op_array->literals[i];
443 j++;
444 n--;
445 }
446 }
447 break;
448 }
449 case IS_ARRAY:
450 ZEND_ASSERT(info[i].num_related == 1);
451 if (zend_hash_num_elements(Z_ARRVAL(op_array->literals[i])) == 0) {
452 if (l_empty_arr < 0) {
453 l_empty_arr = j;
454 if (i != j) {
455 op_array->literals[j] = op_array->literals[i];
456 info[j] = info[i];
457 }
458 j++;
459 } else {
460 zval_ptr_dtor_nogc(&op_array->literals[i]);
461 }
462 map[i] = l_empty_arr;
463 break;
464 }
466 default:
467 /* don't merge other types */
468 ZEND_ASSERT(info[i].num_related == 1);
469 map[i] = j;
470 if (i != j) {
471 op_array->literals[j] = op_array->literals[i];
472 info[j] = info[i];
473 }
474 j++;
475 break;
476 }
477 }
478
479 /* Only clean "hash", as it will be reused in the loop below. */
481 op_array->last_literal = j;
482
483 const_slot = zend_arena_alloc(&ctx->arena, j * 6 * sizeof(int));
484 memset(const_slot, -1, j * 6 * sizeof(int));
485 class_slot = const_slot + j;
486 func_slot = class_slot + j;
487 bind_var_slot = func_slot + j;
488 property_slot = bind_var_slot + j;
489 method_slot = property_slot + j;
490
491 /* Update opcodes to use new literals table */
492 cache_size = zend_op_array_extension_handles * sizeof(void*);
493 opline = op_array->opcodes;
494 end = opline + op_array->last;
495 while (opline < end) {
496 if (opline->op1_type == IS_CONST) {
497 opline->op1.constant = map[opline->op1.constant];
498 }
499 if (opline->op2_type == IS_CONST) {
500 opline->op2.constant = map[opline->op2.constant];
501 }
502 switch (opline->opcode) {
503 case ZEND_RECV_INIT:
504 case ZEND_RECV:
506 {
507 size_t num_classes = type_num_classes(op_array, opline->op1.num);
508 if (num_classes) {
509 opline->extended_value = cache_size;
510 cache_size += num_classes * sizeof(void *);
511 }
512 break;
513 }
515 {
516 size_t num_classes = type_num_classes(op_array, 0);
517 if (num_classes) {
518 opline->op2.num = cache_size;
519 cache_size += num_classes * sizeof(void *);
520 }
521 break;
522 }
524 if (opline->op1_type == IS_CONST) {
525 // op1 static property
526 if (opline->op2_type == IS_CONST) {
527 (opline+1)->extended_value = add_static_slot(&hash, op_array,
528 opline->op2.constant,
529 opline->op1.constant,
531 &cache_size);
532 } else {
533 (opline+1)->extended_value = cache_size;
534 cache_size += 3 * sizeof(void *);
535 }
536 } else if (opline->op2_type == IS_CONST) {
537 // op2 class
538 if (class_slot[opline->op2.constant] >= 0) {
539 (opline+1)->extended_value = class_slot[opline->op2.constant];
540 } else {
541 (opline+1)->extended_value = cache_size;
542 class_slot[opline->op2.constant] = cache_size;
543 cache_size += sizeof(void *);
544 }
545 }
546 break;
548 if (opline->op2_type == IS_CONST) {
549 // op2 property
550 if (opline->op1_type == IS_UNUSED &&
551 property_slot[opline->op2.constant] >= 0) {
552 (opline+1)->extended_value = property_slot[opline->op2.constant];
553 } else {
554 (opline+1)->extended_value = cache_size;
555 cache_size += 3 * sizeof(void *);
556 if (opline->op1_type == IS_UNUSED) {
557 property_slot[opline->op2.constant] = (opline+1)->extended_value;
558 }
559 }
560 }
561 break;
562 case ZEND_ASSIGN_OBJ:
564 case ZEND_FETCH_OBJ_R:
565 case ZEND_FETCH_OBJ_W:
570 case ZEND_UNSET_OBJ:
571 case ZEND_PRE_INC_OBJ:
572 case ZEND_PRE_DEC_OBJ:
575 if (opline->op2_type == IS_CONST) {
576 // op2 property
577 if (opline->op1_type == IS_UNUSED &&
578 property_slot[opline->op2.constant] >= 0) {
579 opline->extended_value = property_slot[opline->op2.constant] | (opline->extended_value & ZEND_FETCH_OBJ_FLAGS);
580 } else {
581 opline->extended_value = cache_size | (opline->extended_value & ZEND_FETCH_OBJ_FLAGS);
582 cache_size += 3 * sizeof(void *);
583 if (opline->op1_type == IS_UNUSED) {
584 property_slot[opline->op2.constant] = opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS;
585 }
586 }
587 }
588 break;
590 if (opline->op2_type == IS_CONST) {
591 // op2 property
592 if (opline->op1_type == IS_UNUSED &&
593 property_slot[opline->op2.constant] >= 0) {
594 opline->extended_value = property_slot[opline->op2.constant] | (opline->extended_value & ZEND_ISEMPTY);
595 } else {
596 opline->extended_value = cache_size | (opline->extended_value & ZEND_ISEMPTY);
597 cache_size += 3 * sizeof(void *);
598 if (opline->op1_type == IS_UNUSED) {
599 property_slot[opline->op2.constant] = opline->extended_value & ~ZEND_ISEMPTY;
600 }
601 }
602 }
603 break;
604 case ZEND_INIT_FCALL:
607 // op2 func
608 if (func_slot[opline->op2.constant] >= 0) {
609 opline->result.num = func_slot[opline->op2.constant];
610 } else {
611 opline->result.num = cache_size;
612 cache_size += sizeof(void *);
613 func_slot[opline->op2.constant] = opline->result.num;
614 }
615 break;
617 if (opline->op2_type == IS_CONST) {
618 // op2 method
619 if (opline->op1_type == IS_UNUSED &&
620 method_slot[opline->op2.constant] >= 0) {
621 opline->result.num = method_slot[opline->op2.constant];
622 } else {
623 opline->result.num = cache_size;
624 cache_size += 2 * sizeof(void *);
625 if (opline->op1_type == IS_UNUSED) {
626 method_slot[opline->op2.constant] = opline->result.num;
627 }
628 }
629 }
630 break;
632 if (opline->op2_type == IS_CONST) {
633 // op2 static method
634 if (opline->op1_type == IS_CONST) {
635 opline->result.num = add_static_slot(&hash, op_array,
636 opline->op1.constant,
637 opline->op2.constant,
639 &cache_size);
640 } else {
641 opline->result.num = cache_size;
642 cache_size += 2 * sizeof(void *);
643 }
644 } else if (opline->op1_type == IS_CONST) {
645 // op1 class
646 if (class_slot[opline->op1.constant] >= 0) {
647 opline->result.num = class_slot[opline->op1.constant];
648 } else {
649 opline->result.num = cache_size;
650 cache_size += sizeof(void *);
651 class_slot[opline->op1.constant] = opline->result.num;
652 }
653 }
654 break;
655 case ZEND_DEFINED:
656 // op1 const
657 if (const_slot[opline->op1.constant] >= 0) {
658 opline->extended_value = const_slot[opline->op1.constant];
659 } else {
660 opline->extended_value = cache_size;
661 cache_size += sizeof(void *);
662 const_slot[opline->op1.constant] = opline->extended_value;
663 }
664 break;
666 // op2 const
667 if (const_slot[opline->op2.constant] >= 0) {
668 opline->extended_value = const_slot[opline->op2.constant];
669 } else {
670 opline->extended_value = cache_size;
671 cache_size += sizeof(void *);
672 const_slot[opline->op2.constant] = opline->extended_value;
673 }
674 break;
676 if (opline->op1_type == IS_CONST
677 && opline->op2_type == IS_CONST
678 && Z_TYPE(op_array->literals[opline->op2.constant]) == IS_STRING) {
679 // op1/op2 class_const
680 opline->extended_value = add_static_slot(&hash, op_array,
681 opline->op1.constant,
682 opline->op2.constant,
684 &cache_size);
685 } else {
686 opline->extended_value = cache_size;
687 cache_size += 2 * sizeof(void *);
688 }
689 break;
704 if (opline->op1_type == IS_CONST) {
705 // op1 static property
706 if (opline->op2_type == IS_CONST) {
707 opline->extended_value = add_static_slot(&hash, op_array,
708 opline->op2.constant,
709 opline->op1.constant,
711 &cache_size) | (opline->extended_value & ZEND_FETCH_OBJ_FLAGS);
712 } else {
713 opline->extended_value = cache_size | (opline->extended_value & ZEND_FETCH_OBJ_FLAGS);
714 cache_size += 3 * sizeof(void *);
715 }
716 } else if (opline->op2_type == IS_CONST) {
717 // op2 class
718 if (class_slot[opline->op2.constant] >= 0) {
719 opline->extended_value = class_slot[opline->op2.constant] | (opline->extended_value & ZEND_FETCH_OBJ_FLAGS);
720 } else {
721 opline->extended_value = cache_size | (opline->extended_value & ZEND_FETCH_OBJ_FLAGS);
722 class_slot[opline->op2.constant] = cache_size;
723 cache_size += sizeof(void *);
724 }
725 }
726 break;
727 case ZEND_FETCH_CLASS:
728 case ZEND_INSTANCEOF:
729 if (opline->op2_type == IS_CONST) {
730 // op2 class
731 if (class_slot[opline->op2.constant] >= 0) {
732 opline->extended_value = class_slot[opline->op2.constant];
733 } else {
734 opline->extended_value = cache_size;
735 cache_size += sizeof(void *);
736 class_slot[opline->op2.constant] = opline->extended_value;
737 }
738 }
739 break;
740 case ZEND_NEW:
741 if (opline->op1_type == IS_CONST) {
742 // op1 class
743 if (class_slot[opline->op1.constant] >= 0) {
744 opline->op2.num = class_slot[opline->op1.constant];
745 } else {
746 opline->op2.num = cache_size;
747 cache_size += sizeof(void *);
748 class_slot[opline->op1.constant] = opline->op2.num;
749 }
750 }
751 break;
752 case ZEND_CATCH:
753 if (opline->op1_type == IS_CONST) {
754 // op1 class
755 if (class_slot[opline->op1.constant] >= 0) {
756 opline->extended_value = class_slot[opline->op1.constant] | (opline->extended_value & ZEND_LAST_CATCH);
757 } else {
758 opline->extended_value = cache_size | (opline->extended_value & ZEND_LAST_CATCH);
759 cache_size += sizeof(void *);
760 class_slot[opline->op1.constant] = opline->extended_value & ~ZEND_LAST_CATCH;
761 }
762 }
763 break;
764 case ZEND_BIND_GLOBAL:
765 // op2 bind var
766 if (bind_var_slot[opline->op2.constant] >= 0) {
767 opline->extended_value = bind_var_slot[opline->op2.constant];
768 } else {
769 opline->extended_value = cache_size;
770 cache_size += sizeof(void *);
771 bind_var_slot[opline->op2.constant] = opline->extended_value;
772 }
773 break;
777 opline->extended_value = cache_size;
778 cache_size += sizeof(void *);
779 break;
780 case ZEND_SEND_VAL:
781 case ZEND_SEND_VAL_EX:
782 case ZEND_SEND_VAR:
783 case ZEND_SEND_VAR_EX:
786 case ZEND_SEND_REF:
789 if (opline->op2_type == IS_CONST) {
790 opline->result.num = cache_size;
791 cache_size += 2 * sizeof(void *);
792 }
793 break;
794 }
795 opline++;
796 }
797 op_array->cache_size = cache_size;
799 zend_arena_release(&ctx->arena, checkpoint);
800
801 if (1) {
802 opline = op_array->opcodes;
803 while (1) {
804 if (opline->opcode == ZEND_RECV_INIT) {
805 zval *val = &op_array->literals[opline->op2.constant];
806
807 if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
808 /* Ensure zval is aligned to 8 bytes */
809 op_array->cache_size = ZEND_MM_ALIGNED_SIZE_EX(op_array->cache_size, 8);
810 Z_CACHE_SLOT_P(val) = op_array->cache_size;
811 op_array->cache_size += sizeof(zval);
812 }
813 } else if (opline->opcode != ZEND_RECV) {
814 break;
815 }
816 opline++;
817 }
818 }
819
820#if DEBUG_COMPACT_LITERALS
821 {
822 fprintf(stderr, "Optimized literals table size %d\n", op_array->last_literal);
823
824 for (int i = 0; i < op_array->last_literal; i++) {
825 zend_string *str = zval_get_string(op_array->literals + i);
826 fprintf(stderr, "Literal %d, val (%zu):%s\n", i, ZSTR_LEN(str), ZSTR_VAL(str));
827 zend_string_release(str);
828 }
829 fflush(stderr);
830 }
831#endif
832 }
833}
fprintf($stream, string $format, mixed ... $values)
count(Countable|array $value, int $mode=COUNT_NORMAL)
fflush($stream)
#define LITERAL_INFO(n, related)
#define LITERAL_CLASS_CONST
void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx *ctx)
#define LITERAL_STATIC_PROPERTY
struct _literal_info literal_info
#define LITERAL_STATIC_METHOD
zval * zv
Definition ffi.c:3975
zend_long n
Definition ffi.c:4979
new_type kind
Definition ffi.c:4363
memset(ptr, 0, type->size)
zval * val
Definition ffi.c:4262
#define NULL
Definition gdcache.h:45
hash(string $algo, string $data, bool $binary=false, array $options=[])
Definition hash.stub.php:12
again j
unsigned const char * end
Definition php_ffi.h:51
unsigned const char * pos
Definition php_ffi.h:52
unsigned char key[REFLECTION_KEY_LEN]
zend_string * filename
zend_arg_info * arg_info
uint32_t num_args
zend_op * opcodes
zend_string * function_name
uint32_t fn_flags
znode_op op1
znode_op op2
uint8_t opcode
uint8_t op1_type
uint8_t op2_type
char val[1]
Definition zend_types.h:377
uint32_t constant
uint32_t num
#define ZEND_MM_ALIGNED_SIZE_EX(size, alignment)
Definition zend_alloc.h:37
struct _zval_struct zval
uint32_t num_args
zend_string_release_ex(func->internal_function.function_name, 0)
ZEND_API zend_string * zend_create_member_string(zend_string *class_name, zend_string *member_name)
struct _zend_op zend_op
#define IS_UNUSED
#define IS_CONST
#define ZEND_ACC_HAS_TYPE_HINTS
struct _zend_op_array zend_op_array
#define ZEND_EXTRA_VALUE
struct _zend_arg_info zend_arg_info
#define ZEND_FETCH_OBJ_FLAGS
#define ZEND_ACC_VARIADIC
#define ZEND_ISEMPTY
#define IS_CONSTANT_UNQUALIFIED_IN_NAMESPACE
#define ZEND_LAST_CATCH
ZEND_API int zend_op_array_extension_handles
ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht)
Definition zend_hash.c:1727
ZEND_API zval *ZEND_FASTCALL zend_hash_index_add_new(HashTable *ht, zend_ulong h, zval *pData)
Definition zend_hash.c:1214
ZEND_API void ZEND_FASTCALL zend_hash_clean(HashTable *ht)
Definition zend_hash.c:1869
ZEND_API zval *ZEND_FASTCALL zend_hash_add_new(HashTable *ht, zend_string *key, zval *pData)
Definition zend_hash.c:1007
ZEND_API zval *ZEND_FASTCALL zend_hash_find(const HashTable *ht, zend_string *key)
Definition zend_hash.c:2668
ZEND_API zval *ZEND_FASTCALL zend_hash_add(HashTable *ht, zend_string *key, zval *pData)
Definition zend_hash.c:992
ZEND_API zval *ZEND_FASTCALL zend_hash_index_find(const HashTable *ht, zend_ulong h)
Definition zend_hash.c:2701
#define zend_hash_init(ht, nSize, pHashFunction, pDestructor, persistent)
Definition zend_hash.h:108
struct _zend_string zend_string
struct _zend_optimizer_ctx zend_optimizer_ctx
#define ZEND_FALLTHROUGH
#define EXPECTED(condition)
#define ZEND_ASSERT(c)
#define UNEXPECTED(condition)
ZEND_API zend_string * zend_string_concat2(const char *str1, size_t str1_len, const char *str2, size_t str2_len)
ZEND_API zend_ulong ZEND_FASTCALL zend_string_hash_func(zend_string *str)
Definition zend_string.c:55
ZEND_API zend_string * zend_string_concat3(const char *str1, size_t str1_len, const char *str2, size_t str2_len, const char *str3, size_t str3_len)
#define ZSTR_H(zstr)
Definition zend_string.h:70
#define ZSTR_VAL(zstr)
Definition zend_string.h:68
#define ZSTR_LEN(zstr)
Definition zend_string.h:69
#define Z_TYPE_P(zval_p)
Definition zend_types.h:660
#define IS_TRUE
Definition zend_types.h:603
#define Z_DVAL(zval)
Definition zend_types.h:968
#define IS_FALSE
Definition zend_types.h:602
#define Z_STRVAL_P(zval_p)
Definition zend_types.h:975
#define ZVAL_LONG(z, l)
#define IS_STRING
Definition zend_types.h:606
#define ZEND_TYPE_IS_INTERSECTION(t)
Definition zend_types.h:186
struct _zend_array HashTable
Definition zend_types.h:386
#define IS_ARRAY
Definition zend_types.h:607
#define IS_DOUBLE
Definition zend_types.h:605
#define ZEND_TYPE_IS_UNION(t)
Definition zend_types.h:189
#define Z_STR_P(zval_p)
Definition zend_types.h:972
#define ZEND_TYPE_HAS_LIST(t)
Definition zend_types.h:180
#define Z_STRLEN_P(zval_p)
Definition zend_types.h:978
#define ZEND_TYPE_LIST_FOREACH_END()
Definition zend_types.h:217
#define IS_NULL
Definition zend_types.h:601
#define Z_STRVAL(zval)
Definition zend_types.h:974
#define Z_STRLEN(zval)
Definition zend_types.h:977
#define Z_EXTRA(zval)
Definition zend_types.h:695
#define IS_LONG
Definition zend_types.h:604
#define IS_CONSTANT_AST
Definition zend_types.h:611
#define Z_CACHE_SLOT_P(zval_p)
Definition zend_types.h:675
#define ZEND_TYPE_LIST_FOREACH(list, type_ptr)
Definition zend_types.h:211
#define Z_TYPE(zval)
Definition zend_types.h:659
#define ZEND_TYPE_LIST(t)
Definition zend_types.h:204
#define Z_ARRVAL(zval)
Definition zend_types.h:986
#define Z_LVAL_P(zval_p)
Definition zend_types.h:966
#define Z_LVAL(zval)
Definition zend_types.h:965
#define ZEND_TYPE_IS_COMPLEX(t)
Definition zend_types.h:171
uint32_t arg_num
op2
op1
zval * ret
#define ZEND_FETCH_STATIC_PROP_IS
#define ZEND_SEND_VAR_EX
#define ZEND_DECLARE_ANON_CLASS
#define ZEND_FETCH_CONSTANT
#define ZEND_ASSIGN_DIM_OP
#define ZEND_ASSIGN_STATIC_PROP_REF
#define ZEND_UNSET_STATIC_PROP
#define ZEND_PRE_DEC_OBJ
#define ZEND_RECV_INIT
#define ZEND_FETCH_OBJ_W
#define ZEND_NEW
#define ZEND_VERIFY_RETURN_TYPE
#define ZEND_SEND_VAL_EX
#define ZEND_FETCH_LIST_R
#define ZEND_FETCH_LIST_W
#define ZEND_INIT_FCALL
#define ZEND_SEND_VAL
#define ZEND_ASSIGN_DIM
#define ZEND_DECLARE_CLASS_DELAYED
#define ZEND_FETCH_OBJ_FUNC_ARG
#define ZEND_PRE_INC_OBJ
#define ZEND_FETCH_STATIC_PROP_R
#define ZEND_PRE_DEC_STATIC_PROP
#define ZEND_ASSIGN_STATIC_PROP_OP
#define ZEND_FETCH_DIM_FUNC_ARG
#define ZEND_DEFINED
#define ZEND_POST_INC_STATIC_PROP
#define ZEND_FETCH_STATIC_PROP_UNSET
#define ZEND_FETCH_OBJ_IS
#define ZEND_INSTANCEOF
#define ZEND_FETCH_OBJ_UNSET
#define ZEND_SEND_VAR
#define ZEND_POST_DEC_OBJ
#define ZEND_CHECK_FUNC_ARG
#define ZEND_ISSET_ISEMPTY_PROP_OBJ
#define ZEND_RECV
#define ZEND_FETCH_STATIC_PROP_FUNC_ARG
#define ZEND_INIT_NS_FCALL_BY_NAME
#define ZEND_UNSET_DIM
#define ZEND_ISSET_ISEMPTY_STATIC_PROP
#define ZEND_ASSIGN_STATIC_PROP
#define ZEND_POST_DEC_STATIC_PROP
#define ZEND_UNSET_OBJ
#define ZEND_INIT_FCALL_BY_NAME
#define ZEND_PRE_INC_STATIC_PROP
#define ZEND_SEND_VAR_NO_REF_EX
#define ZEND_FETCH_CLASS
#define ZEND_SEND_FUNC_ARG
#define ZEND_FETCH_OBJ_R
#define ZEND_ISSET_ISEMPTY_DIM_OBJ
#define ZEND_BIND_GLOBAL
#define ZEND_FETCH_DIM_W
#define ZEND_DECLARE_CLASS
#define ZEND_JMP_FRAMELESS
#define ZEND_INIT_PARENT_PROPERTY_HOOK_CALL
#define ZEND_ASSIGN_OBJ
#define ZEND_FETCH_STATIC_PROP_W
#define ZEND_ASSIGN_OBJ_OP
#define ZEND_ASSIGN_OBJ_REF
#define ZEND_FETCH_STATIC_PROP_RW
#define ZEND_FETCH_CLASS_CONSTANT
#define ZEND_RECV_VARIADIC
#define ZEND_FETCH_DIM_IS
#define ZEND_FETCH_OBJ_RW
#define ZEND_FETCH_DIM_UNSET
#define ZEND_SEND_VAR_NO_REF
#define ZEND_SEND_REF
#define ZEND_POST_INC_OBJ
#define ZEND_FETCH_DIM_R
#define ZEND_INIT_METHOD_CALL
#define ZEND_INIT_STATIC_METHOD_CALL
#define ZEND_CATCH
#define ZEND_FETCH_DIM_RW