1 /*
2 +----------------------------------------------------------------------+
3 | Zend JIT |
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 +----------------------------------------------------------------------+
17 */
18
19 static zend_op_array dummy_op_array;
20 static zend_jit_trace_info *zend_jit_traces = NULL;
21 static const void **zend_jit_exit_groups = NULL;
22
23 #define ZEND_JIT_COUNTER_NUM zend_jit_traces[0].root
24 #define ZEND_JIT_TRACE_NUM zend_jit_traces[0].id
25 #define ZEND_JIT_EXIT_NUM zend_jit_traces[0].exit_count
26 #define ZEND_JIT_EXIT_COUNTERS zend_jit_traces[0].exit_counters
27
28 #define ZEND_JIT_TRACE_STOP_DESCRIPTION(name, description) \
29 description,
30
31 static const char * zend_jit_trace_stop_description[] = {
32 ZEND_JIT_TRACE_STOP(ZEND_JIT_TRACE_STOP_DESCRIPTION)
33 };
34
zend_jit_trace_star_desc(uint8_t trace_flags)35 static zend_always_inline const char *zend_jit_trace_star_desc(uint8_t trace_flags)
36 {
37 if (trace_flags & ZEND_JIT_TRACE_START_LOOP) {
38 return "loop";
39 } else if (trace_flags & ZEND_JIT_TRACE_START_ENTER) {
40 return "enter";
41 } else if (trace_flags & ZEND_JIT_TRACE_START_RETURN) {
42 return "return";
43 } else {
44 ZEND_UNREACHABLE();
45 return "???";
46 }
47 }
48
zend_jit_trace_startup(zend_bool reattached)49 static int zend_jit_trace_startup(zend_bool reattached)
50 {
51 if (!reattached) {
52 zend_jit_traces = (zend_jit_trace_info*)zend_shared_alloc(sizeof(zend_jit_trace_info) * JIT_G(max_root_traces));
53 if (!zend_jit_traces) {
54 return FAILURE;
55 }
56 zend_jit_exit_groups = (const void**)zend_shared_alloc(sizeof(void*) * (ZEND_JIT_TRACE_MAX_EXITS/ZEND_JIT_EXIT_POINTS_PER_GROUP));
57 if (!zend_jit_exit_groups) {
58 return FAILURE;
59 }
60 ZEND_JIT_TRACE_NUM = 1;
61 ZEND_JIT_COUNTER_NUM = 0;
62 ZEND_JIT_EXIT_NUM = 0;
63 ZEND_JIT_EXIT_COUNTERS = 0;
64 ZCSG(jit_traces) = zend_jit_traces;
65 ZCSG(jit_exit_groups) = zend_jit_exit_groups;
66 } else {
67 zend_jit_traces = ZCSG(jit_traces);
68 if (!zend_jit_traces) {
69 return FAILURE;
70 }
71 zend_jit_exit_groups = ZCSG(jit_exit_groups);
72 if (!zend_jit_exit_groups) {
73 return FAILURE;
74 }
75 }
76
77 memset(&dummy_op_array, 0, sizeof(dummy_op_array));
78 dummy_op_array.fn_flags = ZEND_ACC_DONE_PASS_TWO;
79
80 JIT_G(exit_counters) = calloc(JIT_G(max_exit_counters), 1);
81 if (JIT_G(exit_counters) == NULL) {
82 return FAILURE;
83 }
84
85 return SUCCESS;
86 }
87
zend_jit_trace_allocate_exit_group(uint32_t n)88 static const void *zend_jit_trace_allocate_exit_group(uint32_t n)
89 {
90 dasm_State* dasm_state = NULL;
91 const void *entry;
92 char name[32];
93
94 dasm_init(&dasm_state, DASM_MAXSECTION);
95 dasm_setupglobal(&dasm_state, dasm_labels, zend_lb_MAX);
96 dasm_setup(&dasm_state, dasm_actions);
97 zend_jit_trace_exit_group_stub(&dasm_state, n);
98
99 sprintf(name, "jit$$trace_exit_%d", n);
100 entry = dasm_link_and_encode(&dasm_state, NULL, NULL, NULL, NULL, name, 0, SP_ADJ_JIT, SP_ADJ_NONE);
101 dasm_free(&dasm_state);
102
103 #ifdef HAVE_DISASM
104 if (JIT_G(debug) & ZEND_JIT_DEBUG_ASM) {
105 uint32_t i;
106
107 for (i = 0; i < ZEND_JIT_EXIT_POINTS_PER_GROUP; i++) {
108 sprintf(name, "jit$$trace_exit_%d", n + i);
109 zend_jit_disasm_add_symbol(name, (uintptr_t)entry + (i * ZEND_JIT_EXIT_POINTS_SPACING), ZEND_JIT_EXIT_POINTS_SPACING);
110 }
111 }
112 #endif
113
114 return entry;
115 }
116
zend_jit_trace_allocate_exit_point(uint32_t n)117 static const void *zend_jit_trace_allocate_exit_point(uint32_t n)
118 {
119 const void *group = NULL;
120
121 if (UNEXPECTED(n >= ZEND_JIT_TRACE_MAX_EXITS)) {
122 return NULL;
123 }
124 do {
125 group = zend_jit_trace_allocate_exit_group(ZEND_JIT_EXIT_NUM);
126 if (!group) {
127 return NULL;
128 }
129 zend_jit_exit_groups[ZEND_JIT_EXIT_NUM / ZEND_JIT_EXIT_POINTS_PER_GROUP] =
130 group;
131 ZEND_JIT_EXIT_NUM += ZEND_JIT_EXIT_POINTS_PER_GROUP;
132 } while (n >= ZEND_JIT_EXIT_NUM);
133 return (const void*)
134 ((const char*)group +
135 ((n % ZEND_JIT_EXIT_POINTS_PER_GROUP) * ZEND_JIT_EXIT_POINTS_SPACING));
136 }
137
zend_jit_trace_get_exit_addr(uint32_t n)138 static const void *zend_jit_trace_get_exit_addr(uint32_t n)
139 {
140 if (UNEXPECTED(n >= ZEND_JIT_EXIT_NUM)) {
141 return zend_jit_trace_allocate_exit_point(n);
142 }
143 return (const void*)
144 ((const char*)zend_jit_exit_groups[n / ZEND_JIT_EXIT_POINTS_PER_GROUP] +
145 ((n % ZEND_JIT_EXIT_POINTS_PER_GROUP) * ZEND_JIT_EXIT_POINTS_SPACING));
146 }
147
148 #if ZEND_JIT_TARGET_ARM64
zend_jit_get_current_trace_info(void)149 static zend_jit_trace_info *zend_jit_get_current_trace_info(void)
150 {
151 return &zend_jit_traces[ZEND_JIT_TRACE_NUM];
152 }
153
zend_jit_trace_find_exit_point(const void * addr)154 static uint32_t zend_jit_trace_find_exit_point(const void* addr)
155 {
156 uint32_t n = ZEND_JIT_EXIT_NUM / ZEND_JIT_EXIT_POINTS_PER_GROUP;
157 uint32_t i;
158
159 for (i = 0; i < n; i++) {
160 if ((const char*)addr >= (const char*)zend_jit_exit_groups[i]
161 && (const char*)addr < (const char*)zend_jit_exit_groups[i] +
162 (ZEND_JIT_EXIT_POINTS_PER_GROUP * ZEND_JIT_EXIT_POINTS_SPACING)) {
163 return (i * ZEND_JIT_EXIT_POINTS_PER_GROUP) +
164 ((const char*)addr - (const char*)zend_jit_exit_groups[i]) / ZEND_JIT_EXIT_POINTS_SPACING;
165 }
166 }
167 return (uint32_t)-1;
168 }
169 #endif
170
zend_jit_trace_get_exit_point(const zend_op * to_opline,uint32_t flags)171 static uint32_t zend_jit_trace_get_exit_point(const zend_op *to_opline, uint32_t flags)
172 {
173 zend_jit_trace_info *t = &zend_jit_traces[ZEND_JIT_TRACE_NUM];
174 uint32_t exit_point;
175 const zend_op_array *op_array;
176 uint32_t stack_offset = (uint32_t)-1;
177 uint32_t stack_size;
178 zend_jit_trace_stack *stack = NULL;
179
180 if (delayed_call_chain) {
181 assert(to_opline != NULL); /* CALL and IP share the same register */
182 flags |= ZEND_JIT_EXIT_RESTORE_CALL;
183 }
184 if (JIT_G(current_frame)) {
185 op_array = &JIT_G(current_frame)->func->op_array;
186 stack_size = op_array->last_var + op_array->T;
187 if (stack_size) {
188 stack = JIT_G(current_frame)->stack;
189 do {
190 if (STACK_TYPE(stack, stack_size-1) != IS_UNKNOWN
191 || STACK_MEM_TYPE(stack, stack_size-1) != IS_UNKNOWN
192 || STACK_REG(stack, stack_size-1) != ZREG_NONE) {
193 break;
194 }
195 stack_size--;
196 } while (stack_size);
197 }
198 } else {
199 op_array = NULL;
200 stack_size = 0;
201 }
202
203 /* Try to reuse exit points */
204 if (to_opline != NULL && t->exit_count > 0) {
205 uint32_t i = t->exit_count;
206
207 do {
208 i--;
209 if (stack_size == 0
210 || (t->exit_info[i].stack_size >= stack_size
211 && memcmp(t->stack_map + t->exit_info[i].stack_offset, stack, stack_size * sizeof(zend_jit_trace_stack)) == 0)) {
212 stack_offset = t->exit_info[i].stack_offset;
213 if (t->exit_info[i].opline == to_opline
214 && t->exit_info[i].flags == flags
215 && t->exit_info[i].stack_size == stack_size) {
216 return i;
217 }
218 }
219 } while (i > 0);
220 }
221
222 exit_point = t->exit_count;
223 if (exit_point < ZEND_JIT_TRACE_MAX_EXITS) {
224 if (stack_size != 0 && stack_offset == (uint32_t)-1) {
225 stack_offset = t->stack_map_size;
226 t->stack_map_size += stack_size;
227 // TODO: reduce number of reallocations ???
228 t->stack_map = erealloc(t->stack_map, t->stack_map_size * sizeof(zend_jit_trace_stack));
229 memcpy(t->stack_map + stack_offset, stack, stack_size * sizeof(zend_jit_trace_stack));
230 }
231 t->exit_count++;
232 t->exit_info[exit_point].opline = to_opline;
233 t->exit_info[exit_point].op_array = op_array;
234 t->exit_info[exit_point].flags = flags;
235 t->exit_info[exit_point].stack_size = stack_size;
236 t->exit_info[exit_point].stack_offset = stack_offset;
237 }
238
239 return exit_point;
240 }
241
zend_jit_trace_add_code(const void * start,uint32_t size)242 static void zend_jit_trace_add_code(const void *start, uint32_t size)
243 {
244 zend_jit_trace_info *t = &zend_jit_traces[ZEND_JIT_TRACE_NUM];
245
246 t->code_start = start;
247 t->code_size = size;
248 }
249
250 /**
251 * Locate a trace in the #zend_jit_traces array with the specified
252 * #code_start address.
253 *
254 * @return the #zend_jit_traces index or 0 if no such #code_start
255 * address was found
256 */
zend_jit_find_trace(const void * addr)257 static uint32_t zend_jit_find_trace(const void *addr)
258 {
259 uint32_t i;
260
261 for (i = 1; i < ZEND_JIT_TRACE_NUM; i++) {
262 if (zend_jit_traces[i].code_start == addr) {
263 return i;
264 }
265 }
266 return 0;
267 }
268
zend_jit_trace_name(const zend_op_array * op_array,uint32_t lineno)269 static zend_string *zend_jit_trace_name(const zend_op_array *op_array, uint32_t lineno)
270 {
271 smart_str buf = {0};
272
273 smart_str_appends(&buf, TRACE_PREFIX);
274 smart_str_append_long(&buf, (zend_long)ZEND_JIT_TRACE_NUM);
275 smart_str_appendc(&buf, '$');
276 if (op_array->function_name) {
277 if (op_array->scope) {
278 smart_str_appendl(&buf, ZSTR_VAL(op_array->scope->name), ZSTR_LEN(op_array->scope->name));
279 smart_str_appends(&buf, "::");
280 smart_str_appendl(&buf, ZSTR_VAL(op_array->function_name), ZSTR_LEN(op_array->function_name));
281 } else {
282 smart_str_appendl(&buf, ZSTR_VAL(op_array->function_name), ZSTR_LEN(op_array->function_name));
283 }
284 } else if (op_array->filename) {
285 smart_str_appendl(&buf, ZSTR_VAL(op_array->filename), ZSTR_LEN(op_array->filename));
286 }
287 smart_str_appendc(&buf, '$');
288 smart_str_append_long(&buf, (zend_long)lineno);
289 smart_str_0(&buf);
290 return buf.s;
291 }
292
zend_jit_trace_may_exit(const zend_op_array * op_array,const zend_op * opline)293 static int zend_jit_trace_may_exit(const zend_op_array *op_array, const zend_op *opline)
294 {
295 switch (opline->opcode) {
296 case ZEND_IS_IDENTICAL:
297 case ZEND_IS_NOT_IDENTICAL:
298 case ZEND_IS_EQUAL:
299 case ZEND_IS_NOT_EQUAL:
300 case ZEND_IS_SMALLER:
301 case ZEND_IS_SMALLER_OR_EQUAL:
302 case ZEND_CASE:
303 case ZEND_CASE_STRICT:
304 case ZEND_ISSET_ISEMPTY_CV:
305 case ZEND_ISSET_ISEMPTY_VAR:
306 case ZEND_ISSET_ISEMPTY_DIM_OBJ:
307 case ZEND_ISSET_ISEMPTY_PROP_OBJ:
308 case ZEND_ISSET_ISEMPTY_STATIC_PROP:
309 case ZEND_INSTANCEOF:
310 case ZEND_TYPE_CHECK:
311 case ZEND_DEFINED:
312 case ZEND_IN_ARRAY:
313 case ZEND_ARRAY_KEY_EXISTS:
314 if (opline->result_type & (IS_SMART_BRANCH_JMPNZ | IS_SMART_BRANCH_JMPZ)) {
315 /* smart branch */
316 return 1;
317 }
318 break;
319 case ZEND_JMPZNZ:
320 case ZEND_JMPZ:
321 case ZEND_JMPNZ:
322 case ZEND_JMPZ_EX:
323 case ZEND_JMPNZ_EX:
324 case ZEND_JMP_SET:
325 case ZEND_COALESCE:
326 case ZEND_JMP_NULL:
327 case ZEND_FE_RESET_R:
328 case ZEND_FE_RESET_RW:
329 case ZEND_ASSERT_CHECK:
330 case ZEND_FE_FETCH_R:
331 case ZEND_FE_FETCH_RW:
332 case ZEND_SWITCH_LONG:
333 case ZEND_SWITCH_STRING:
334 case ZEND_MATCH:
335 /* branch opcodes */
336 return 1;
337 case ZEND_NEW:
338 if (opline->extended_value == 0 && (opline+1)->opcode == ZEND_DO_FCALL) {
339 /* NEW may skip constructor without arguments */
340 return 1;
341 }
342 break;
343 case ZEND_CATCH:
344 case ZEND_FAST_CALL:
345 case ZEND_FAST_RET:
346 case ZEND_GENERATOR_CREATE:
347 case ZEND_GENERATOR_RETURN:
348 case ZEND_EXIT:
349 case ZEND_YIELD:
350 case ZEND_YIELD_FROM:
351 case ZEND_INCLUDE_OR_EVAL:
352 case ZEND_MATCH_ERROR:
353 /* unsupported */
354 return 1;
355 case ZEND_DO_FCALL:
356 /* potentially polymorphic call */
357 return 1;
358 #if 0
359 case ZEND_DO_UCALL:
360 case ZEND_DO_FCALL_BY_NAME:
361 /* monomorphic call */
362 // TODO: recompilation may change target ???
363 return 0;
364 #endif
365 case ZEND_RETURN_BY_REF:
366 case ZEND_RETURN:
367 /* return */
368 return !JIT_G(current_frame) || TRACE_FRAME_IS_UNKNOWN_RETURN(JIT_G(current_frame));
369 default:
370 break;
371 }
372 return 0;
373 }
374
zend_jit_trace_type_to_info_ex(zend_uchar type,uint32_t info)375 static zend_always_inline uint32_t zend_jit_trace_type_to_info_ex(zend_uchar type, uint32_t info)
376 {
377 if (type == IS_UNKNOWN) {
378 return info;
379 }
380 ZEND_ASSERT(info & (1 << type));
381 if (type < IS_STRING) {
382 return (1 << type);
383 } else if (type != IS_ARRAY) {
384 return (1 << type) | (info & (MAY_BE_RC1|MAY_BE_RCN));
385 } else {
386 return MAY_BE_ARRAY | (info & (MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF|MAY_BE_ARRAY_KEY_ANY|MAY_BE_RC1|MAY_BE_RCN));
387 }
388 }
389
zend_jit_trace_type_to_info(zend_uchar type)390 static zend_always_inline uint32_t zend_jit_trace_type_to_info(zend_uchar type)
391 {
392 return zend_jit_trace_type_to_info_ex(type, -1);
393 }
394
zend_jit_var_may_alias(const zend_op_array * op_array,const zend_ssa * ssa,uint32_t var)395 static zend_always_inline zend_ssa_alias_kind zend_jit_var_may_alias(const zend_op_array *op_array, const zend_ssa *ssa, uint32_t var)
396 {
397 if (var >= op_array->last_var) {
398 return NO_ALIAS;
399 } else if ((!op_array->function_name || (ssa->cfg.flags & ZEND_FUNC_INDIRECT_VAR_ACCESS))) {
400 return SYMTABLE_ALIAS;
401 } else if (ssa->vars) {
402 return ssa->vars[var].alias;
403 } else if (zend_string_equals_literal(op_array->vars[var], "http_response_header")) {
404 return HTTP_RESPONSE_HEADER_ALIAS;
405 }
406 return NO_ALIAS;
407 }
408
zend_jit_trace_add_op_guard(zend_ssa * tssa,int ssa_var,uint8_t op_type)409 static zend_always_inline void zend_jit_trace_add_op_guard(zend_ssa *tssa,
410 int ssa_var,
411 uint8_t op_type)
412 {
413 zend_ssa_var_info *info = &tssa->var_info[ssa_var];
414
415 if ((info->type & (MAY_BE_ANY|MAY_BE_UNDEF)) != (1 << op_type)) {
416 if (UNEXPECTED(tssa->vars[ssa_var].alias != NO_ALIAS)) {
417 info->type |= MAY_BE_GUARD;
418 } else {
419 info->type = MAY_BE_GUARD | zend_jit_trace_type_to_info_ex(op_type, info->type);
420 }
421 }
422 }
423
424 #define ADD_OP_GUARD(_ssa_var, _op_type) do { \
425 if (_ssa_var >= 0 && _op_type != IS_UNKNOWN) { \
426 zend_jit_trace_add_op_guard(tssa, _ssa_var, _op_type); \
427 } \
428 } while (0)
429
430 #define CHECK_OP_TRACE_TYPE(_var, _ssa_var, op_info, op_type) do { \
431 if (op_type != IS_UNKNOWN) { \
432 if ((op_info & MAY_BE_GUARD) != 0) { \
433 if (!zend_jit_type_guard(&dasm_state, opline, _var, op_type)) { \
434 goto jit_failure; \
435 } \
436 if (ssa->vars[_ssa_var].alias != NO_ALIAS) { \
437 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(_var), IS_UNKNOWN, 1); \
438 op_info = zend_jit_trace_type_to_info(op_type); \
439 } else { \
440 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(_var), op_type, 1); \
441 op_info &= ~MAY_BE_GUARD; \
442 ssa->var_info[_ssa_var].type &= op_info; \
443 } \
444 } \
445 } \
446 } while (0)
447
448 #define ADD_OP1_TRACE_GUARD() \
449 ADD_OP_GUARD(tssa->ops[idx].op1_use, op1_type)
450 #define ADD_OP2_TRACE_GUARD() \
451 ADD_OP_GUARD(tssa->ops[idx].op2_use, op2_type)
452 #define ADD_OP1_DATA_TRACE_GUARD() \
453 ADD_OP_GUARD(tssa->ops[idx+1].op1_use, op3_type)
454
455 #define CHECK_OP1_TRACE_TYPE() \
456 CHECK_OP_TRACE_TYPE(opline->op1.var, ssa_op->op1_use, op1_info, op1_type)
457 #define CHECK_OP2_TRACE_TYPE() \
458 CHECK_OP_TRACE_TYPE(opline->op2.var, ssa_op->op2_use, op2_info, op2_type)
459 #define CHECK_OP1_DATA_TRACE_TYPE() \
460 CHECK_OP_TRACE_TYPE((opline+1)->op1.var, (ssa_op+1)->op1_use, op1_data_info, op3_type)
461
zend_jit_trace_frame_size(const zend_op_array * op_array)462 static zend_always_inline size_t zend_jit_trace_frame_size(const zend_op_array *op_array)
463 {
464 if (op_array && op_array->type == ZEND_USER_FUNCTION) {
465 return ZEND_MM_ALIGNED_SIZE(offsetof(zend_jit_trace_stack_frame, stack) + ZEND_MM_ALIGNED_SIZE((op_array->last_var + op_array->T) * sizeof(zend_jit_trace_stack)));
466 } else if (op_array) {
467 return ZEND_MM_ALIGNED_SIZE(offsetof(zend_jit_trace_stack_frame, stack) + ZEND_MM_ALIGNED_SIZE(op_array->num_args * sizeof(zend_jit_trace_stack)));
468 } else {
469 return ZEND_MM_ALIGNED_SIZE(offsetof(zend_jit_trace_stack_frame, stack));
470 }
471 }
472
zend_jit_trace_call_frame(zend_jit_trace_stack_frame * frame,const zend_op_array * op_array)473 static zend_jit_trace_stack_frame* zend_jit_trace_call_frame(zend_jit_trace_stack_frame *frame, const zend_op_array *op_array)
474 {
475 return (zend_jit_trace_stack_frame*)((char*)frame + zend_jit_trace_frame_size(op_array));
476 }
477
zend_jit_trace_ret_frame(zend_jit_trace_stack_frame * frame,const zend_op_array * op_array)478 static zend_jit_trace_stack_frame* zend_jit_trace_ret_frame(zend_jit_trace_stack_frame *frame, const zend_op_array *op_array)
479 {
480 return (zend_jit_trace_stack_frame*)((char*)frame - zend_jit_trace_frame_size(op_array));
481 }
482
zend_jit_trace_send_type(const zend_op * opline,zend_jit_trace_stack_frame * call,zend_uchar type)483 static void zend_jit_trace_send_type(const zend_op *opline, zend_jit_trace_stack_frame *call, zend_uchar type)
484 {
485 zend_jit_trace_stack *stack = call->stack;
486 const zend_op_array *op_array = &call->func->op_array;
487 uint32_t arg_num = opline->op2.num;
488
489 if (arg_num > op_array->num_args) {
490 return;
491 }
492 if (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
493 zend_arg_info *arg_info;
494
495 ZEND_ASSERT(arg_num <= op_array->num_args);
496 arg_info = &op_array->arg_info[arg_num-1];
497
498 if (ZEND_TYPE_IS_SET(arg_info->type)) {
499 if (!(ZEND_TYPE_FULL_MASK(arg_info->type) & (1u << type))) {
500 return;
501 }
502 }
503 }
504 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), type, 1);
505 }
506
zend_jit_needs_arg_dtor(const zend_function * func,uint32_t arg_num,zend_call_info * call_info)507 static bool zend_jit_needs_arg_dtor(const zend_function *func, uint32_t arg_num, zend_call_info *call_info)
508 {
509 if (func
510 && func->type == ZEND_INTERNAL_FUNCTION
511 && (func->internal_function.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0
512 && arg_num < func->internal_function.num_args) {
513 const zend_internal_arg_info *arg_info = &func->internal_function.arg_info[arg_num];
514
515 if (ZEND_ARG_SEND_MODE(arg_info) == ZEND_SEND_BY_VAL
516 && ZEND_TYPE_IS_SET(arg_info->type)
517 && (ZEND_TYPE_FULL_MASK(arg_info->type) & MAY_BE_ANY) != MAY_BE_ANY) {
518 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
519 && JIT_G(current_frame)
520 && JIT_G(current_frame)->call
521 && JIT_G(current_frame)->call->func) {
522 uint32_t type = STACK_TYPE(JIT_G(current_frame)->call->stack, arg_num);
523
524 if (type != IS_UNKNOWN
525 && type < IS_STRING
526 && ZEND_TYPE_FULL_MASK(arg_info->type) & (1u << type)) {
527 return 0;
528 }
529 }
530 if (call_info && arg_num < call_info->num_args && call_info->arg_info[arg_num].opline) {
531 const zend_op *opline = call_info->arg_info[arg_num].opline;
532
533 if (opline->opcode == ZEND_SEND_VAL && opline->op1_type == IS_CONST) {
534 zval *zv = RT_CONSTANT(opline, opline->op1);
535
536 if (!Z_REFCOUNTED_P(zv)) {
537 uint32_t type = Z_TYPE_P(zv);
538
539 // TODO: few functions (e.g. pcntl_exec) modify arrays in-place ???
540 if (type != IS_ARRAY
541 && (ZEND_TYPE_FULL_MASK(arg_info->type) & (1u << type))) {
542 return 0;
543 }
544 }
545 }
546 }
547 }
548 }
549
550 return 1;
551 }
552
zend_jit_trace_build_ssa(const zend_op_array * op_array,zend_script * script)553 static zend_ssa *zend_jit_trace_build_ssa(const zend_op_array *op_array, zend_script *script)
554 {
555 zend_jit_op_array_trace_extension *jit_extension;
556 zend_ssa *ssa;
557
558 jit_extension =
559 (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
560 jit_extension->func_info.num = 0;
561 jit_extension->func_info.flags &= ZEND_FUNC_JIT_ON_FIRST_EXEC
562 | ZEND_FUNC_JIT_ON_PROF_REQUEST
563 | ZEND_FUNC_JIT_ON_HOT_COUNTERS
564 | ZEND_FUNC_JIT_ON_HOT_TRACE;
565 memset(&jit_extension->func_info.ssa, 0, sizeof(zend_func_info) - offsetof(zend_func_info, ssa));
566 ssa = &jit_extension->func_info.ssa;
567
568 if (JIT_G(opt_level) >= ZEND_JIT_LEVEL_OPT_FUNC) {
569 do {
570 if (zend_jit_op_array_analyze1(op_array, script, ssa) != SUCCESS) {
571 break;
572 }
573
574 if (JIT_G(opt_level) >= ZEND_JIT_LEVEL_OPT_FUNCS) {
575 if (zend_analyze_calls(&CG(arena), script, ZEND_CALL_TREE, (zend_op_array*)op_array, &jit_extension->func_info) != SUCCESS) {
576 break;
577 }
578 jit_extension->func_info.call_map = zend_build_call_map(&CG(arena), &jit_extension->func_info, op_array);
579 if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
580 zend_init_func_return_info(op_array, script, &jit_extension->func_info.return_info);
581 }
582 }
583
584 if (zend_jit_op_array_analyze2(op_array, script, ssa, 0) != SUCCESS) {
585 break;
586 }
587
588 if (JIT_G(debug) & ZEND_JIT_DEBUG_SSA) {
589 zend_dump_op_array(op_array, ZEND_DUMP_HIDE_UNREACHABLE|ZEND_DUMP_RC_INFERENCE|ZEND_DUMP_SSA, "JIT", ssa);
590 }
591 return ssa;
592 } while (0);
593 }
594
595 memset(ssa, 0, sizeof(zend_ssa));
596 ssa->cfg.blocks_count = 1;
597
598 if (JIT_G(opt_level) == ZEND_JIT_LEVEL_INLINE) {
599 zend_cfg cfg;
600 void *checkpoint = zend_arena_checkpoint(CG(arena));
601
602 if (zend_jit_build_cfg(op_array, &cfg) == SUCCESS) {
603 ssa->cfg.flags = cfg.flags;
604 } else{
605 ssa->cfg.flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
606 }
607
608 /* TODO: move this to zend_cfg.c ? */
609 if (!op_array->function_name) {
610 ssa->cfg.flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
611 }
612
613 zend_arena_release(&CG(arena), checkpoint);
614 }
615
616 return ssa;
617 }
618
619 static void zend_jit_dump_trace(zend_jit_trace_rec *trace_buffer, zend_ssa *tssa);
620 static void zend_jit_dump_exit_info(zend_jit_trace_info *t);
621
zend_jit_trace_op_len(const zend_op * opline)622 static zend_always_inline int zend_jit_trace_op_len(const zend_op *opline)
623 {
624 int len;
625
626 switch (opline->opcode) {
627 case ZEND_ASSIGN_DIM:
628 case ZEND_ASSIGN_OBJ:
629 case ZEND_ASSIGN_STATIC_PROP:
630 case ZEND_ASSIGN_DIM_OP:
631 case ZEND_ASSIGN_OBJ_OP:
632 case ZEND_ASSIGN_STATIC_PROP_OP:
633 case ZEND_ASSIGN_OBJ_REF:
634 case ZEND_ASSIGN_STATIC_PROP_REF:
635 return 2; /* OP_DATA */
636 case ZEND_RECV_INIT:
637 len = 1;
638 opline++;
639 while (opline->opcode == ZEND_RECV_INIT) {
640 len++;
641 opline++;
642 }
643 return len;
644 case ZEND_BIND_GLOBAL:
645 len = 1;
646 opline++;
647 while (opline->opcode == ZEND_BIND_GLOBAL) {
648 len++;
649 opline++;
650 }
651 return len;
652 // case ZEND_IS_IDENTICAL:
653 // case ZEND_IS_NOT_IDENTICAL:
654 // case ZEND_IS_EQUAL:
655 // case ZEND_IS_NOT_EQUAL:
656 // case ZEND_IS_SMALLER:
657 // case ZEND_IS_SMALLER_OR_EQUAL:
658 // case ZEND_CASE:
659 // case ZEND_ISSET_ISEMPTY_CV:
660 // case ZEND_ISSET_ISEMPTY_VAR:
661 // case ZEND_ISSET_ISEMPTY_DIM_OBJ:
662 // case ZEND_ISSET_ISEMPTY_PROP_OBJ:
663 // case ZEND_ISSET_ISEMPTY_STATIC_PROP:
664 // case ZEND_INSTANCEOF:
665 // case ZEND_TYPE_CHECK:
666 // case ZEND_DEFINED:
667 // case ZEND_IN_ARRAY:
668 // case ZEND_ARRAY_KEY_EXISTS:
669 default:
670 if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
671 return 2; /* JMPZ/JMPNZ */
672 }
673 return 1;
674 }
675 }
676
zend_jit_trace_add_phis(zend_jit_trace_rec * trace_buffer,uint32_t ssa_vars_count,zend_ssa * tssa,zend_jit_trace_stack * stack)677 static int zend_jit_trace_add_phis(zend_jit_trace_rec *trace_buffer, uint32_t ssa_vars_count, zend_ssa *tssa, zend_jit_trace_stack *stack)
678 {
679 const zend_op_array *op_array;
680 zend_jit_trace_rec *p;
681 int k, vars_count;
682 zend_bitset use, def;
683 uint32_t build_flags = ZEND_SSA_RC_INFERENCE | ZEND_SSA_USE_CV_RESULTS;
684 uint32_t set_size;
685 zend_ssa_phi *prev = NULL;
686 int level = 0;
687 ALLOCA_FLAG(use_heap);
688
689 op_array = trace_buffer->op_array;
690 set_size = zend_bitset_len(op_array->last_var + op_array->T);
691 use = ZEND_BITSET_ALLOCA(set_size * 2, use_heap);
692 memset(use, 0, set_size * 2 * ZEND_BITSET_ELM_SIZE);
693 def = use + set_size;
694 p = trace_buffer + ZEND_JIT_TRACE_START_REC_SIZE;
695 for (;;p++) {
696 if (p->op == ZEND_JIT_TRACE_VM && level == 0) {
697 const zend_op *opline = p->opline;
698 int len;
699
700 zend_dfg_add_use_def_op(op_array, opline, build_flags, use, def);
701 len = zend_jit_trace_op_len(opline);
702 while (len > 1) {
703 opline++;
704 if (opline->opcode != ZEND_OP_DATA) {
705 zend_dfg_add_use_def_op(op_array, opline, build_flags, use, def);
706 }
707 len--;
708 }
709 } else if (p->op == ZEND_JIT_TRACE_INIT_CALL) {
710 } else if (p->op == ZEND_JIT_TRACE_DO_ICALL) {
711 } else if (p->op == ZEND_JIT_TRACE_ENTER) {
712 level++;
713 } else if (p->op == ZEND_JIT_TRACE_BACK) {
714 if (level == 0) {
715 // Phi for recursive calls and returns are not supported yet ???
716 assert(0);
717 } else {
718 level--;
719 }
720 } else if (p->op == ZEND_JIT_TRACE_END) {
721 break;
722 }
723 }
724
725 zend_bitset_intersection(use, def, set_size);
726
727 if (trace_buffer->start == ZEND_JIT_TRACE_START_ENTER) {
728 vars_count = op_array->last_var;
729 } else {
730 vars_count = op_array->last_var + op_array->T;
731 }
732 for (k = 0; k < vars_count; k++) {
733 if (zend_bitset_in(use, k)) {
734 zend_ssa_phi *phi = zend_arena_calloc(&CG(arena), 1,
735 ZEND_MM_ALIGNED_SIZE(sizeof(zend_ssa_phi)) +
736 ZEND_MM_ALIGNED_SIZE(sizeof(int) * 2) +
737 sizeof(void*) * 2);
738 phi->sources = (int*)(((char*)phi) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_ssa_phi)));
739 phi->sources[0] = STACK_VAR(stack, k);
740 phi->sources[1] = -1;
741 phi->use_chains = (zend_ssa_phi**)(((char*)phi->sources) + ZEND_MM_ALIGNED_SIZE(sizeof(int) * 2));
742 phi->pi = -1;
743 phi->var = k;
744 phi->ssa_var = ssa_vars_count;
745 SET_STACK_VAR(stack, k, ssa_vars_count);
746 ssa_vars_count++;
747 phi->block = 1;
748 if (prev) {
749 prev->next = phi;
750 } else {
751 tssa->blocks[1].phis = phi;
752 }
753 prev = phi;
754 }
755 }
756
757 free_alloca(use, use_heap);
758
759 return ssa_vars_count;
760 }
761
zend_jit_trace_add_call_phis(zend_jit_trace_rec * trace_buffer,uint32_t ssa_vars_count,zend_ssa * tssa,zend_jit_trace_stack * stack)762 static int zend_jit_trace_add_call_phis(zend_jit_trace_rec *trace_buffer, uint32_t ssa_vars_count, zend_ssa *tssa, zend_jit_trace_stack *stack)
763 {
764 zend_ssa_phi *prev = NULL;
765 const zend_op_array *op_array = trace_buffer->op_array;
766 const zend_op *opline = trace_buffer[1].opline;
767 int count = opline - op_array->opcodes;
768 int i;
769
770 for(i = 0; i < count; i++) {
771 zend_ssa_phi *phi = zend_arena_calloc(&CG(arena), 1,
772 ZEND_MM_ALIGNED_SIZE(sizeof(zend_ssa_phi)) +
773 ZEND_MM_ALIGNED_SIZE(sizeof(int) * 2) +
774 sizeof(void*) * 2);
775 phi->sources = (int*)(((char*)phi) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_ssa_phi)));
776 phi->sources[0] = STACK_VAR(stack, i);
777 phi->sources[1] = -1;
778 phi->use_chains = (zend_ssa_phi**)(((char*)phi->sources) + ZEND_MM_ALIGNED_SIZE(sizeof(int) * 2));
779 phi->pi = -1;
780 phi->var = i;
781 phi->ssa_var = ssa_vars_count;
782 SET_STACK_VAR(stack, i, ssa_vars_count);
783 ssa_vars_count++;
784 phi->block = 1;
785 if (prev) {
786 prev->next = phi;
787 } else {
788 tssa->blocks[1].phis = phi;
789 }
790 prev = phi;
791 }
792 return ssa_vars_count;
793 }
794
zend_jit_trace_add_ret_phis(zend_jit_trace_rec * trace_buffer,uint32_t ssa_vars_count,zend_ssa * tssa,zend_jit_trace_stack * stack)795 static int zend_jit_trace_add_ret_phis(zend_jit_trace_rec *trace_buffer, uint32_t ssa_vars_count, zend_ssa *tssa, zend_jit_trace_stack *stack)
796 {
797 const zend_op *opline = trace_buffer[1].opline - 1;
798 int i;
799
800 if (RETURN_VALUE_USED(opline)) {
801 zend_ssa_phi *phi = zend_arena_calloc(&CG(arena), 1,
802 ZEND_MM_ALIGNED_SIZE(sizeof(zend_ssa_phi)) +
803 ZEND_MM_ALIGNED_SIZE(sizeof(int) * 2) +
804 sizeof(void*) * 2);
805
806 i = EX_VAR_TO_NUM(opline->result.var);
807 phi->sources = (int*)(((char*)phi) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_ssa_phi)));
808 phi->sources[0] = STACK_VAR(stack, i);
809 phi->sources[1] = -1;
810 phi->use_chains = (zend_ssa_phi**)(((char*)phi->sources) + ZEND_MM_ALIGNED_SIZE(sizeof(int) * 2));
811 phi->pi = -1;
812 phi->var = i;
813 phi->ssa_var = ssa_vars_count;
814 SET_STACK_VAR(stack, i, ssa_vars_count);
815 ssa_vars_count++;
816 phi->block = 1;
817 tssa->blocks[1].phis = phi;
818 }
819 return ssa_vars_count;
820 }
821
zend_jit_trace_copy_ssa_var_info(const zend_op_array * op_array,const zend_ssa * ssa,const zend_op ** tssa_opcodes,zend_ssa * tssa,int ssa_var)822 static int zend_jit_trace_copy_ssa_var_info(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op **tssa_opcodes, zend_ssa *tssa, int ssa_var)
823 {
824 int var, use;
825 zend_ssa_op *op;
826 zend_ssa_var_info *info;
827 unsigned int no_val;
828 zend_ssa_alias_kind alias;
829
830 if (tssa->vars[ssa_var].phi_use_chain) {
831 // TODO: this may be incorrect ???
832 var = tssa->vars[ssa_var].phi_use_chain->ssa_var;
833 } else {
834 var = ssa_var;
835 }
836 use = tssa->vars[var].use_chain;
837 if (use >= 0) {
838 ZEND_ASSERT((tssa_opcodes[use] - op_array->opcodes) < op_array->last);
839 op = ssa->ops + (tssa_opcodes[use] - op_array->opcodes);
840 if (tssa->ops[use].op1_use == var) {
841 no_val = ssa->vars[op->op1_use].no_val;
842 alias = ssa->vars[op->op1_use].alias;
843 info = ssa->var_info + op->op1_use;
844 } else if (tssa->ops[use].op2_use == var) {
845 no_val = ssa->vars[op->op2_use].no_val;
846 alias = ssa->vars[op->op2_use].alias;
847 info = ssa->var_info + op->op2_use;
848 } else if (tssa->ops[use].result_use == var) {
849 no_val = ssa->vars[op->result_use].no_val;
850 alias = ssa->vars[op->result_use].alias;
851 info = ssa->var_info + op->result_use;
852 } else {
853 assert(0);
854 return 0;
855 }
856 tssa->vars[ssa_var].no_val = no_val;
857 tssa->vars[ssa_var].alias = alias;
858 memcpy(&tssa->var_info[ssa_var], info, sizeof(zend_ssa_var_info));
859 return 1;
860 }
861 return 0;
862 }
863
zend_jit_trace_propagate_range(const zend_op_array * op_array,const zend_op ** tssa_opcodes,zend_ssa * tssa,int ssa_var)864 static void zend_jit_trace_propagate_range(const zend_op_array *op_array, const zend_op **tssa_opcodes, zend_ssa *tssa, int ssa_var)
865 {
866 zend_ssa_range tmp;
867 int def = tssa->vars[ssa_var].definition;
868
869 if (tssa->vars[ssa_var].alias == NO_ALIAS
870 && zend_inference_propagate_range(op_array, tssa, (zend_op*)tssa_opcodes[def], (zend_ssa_op*)&tssa->ops[def], ssa_var, &tmp)) {
871 tssa->var_info[ssa_var].range.min = tmp.min;
872 tssa->var_info[ssa_var].range.max = tmp.max;
873 tssa->var_info[ssa_var].range.underflow = tmp.underflow;
874 tssa->var_info[ssa_var].range.overflow = tmp.overflow;
875 tssa->var_info[ssa_var].has_range = 1;
876 }
877 }
878
zend_jit_trace_copy_ssa_var_range(const zend_op_array * op_array,const zend_ssa * ssa,const zend_op ** tssa_opcodes,zend_ssa * tssa,int ssa_var)879 static void zend_jit_trace_copy_ssa_var_range(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op **tssa_opcodes, zend_ssa *tssa, int ssa_var)
880 {
881 int def;
882 zend_ssa_op *op;
883 zend_ssa_var_info *info;
884 unsigned int no_val;
885 zend_ssa_alias_kind alias;
886
887 def = tssa->vars[ssa_var].definition;
888 if (def >= 0) {
889 ZEND_ASSERT((tssa_opcodes[def] - op_array->opcodes) < op_array->last);
890 op = ssa->ops + (tssa_opcodes[def] - op_array->opcodes);
891 if (tssa->ops[def].op1_def == ssa_var) {
892 no_val = ssa->vars[op->op1_def].no_val;
893 alias = ssa->vars[op->op1_def].alias;
894 info = ssa->var_info + op->op1_def;
895 } else if (tssa->ops[def].op2_def == ssa_var) {
896 no_val = ssa->vars[op->op2_def].no_val;
897 alias = ssa->vars[op->op2_def].alias;
898 info = ssa->var_info + op->op2_def;
899 } else if (tssa->ops[def].result_def == ssa_var) {
900 no_val = ssa->vars[op->result_def].no_val;
901 alias = ssa->vars[op->result_def].alias;
902 info = ssa->var_info + op->result_def;
903 } else {
904 assert(0);
905 return;
906 }
907
908 tssa->vars[ssa_var].no_val = no_val;
909 tssa->vars[ssa_var].alias = alias;
910
911 if (!(info->type & MAY_BE_REF)) {
912 zend_jit_trace_propagate_range(op_array, tssa_opcodes, tssa, ssa_var);
913 }
914
915 if (info->has_range) {
916 if (tssa->var_info[ssa_var].has_range) {
917 tssa->var_info[ssa_var].range.min = MAX(tssa->var_info[ssa_var].range.min, info->range.min);
918 tssa->var_info[ssa_var].range.max = MIN(tssa->var_info[ssa_var].range.max, info->range.max);
919 tssa->var_info[ssa_var].range.underflow = tssa->var_info[ssa_var].range.underflow && info->range.underflow;
920 tssa->var_info[ssa_var].range.overflow = tssa->var_info[ssa_var].range.overflow && info->range.overflow;
921 } else {
922 tssa->var_info[ssa_var].has_range = 1;
923 tssa->var_info[ssa_var].range = info->range;
924 }
925 }
926 }
927 }
928
zend_jit_trace_restrict_ssa_var_info(const zend_op_array * op_array,const zend_ssa * ssa,const zend_op ** tssa_opcodes,zend_ssa * tssa,int ssa_var)929 static int zend_jit_trace_restrict_ssa_var_info(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op **tssa_opcodes, zend_ssa *tssa, int ssa_var)
930 {
931 int def;
932 zend_ssa_op *op;
933 zend_ssa_var_info *info;
934
935 def = tssa->vars[ssa_var].definition;
936 if (def >= 0) {
937 ZEND_ASSERT((tssa_opcodes[def] - op_array->opcodes) < op_array->last);
938 op = ssa->ops + (tssa_opcodes[def] - op_array->opcodes);
939 if (tssa->ops[def].op1_def == ssa_var) {
940 info = ssa->var_info + op->op1_def;
941 } else if (tssa->ops[def].op2_def == ssa_var) {
942 info = ssa->var_info + op->op2_def;
943 } else if (tssa->ops[def].result_def == ssa_var) {
944 info = ssa->var_info + op->result_def;
945 } else {
946 assert(0);
947 return 0;
948 }
949 tssa->var_info[ssa_var].type &= info->type;
950 if (info->ce) {
951 if (tssa->var_info[ssa_var].ce) {
952 if (tssa->var_info[ssa_var].ce != info->ce) {
953 if (instanceof_function(tssa->var_info[ssa_var].ce, info->ce)) {
954 /* everything fine */
955 } else if (instanceof_function(info->ce, tssa->var_info[ssa_var].ce)) {
956 // TODO: TSSA may miss Pi() functions and corresponding instanceof() constraints ???
957 } else {
958 // TODO: classes may implement the same interface ???
959 //ZEND_UNREACHABLE();
960 }
961 }
962 tssa->var_info[ssa_var].is_instanceof =
963 tssa->var_info[ssa_var].is_instanceof && info->is_instanceof;
964 } else {
965 tssa->var_info[ssa_var].ce = info->ce;
966 tssa->var_info[ssa_var].is_instanceof = info->is_instanceof;
967 }
968 }
969 if (info->has_range) {
970 if (tssa->var_info[ssa_var].has_range) {
971 tssa->var_info[ssa_var].range.min = MAX(tssa->var_info[ssa_var].range.min, info->range.min);
972 tssa->var_info[ssa_var].range.max = MIN(tssa->var_info[ssa_var].range.max, info->range.max);
973 tssa->var_info[ssa_var].range.underflow = tssa->var_info[ssa_var].range.underflow && info->range.underflow;
974 tssa->var_info[ssa_var].range.overflow = tssa->var_info[ssa_var].range.overflow && info->range.overflow;
975 } else {
976 tssa->var_info[ssa_var].has_range = 1;
977 tssa->var_info[ssa_var].range = info->range;
978 }
979 }
980 return 1;
981 }
982 return 0;
983 }
984
find_return_ssa_var(zend_jit_trace_rec * p,zend_ssa_op * ssa_op)985 static int find_return_ssa_var(zend_jit_trace_rec *p, zend_ssa_op *ssa_op)
986 {
987 while (1) {
988 if (p->op == ZEND_JIT_TRACE_VM) {
989 if (p->opline->opcode == ZEND_DO_UCALL
990 || p->opline->opcode == ZEND_DO_FCALL_BY_NAME
991 || p->opline->opcode == ZEND_DO_FCALL) {
992 if (p->opline->result_type != IS_UNUSED) {
993 return ssa_op->result_def;
994 }
995 }
996 return -1;
997 } else if (p->op >= ZEND_JIT_TRACE_OP1_TYPE && p->op <= ZEND_JIT_TRACE_VAL_INFO) {
998 /*skip */
999 } else {
1000 return -1;
1001 }
1002 p--;
1003 }
1004 }
1005
zend_jit_trace_find_init_fcall_op(zend_jit_trace_rec * p,const zend_op_array * op_array)1006 static const zend_op *zend_jit_trace_find_init_fcall_op(zend_jit_trace_rec *p, const zend_op_array *op_array)
1007 {
1008 if (!(p->info & ZEND_JIT_TRACE_FAKE_INIT_CALL)) {
1009 p--;
1010 while (1) {
1011 if (p->op == ZEND_JIT_TRACE_VM) {
1012 if (p->opline->opcode == ZEND_INIT_FCALL
1013 || p->opline->opcode == ZEND_INIT_FCALL_BY_NAME
1014 || p->opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME
1015 || p->opline->opcode == ZEND_INIT_DYNAMIC_CALL
1016 || p->opline->opcode == ZEND_INIT_USER_CALL
1017 || p->opline->opcode == ZEND_NEW
1018 || p->opline->opcode == ZEND_INIT_METHOD_CALL
1019 || p->opline->opcode == ZEND_INIT_STATIC_METHOD_CALL) {
1020 return p->opline;
1021 }
1022 return NULL;
1023 } else if (p->op >= ZEND_JIT_TRACE_OP1_TYPE && p->op <= ZEND_JIT_TRACE_VAL_INFO) {
1024 /*skip */
1025 } else {
1026 return NULL;
1027 }
1028 p--;
1029 }
1030 } else {
1031 const zend_op *opline = NULL;
1032 int call_level = 0;
1033
1034 p++;
1035 while (1) {
1036 if (p->op == ZEND_JIT_TRACE_VM) {
1037 opline = p->opline;
1038 break;
1039 } else if (p->op == ZEND_JIT_TRACE_INIT_CALL) {
1040 call_level++;
1041 /*skip */
1042 } else {
1043 return NULL;
1044 }
1045 p--;
1046 }
1047 if (opline) {
1048 while (opline > op_array->opcodes) {
1049 opline--;
1050 switch (opline->opcode) {
1051 case ZEND_INIT_FCALL:
1052 case ZEND_INIT_FCALL_BY_NAME:
1053 case ZEND_INIT_NS_FCALL_BY_NAME:
1054 case ZEND_INIT_METHOD_CALL:
1055 case ZEND_INIT_DYNAMIC_CALL:
1056 case ZEND_INIT_STATIC_METHOD_CALL:
1057 case ZEND_INIT_USER_CALL:
1058 case ZEND_NEW:
1059 if (call_level == 0) {
1060 return opline;
1061 }
1062 call_level--;
1063 break;
1064 case ZEND_DO_FCALL:
1065 case ZEND_DO_ICALL:
1066 case ZEND_DO_UCALL:
1067 case ZEND_DO_FCALL_BY_NAME:
1068 case ZEND_CALLABLE_CONVERT:
1069 call_level++;
1070 break;
1071 }
1072 }
1073 }
1074 }
1075 return NULL;
1076 }
1077
is_checked_guard(const zend_ssa * tssa,const zend_op ** ssa_opcodes,uint32_t var,uint32_t phi_var)1078 static int is_checked_guard(const zend_ssa *tssa, const zend_op **ssa_opcodes, uint32_t var, uint32_t phi_var)
1079 {
1080 if ((tssa->var_info[phi_var].type & MAY_BE_ANY) == MAY_BE_LONG
1081 && !(tssa->var_info[var].type & MAY_BE_REF)) {
1082 int idx = tssa->vars[var].definition;
1083
1084 if (idx >= 0) {
1085 if (tssa->ops[idx].op1_def == var) {
1086 const zend_op *opline = ssa_opcodes[idx];
1087 if (opline->opcode == ZEND_PRE_DEC
1088 || opline->opcode == ZEND_PRE_INC
1089 || opline->opcode == ZEND_POST_DEC
1090 || opline->opcode == ZEND_POST_INC) {
1091 if (tssa->ops[idx].op1_use >= 0
1092 && (tssa->var_info[tssa->ops[idx].op1_use].type & MAY_BE_STRING)) {
1093 return 0;
1094 }
1095 if (!(tssa->var_info[tssa->ops[idx].op1_use].type & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
1096 return 0;
1097 }
1098 return 1;
1099 } else if (opline->opcode == ZEND_ASSIGN_OP
1100 && (opline->extended_value == ZEND_ADD
1101 || opline->extended_value == ZEND_SUB
1102 || opline->extended_value == ZEND_MUL)) {
1103 if ((opline->op2_type & (IS_VAR|IS_CV))
1104 && tssa->ops[idx].op2_use >= 0
1105 && (tssa->var_info[tssa->ops[idx].op2_use].type & MAY_BE_REF)) {
1106 return 0;
1107 }
1108 if (!(tssa->var_info[tssa->ops[idx].op1_use].type & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
1109 return 0;
1110 }
1111 if (opline->op2_type == IS_CONST) {
1112 zval *zv = RT_CONSTANT(opline, opline->op2);
1113 if (Z_TYPE_P(zv) != IS_LONG && Z_TYPE_P(zv) != IS_DOUBLE) {
1114 return 0;
1115 }
1116 } else if (!(tssa->var_info[tssa->ops[idx].op2_use].type & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
1117 return 0;
1118 }
1119 return 1;
1120 }
1121 }
1122 if (tssa->ops[idx].result_def == var) {
1123 const zend_op *opline = ssa_opcodes[idx];
1124 if (opline->opcode == ZEND_ADD
1125 || opline->opcode == ZEND_SUB
1126 || opline->opcode == ZEND_MUL) {
1127 if ((opline->op1_type & (IS_VAR|IS_CV))
1128 && tssa->ops[idx].op1_use >= 0
1129 && (tssa->var_info[tssa->ops[idx].op1_use].type & MAY_BE_REF)) {
1130 return 0;
1131 }
1132 if ((opline->op2_type & (IS_VAR|IS_CV))
1133 && tssa->ops[idx].op2_use >= 0
1134 && (tssa->var_info[tssa->ops[idx].op2_use].type & MAY_BE_REF)) {
1135 return 0;
1136 }
1137 if (opline->op1_type == IS_CONST) {
1138 zval *zv = RT_CONSTANT(opline, opline->op1);
1139 if (Z_TYPE_P(zv) != IS_LONG && Z_TYPE_P(zv) != IS_DOUBLE) {
1140 return 0;
1141 }
1142 } else if (!(tssa->var_info[tssa->ops[idx].op1_use].type & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
1143 return 0;
1144 }
1145 if (opline->op2_type == IS_CONST) {
1146 zval *zv = RT_CONSTANT(opline, opline->op2);
1147 if (Z_TYPE_P(zv) != IS_LONG && Z_TYPE_P(zv) != IS_DOUBLE) {
1148 return 0;
1149 }
1150 } else if (!(tssa->var_info[tssa->ops[idx].op2_use].type & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
1151 return 0;
1152 }
1153 } else if (opline->opcode == ZEND_PRE_DEC
1154 || opline->opcode == ZEND_PRE_INC
1155 || opline->opcode == ZEND_POST_DEC
1156 || opline->opcode == ZEND_POST_INC) {
1157 if ((opline->op1_type & (IS_VAR|IS_CV))
1158 && tssa->ops[idx].op1_use >= 0
1159 && (tssa->var_info[tssa->ops[idx].op1_use].type & MAY_BE_REF)) {
1160 return 0;
1161 }
1162 if (!(tssa->var_info[tssa->ops[idx].op1_use].type & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
1163 return 0;
1164 }
1165 return 1;
1166 }
1167 }
1168 }
1169 }
1170 return 0;
1171 }
1172
1173 typedef struct _zend_tssa {
1174 zend_ssa ssa;
1175 const zend_op **tssa_opcodes;
1176 int used_stack;
1177 } zend_tssa;
1178
1179 static const zend_op _nop_opcode = {0};
1180
zend_jit_trace_build_tssa(zend_jit_trace_rec * trace_buffer,uint32_t parent_trace,uint32_t exit_num,zend_script * script,const zend_op_array ** op_arrays,int * num_op_arrays_ptr)1181 static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uint32_t parent_trace, uint32_t exit_num, zend_script *script, const zend_op_array **op_arrays, int *num_op_arrays_ptr)
1182 {
1183 zend_ssa *tssa;
1184 zend_ssa_op *ssa_ops, *op;
1185 zend_ssa_var *ssa_vars;
1186 zend_ssa_var_info *ssa_var_info;
1187 const zend_op_array *op_array;
1188 const zend_op *opline;
1189 const zend_op **ssa_opcodes;
1190 zend_jit_trace_rec *p;
1191 int i, v, idx, len, ssa_ops_count, vars_count, ssa_vars_count;
1192 zend_jit_trace_stack *stack;
1193 uint32_t build_flags = ZEND_SSA_RC_INFERENCE | ZEND_SSA_USE_CV_RESULTS;
1194 uint32_t optimization_level = 0;
1195 int call_level, level, num_op_arrays, used_stack, max_used_stack;
1196 size_t frame_size, stack_top, stack_size, stack_bottom;
1197 zend_jit_op_array_trace_extension *jit_extension;
1198 zend_ssa *ssa;
1199 zend_jit_trace_stack_frame *frame, *top, *call;
1200 zend_ssa_var_info return_value_info;
1201
1202 /* 1. Count number of TSSA opcodes;
1203 * Count number of activation frames;
1204 * Calculate size of abstract stack;
1205 * Construct regular SSA for involved op_array */
1206 op_array = trace_buffer->op_array;
1207 stack_top = stack_size = zend_jit_trace_frame_size(op_array);
1208 stack_bottom = 0;
1209 p = trace_buffer + ZEND_JIT_TRACE_START_REC_SIZE;
1210 ssa_ops_count = 0;
1211 call_level = 0;
1212 level = 0;
1213 num_op_arrays = 0;
1214 /* Remember op_array to cleanup */
1215 op_arrays[num_op_arrays++] = op_array;
1216 /* Build SSA */
1217 ssa = zend_jit_trace_build_ssa(op_array, script);
1218 for (;;p++) {
1219 if (p->op == ZEND_JIT_TRACE_VM) {
1220 if (JIT_G(opt_level) < ZEND_JIT_LEVEL_OPT_FUNC) {
1221 const zend_op *opline = p->opline;
1222
1223 switch (opline->opcode) {
1224 case ZEND_INCLUDE_OR_EVAL:
1225 ssa->cfg.flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
1226 break;
1227 case ZEND_FETCH_R:
1228 case ZEND_FETCH_W:
1229 case ZEND_FETCH_RW:
1230 case ZEND_FETCH_FUNC_ARG:
1231 case ZEND_FETCH_IS:
1232 case ZEND_FETCH_UNSET:
1233 case ZEND_UNSET_VAR:
1234 case ZEND_ISSET_ISEMPTY_VAR:
1235 if (opline->extended_value & ZEND_FETCH_LOCAL) {
1236 ssa->cfg.flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
1237 } else if ((opline->extended_value & (ZEND_FETCH_GLOBAL | ZEND_FETCH_GLOBAL_LOCK)) &&
1238 !op_array->function_name) {
1239 ssa->cfg.flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
1240 }
1241 break;
1242 }
1243 }
1244 ssa_ops_count += zend_jit_trace_op_len(p->opline);
1245 } else if (p->op == ZEND_JIT_TRACE_INIT_CALL) {
1246 call_level++;
1247 stack_top += zend_jit_trace_frame_size(p->op_array);
1248 if (stack_top > stack_size) {
1249 stack_size = stack_top;
1250 }
1251 } else if (p->op == ZEND_JIT_TRACE_DO_ICALL) {
1252 if (JIT_G(opt_level) < ZEND_JIT_LEVEL_OPT_FUNC) {
1253 if (p->func != (zend_function*)&zend_pass_function
1254 && (zend_string_equals_literal(p->func->common.function_name, "extract")
1255 || zend_string_equals_literal(p->func->common.function_name, "compact")
1256 || zend_string_equals_literal(p->func->common.function_name, "get_defined_vars"))) {
1257 ssa->cfg.flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
1258 }
1259 }
1260 frame_size = zend_jit_trace_frame_size(p->op_array);
1261 if (call_level == 0) {
1262 if (stack_top + frame_size > stack_size) {
1263 stack_size = stack_top + frame_size;
1264 }
1265 } else {
1266 call_level--;
1267 stack_top -= frame_size;
1268 }
1269 } else if (p->op == ZEND_JIT_TRACE_ENTER) {
1270 op_array = p->op_array;
1271 if (call_level == 0) {
1272 stack_top += zend_jit_trace_frame_size(op_array);
1273 if (stack_top > stack_size) {
1274 stack_size = stack_top;
1275 }
1276 } else {
1277 call_level--;
1278 }
1279 level++;
1280 jit_extension =
1281 (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
1282 ssa = &jit_extension->func_info.ssa;
1283 if (ssa->cfg.blocks_count) {
1284 /* pass */
1285 } else if (num_op_arrays == ZEND_JIT_TRACE_MAX_FUNCS) {
1286 /* Too many functions in single trace */
1287 *num_op_arrays_ptr = num_op_arrays;
1288 return NULL;
1289 } else {
1290 /* Remember op_array to cleanup */
1291 op_arrays[num_op_arrays++] = op_array;
1292 /* Build SSA */
1293 ssa = zend_jit_trace_build_ssa(op_array, script);
1294 }
1295 } else if (p->op == ZEND_JIT_TRACE_BACK) {
1296 if (level == 0) {
1297 stack_bottom += zend_jit_trace_frame_size(p->op_array);
1298 jit_extension =
1299 (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
1300 ssa = &jit_extension->func_info.ssa;
1301 if (ssa->cfg.blocks_count) {
1302 /* pass */
1303 } else if (num_op_arrays == ZEND_JIT_TRACE_MAX_FUNCS) {
1304 /* Too many functions in single trace */
1305 *num_op_arrays_ptr = num_op_arrays;
1306 return NULL;
1307 } else {
1308 /* Remember op_array to cleanup */
1309 op_arrays[num_op_arrays++] = op_array;
1310 /* Build SSA */
1311 ssa = zend_jit_trace_build_ssa(op_array, script);
1312 }
1313 } else {
1314 stack_top -= zend_jit_trace_frame_size(op_array);
1315 level--;
1316 }
1317 op_array = p->op_array;
1318 } else if (p->op == ZEND_JIT_TRACE_END) {
1319 break;
1320 }
1321 }
1322 *num_op_arrays_ptr = num_op_arrays;
1323
1324 /* Allocate space for abstract stack */
1325 JIT_G(current_frame) = frame = (zend_jit_trace_stack_frame*)((char*)zend_arena_alloc(&CG(arena), stack_bottom + stack_size) + stack_bottom);
1326
1327 /* 2. Construct TSSA */
1328 tssa = zend_arena_calloc(&CG(arena), 1, sizeof(zend_tssa));
1329 tssa->cfg.flags = ZEND_SSA_TSSA;
1330 tssa->cfg.blocks = zend_arena_calloc(&CG(arena), 2, sizeof(zend_basic_block));
1331 tssa->blocks = zend_arena_calloc(&CG(arena), 2, sizeof(zend_ssa_block));
1332 tssa->cfg.predecessors = zend_arena_calloc(&CG(arena), 2, sizeof(int));
1333
1334 if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
1335 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
1336 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
1337 tssa->cfg.blocks_count = 2;
1338 tssa->cfg.edges_count = 2;
1339
1340 tssa->cfg.predecessors[0] = 0;
1341 tssa->cfg.predecessors[1] = 1;
1342
1343 tssa->cfg.blocks[0].flags = ZEND_BB_START|ZEND_BB_REACHABLE;
1344 tssa->cfg.blocks[0].successors_count = 1;
1345 tssa->cfg.blocks[0].predecessors_count = 0;
1346 tssa->cfg.blocks[0].successors = tssa->cfg.blocks[0].successors_storage;
1347 tssa->cfg.blocks[0].successors[0] = 1;
1348
1349 tssa->cfg.blocks[0].flags = ZEND_BB_FOLLOW|ZEND_BB_TARGET|ZEND_BB_LOOP_HEADER|ZEND_BB_REACHABLE;
1350 tssa->cfg.blocks[1].successors_count = 1;
1351 tssa->cfg.blocks[1].predecessors_count = 2;
1352 tssa->cfg.blocks[1].successors = tssa->cfg.blocks[1].successors_storage;
1353 tssa->cfg.blocks[1].successors[1] = 1;
1354 } else {
1355 tssa->cfg.blocks_count = 1;
1356 tssa->cfg.edges_count = 0;
1357
1358 tssa->cfg.blocks[0].flags = ZEND_BB_START|ZEND_BB_EXIT|ZEND_BB_REACHABLE;
1359 tssa->cfg.blocks[0].successors_count = 0;
1360 tssa->cfg.blocks[0].predecessors_count = 0;
1361 }
1362 ((zend_tssa*)tssa)->used_stack = -1;
1363
1364 if (JIT_G(opt_level) < ZEND_JIT_LEVEL_INLINE) {
1365 return tssa;
1366 }
1367
1368 tssa->ops = ssa_ops = zend_arena_alloc(&CG(arena), ssa_ops_count * sizeof(zend_ssa_op));
1369 memset(ssa_ops, -1, ssa_ops_count * sizeof(zend_ssa_op));
1370 ssa_opcodes = zend_arena_calloc(&CG(arena), ssa_ops_count + 1, sizeof(zend_op*));
1371 ((zend_tssa*)tssa)->tssa_opcodes = ssa_opcodes;
1372 ssa_opcodes[ssa_ops_count] = &_nop_opcode;
1373
1374 op_array = trace_buffer->op_array;
1375 if (trace_buffer->start == ZEND_JIT_TRACE_START_ENTER) {
1376 ssa_vars_count = op_array->last_var;
1377 } else {
1378 ssa_vars_count = op_array->last_var + op_array->T;
1379 }
1380 stack = frame->stack;
1381 for (i = 0; i < ssa_vars_count; i++) {
1382 SET_STACK_VAR(stack, i, i);
1383 }
1384
1385 if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP) {
1386 // TODO: For tracing, it's possible, to create pseudo Phi functions
1387 // at the end of loop, without this additional pass (like LuaJIT) ???
1388 ssa_vars_count = zend_jit_trace_add_phis(trace_buffer, ssa_vars_count, tssa, stack);
1389 } else if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL) {
1390 ssa_vars_count = zend_jit_trace_add_call_phis(trace_buffer, ssa_vars_count, tssa, stack);
1391 } else if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
1392 ssa_vars_count = zend_jit_trace_add_ret_phis(trace_buffer, ssa_vars_count, tssa, stack);
1393 }
1394
1395 p = trace_buffer + ZEND_JIT_TRACE_START_REC_SIZE;
1396 idx = 0;
1397 level = 0;
1398 for (;;p++) {
1399 if (p->op == ZEND_JIT_TRACE_VM) {
1400 opline = p->opline;
1401 ssa_opcodes[idx] = opline;
1402 ssa_vars_count = zend_ssa_rename_op(op_array, opline, idx, build_flags, ssa_vars_count, ssa_ops, (int*)stack);
1403 idx++;
1404 len = zend_jit_trace_op_len(p->opline);
1405 while (len > 1) {
1406 opline++;
1407 ssa_opcodes[idx] = opline;
1408 if (opline->opcode != ZEND_OP_DATA) {
1409 ssa_vars_count = zend_ssa_rename_op(op_array, opline, idx, build_flags, ssa_vars_count, ssa_ops, (int*)stack);
1410 }
1411 idx++;
1412 len--;
1413 }
1414 } else if (p->op == ZEND_JIT_TRACE_ENTER) {
1415 frame = zend_jit_trace_call_frame(frame, op_array);
1416 stack = frame->stack;
1417 op_array = p->op_array;
1418 level++;
1419 if (ssa_vars_count >= ZEND_JIT_TRACE_MAX_SSA_VAR) {
1420 return NULL;
1421 }
1422 ZEND_JIT_TRACE_SET_FIRST_SSA_VAR(p->info, ssa_vars_count);
1423 for (i = 0; i < op_array->last_var; i++) {
1424 SET_STACK_VAR(stack, i, ssa_vars_count++);
1425 }
1426 } else if (p->op == ZEND_JIT_TRACE_BACK) {
1427 op_array = p->op_array;
1428 frame = zend_jit_trace_ret_frame(frame, op_array);
1429 stack = frame->stack;
1430 if (level == 0) {
1431 if (ssa_vars_count >= ZEND_JIT_TRACE_MAX_SSA_VAR) {
1432 return NULL;
1433 }
1434 ZEND_JIT_TRACE_SET_FIRST_SSA_VAR(p->info, ssa_vars_count);
1435 for (i = 0; i < op_array->last_var + op_array->T; i++) {
1436 SET_STACK_VAR(stack, i, ssa_vars_count++);
1437 }
1438 } else {
1439 level--;
1440 }
1441 } else if (p->op == ZEND_JIT_TRACE_END) {
1442 break;
1443 }
1444 }
1445
1446 op_array = trace_buffer->op_array;
1447 tssa->vars_count = ssa_vars_count;
1448 tssa->vars = ssa_vars = zend_arena_calloc(&CG(arena), tssa->vars_count, sizeof(zend_ssa_var));
1449 if (trace_buffer->start == ZEND_JIT_TRACE_START_ENTER) {
1450 vars_count = op_array->last_var;
1451 } else {
1452 vars_count = op_array->last_var + op_array->T;
1453 }
1454 i = 0;
1455 while (i < vars_count) {
1456 ssa_vars[i].var = i;
1457 ssa_vars[i].scc = -1;
1458 ssa_vars[i].definition = -1;
1459 ssa_vars[i].use_chain = -1;
1460 i++;
1461 }
1462 while (i < tssa->vars_count) {
1463 ssa_vars[i].var = -1;
1464 ssa_vars[i].scc = -1;
1465 ssa_vars[i].definition = -1;
1466 ssa_vars[i].use_chain = -1;
1467 i++;
1468 }
1469
1470 if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
1471 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
1472 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
1473 /* Update Phi sources */
1474 zend_ssa_phi *phi = tssa->blocks[1].phis;
1475
1476 while (phi) {
1477 phi->sources[1] = STACK_VAR(stack, phi->var);
1478 ssa_vars[phi->ssa_var].var = phi->var;
1479 ssa_vars[phi->ssa_var].definition_phi = phi;
1480 ssa_vars[phi->sources[0]].phi_use_chain = phi;
1481 ssa_vars[phi->sources[1]].phi_use_chain = phi;
1482 phi = phi->next;
1483 }
1484 }
1485
1486 /* 3. Compute use-def chains */
1487 idx = (ssa_ops_count - 1);
1488 op = ssa_ops + idx;
1489 while (idx >= 0) {
1490 opline = ssa_opcodes[idx];
1491 if (op->op1_use >= 0) {
1492 op->op1_use_chain = ssa_vars[op->op1_use].use_chain;
1493 ssa_vars[op->op1_use].use_chain = idx;
1494 }
1495 if (op->op2_use >= 0 && op->op2_use != op->op1_use) {
1496 op->op2_use_chain = ssa_vars[op->op2_use].use_chain;
1497 ssa_vars[op->op2_use].use_chain = idx;
1498 }
1499 if (op->result_use >= 0 && op->result_use != op->op1_use && op->result_use != op->op2_use) {
1500 op->res_use_chain = ssa_vars[op->result_use].use_chain;
1501 ssa_vars[op->result_use].use_chain = idx;
1502 }
1503 if (op->op1_def >= 0) {
1504 ssa_vars[op->op1_def].var = EX_VAR_TO_NUM(opline->op1.var);
1505 ssa_vars[op->op1_def].definition = idx;
1506 }
1507 if (op->op2_def >= 0) {
1508 ssa_vars[op->op2_def].var = EX_VAR_TO_NUM(opline->op2.var);
1509 ssa_vars[op->op2_def].definition = idx;
1510 }
1511 if (op->result_def >= 0) {
1512 ssa_vars[op->result_def].var = EX_VAR_TO_NUM(opline->result.var);
1513 ssa_vars[op->result_def].definition = idx;
1514 }
1515 op--;
1516 idx--;
1517 }
1518
1519 /* 4. Type inference */
1520 op_array = trace_buffer->op_array;
1521 jit_extension =
1522 (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
1523 ssa = &jit_extension->func_info.ssa;
1524
1525 tssa->var_info = ssa_var_info = zend_arena_calloc(&CG(arena), tssa->vars_count, sizeof(zend_ssa_var_info));
1526
1527 if (trace_buffer->start == ZEND_JIT_TRACE_START_ENTER) {
1528 i = 0;
1529 while (i < op_array->last_var) {
1530 if (i < op_array->num_args) {
1531 if (ssa->var_info
1532 && zend_jit_trace_copy_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, i)) {
1533 /* pass */
1534 } else {
1535 if (ssa->vars) {
1536 ssa_vars[i].no_val = ssa->vars[i].no_val;
1537 ssa_vars[i].alias = ssa->vars[i].alias;
1538 } else {
1539 ssa_vars[i].alias = zend_jit_var_may_alias(op_array, ssa, i);
1540 }
1541 if (op_array->arg_info) {
1542 zend_arg_info *arg_info = &op_array->arg_info[i];
1543 zend_class_entry *ce;
1544 uint32_t tmp = zend_fetch_arg_info_type(script, arg_info, &ce);
1545
1546 if (ZEND_ARG_SEND_MODE(arg_info)) {
1547 tmp |= MAY_BE_REF;
1548 }
1549 ssa_var_info[i].type = tmp;
1550 ssa_var_info[i].ce = ce;
1551 ssa_var_info[i].is_instanceof = 1;
1552 } else {
1553 ssa_var_info[i].type = MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
1554 }
1555 }
1556 } else {
1557 if (ssa->vars) {
1558 ssa_vars[i].no_val = ssa->vars[i].no_val;
1559 ssa_vars[i].alias = ssa->vars[i].alias;
1560 } else {
1561 ssa_vars[i].alias = zend_jit_var_may_alias(op_array, ssa, i);
1562 }
1563 if (ssa_vars[i].alias == NO_ALIAS) {
1564 ssa_var_info[i].type = MAY_BE_UNDEF;
1565 } else {
1566 ssa_var_info[i].type = MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
1567 }
1568 }
1569 i++;
1570 }
1571 } else {
1572 int parent_vars_count = 0;
1573 zend_jit_trace_stack *parent_stack = NULL;
1574
1575 i = 0;
1576 if (parent_trace) {
1577 parent_vars_count = MIN(zend_jit_traces[parent_trace].exit_info[exit_num].stack_size,
1578 op_array->last_var + op_array->T);
1579 if (parent_vars_count) {
1580 parent_stack =
1581 zend_jit_traces[parent_trace].stack_map +
1582 zend_jit_traces[parent_trace].exit_info[exit_num].stack_offset;
1583 }
1584 }
1585 while (i < op_array->last_var + op_array->T) {
1586 if (!ssa->var_info
1587 || !zend_jit_trace_copy_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, i)) {
1588 if (ssa->vars && i < ssa->vars_count) {
1589 ssa_vars[i].alias = ssa->vars[i].alias;
1590 } else {
1591 ssa_vars[i].alias = zend_jit_var_may_alias(op_array, ssa, i);
1592 }
1593 if (i < op_array->last_var) {
1594 ssa_var_info[i].type = MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
1595 } else {
1596 ssa_var_info[i].type = MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
1597 }
1598 }
1599 if (i < parent_vars_count) {
1600 /* Initialize TSSA variable from parent trace */
1601 zend_uchar op_type = STACK_TYPE(parent_stack, i);
1602
1603 if (op_type != IS_UNKNOWN) {
1604 ssa_var_info[i].type &= zend_jit_trace_type_to_info(op_type);
1605 if (!ssa_var_info[i].type
1606 && op_type == IS_UNDEF
1607 && i >= op_array->last_var) {
1608 // TODO: It's better to use NULL instead of UNDEF for temporary variables
1609 ssa_var_info[i].type |= MAY_BE_UNDEF;
1610 }
1611 }
1612 }
1613 i++;
1614 }
1615 }
1616
1617 if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
1618 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
1619 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
1620 /* Propagate initial value through Phi functions */
1621 zend_ssa_phi *phi = tssa->blocks[1].phis;
1622
1623 while (phi) {
1624 if (!ssa->var_info
1625 || !zend_jit_trace_copy_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, phi->ssa_var)) {
1626 ssa_vars[phi->ssa_var].alias = ssa_vars[phi->sources[0]].alias;
1627 ssa_var_info[phi->ssa_var].type = ssa_var_info[phi->sources[0]].type;
1628 }
1629 phi = phi->next;
1630 }
1631 }
1632
1633 frame = JIT_G(current_frame);
1634 top = zend_jit_trace_call_frame(frame, op_array);
1635 TRACE_FRAME_INIT(frame, op_array, 0, 0);
1636 TRACE_FRAME_SET_RETURN_SSA_VAR(frame, -1);
1637 frame->used_stack = 0;
1638 for (i = 0; i < op_array->last_var + op_array->T; i++) {
1639 SET_STACK_TYPE(frame->stack, i, IS_UNKNOWN, 1);
1640 }
1641 memset(&return_value_info, 0, sizeof(return_value_info));
1642
1643 if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP) {
1644 max_used_stack = used_stack = 0;
1645 } else {
1646 max_used_stack = used_stack = -1;
1647 }
1648
1649 p = trace_buffer + ZEND_JIT_TRACE_START_REC_SIZE;
1650 idx = 0;
1651 level = 0;
1652 opline = NULL;
1653 for (;;p++) {
1654 if (p->op == ZEND_JIT_TRACE_VM) {
1655 uint8_t orig_op1_type, orig_op2_type, op1_type, op2_type, op3_type;
1656 uint8_t val_type = IS_UNKNOWN;
1657 // zend_class_entry *op1_ce = NULL;
1658 zend_class_entry *op2_ce = NULL;
1659
1660 opline = p->opline;
1661
1662 op1_type = orig_op1_type = p->op1_type;
1663 op2_type = orig_op2_type = p->op2_type;
1664 op3_type = p->op3_type;
1665 if (op1_type & (IS_TRACE_REFERENCE|IS_TRACE_INDIRECT)) {
1666 op1_type = IS_UNKNOWN;
1667 }
1668 if (op1_type != IS_UNKNOWN) {
1669 op1_type &= ~IS_TRACE_PACKED;
1670 }
1671 if (op2_type & (IS_TRACE_REFERENCE|IS_TRACE_INDIRECT)) {
1672 op2_type = IS_UNKNOWN;
1673 }
1674 if (op3_type & (IS_TRACE_REFERENCE|IS_TRACE_INDIRECT)) {
1675 op3_type = IS_UNKNOWN;
1676 }
1677
1678 if ((p+1)->op == ZEND_JIT_TRACE_OP1_TYPE) {
1679 // op1_ce = (zend_class_entry*)(p+1)->ce;
1680 p++;
1681 }
1682 if ((p+1)->op == ZEND_JIT_TRACE_OP2_TYPE) {
1683 op2_ce = (zend_class_entry*)(p+1)->ce;
1684 p++;
1685 }
1686 if ((p+1)->op == ZEND_JIT_TRACE_VAL_INFO) {
1687 val_type = (p+1)->op1_type;
1688 p++;
1689 }
1690
1691 switch (opline->opcode) {
1692 case ZEND_ASSIGN_OP:
1693 if (opline->extended_value == ZEND_POW
1694 || opline->extended_value == ZEND_DIV) {
1695 // TODO: check for division by zero ???
1696 break;
1697 }
1698 if (opline->op1_type != IS_CV || opline->result_type != IS_UNUSED) {
1699 break;
1700 }
1701 ADD_OP1_TRACE_GUARD();
1702 ADD_OP2_TRACE_GUARD();
1703 break;
1704 case ZEND_ASSIGN_DIM_OP:
1705 if (opline->extended_value == ZEND_POW
1706 || opline->extended_value == ZEND_DIV) {
1707 // TODO: check for division by zero ???
1708 break;
1709 }
1710 if (opline->result_type != IS_UNUSED) {
1711 break;
1712 }
1713 if (op3_type != IS_UNKNOWN
1714 && !zend_jit_supported_binary_op(
1715 opline->extended_value, MAY_BE_ANY, (1<<op3_type))) {
1716 break;
1717 }
1718 ZEND_FALLTHROUGH;
1719 case ZEND_ASSIGN_DIM:
1720 if (opline->op1_type == IS_CV) {
1721 if ((opline+1)->op1_type == IS_CV
1722 && (opline+1)->op1.var == opline->op1.var) {
1723 /* skip $a[x] = $a; */
1724 break;
1725 }
1726 ADD_OP1_DATA_TRACE_GUARD();
1727 ADD_OP2_TRACE_GUARD();
1728 ADD_OP1_TRACE_GUARD();
1729 } else if (orig_op1_type != IS_UNKNOWN
1730 && (orig_op1_type & IS_TRACE_INDIRECT)
1731 && opline->result_type == IS_UNUSED) {
1732 if (opline->opcode == ZEND_ASSIGN_DIM_OP) {
1733 ADD_OP1_DATA_TRACE_GUARD();
1734 }
1735 ADD_OP2_TRACE_GUARD();
1736 }
1737 if (op1_type == IS_ARRAY
1738 && ((opline->op2_type == IS_CONST
1739 && Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_LONG)
1740 || (opline->op2_type != IS_CONST
1741 && op2_type == IS_LONG))) {
1742
1743 if (!(orig_op1_type & IS_TRACE_PACKED)) {
1744 zend_ssa_var_info *info = &tssa->var_info[tssa->ops[idx].op1_use];
1745
1746 if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type)) {
1747 info->type |= MAY_BE_PACKED_GUARD;
1748 info->type &= ~MAY_BE_ARRAY_PACKED;
1749 }
1750 } else if (opline->opcode == ZEND_ASSIGN_DIM_OP
1751 && val_type != IS_UNKNOWN
1752 && val_type != IS_UNDEF) {
1753 zend_ssa_var_info *info = &tssa->var_info[tssa->ops[idx].op1_use];
1754
1755 if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type)) {
1756 info->type |= MAY_BE_PACKED_GUARD;
1757 info->type &= ~(MAY_BE_ARRAY_NUMERIC_HASH|MAY_BE_ARRAY_STRING_HASH);
1758 }
1759 }
1760 }
1761 break;
1762 case ZEND_ASSIGN_OBJ_OP:
1763 if (opline->extended_value == ZEND_POW
1764 || opline->extended_value == ZEND_DIV) {
1765 // TODO: check for division by zero ???
1766 break;
1767 }
1768 if (opline->result_type != IS_UNUSED) {
1769 break;
1770 }
1771 ZEND_FALLTHROUGH;
1772 case ZEND_ASSIGN_OBJ:
1773 case ZEND_PRE_INC_OBJ:
1774 case ZEND_PRE_DEC_OBJ:
1775 case ZEND_POST_INC_OBJ:
1776 case ZEND_POST_DEC_OBJ:
1777 if (opline->op2_type != IS_CONST
1778 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
1779 || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
1780 break;
1781 }
1782 if (opline->opcode == ZEND_ASSIGN_OBJ_OP) {
1783 if (opline->op1_type == IS_CV
1784 && (opline+1)->op1_type == IS_CV
1785 && (opline+1)->op1.var == opline->op1.var) {
1786 /* skip $a->prop += $a; */
1787 break;
1788 }
1789 ADD_OP1_DATA_TRACE_GUARD();
1790 }
1791 ADD_OP1_TRACE_GUARD();
1792 break;
1793 case ZEND_CONCAT:
1794 case ZEND_FAST_CONCAT:
1795 if ((opline->op1_type == IS_CONST || orig_op1_type == IS_STRING)
1796 && (opline->op2_type == IS_CONST || orig_op2_type == IS_STRING)) {
1797 ADD_OP2_TRACE_GUARD();
1798 ADD_OP1_TRACE_GUARD();
1799 }
1800 break;
1801 case ZEND_IS_EQUAL:
1802 case ZEND_IS_NOT_EQUAL:
1803 case ZEND_IS_SMALLER:
1804 case ZEND_IS_SMALLER_OR_EQUAL:
1805 case ZEND_CASE:
1806 case ZEND_IS_IDENTICAL:
1807 case ZEND_IS_NOT_IDENTICAL:
1808 case ZEND_CASE_STRICT:
1809 case ZEND_BW_OR:
1810 case ZEND_BW_AND:
1811 case ZEND_BW_XOR:
1812 case ZEND_SL:
1813 case ZEND_SR:
1814 case ZEND_MOD:
1815 case ZEND_ADD:
1816 case ZEND_SUB:
1817 case ZEND_MUL:
1818 // case ZEND_DIV: // TODO: check for division by zero ???
1819 ADD_OP2_TRACE_GUARD();
1820 ZEND_FALLTHROUGH;
1821 case ZEND_ECHO:
1822 case ZEND_STRLEN:
1823 case ZEND_COUNT:
1824 case ZEND_QM_ASSIGN:
1825 case ZEND_FE_RESET_R:
1826 case ZEND_FE_FETCH_R:
1827 ADD_OP1_TRACE_GUARD();
1828 break;
1829 case ZEND_VERIFY_RETURN_TYPE:
1830 if (opline->op1_type == IS_UNUSED) {
1831 /* Always throws */
1832 break;
1833 }
1834 if (opline->op1_type == IS_CONST) {
1835 /* TODO Different instruction format, has return value */
1836 break;
1837 }
1838 if (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
1839 /* Not worth bothering with */
1840 break;
1841 }
1842 ADD_OP1_TRACE_GUARD();
1843 break;
1844 case ZEND_FETCH_DIM_FUNC_ARG:
1845 if (!frame
1846 || !frame->call
1847 || !frame->call->func
1848 || !TRACE_FRAME_IS_LAST_SEND_BY_VAL(frame->call)) {
1849 break;
1850 }
1851 ADD_OP2_TRACE_GUARD();
1852 ADD_OP1_TRACE_GUARD();
1853 break;
1854 case ZEND_PRE_INC:
1855 case ZEND_PRE_DEC:
1856 case ZEND_POST_INC:
1857 case ZEND_POST_DEC:
1858 if (opline->op1_type != IS_CV) {
1859 break;
1860 }
1861 ADD_OP1_TRACE_GUARD();
1862 break;
1863 case ZEND_ASSIGN:
1864 if (opline->op1_type != IS_CV) {
1865 break;
1866 }
1867 ADD_OP2_TRACE_GUARD();
1868 if (op1_type != IS_UNKNOWN
1869 && (tssa->var_info[tssa->ops[idx].op1_use].type & MAY_BE_REF)) {
1870 ADD_OP1_TRACE_GUARD();
1871 }
1872 break;
1873 case ZEND_CAST:
1874 if (opline->extended_value != op1_type) {
1875 break;
1876 }
1877 ADD_OP1_TRACE_GUARD();
1878 break;
1879 case ZEND_JMPZ:
1880 case ZEND_JMPNZ:
1881 case ZEND_JMPZNZ:
1882 case ZEND_JMPZ_EX:
1883 case ZEND_JMPNZ_EX:
1884 case ZEND_BOOL:
1885 case ZEND_BOOL_NOT:
1886 ADD_OP1_TRACE_GUARD();
1887 break;
1888 case ZEND_ISSET_ISEMPTY_CV:
1889 if ((opline->extended_value & ZEND_ISEMPTY)) {
1890 // TODO: support for empty() ???
1891 break;
1892 }
1893 ADD_OP1_TRACE_GUARD();
1894 break;
1895 case ZEND_IN_ARRAY:
1896 if (opline->op1_type == IS_VAR || opline->op1_type == IS_TMP_VAR) {
1897 break;
1898 }
1899 ADD_OP1_TRACE_GUARD();
1900 break;
1901 case ZEND_ISSET_ISEMPTY_DIM_OBJ:
1902 if ((opline->extended_value & ZEND_ISEMPTY)) {
1903 // TODO: support for empty() ???
1904 break;
1905 }
1906 ZEND_FALLTHROUGH;
1907 case ZEND_FETCH_DIM_R:
1908 case ZEND_FETCH_DIM_IS:
1909 case ZEND_FETCH_LIST_R:
1910 ADD_OP1_TRACE_GUARD();
1911 ADD_OP2_TRACE_GUARD();
1912
1913 if (op1_type == IS_ARRAY
1914 && opline->op1_type != IS_CONST
1915 && ((opline->op2_type == IS_CONST
1916 && Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_LONG)
1917 || (opline->op2_type != IS_CONST
1918 && op2_type == IS_LONG))) {
1919
1920 zend_ssa_var_info *info = &tssa->var_info[tssa->ops[idx].op1_use];
1921
1922 if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type)) {
1923 info->type |= MAY_BE_PACKED_GUARD;
1924 if (orig_op1_type & IS_TRACE_PACKED) {
1925 info->type &= ~(MAY_BE_ARRAY_NUMERIC_HASH|MAY_BE_ARRAY_STRING_HASH);
1926 } else {
1927 info->type &= ~MAY_BE_ARRAY_PACKED;
1928 }
1929 }
1930 }
1931 break;
1932 case ZEND_FETCH_DIM_W:
1933 case ZEND_FETCH_DIM_RW:
1934 // case ZEND_FETCH_DIM_UNSET:
1935 case ZEND_FETCH_LIST_W:
1936 if (opline->op1_type != IS_CV
1937 && (orig_op1_type == IS_UNKNOWN
1938 || !(orig_op1_type & IS_TRACE_INDIRECT))) {
1939 break;
1940 }
1941 ADD_OP1_TRACE_GUARD();
1942 ADD_OP2_TRACE_GUARD();
1943 if (op1_type == IS_ARRAY
1944 && !(orig_op1_type & IS_TRACE_PACKED)
1945 && ((opline->op2_type == IS_CONST
1946 && Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_LONG)
1947 || (opline->op2_type != IS_CONST
1948 && op2_type == IS_LONG))) {
1949
1950 zend_ssa_var_info *info = &tssa->var_info[tssa->ops[idx].op1_use];
1951
1952 if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type)) {
1953 info->type |= MAY_BE_PACKED_GUARD;
1954 info->type &= ~MAY_BE_ARRAY_PACKED;
1955 }
1956 }
1957 break;
1958 case ZEND_SEND_VAL_EX:
1959 case ZEND_SEND_VAR_EX:
1960 case ZEND_SEND_VAR_NO_REF_EX:
1961 if (opline->op2_type == IS_CONST) {
1962 /* Named parameters not supported in JIT */
1963 break;
1964 }
1965 if (opline->op2.num > MAX_ARG_FLAG_NUM) {
1966 goto propagate_arg;
1967 }
1968 ZEND_FALLTHROUGH;
1969 case ZEND_SEND_VAL:
1970 case ZEND_SEND_VAR:
1971 case ZEND_SEND_VAR_NO_REF:
1972 case ZEND_SEND_FUNC_ARG:
1973 if (opline->op2_type == IS_CONST) {
1974 /* Named parameters not supported in JIT */
1975 break;
1976 }
1977 ADD_OP1_TRACE_GUARD();
1978 propagate_arg:
1979 /* Propagate argument type */
1980 if (frame->call
1981 && frame->call->func
1982 && frame->call->func->type == ZEND_USER_FUNCTION
1983 && opline->op2.num <= frame->call->func->op_array.num_args) {
1984 uint32_t info;
1985
1986 if (opline->op1_type == IS_CONST) {
1987 info = _const_op_type(RT_CONSTANT(opline, opline->op1));
1988 } else {
1989 ZEND_ASSERT(ssa_ops[idx].op1_use >= 0);
1990 info = ssa_var_info[ssa_ops[idx].op1_use].type & ~MAY_BE_GUARD;
1991 }
1992 if (frame->call->func->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
1993 zend_arg_info *arg_info;
1994
1995 ZEND_ASSERT(frame->call->func->op_array.arg_info);
1996 arg_info = &frame->call->func->op_array.arg_info[opline->op2.num - 1];
1997 if (ZEND_TYPE_IS_SET(arg_info->type)) {
1998 zend_class_entry *ce;
1999 uint32_t tmp = zend_fetch_arg_info_type(script, arg_info, &ce);
2000 info &= tmp;
2001 if (!info) {
2002 break;
2003 }
2004 }
2005 }
2006 if (opline->op1_type == IS_CV && (info & MAY_BE_RC1)) {
2007 info |= MAY_BE_RCN;
2008 }
2009 if (info & MAY_BE_UNDEF) {
2010 info |= MAY_BE_NULL;
2011 info &= ~MAY_BE_UNDEF;
2012 }
2013 if (ARG_SHOULD_BE_SENT_BY_REF(frame->call->func, opline->op2.num)) {
2014 info |= MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_KEY_ANY;
2015 }
2016 SET_STACK_INFO(frame->call->stack, opline->op2.num - 1, info);
2017 }
2018 break;
2019 case ZEND_RETURN:
2020 ADD_OP1_TRACE_GUARD();
2021 /* Propagate return value types */
2022 if (opline->op1_type == IS_UNUSED) {
2023 return_value_info.type = MAY_BE_NULL;
2024 } else if (opline->op1_type == IS_CONST) {
2025 return_value_info.type = _const_op_type(RT_CONSTANT(opline, opline->op1));
2026 } else {
2027 ZEND_ASSERT(ssa_ops[idx].op1_use >= 0);
2028 return_value_info = ssa_var_info[ssa_ops[idx].op1_use];
2029 if (return_value_info.type & MAY_BE_UNDEF) {
2030 return_value_info.type &= ~MAY_BE_UNDEF;
2031 return_value_info.type |= MAY_BE_NULL;
2032 }
2033 if (return_value_info.type & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
2034 /* CVs are going to be destructed and the reference-counter
2035 of return value may be decremented to 1 */
2036 return_value_info.type |= MAY_BE_RC1;
2037 }
2038 return_value_info.type &= ~MAY_BE_GUARD;
2039 }
2040 break;
2041 case ZEND_CHECK_FUNC_ARG:
2042 if (!frame
2043 || !frame->call
2044 || !frame->call->func) {
2045 break;
2046 }
2047 if (opline->op2_type == IS_CONST
2048 || opline->op2.num > MAX_ARG_FLAG_NUM) {
2049 /* Named parameters not supported in JIT */
2050 TRACE_FRAME_SET_LAST_SEND_UNKNOWN(frame->call);
2051 break;
2052 }
2053 if (ARG_SHOULD_BE_SENT_BY_REF(frame->call->func, opline->op2.num)) {
2054 TRACE_FRAME_SET_LAST_SEND_BY_REF(frame->call);
2055 } else {
2056 TRACE_FRAME_SET_LAST_SEND_BY_VAL(frame->call);
2057 }
2058 break;
2059 case ZEND_FETCH_OBJ_FUNC_ARG:
2060 if (!frame
2061 || !frame->call
2062 || !frame->call->func
2063 || !TRACE_FRAME_IS_LAST_SEND_BY_VAL(frame->call)) {
2064 break;
2065 }
2066 ZEND_FALLTHROUGH;
2067 case ZEND_FETCH_OBJ_R:
2068 case ZEND_FETCH_OBJ_IS:
2069 case ZEND_FETCH_OBJ_W:
2070 if (opline->op2_type != IS_CONST
2071 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
2072 || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
2073 break;
2074 }
2075 if (opline->op1_type != IS_UNUSED && op1_type == IS_OBJECT) {
2076 ADD_OP1_TRACE_GUARD();
2077 }
2078 break;
2079 case ZEND_INIT_METHOD_CALL:
2080 if (opline->op2_type != IS_CONST
2081 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING) {
2082 break;
2083 }
2084 ADD_OP1_TRACE_GUARD();
2085 break;
2086 case ZEND_INIT_DYNAMIC_CALL:
2087 if (orig_op2_type == IS_OBJECT && op2_ce == zend_ce_closure) {
2088 ADD_OP2_TRACE_GUARD();
2089 }
2090 break;
2091 case ZEND_SEND_ARRAY:
2092 case ZEND_SEND_UNPACK:
2093 case ZEND_CHECK_UNDEF_ARGS:
2094 case ZEND_INCLUDE_OR_EVAL:
2095 max_used_stack = used_stack = -1;
2096 break;
2097 case ZEND_TYPE_CHECK:
2098 if (opline->extended_value == MAY_BE_RESOURCE) {
2099 // TODO: support for is_resource() ???
2100 break;
2101 }
2102 if (op1_type != IS_UNKNOWN
2103 && (opline->extended_value == (1 << op1_type)
2104 || opline->extended_value == MAY_BE_ANY - (1 << op1_type))) {
2105 /* add guards only for exact checks, to avoid code duplication */
2106 ADD_OP1_TRACE_GUARD();
2107 }
2108 break;
2109 case ZEND_ROPE_INIT:
2110 case ZEND_ROPE_ADD:
2111 case ZEND_ROPE_END:
2112 if (op2_type == IS_STRING) {
2113 ADD_OP2_TRACE_GUARD();
2114 }
2115 break;
2116 default:
2117 break;
2118 }
2119 len = zend_jit_trace_op_len(opline);
2120 if (ssa->var_info) {
2121 /* Add statically inferred ranges */
2122 if (ssa_ops[idx].op1_def >= 0) {
2123 zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].op1_def);
2124 }
2125 if (ssa_ops[idx].op2_def >= 0) {
2126 zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].op2_def);
2127 }
2128 if (ssa_ops[idx].result_def >= 0) {
2129 zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].result_def);
2130 }
2131 if (len == 2 && (opline+1)->opcode == ZEND_OP_DATA) {
2132 if (ssa_ops[idx+1].op1_def >= 0) {
2133 zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx+1].op1_def);
2134 }
2135 if (ssa_ops[idx+1].op2_def >= 0) {
2136 zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx+1].op2_def);
2137 }
2138 if (ssa_ops[idx+1].result_def >= 0) {
2139 zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx+1].result_def);
2140 }
2141 }
2142 } else {
2143 if (ssa_ops[idx].op1_def >= 0) {
2144 ssa_vars[ssa_ops[idx].op1_def].alias = zend_jit_var_may_alias(op_array, ssa, EX_VAR_TO_NUM(opline->op1.var));
2145 if (ssa_ops[idx].op1_use < 0 || !(ssa_var_info[ssa_ops[idx].op1_use].type & MAY_BE_REF)) {
2146 zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx].op1_def);
2147 }
2148 }
2149 if (ssa_ops[idx].op2_def >= 0) {
2150 ssa_vars[ssa_ops[idx].op2_def].alias = zend_jit_var_may_alias(op_array, ssa, EX_VAR_TO_NUM(opline->op2.var));
2151 if (ssa_ops[idx].op2_use < 0 || !(ssa_var_info[ssa_ops[idx].op2_use].type & MAY_BE_REF)) {
2152 zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx].op2_def);
2153 }
2154 }
2155 if (ssa_ops[idx].result_def >= 0) {
2156 ssa_vars[ssa_ops[idx].result_def].alias = zend_jit_var_may_alias(op_array, ssa, EX_VAR_TO_NUM(opline->result.var));
2157 if (ssa_ops[idx].result_use < 0 || !(ssa_var_info[ssa_ops[idx].result_use].type & MAY_BE_REF)) {
2158 zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx].result_def);
2159 }
2160 }
2161 if (len == 2 && (opline+1)->opcode == ZEND_OP_DATA) {
2162 if (ssa_ops[idx+1].op1_def >= 0) {
2163 ssa_vars[ssa_ops[idx+1].op1_def].alias = zend_jit_var_may_alias(op_array, ssa, EX_VAR_TO_NUM((opline+1)->op1.var));
2164 if (ssa_ops[idx+1].op1_use < 0 || !(ssa_var_info[ssa_ops[idx+1].op1_use].type & MAY_BE_REF)) {
2165 zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx+1].op1_def);
2166 }
2167 }
2168 if (ssa_ops[idx+1].op2_def >= 0) {
2169 ssa_vars[ssa_ops[idx+1].op2_def].alias = zend_jit_var_may_alias(op_array, ssa, EX_VAR_TO_NUM((opline+1)->op2.var));
2170 if (ssa_ops[idx+1].op2_use < 0 || !(ssa_var_info[ssa_ops[idx+1].op2_use].type & MAY_BE_REF)) {
2171 zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx+1].op2_def);
2172 }
2173 }
2174 if (ssa_ops[idx+1].result_def >= 0) {
2175 ssa_vars[ssa_ops[idx+1].result_def].alias = zend_jit_var_may_alias(op_array, ssa, EX_VAR_TO_NUM((opline+1)->result.var));
2176 if (ssa_ops[idx+1].result_use < 0 || !(ssa_var_info[ssa_ops[idx+1].result_use].type & MAY_BE_REF)) {
2177 zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx+1].result_def);
2178 }
2179 }
2180 }
2181 }
2182 if (opline->opcode == ZEND_RECV_INIT
2183 && !(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
2184 /* RECV_INIT always copy the constant */
2185 ssa_var_info[ssa_ops[idx].result_def].type = _const_op_type(RT_CONSTANT(opline, opline->op2));
2186 } else if ((opline->opcode == ZEND_FE_FETCH_R || opline->opcode == ZEND_FE_FETCH_RW)
2187 && ssa_opcodes[idx + 1] == ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value)) {
2188 if (ssa_ops[idx].op2_use >= 0 && ssa_ops[idx].op2_def >= 0) {
2189 ssa_var_info[ssa_ops[idx].op2_def] = ssa_var_info[ssa_ops[idx].op2_use];
2190 }
2191 } else {
2192 if (zend_update_type_info(op_array, tssa, script, (zend_op*)opline, ssa_ops + idx, ssa_opcodes, optimization_level) == FAILURE) {
2193 // TODO:
2194 assert(0);
2195 }
2196 if (opline->opcode == ZEND_ASSIGN_DIM_OP
2197 && ssa_ops[idx].op1_def > 0
2198 && op1_type == IS_ARRAY
2199 && (orig_op1_type & IS_TRACE_PACKED)
2200 && val_type != IS_UNKNOWN
2201 && val_type != IS_UNDEF
2202 && ((opline->op2_type == IS_CONST
2203 && Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_LONG)
2204 || (opline->op2_type != IS_CONST
2205 && op2_type == IS_LONG))) {
2206 zend_ssa_var_info *info = &ssa_var_info[ssa_ops[idx].op1_def];
2207
2208 info->type &= ~(MAY_BE_ARRAY_NUMERIC_HASH|MAY_BE_ARRAY_STRING_HASH);
2209 }
2210 }
2211 if (ssa->var_info) {
2212 /* Add statically inferred restrictions */
2213 if (ssa_ops[idx].op1_def >= 0) {
2214 if (opline->opcode == ZEND_SEND_VAR_EX
2215 && frame
2216 && frame->call
2217 && frame->call->func
2218 && !ARG_SHOULD_BE_SENT_BY_REF(frame->call->func, opline->op2.num)) {
2219 ssa_var_info[ssa_ops[idx].op1_def] = ssa_var_info[ssa_ops[idx].op1_use];
2220 ssa_var_info[ssa_ops[idx].op1_def].type &= ~MAY_BE_GUARD;
2221 if (ssa_var_info[ssa_ops[idx].op1_def].type & MAY_BE_RC1) {
2222 ssa_var_info[ssa_ops[idx].op1_def].type |= MAY_BE_RCN;
2223 }
2224 } else {
2225 zend_jit_trace_restrict_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].op1_def);
2226 }
2227 }
2228 if (ssa_ops[idx].op2_def >= 0) {
2229 if ((opline->opcode != ZEND_FE_FETCH_R && opline->opcode != ZEND_FE_FETCH_RW)
2230 || ssa_opcodes[idx + 1] != ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value)) {
2231 zend_jit_trace_restrict_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].op2_def);
2232 }
2233 }
2234 if (ssa_ops[idx].result_def >= 0) {
2235 zend_jit_trace_restrict_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].result_def);
2236 }
2237 }
2238 idx++;
2239 while (len > 1) {
2240 opline++;
2241 if (opline->opcode != ZEND_OP_DATA) {
2242 if (ssa->var_info) {
2243 /* Add statically inferred ranges */
2244 if (ssa_ops[idx].op1_def >= 0) {
2245 zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].op1_def);
2246 }
2247 if (ssa_ops[idx].op2_def >= 0) {
2248 zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].op2_def);
2249 }
2250 if (ssa_ops[idx].result_def >= 0) {
2251 zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].result_def);
2252 }
2253 } else {
2254 if (ssa_ops[idx].op1_def >= 0) {
2255 ssa_vars[ssa_ops[idx].op1_def].alias = zend_jit_var_may_alias(op_array, ssa, EX_VAR_TO_NUM(opline->op1.var));
2256 if (ssa_ops[idx].op1_use < 0 || !(ssa_var_info[ssa_ops[idx].op1_use].type & MAY_BE_REF)) {
2257 zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx].op1_def);
2258 }
2259 }
2260 if (ssa_ops[idx].op2_def >= 0) {
2261 ssa_vars[ssa_ops[idx].op2_def].alias = zend_jit_var_may_alias(op_array, ssa, EX_VAR_TO_NUM(opline->op2.var));
2262 if (ssa_ops[idx].op2_use < 0 || !(ssa_var_info[ssa_ops[idx].op2_use].type & MAY_BE_REF)) {
2263 zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx].op2_def);
2264 }
2265 }
2266 if (ssa_ops[idx].result_def >= 0) {
2267 ssa_vars[ssa_ops[idx].result_def].alias = zend_jit_var_may_alias(op_array, ssa, EX_VAR_TO_NUM(opline->result.var));
2268 if (ssa_ops[idx].result_use < 0 || !(ssa_var_info[ssa_ops[idx].result_use].type & MAY_BE_REF)) {
2269 zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx].result_def);
2270 }
2271 }
2272 }
2273 if (opline->opcode == ZEND_RECV_INIT
2274 && !(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
2275 /* RECV_INIT always copy the constant */
2276 ssa_var_info[ssa_ops[idx].result_def].type = _const_op_type(RT_CONSTANT(opline, opline->op2));
2277 } else {
2278 if (zend_update_type_info(op_array, tssa, script, (zend_op*)opline, ssa_ops + idx, ssa_opcodes, optimization_level) == FAILURE) {
2279 // TODO:
2280 assert(0);
2281 }
2282 }
2283 }
2284 if (ssa->var_info) {
2285 /* Add statically inferred restrictions */
2286 if (ssa_ops[idx].op1_def >= 0) {
2287 zend_jit_trace_restrict_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].op1_def);
2288 }
2289 if (ssa_ops[idx].op2_def >= 0) {
2290 zend_jit_trace_restrict_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].op2_def);
2291 }
2292 if (ssa_ops[idx].result_def >= 0) {
2293 zend_jit_trace_restrict_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].result_def);
2294 }
2295 }
2296 idx++;
2297 len--;
2298 }
2299
2300 } else if (p->op == ZEND_JIT_TRACE_ENTER) {
2301 op_array = p->op_array;
2302 jit_extension =
2303 (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
2304 ssa = &jit_extension->func_info.ssa;
2305
2306 call = frame->call;
2307 if (!call) {
2308 /* Trace missed INIT_FCALL opcode */
2309 call = top;
2310 TRACE_FRAME_INIT(call, op_array, 0, 0);
2311 call->used_stack = 0;
2312 top = zend_jit_trace_call_frame(top, op_array);
2313 for (i = 0; i < op_array->last_var + op_array->T; i++) {
2314 SET_STACK_TYPE(call->stack, i, IS_UNKNOWN, 1);
2315 }
2316 } else {
2317 ZEND_ASSERT(&call->func->op_array == op_array);
2318 }
2319 frame->call = call->prev;
2320 call->prev = frame;
2321 TRACE_FRAME_SET_RETURN_SSA_VAR(call, find_return_ssa_var(p - 1, ssa_ops + (idx - 1)));
2322 frame = call;
2323
2324 level++;
2325 i = 0;
2326 v = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
2327 while (i < op_array->last_var) {
2328 ssa_vars[v].var = i;
2329 if (i < op_array->num_args) {
2330 if (ssa->var_info
2331 && zend_jit_trace_copy_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, v)) {
2332 /* pass */
2333 } else {
2334 ssa_vars[v].alias = zend_jit_var_may_alias(op_array, ssa, i);
2335 if (op_array->arg_info) {
2336 zend_arg_info *arg_info = &op_array->arg_info[i];
2337 zend_class_entry *ce;
2338 uint32_t tmp = zend_fetch_arg_info_type(script, arg_info, &ce);
2339
2340 if (ZEND_ARG_SEND_MODE(arg_info)) {
2341 tmp |= MAY_BE_REF;
2342 }
2343 ssa_var_info[v].type = tmp;
2344 ssa_var_info[v].ce = ce;
2345 ssa_var_info[v].is_instanceof = 1;
2346 } else {
2347 ssa_var_info[v].type = MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
2348 }
2349 }
2350 } else {
2351 if (ssa->vars) {
2352 ssa_vars[v].no_val = ssa->vars[i].no_val;
2353 ssa_vars[v].alias = ssa->vars[i].alias;
2354 } else {
2355 ssa_vars[v].alias = zend_jit_var_may_alias(op_array, ssa, i);
2356 }
2357 if (ssa_vars[v].alias == NO_ALIAS) {
2358 ssa_var_info[v].type = MAY_BE_UNDEF;
2359 } else {
2360 ssa_var_info[v].type = MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
2361 }
2362 }
2363 if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)
2364 && i < op_array->num_args) {
2365 /* Propagate argument type */
2366 ssa_var_info[v].type &= STACK_INFO(frame->stack, i);
2367 }
2368 i++;
2369 v++;
2370 }
2371 } else if (p->op == ZEND_JIT_TRACE_BACK) {
2372 op_array = p->op_array;
2373 jit_extension =
2374 (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
2375 ssa = &jit_extension->func_info.ssa;
2376 if (level == 0) {
2377 i = 0;
2378 v = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
2379 while (i < op_array->last_var) {
2380 ssa_vars[v].var = i;
2381 if (!ssa->var_info
2382 || !zend_jit_trace_copy_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, v)) {
2383 ssa_var_info[v].type = MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
2384 }
2385 i++;
2386 v++;
2387 }
2388 while (i < op_array->last_var + op_array->T) {
2389 ssa_vars[v].var = i;
2390 if (!ssa->var_info
2391 || !zend_jit_trace_copy_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, v)) {
2392 ssa_var_info[v].type = MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
2393 }
2394 i++;
2395 v++;
2396 }
2397 if (return_value_info.type != 0) {
2398 zend_jit_trace_rec *q = p + 1;
2399 while (q->op == ZEND_JIT_TRACE_INIT_CALL) {
2400 q++;
2401 }
2402 if (q->op == ZEND_JIT_TRACE_VM
2403 || (q->op == ZEND_JIT_TRACE_END
2404 && q->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET)) {
2405 const zend_op *opline = q->opline - 1;
2406 if (opline->result_type != IS_UNUSED) {
2407 ssa_var_info[
2408 ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info) +
2409 EX_VAR_TO_NUM(opline->result.var)] = return_value_info;
2410 }
2411 }
2412 memset(&return_value_info, 0, sizeof(return_value_info));
2413 }
2414 } else {
2415 level--;
2416 if (return_value_info.type != 0) {
2417 if ((p+1)->op == ZEND_JIT_TRACE_VM) {
2418 const zend_op *opline = (p+1)->opline - 1;
2419 if (opline->result_type != IS_UNUSED) {
2420 if (TRACE_FRAME_RETURN_SSA_VAR(frame) >= 0) {
2421 ssa_var_info[TRACE_FRAME_RETURN_SSA_VAR(frame)] = return_value_info;
2422 }
2423 }
2424 }
2425 memset(&return_value_info, 0, sizeof(return_value_info));
2426 }
2427 }
2428
2429 top = frame;
2430 if (frame->prev) {
2431 if (used_stack > 0) {
2432 used_stack -= frame->used_stack;
2433 }
2434 frame = frame->prev;
2435 ZEND_ASSERT(&frame->func->op_array == op_array);
2436 } else {
2437 max_used_stack = used_stack = -1;
2438 frame = zend_jit_trace_ret_frame(frame, op_array);
2439 TRACE_FRAME_INIT(frame, op_array, 0, 0);
2440 TRACE_FRAME_SET_RETURN_SSA_VAR(frame, -1);
2441 frame->used_stack = 0;
2442 for (i = 0; i < op_array->last_var + op_array->T; i++) {
2443 SET_STACK_TYPE(frame->stack, i, IS_UNKNOWN, 1);
2444 }
2445 }
2446
2447 } else if (p->op == ZEND_JIT_TRACE_INIT_CALL) {
2448 call = top;
2449 TRACE_FRAME_INIT(call, p->func, 0, 0);
2450 call->prev = frame->call;
2451 call->used_stack = 0;
2452 frame->call = call;
2453 top = zend_jit_trace_call_frame(top, p->op_array);
2454 if (p->func && p->func->type == ZEND_USER_FUNCTION) {
2455 for (i = 0; i < p->op_array->last_var + p->op_array->T; i++) {
2456 SET_STACK_INFO(call->stack, i, -1);
2457 }
2458 }
2459 if (used_stack >= 0
2460 && !(p->info & ZEND_JIT_TRACE_FAKE_INIT_CALL)) {
2461 if (p->func == NULL || (p-1)->op != ZEND_JIT_TRACE_VM) {
2462 max_used_stack = used_stack = -1;
2463 } else {
2464 const zend_op *opline = (p-1)->opline;
2465
2466 switch (opline->opcode) {
2467 case ZEND_INIT_FCALL:
2468 case ZEND_INIT_FCALL_BY_NAME:
2469 case ZEND_INIT_NS_FCALL_BY_NAME:
2470 case ZEND_INIT_METHOD_CALL:
2471 case ZEND_INIT_DYNAMIC_CALL:
2472 //case ZEND_INIT_STATIC_METHOD_CALL:
2473 //case ZEND_INIT_USER_CALL:
2474 //case ZEND_NEW:
2475 frame->used_stack = zend_vm_calc_used_stack(opline->extended_value, (zend_function*)p->func);
2476 used_stack += frame->used_stack;
2477 if (used_stack > max_used_stack) {
2478 max_used_stack = used_stack;
2479 }
2480 break;
2481 default:
2482 max_used_stack = used_stack = -1;
2483 }
2484 }
2485 }
2486 } else if (p->op == ZEND_JIT_TRACE_DO_ICALL) {
2487 call = frame->call;
2488 if (call) {
2489 top = call;
2490 frame->call = call->prev;
2491 }
2492
2493 if (idx > 0
2494 && ssa_ops[idx-1].result_def >= 0
2495 && (p->func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE)
2496 && !(p->func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
2497 ZEND_ASSERT(ssa_opcodes[idx-1] == opline);
2498 ZEND_ASSERT(opline->opcode == ZEND_DO_ICALL ||
2499 opline->opcode == ZEND_DO_FCALL ||
2500 opline->opcode == ZEND_DO_FCALL_BY_NAME);
2501
2502 if (opline->result_type != IS_UNDEF) {
2503 zend_class_entry *ce;
2504 const zend_function *func = p->func;
2505 zend_arg_info *ret_info = func->common.arg_info - 1;
2506 uint32_t ret_type = zend_fetch_arg_info_type(NULL, ret_info, &ce);
2507
2508 ssa_var_info[ssa_ops[idx-1].result_def].type &= ret_type;
2509 }
2510 }
2511 } else if (p->op == ZEND_JIT_TRACE_END) {
2512 break;
2513 }
2514 }
2515
2516 ((zend_tssa*)tssa)->used_stack = max_used_stack;
2517
2518 if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
2519 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
2520 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
2521 /* Propagate guards through Phi sources */
2522 zend_ssa_phi *phi = tssa->blocks[1].phis;
2523
2524 op_array = trace_buffer->op_array;
2525 jit_extension =
2526 (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
2527 ssa = &jit_extension->func_info.ssa;
2528
2529 while (phi) {
2530 uint32_t t = ssa_var_info[phi->ssa_var].type;
2531
2532 if ((t & MAY_BE_GUARD) && tssa->vars[phi->ssa_var].alias == NO_ALIAS) {
2533 uint32_t t0 = ssa_var_info[phi->sources[0]].type;
2534 uint32_t t1 = ssa_var_info[phi->sources[1]].type;
2535
2536 if (((t0 | t1) & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) == (t & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF))) {
2537 if (!((t0 | t1) & MAY_BE_GUARD)) {
2538 ssa_var_info[phi->ssa_var].type = t & ~MAY_BE_GUARD;
2539 }
2540 } else if ((t1 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) == (t & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF))) {
2541 if (!(t1 & MAY_BE_GUARD)
2542 || is_checked_guard(tssa, ssa_opcodes, phi->sources[1], phi->ssa_var)) {
2543 ssa_var_info[phi->ssa_var].type = t & ~MAY_BE_GUARD;
2544 t0 = (t & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) |
2545 (t0 & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) |
2546 MAY_BE_GUARD;
2547 if (!(t0 & MAY_BE_ARRAY)) {
2548 t0 &= ~(MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF|MAY_BE_ARRAY_KEY_ANY);
2549 }
2550 if (!(t0 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
2551 t0 &= ~(MAY_BE_RC1|MAY_BE_RCN);
2552 }
2553 ssa_var_info[phi->sources[0]].type = t0;
2554 ssa_var_info[phi->sources[0]].type = t0;
2555 }
2556 } else {
2557 if ((t0 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != (t & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF))) {
2558 t0 = (t & t0 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) |
2559 (t0 & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) |
2560 MAY_BE_GUARD;
2561 if (!(t0 & MAY_BE_ARRAY)) {
2562 t0 &= ~(MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF|MAY_BE_ARRAY_KEY_ANY);
2563 }
2564 if (!(t0 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
2565 t0 &= ~(MAY_BE_RC1|MAY_BE_RCN);
2566 }
2567 ssa_var_info[phi->sources[0]].type = t0;
2568 }
2569 if ((t1 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != (t & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF))) {
2570 if (((t & t1) & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != 0
2571 && is_checked_guard(tssa, ssa_opcodes, phi->sources[1], phi->ssa_var)) {
2572 t1 = (t & t1 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) |
2573 (t1 & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) |
2574 MAY_BE_GUARD;
2575 if (!(t1 & MAY_BE_ARRAY)) {
2576 t1 &= ~(MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF|MAY_BE_ARRAY_KEY_ANY);
2577 }
2578 if (!(t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
2579 t1 &= ~(MAY_BE_RC1|MAY_BE_RCN);
2580 }
2581 ssa_var_info[phi->sources[1]].type = t1;
2582 ssa_var_info[phi->ssa_var].type = t & ~MAY_BE_GUARD;
2583 }
2584 }
2585 }
2586 t = ssa_var_info[phi->ssa_var].type;
2587 }
2588
2589 if ((t & MAY_BE_PACKED_GUARD) && tssa->vars[phi->ssa_var].alias == NO_ALIAS) {
2590 uint32_t t0 = ssa_var_info[phi->sources[0]].type;
2591 uint32_t t1 = ssa_var_info[phi->sources[1]].type;
2592
2593 if (((t0 | t1) & MAY_BE_ARRAY_KEY_ANY) == (t & MAY_BE_ARRAY_KEY_ANY)) {
2594 if (!((t0 | t1) & MAY_BE_PACKED_GUARD)) {
2595 ssa_var_info[phi->ssa_var].type = t & ~MAY_BE_PACKED_GUARD;
2596 }
2597 } else if ((t1 & MAY_BE_ARRAY_KEY_ANY) == (t & MAY_BE_ARRAY_KEY_ANY)) {
2598 if (!(t1 & MAY_BE_PACKED_GUARD)) {
2599 ssa_var_info[phi->ssa_var].type = t & ~MAY_BE_PACKED_GUARD;
2600 ssa_var_info[phi->sources[0]].type =
2601 (t0 & ~MAY_BE_ARRAY_KEY_ANY) | (t & MAY_BE_ARRAY_KEY_ANY) | MAY_BE_PACKED_GUARD;
2602 }
2603 }
2604 }
2605 phi = phi->next;
2606 }
2607 }
2608
2609 if (UNEXPECTED(JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_TSSA)) {
2610 if (parent_trace) {
2611 fprintf(stderr, "---- TRACE %d TSSA start (side trace %d/%d) %s%s%s() %s:%d\n",
2612 ZEND_JIT_TRACE_NUM,
2613 parent_trace,
2614 exit_num,
2615 trace_buffer->op_array->scope ? ZSTR_VAL(trace_buffer->op_array->scope->name) : "",
2616 trace_buffer->op_array->scope ? "::" : "",
2617 trace_buffer->op_array->function_name ?
2618 ZSTR_VAL(trace_buffer->op_array->function_name) : "$main",
2619 ZSTR_VAL(trace_buffer->op_array->filename),
2620 trace_buffer[1].opline->lineno);
2621 } else {
2622 fprintf(stderr, "---- TRACE %d TSSA start (%s) %s%s%s() %s:%d\n",
2623 ZEND_JIT_TRACE_NUM,
2624 zend_jit_trace_star_desc(trace_buffer->start),
2625 trace_buffer->op_array->scope ? ZSTR_VAL(trace_buffer->op_array->scope->name) : "",
2626 trace_buffer->op_array->scope ? "::" : "",
2627 trace_buffer->op_array->function_name ?
2628 ZSTR_VAL(trace_buffer->op_array->function_name) : "$main",
2629 ZSTR_VAL(trace_buffer->op_array->filename),
2630 trace_buffer[1].opline->lineno);
2631 }
2632 zend_jit_dump_trace(trace_buffer, tssa);
2633 if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LINK) {
2634 uint32_t idx = trace_buffer[1].last;
2635 uint32_t link_to = zend_jit_find_trace(trace_buffer[idx].opline->handler);
2636 fprintf(stderr, "---- TRACE %d TSSA stop (link to %d)\n",
2637 ZEND_JIT_TRACE_NUM,
2638 link_to);
2639 } else {
2640 fprintf(stderr, "---- TRACE %d TSSA stop (%s)\n",
2641 ZEND_JIT_TRACE_NUM,
2642 zend_jit_trace_stop_description[trace_buffer->stop]);
2643 }
2644 }
2645
2646 return tssa;
2647 }
2648
zend_jit_close_var(zend_jit_trace_stack * stack,uint32_t n,int * start,int * end,uint8_t * flags,int line)2649 static void zend_jit_close_var(zend_jit_trace_stack *stack, uint32_t n, int *start, int *end, uint8_t *flags, int line)
2650 {
2651 int32_t var = STACK_VAR(stack, n);
2652
2653 if (var >= 0 && start[var] >= 0 && !(flags[var] & ZREG_LAST_USE)) {
2654 // TODO: shrink interval to last side exit ????
2655 end[var] = line;
2656 }
2657 }
2658
zend_jit_trace_use_var(int line,int var,int def,int use_chain,int * start,int * end,uint8_t * flags,const zend_ssa * ssa,const zend_op ** ssa_opcodes,const zend_op_array * op_array,const zend_ssa * op_array_ssa)2659 static void zend_jit_trace_use_var(int line, int var, int def, int use_chain, int *start, int *end, uint8_t *flags, const zend_ssa *ssa, const zend_op **ssa_opcodes, const zend_op_array *op_array, const zend_ssa *op_array_ssa)
2660 {
2661 ZEND_ASSERT(start[var] >= 0);
2662 ZEND_ASSERT(!(flags[var] & ZREG_LAST_USE));
2663 end[var] = line;
2664 if (def >= 0) {
2665 flags[var] |= ZREG_LAST_USE;
2666 } else if (use_chain < 0 && (flags[var] & (ZREG_LOAD|ZREG_STORE))) {
2667 flags[var] |= ZREG_LAST_USE;
2668 } else if (use_chain >= 0 && !zend_ssa_is_no_val_use(ssa_opcodes[use_chain], ssa->ops + use_chain, var)) {
2669 /* pass */
2670 } else if (op_array_ssa->vars) {
2671 uint32_t use = ssa_opcodes[line] - op_array->opcodes;
2672
2673 if (ssa->ops[line].op1_use == var) {
2674 if (zend_ssa_is_last_use(op_array, op_array_ssa, op_array_ssa->ops[use].op1_use, use)) {
2675 flags[var] |= ZREG_LAST_USE;
2676 }
2677 } else if (ssa->ops[line].op2_use == var) {
2678 if (zend_ssa_is_last_use(op_array, op_array_ssa, op_array_ssa->ops[use].op2_use, use)) {
2679 flags[var] |= ZREG_LAST_USE;
2680 }
2681 } else if (ssa->ops[line].result_use == var) {
2682 if (zend_ssa_is_last_use(op_array, op_array_ssa, op_array_ssa->ops[use].result_use, use)) {
2683 flags[var] |= ZREG_LAST_USE;
2684 }
2685 }
2686 }
2687 }
2688
zend_jit_trace_allocate_registers(zend_jit_trace_rec * trace_buffer,zend_ssa * ssa,uint32_t parent_trace,uint32_t exit_num)2689 static zend_lifetime_interval** zend_jit_trace_allocate_registers(zend_jit_trace_rec *trace_buffer, zend_ssa *ssa, uint32_t parent_trace, uint32_t exit_num)
2690 {
2691 const zend_op **ssa_opcodes = ((zend_tssa*)ssa)->tssa_opcodes;
2692 zend_jit_trace_rec *p;
2693 const zend_op_array *op_array;
2694 zend_jit_op_array_trace_extension *jit_extension;
2695 const zend_ssa *op_array_ssa;
2696 const zend_ssa_op *ssa_op;
2697 int i, j, idx, count, level;
2698 int last_idx = -1;
2699 int *start, *end;
2700 uint8_t *flags;
2701 const zend_op_array **vars_op_array;
2702 zend_lifetime_interval **intervals, *list, *ival;
2703 void *checkpoint;
2704 zend_jit_trace_stack_frame *frame;
2705 zend_jit_trace_stack *stack;
2706 uint32_t parent_vars_count = parent_trace ?
2707 zend_jit_traces[parent_trace].exit_info[exit_num].stack_size : 0;
2708 zend_jit_trace_stack *parent_stack = parent_trace ?
2709 zend_jit_traces[parent_trace].stack_map +
2710 zend_jit_traces[parent_trace].exit_info[exit_num].stack_offset : NULL;
2711 ALLOCA_FLAG(use_heap);
2712
2713 ZEND_ASSERT(ssa->var_info != NULL);
2714
2715 start = do_alloca(sizeof(int) * ssa->vars_count * 2 +
2716 ZEND_MM_ALIGNED_SIZE(sizeof(uint8_t) * ssa->vars_count),
2717 use_heap);
2718 if (!start) {
2719 return NULL;
2720 }
2721 end = start + ssa->vars_count;
2722 flags = (uint8_t*)(end + ssa->vars_count);
2723 checkpoint = zend_arena_checkpoint(CG(arena));
2724 vars_op_array = zend_arena_calloc(&CG(arena), ssa->vars_count, sizeof(zend_op_array*));
2725
2726 memset(start, -1, sizeof(int) * ssa->vars_count * 2);
2727 memset(flags, 0, sizeof(uint8_t) * ssa->vars_count);
2728 memset(ZEND_VOIDP(vars_op_array), 0, sizeof(zend_op_array*) * ssa->vars_count);
2729
2730 op_array = trace_buffer->op_array;
2731 jit_extension =
2732 (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
2733 op_array_ssa = &jit_extension->func_info.ssa;
2734 frame = JIT_G(current_frame);
2735 frame->prev = NULL;
2736 frame->func = (const zend_function*)op_array;
2737 stack = frame->stack;
2738
2739 count = 0;
2740
2741 i = 0;
2742 j = op_array->last_var;
2743 if (trace_buffer->start != ZEND_JIT_TRACE_START_ENTER) {
2744 j += op_array->T;
2745 }
2746 while (i < j) {
2747 SET_STACK_VAR(stack, i, i);
2748 vars_op_array[i] = op_array;
2749 /* We don't start intervals for variables used in Phi */
2750 if ((ssa->vars[i].use_chain >= 0 /*|| ssa->vars[i].phi_use_chain*/)
2751 && !zend_ssa_is_no_val_use(ssa_opcodes[ssa->vars[i].use_chain], ssa->ops + ssa->vars[i].use_chain, i)
2752 && ssa->vars[i].alias == NO_ALIAS
2753 && zend_jit_var_supports_reg(ssa, i)) {
2754 start[i] = 0;
2755 if (i < parent_vars_count
2756 && STACK_REG(parent_stack, i) != ZREG_NONE
2757 && STACK_REG(parent_stack, i) < ZREG_NUM) {
2758 /* We will try to reuse register from parent trace */
2759 flags[i] = STACK_FLAGS(parent_stack, i);
2760 count += 2;
2761 } else {
2762 flags[i] = ZREG_LOAD;
2763 count++;
2764 }
2765 }
2766 i++;
2767 }
2768
2769 if (trace_buffer->start == ZEND_JIT_TRACE_START_ENTER) {
2770 j = op_array->last_var + op_array->T;
2771 while (i < j) {
2772 SET_STACK_VAR(stack, i, -1);
2773 i++;
2774 }
2775 }
2776
2777 if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
2778 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
2779 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
2780 zend_ssa_phi *phi = ssa->blocks[1].phis;
2781
2782 while (phi) {
2783 SET_STACK_VAR(stack, phi->var, phi->ssa_var);
2784 vars_op_array[phi->ssa_var] = op_array;
2785 if (ssa->vars[phi->ssa_var].use_chain >= 0
2786 && ssa->vars[phi->ssa_var].alias == NO_ALIAS
2787 && zend_jit_var_supports_reg(ssa, phi->ssa_var)) {
2788 start[phi->ssa_var] = 0;
2789 count++;
2790 }
2791 phi = phi->next;
2792 }
2793 }
2794
2795 p = trace_buffer + ZEND_JIT_TRACE_START_REC_SIZE;
2796 level = 0;
2797 ssa_op = ssa->ops;
2798 idx = 0;
2799 for (;;p++) {
2800 if (p->op == ZEND_JIT_TRACE_VM) {
2801 const zend_op *opline = p->opline;
2802 int len;
2803 bool support_opline;
2804
2805 support_opline =
2806 zend_jit_opline_supports_reg(op_array, ssa, opline, ssa_op, p);
2807
2808 if (support_opline
2809 && opline->opcode == ZEND_ASSIGN
2810 && opline->op1_type == IS_CV
2811 && ssa_op->op1_def >= 0
2812 && ssa->vars[ssa_op->op1_def].alias != NO_ALIAS) {
2813 /* avoid register allocation in case of possibility of indirect modification*/
2814 support_opline = 0;
2815 }
2816
2817 if (ssa_op->op1_use >= 0
2818 && start[ssa_op->op1_use] >= 0
2819 && !zend_ssa_is_no_val_use(opline, ssa_op, ssa_op->op1_use)) {
2820 if (support_opline) {
2821 zend_jit_trace_use_var(idx, ssa_op->op1_use, ssa_op->op1_def, ssa_op->op1_use_chain, start, end, flags, ssa, ssa_opcodes, op_array, op_array_ssa);
2822 if (opline->op1_type != IS_CV) {
2823 if (opline->opcode == ZEND_CASE
2824 || opline->opcode == ZEND_CASE_STRICT
2825 || opline->opcode == ZEND_SWITCH_LONG
2826 || opline->opcode == ZEND_MATCH
2827 || opline->opcode == ZEND_FETCH_LIST_R
2828 || opline->opcode == ZEND_COPY_TMP
2829 || opline->opcode == ZEND_SWITCH_STRING
2830 || opline->opcode == ZEND_FE_FETCH_R
2831 || opline->opcode == ZEND_FE_FETCH_RW
2832 || opline->opcode == ZEND_FETCH_LIST_W
2833 || opline->opcode == ZEND_VERIFY_RETURN_TYPE
2834 || opline->opcode == ZEND_BIND_LEXICAL
2835 || opline->opcode == ZEND_ROPE_ADD) {
2836 /* The value is kept alive and may be used outside of the trace */
2837 flags[ssa_op->op1_use] |= ZREG_STORE;
2838 } else {
2839 flags[ssa_op->op1_use] |= ZREG_LAST_USE;
2840 }
2841 }
2842 } else {
2843 start[ssa_op->op1_use] = -1;
2844 end[ssa_op->op1_use] = -1;
2845 count--;
2846 }
2847 }
2848 if (ssa_op->op2_use >= 0
2849 && ssa_op->op2_use != ssa_op->op1_use
2850 && start[ssa_op->op2_use] >= 0
2851 && !zend_ssa_is_no_val_use(opline, ssa_op, ssa_op->op2_use)) {
2852 if (support_opline) {
2853 zend_jit_trace_use_var(idx, ssa_op->op2_use, ssa_op->op2_def, ssa_op->op2_use_chain, start, end, flags, ssa, ssa_opcodes, op_array, op_array_ssa);
2854 if (opline->op2_type != IS_CV) {
2855 flags[ssa_op->op2_use] |= ZREG_LAST_USE;
2856 }
2857 } else {
2858 start[ssa_op->op2_use] = -1;
2859 end[ssa_op->op2_use] = -1;
2860 count--;
2861 }
2862 }
2863 if (ssa_op->result_use >= 0
2864 && ssa_op->result_use != ssa_op->op1_use
2865 && ssa_op->result_use != ssa_op->op2_use
2866 && start[ssa_op->result_use] >= 0
2867 && !zend_ssa_is_no_val_use(opline, ssa_op, ssa_op->result_use)) {
2868 if (support_opline) {
2869 zend_jit_trace_use_var(idx, ssa_op->result_use, ssa_op->result_def, ssa_op->res_use_chain, start, end, flags, ssa, ssa_opcodes, op_array, op_array_ssa);
2870 } else {
2871 start[ssa_op->result_use] = -1;
2872 end[ssa_op->result_use] = -1;
2873 count--;
2874 }
2875 }
2876
2877 if (ssa_op->op1_def >= 0) {
2878 zend_jit_close_var(stack, EX_VAR_TO_NUM(opline->op1.var), start, end, flags, idx);
2879 SET_STACK_VAR(stack, EX_VAR_TO_NUM(opline->op1.var), ssa_op->op1_def);
2880 }
2881 if (ssa_op->op2_def >= 0) {
2882 zend_jit_close_var(stack, EX_VAR_TO_NUM(opline->op2.var), start, end, flags, idx);
2883 SET_STACK_VAR(stack, EX_VAR_TO_NUM(opline->op2.var), ssa_op->op2_def);
2884 }
2885 if (ssa_op->result_def >= 0) {
2886 zend_jit_close_var(stack, EX_VAR_TO_NUM(opline->result.var), start, end, flags, idx);
2887 SET_STACK_VAR(stack, EX_VAR_TO_NUM(opline->result.var), ssa_op->result_def);
2888 }
2889
2890 if (support_opline) {
2891 if (ssa_op->result_def >= 0
2892 && (ssa->vars[ssa_op->result_def].use_chain >= 0
2893 || ssa->vars[ssa_op->result_def].phi_use_chain)
2894 && ssa->vars[ssa_op->result_def].alias == NO_ALIAS
2895 && zend_jit_var_supports_reg(ssa, ssa_op->result_def)) {
2896 if (!(ssa->var_info[ssa_op->result_def].type & MAY_BE_GUARD)
2897 || opline->opcode == ZEND_PRE_INC
2898 || opline->opcode == ZEND_PRE_DEC
2899 || opline->opcode == ZEND_POST_INC
2900 || opline->opcode == ZEND_POST_DEC
2901 || opline->opcode == ZEND_ADD
2902 || opline->opcode == ZEND_SUB
2903 || opline->opcode == ZEND_MUL
2904 || opline->opcode == ZEND_FETCH_DIM_R
2905 || opline->opcode == ZEND_FETCH_CONSTANT) {
2906 if (!(ssa->var_info[ssa_op->result_def].type & MAY_BE_DOUBLE)
2907 || (opline->opcode != ZEND_PRE_INC && opline->opcode != ZEND_PRE_DEC)) {
2908 start[ssa_op->result_def] = idx;
2909 vars_op_array[ssa_op->result_def] = op_array;
2910 count++;
2911 }
2912 }
2913 }
2914 if (ssa_op->op1_def >= 0
2915 && (ssa->vars[ssa_op->op1_def].use_chain >= 0
2916 || ssa->vars[ssa_op->op1_def].phi_use_chain)
2917 && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS
2918 && zend_jit_var_supports_reg(ssa, ssa_op->op1_def)) {
2919 start[ssa_op->op1_def] = idx;
2920 vars_op_array[ssa_op->op1_def] = op_array;
2921 count++;
2922 }
2923 if (ssa_op->op2_def >= 0
2924 && (ssa->vars[ssa_op->op2_def].use_chain >= 0
2925 || ssa->vars[ssa_op->op2_def].phi_use_chain)
2926 && ssa->vars[ssa_op->op2_def].alias == NO_ALIAS
2927 && zend_jit_var_supports_reg(ssa, ssa_op->op2_def)) {
2928 start[ssa_op->op2_def] = idx;
2929 vars_op_array[ssa_op->op2_def] = op_array;
2930 count++;
2931 }
2932 }
2933
2934 len = zend_jit_trace_op_len(opline);
2935 switch (opline->opcode) {
2936 case ZEND_ASSIGN_DIM:
2937 case ZEND_ASSIGN_OBJ:
2938 case ZEND_ASSIGN_STATIC_PROP:
2939 case ZEND_ASSIGN_DIM_OP:
2940 case ZEND_ASSIGN_OBJ_OP:
2941 case ZEND_ASSIGN_STATIC_PROP_OP:
2942 case ZEND_ASSIGN_OBJ_REF:
2943 case ZEND_ASSIGN_STATIC_PROP_REF:
2944 /* OP_DATA */
2945 ssa_op++;
2946 opline++;
2947 if (ssa_op->op1_use >= 0
2948 && start[ssa_op->op1_use] >= 0
2949 && !zend_ssa_is_no_val_use(opline, ssa_op, ssa_op->op1_use)) {
2950 if (support_opline) {
2951 zend_jit_trace_use_var(idx, ssa_op->op1_use, ssa_op->op1_def, ssa_op->op1_use_chain, start, end, flags, ssa, ssa_opcodes, op_array, op_array_ssa);
2952 if (opline->op1_type != IS_CV) {
2953 flags[ssa_op->op1_use] |= ZREG_LAST_USE;
2954 }
2955 } else {
2956 start[ssa_op->op1_use] = -1;
2957 end[ssa_op->op1_use] = -1;
2958 count--;
2959 }
2960 }
2961 if (ssa_op->op1_def >= 0) {
2962 zend_jit_close_var(stack, EX_VAR_TO_NUM(opline->op1.var), start, end, flags, idx);
2963 SET_STACK_VAR(stack, EX_VAR_TO_NUM(opline->op1.var), ssa_op->op1_def);
2964 if (support_opline
2965 && (ssa->vars[ssa_op->op1_def].use_chain >= 0
2966 || ssa->vars[ssa_op->op1_def].phi_use_chain)
2967 && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS
2968 && zend_jit_var_supports_reg(ssa, ssa_op->op1_def)) {
2969 start[ssa_op->op1_def] = idx;
2970 vars_op_array[ssa_op->op1_def] = op_array;
2971 count++;
2972 }
2973 }
2974 ssa_op++;
2975 opline++;
2976 idx+=2;
2977 break;
2978 case ZEND_RECV_INIT:
2979 ssa_op++;
2980 opline++;
2981 idx++;
2982 while (opline->opcode == ZEND_RECV_INIT) {
2983 /* RECV_INIT doesn't support registers */
2984 if (ssa_op->result_def >= 0) {
2985 zend_jit_close_var(stack, EX_VAR_TO_NUM(opline->result.var), start, end, flags, idx);
2986 SET_STACK_VAR(stack, EX_VAR_TO_NUM(opline->result.var), ssa_op->result_def);
2987 }
2988 ssa_op++;
2989 opline++;
2990 idx++;
2991 }
2992 break;
2993 case ZEND_BIND_GLOBAL:
2994 ssa_op++;
2995 opline++;
2996 idx++;
2997 while (opline->opcode == ZEND_BIND_GLOBAL) {
2998 /* BIND_GLOBAL doesn't support registers */
2999 if (ssa_op->op1_def >= 0) {
3000 zend_jit_close_var(stack, EX_VAR_TO_NUM(opline->op1.var), start, end, flags, idx);
3001 SET_STACK_VAR(stack, EX_VAR_TO_NUM(opline->op1.var), ssa_op->op1_def);
3002 }
3003 ssa_op++;
3004 opline++;
3005 idx++;
3006 }
3007 break;
3008 default:
3009 ssa_op += len;
3010 idx += len;
3011 break;
3012 }
3013 } else if (p->op == ZEND_JIT_TRACE_ENTER) {
3014 /* New call frames */
3015 zend_jit_trace_stack_frame *prev_frame = frame;
3016
3017 frame = zend_jit_trace_call_frame(frame, op_array);
3018 frame->prev = prev_frame;
3019 frame->func = (const zend_function*)p->op_array;
3020 stack = frame->stack;
3021 op_array = p->op_array;
3022 jit_extension =
3023 (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
3024 op_array_ssa = &jit_extension->func_info.ssa;
3025 j = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
3026 for (i = 0; i < op_array->last_var; i++) {
3027 SET_STACK_VAR(stack, i, j);
3028 vars_op_array[j] = op_array;
3029 if (ssa->vars[j].use_chain >= 0
3030 && ssa->vars[j].alias == NO_ALIAS
3031 && zend_jit_var_supports_reg(ssa, j)) {
3032 start[j] = idx;
3033 flags[j] = ZREG_LOAD;
3034 count++;
3035 }
3036 j++;
3037 }
3038 for (i = op_array->last_var; i < op_array->last_var + op_array->T; i++) {
3039 SET_STACK_VAR(stack, i, -1);
3040 }
3041 level++;
3042 } else if (p->op == ZEND_JIT_TRACE_BACK) {
3043 /* Close exiting call frames */
3044 for (i = 0; i < op_array->last_var; i++) {
3045 zend_jit_close_var(stack, i, start, end, flags, idx-1);
3046 }
3047 op_array = p->op_array;
3048 jit_extension =
3049 (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
3050 op_array_ssa = &jit_extension->func_info.ssa;
3051 frame = zend_jit_trace_ret_frame(frame, op_array);
3052 stack = frame->stack;
3053 if (level == 0) {
3054 /* New return frames */
3055 frame->prev = NULL;
3056 frame->func = (const zend_function*)op_array;
3057 j = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
3058 for (i = 0; i < op_array->last_var + op_array->T; i++) {
3059 SET_STACK_VAR(stack, i, j);
3060 vars_op_array[j] = op_array;
3061 if (ssa->vars[j].use_chain >= 0
3062 && ssa->vars[j].alias == NO_ALIAS
3063 && zend_jit_var_supports_reg(ssa, j)) {
3064 start[j] = idx;
3065 flags[j] = ZREG_LOAD;
3066 count++;
3067 }
3068 j++;
3069 }
3070 } else {
3071 level--;
3072 }
3073 } else if (p->op == ZEND_JIT_TRACE_END) {
3074 break;
3075 }
3076 }
3077
3078 if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
3079 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
3080 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
3081 zend_ssa_phi *phi = ssa->blocks[1].phis;
3082
3083 while (phi) {
3084 i = phi->sources[1];
3085 if (start[i] >= 0 && !ssa->vars[phi->ssa_var].no_val) {
3086 end[i] = idx;
3087 flags[i] &= ~ZREG_LAST_USE;
3088 }
3089 phi = phi->next;
3090 }
3091
3092 if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP) {
3093 for (i = 0; i < op_array->last_var; i++) {
3094 if (start[i] >= 0 && !ssa->vars[i].phi_use_chain) {
3095 end[i] = idx;
3096 flags[i] &= ~ZREG_LAST_USE;
3097 } else {
3098 zend_jit_close_var(stack, i, start, end, flags, idx);
3099 }
3100 }
3101 }
3102 } else {
3103 last_idx = idx;
3104 for (i = 0; i < op_array->last_var; i++) {
3105 zend_jit_close_var(stack, i, start, end, flags, idx);
3106 }
3107 while (frame->prev) {
3108 frame = frame->prev;
3109 op_array = &frame->func->op_array;
3110 stack = frame->stack;
3111 for (i = 0; i < op_array->last_var; i++) {
3112 zend_jit_close_var(stack, i, start, end, flags, idx);
3113 }
3114 }
3115 }
3116
3117 if (!count) {
3118 free_alloca(start, use_heap);
3119 zend_arena_release(&CG(arena), checkpoint);
3120 return NULL;
3121 }
3122
3123 intervals = zend_arena_calloc(&CG(arena), ssa->vars_count, sizeof(zend_lifetime_interval));
3124 memset(intervals, 0, sizeof(zend_lifetime_interval*) * ssa->vars_count);
3125 list = zend_arena_alloc(&CG(arena), sizeof(zend_lifetime_interval) * count);
3126 j = 0;
3127 for (i = 0; i < ssa->vars_count; i++) {
3128 if (start[i] >= 0 && end[i] >= 0) {
3129 ZEND_ASSERT(j < count);
3130 if ((flags[i] & ZREG_LOAD) &&
3131 (flags[i] & ZREG_LAST_USE) &&
3132 end[i] == ssa->vars[i].use_chain) {
3133 /* skip life range with single use */
3134 continue;
3135 }
3136 intervals[i] = &list[j];
3137 list[j].ssa_var = i;
3138 list[j].reg = ZREG_NONE;
3139 list[j].flags = flags[i];
3140 list[j].range.start = start[i];
3141 list[j].range.end = end[i];
3142 list[j].range.next = NULL;
3143 list[j].hint = NULL;
3144 list[j].used_as_hint = NULL;
3145 list[j].list_next = NULL;
3146 j++;
3147 }
3148 }
3149 count = j;
3150 free_alloca(start, use_heap);
3151 start = end = NULL;
3152
3153 if (!count) {
3154 zend_arena_release(&CG(arena), checkpoint);
3155 return NULL;
3156 }
3157
3158 /* Add hints */
3159 if (parent_vars_count) {
3160 i = trace_buffer->op_array->last_var;
3161 if (trace_buffer->start != ZEND_JIT_TRACE_START_ENTER) {
3162 i += trace_buffer->op_array->T;
3163 }
3164 if ((uint32_t)i > parent_vars_count) {
3165 i = parent_vars_count;
3166 }
3167 while (i > 0) {
3168 i--;
3169 if (intervals[i]
3170 && STACK_REG(parent_stack, i) != ZREG_NONE
3171 && STACK_REG(parent_stack, i) < ZREG_NUM) {
3172 list[j].ssa_var = - 1;
3173 list[j].reg = STACK_REG(parent_stack, i);
3174 list[j].flags = 0;
3175 list[j].range.start = -1;
3176 list[j].range.end = -1;
3177 list[j].range.next = NULL;
3178 list[j].hint = NULL;
3179 list[j].used_as_hint = NULL;
3180 list[j].list_next = NULL;
3181 intervals[i]->hint = &list[j];
3182 j++;
3183 }
3184 }
3185 }
3186
3187 if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
3188 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
3189 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
3190 zend_ssa_phi *phi = ssa->blocks[1].phis;
3191
3192 while (phi) {
3193 if (intervals[phi->ssa_var]) {
3194 if (intervals[phi->sources[1]]
3195 && (ssa->var_info[phi->sources[1]].type & MAY_BE_ANY) ==
3196 (ssa->var_info[phi->ssa_var].type & MAY_BE_ANY)) {
3197 intervals[phi->sources[1]]->hint = intervals[phi->ssa_var];
3198 }
3199 }
3200 phi = phi->next;
3201 }
3202 }
3203
3204 for (i = 0; i < ssa->vars_count; i++) {
3205 if (intervals[i] && !intervals[i]->hint) {
3206
3207 if (ssa->vars[i].definition >= 0) {
3208 uint32_t line = ssa->vars[i].definition;
3209 const zend_op *opline = ssa_opcodes[line];
3210
3211 switch (opline->opcode) {
3212 case ZEND_QM_ASSIGN:
3213 case ZEND_POST_INC:
3214 case ZEND_POST_DEC:
3215 if (ssa->ops[line].op1_use >= 0 &&
3216 intervals[ssa->ops[line].op1_use] &&
3217 (i == ssa->ops[line].op1_def ||
3218 (i == ssa->ops[line].result_def &&
3219 (ssa->ops[line].op1_def < 0 ||
3220 !intervals[ssa->ops[line].op1_def])))) {
3221 zend_jit_add_hint(intervals, i, ssa->ops[line].op1_use);
3222 }
3223 break;
3224 case ZEND_SEND_VAR:
3225 if (opline->op2_type == IS_CONST) {
3226 /* Named parameters not supported in JIT */
3227 break;
3228 }
3229 case ZEND_PRE_INC:
3230 case ZEND_PRE_DEC:
3231 if (i == ssa->ops[line].op1_def &&
3232 ssa->ops[line].op1_use >= 0 &&
3233 intervals[ssa->ops[line].op1_use]) {
3234 zend_jit_add_hint(intervals, i, ssa->ops[line].op1_use);
3235 }
3236 break;
3237 case ZEND_ASSIGN:
3238 if (ssa->ops[line].op2_use >= 0 &&
3239 intervals[ssa->ops[line].op2_use] &&
3240 (i == ssa->ops[line].op2_def ||
3241 (i == ssa->ops[line].op1_def &&
3242 (ssa->ops[line].op2_def < 0 ||
3243 !intervals[ssa->ops[line].op2_def])) ||
3244 (i == ssa->ops[line].result_def &&
3245 (ssa->ops[line].op2_def < 0 ||
3246 !intervals[ssa->ops[line].op2_def]) &&
3247 (ssa->ops[line].op1_def < 0 ||
3248 !intervals[ssa->ops[line].op1_def])))) {
3249 zend_jit_add_hint(intervals, i, ssa->ops[line].op2_use);
3250 }
3251 break;
3252 case ZEND_SUB:
3253 case ZEND_ADD:
3254 case ZEND_MUL:
3255 case ZEND_BW_OR:
3256 case ZEND_BW_AND:
3257 case ZEND_BW_XOR:
3258 if (i == ssa->ops[line].result_def) {
3259 if (ssa->ops[line].op1_use >= 0 &&
3260 intervals[ssa->ops[line].op1_use] &&
3261 ssa->ops[line].op1_use_chain < 0 &&
3262 !ssa->vars[ssa->ops[line].op1_use].phi_use_chain &&
3263 (ssa->var_info[i].type & MAY_BE_ANY) ==
3264 (ssa->var_info[ssa->ops[line].op1_use].type & MAY_BE_ANY)) {
3265
3266 zend_ssa_phi *phi = ssa->vars[ssa->ops[line].op1_use].definition_phi;
3267 if (phi &&
3268 intervals[phi->sources[1]] &&
3269 intervals[phi->sources[1]]->hint == intervals[ssa->ops[line].op1_use]) {
3270 break;
3271 }
3272 zend_jit_add_hint(intervals, i, ssa->ops[line].op1_use);
3273 } else if (opline->opcode != ZEND_SUB &&
3274 ssa->ops[line].op2_use >= 0 &&
3275 intervals[ssa->ops[line].op2_use] &&
3276 ssa->ops[line].op2_use_chain < 0 &&
3277 !ssa->vars[ssa->ops[line].op2_use].phi_use_chain &&
3278 (ssa->var_info[i].type & MAY_BE_ANY) ==
3279 (ssa->var_info[ssa->ops[line].op2_use].type & MAY_BE_ANY)) {
3280
3281 zend_ssa_phi *phi = ssa->vars[ssa->ops[line].op2_use].definition_phi;
3282 if (phi &&
3283 intervals[phi->sources[1]] &&
3284 intervals[phi->sources[1]]->hint == intervals[ssa->ops[line].op2_use]) {
3285 break;
3286 }
3287 zend_jit_add_hint(intervals, i, ssa->ops[line].op2_use);
3288 }
3289 }
3290 break;
3291 }
3292 }
3293 }
3294 }
3295
3296 list = zend_jit_sort_intervals(intervals, ssa->vars_count);
3297
3298 if (list) {
3299 ival = list;
3300 while (ival) {
3301 if (ival->hint) {
3302 ival->hint->used_as_hint = ival;
3303 }
3304 ival = ival->list_next;
3305 }
3306 }
3307
3308 if (list) {
3309 if (JIT_G(debug) & ZEND_JIT_DEBUG_REG_ALLOC) {
3310 fprintf(stderr, "---- TRACE %d Live Ranges\n", ZEND_JIT_TRACE_NUM);
3311 ival = list;
3312 while (ival) {
3313 zend_jit_dump_lifetime_interval(vars_op_array[ival->ssa_var], ssa, ival);
3314 ival = ival->list_next;
3315 }
3316 }
3317 }
3318
3319 /* Linear Scan Register Allocation (op_array is not actually used, only fn_flags matters) */
3320 list = zend_jit_linear_scan(&dummy_op_array, ssa_opcodes, ssa, list);
3321
3322 if (list) {
3323 zend_lifetime_interval *ival, *next;
3324
3325 memset(intervals, 0, ssa->vars_count * sizeof(zend_lifetime_interval*));
3326 ival = list;
3327 count = 0;
3328 while (ival != NULL) {
3329 ZEND_ASSERT(ival->reg != ZREG_NONE);
3330 count++;
3331 next = ival->list_next;
3332 ival->list_next = intervals[ival->ssa_var];
3333 intervals[ival->ssa_var] = ival;
3334 ival = next;
3335 }
3336
3337 if (!count) {
3338 zend_arena_release(&CG(arena), checkpoint);
3339 return NULL;
3340 }
3341
3342 /* Add LOAD flag to registers that can't reuse register from parent trace */
3343 if (parent_vars_count) {
3344 i = trace_buffer->op_array->last_var;
3345 if (trace_buffer->start != ZEND_JIT_TRACE_START_ENTER) {
3346 i += trace_buffer->op_array->T;
3347 }
3348 if ((uint32_t)i > parent_vars_count) {
3349 i = parent_vars_count;
3350 }
3351 while (i > 0) {
3352 i--;
3353 if (intervals[i] && intervals[i]->reg != STACK_REG(parent_stack, i)) {
3354 intervals[i]->flags |= ZREG_LOAD;
3355 }
3356 }
3357 }
3358
3359 /* SSA resolution */
3360 if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
3361 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
3362 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
3363 zend_ssa_phi *phi = ssa->blocks[1].phis;
3364
3365 while (phi) {
3366 int def = phi->ssa_var;
3367 int use = phi->sources[1];
3368
3369 if (intervals[def]) {
3370 if (!intervals[use]) {
3371 intervals[def]->flags |= ZREG_LOAD;
3372 if ((intervals[def]->flags & ZREG_LAST_USE)
3373 && ssa->vars[def].use_chain >= 0
3374 && ssa->vars[def].use_chain == intervals[def]->range.end) {
3375 /* remove interval used once */
3376 intervals[def] = NULL;
3377 count--;
3378 }
3379 } else if (intervals[def]->reg != intervals[use]->reg) {
3380 intervals[def]->flags |= ZREG_LOAD;
3381 if (ssa->vars[use].use_chain >= 0) {
3382 intervals[use]->flags |= ZREG_STORE;
3383 } else {
3384 intervals[use] = NULL;
3385 count--;
3386 }
3387 } else {
3388 use = phi->sources[0];
3389 ZEND_ASSERT(!intervals[use]);
3390 intervals[use] = zend_arena_alloc(&CG(arena), sizeof(zend_lifetime_interval));
3391 intervals[use]->ssa_var = phi->sources[0];
3392 intervals[use]->reg = intervals[def]->reg;
3393 intervals[use]->flags = ZREG_LOAD;
3394 intervals[use]->range.start = 0;
3395 intervals[use]->range.end = 0;
3396 intervals[use]->range.next = NULL;
3397 intervals[use]->hint = NULL;
3398 intervals[use]->used_as_hint = NULL;
3399 intervals[use]->list_next = NULL;
3400 }
3401 } else if (intervals[use]
3402 && (!ssa->vars[def].no_val
3403 || ssa->var_info[def].type != ssa->var_info[use].type)) {
3404 if (ssa->vars[use].use_chain >= 0) {
3405 intervals[use]->flags |= ZREG_STORE;
3406 } else {
3407 intervals[use] = NULL;
3408 count--;
3409 }
3410 }
3411 phi = phi->next;
3412 }
3413 } else {
3414 for (i = 0; i < ssa->vars_count; i++) {
3415 if (intervals[i]
3416 && intervals[i]->range.end == last_idx
3417 && !(intervals[i]->flags & (ZREG_LOAD|ZREG_STORE))) {
3418 intervals[i]->flags |= ZREG_STORE;
3419 }
3420 }
3421 }
3422
3423 if (!count) {
3424 zend_arena_release(&CG(arena), checkpoint);
3425 return NULL;
3426 }
3427
3428 if (JIT_G(debug) & ZEND_JIT_DEBUG_REG_ALLOC) {
3429 fprintf(stderr, "---- TRACE %d Allocated Live Ranges\n", ZEND_JIT_TRACE_NUM);
3430 for (i = 0; i < ssa->vars_count; i++) {
3431 ival = intervals[i];
3432 while (ival) {
3433 zend_jit_dump_lifetime_interval(vars_op_array[ival->ssa_var], ssa, ival);
3434 ival = ival->list_next;
3435 }
3436 }
3437 }
3438
3439 return intervals;
3440 }
3441
3442 zend_arena_release(&CG(arena), checkpoint); //???
3443 return NULL;
3444 }
3445
zend_jit_trace_clenup_stack(zend_jit_trace_stack * stack,const zend_op * opline,const zend_ssa_op * ssa_op,const zend_ssa * ssa,zend_lifetime_interval ** ra)3446 static void zend_jit_trace_clenup_stack(zend_jit_trace_stack *stack, const zend_op *opline, const zend_ssa_op *ssa_op, const zend_ssa *ssa, zend_lifetime_interval **ra)
3447 {
3448 uint32_t line = ssa_op - ssa->ops;
3449
3450 if (ssa_op->op1_use >= 0
3451 && ra[ssa_op->op1_use]
3452 && ra[ssa_op->op1_use]->range.end == line) {
3453 SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
3454 }
3455 if (ssa_op->op2_use >= 0
3456 && ra[ssa_op->op2_use]
3457 && ra[ssa_op->op2_use]->range.end == line) {
3458 SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->op2.var), ZREG_NONE);
3459 }
3460 if (ssa_op->result_use >= 0
3461 && ra[ssa_op->result_use]
3462 && ra[ssa_op->result_use]->range.end == line) {
3463 SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_NONE);
3464 }
3465 }
3466
zend_jit_trace_setup_ret_counter(const zend_op * opline,size_t offset)3467 static void zend_jit_trace_setup_ret_counter(const zend_op *opline, size_t offset)
3468 {
3469 zend_op *next_opline = (zend_op*)(opline + 1);
3470
3471 if (JIT_G(hot_return) && !ZEND_OP_TRACE_INFO(next_opline, offset)->trace_flags) {
3472 ZEND_ASSERT(zend_jit_ret_trace_counter_handler != NULL);
3473 if (!ZEND_OP_TRACE_INFO(next_opline, offset)->counter) {
3474 ZEND_OP_TRACE_INFO(next_opline, offset)->counter =
3475 &zend_jit_hot_counters[ZEND_JIT_COUNTER_NUM];
3476 ZEND_JIT_COUNTER_NUM = (ZEND_JIT_COUNTER_NUM + 1) % ZEND_HOT_COUNTERS_COUNT;
3477 }
3478 ZEND_OP_TRACE_INFO(next_opline, offset)->trace_flags = ZEND_JIT_TRACE_START_RETURN;
3479 next_opline->handler = (const void*)zend_jit_ret_trace_counter_handler;
3480 }
3481 }
3482
zend_jit_may_delay_fetch_this(const zend_op_array * op_array,zend_ssa * ssa,const zend_op ** ssa_opcodes,const zend_ssa_op * ssa_op)3483 static bool zend_jit_may_delay_fetch_this(const zend_op_array *op_array, zend_ssa *ssa, const zend_op **ssa_opcodes, const zend_ssa_op *ssa_op)
3484 {
3485 int var = ssa_op->result_def;
3486 int i;
3487 int use = ssa->vars[var].use_chain;
3488 const zend_op *opline;
3489
3490 if (use < 0
3491 || ssa->vars[var].phi_use_chain
3492 || ssa->ops[use].op1_use != var
3493 || ssa->ops[use].op1_use_chain != -1) {
3494 return 0;
3495 }
3496
3497 opline = ssa_opcodes[use];
3498 if (opline->opcode == ZEND_INIT_METHOD_CALL) {
3499 return (opline->op2_type == IS_CONST &&
3500 Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_STRING);
3501 } else if (opline->opcode == ZEND_FETCH_OBJ_FUNC_ARG) {
3502 if (!JIT_G(current_frame)
3503 || !JIT_G(current_frame)->call
3504 || !JIT_G(current_frame)->call->func
3505 || !TRACE_FRAME_IS_LAST_SEND_BY_VAL(JIT_G(current_frame)->call)) {
3506 return 0;
3507 }
3508 } else if (opline->opcode != ZEND_FETCH_OBJ_R
3509 && opline->opcode != ZEND_FETCH_OBJ_IS
3510 && opline->opcode != ZEND_FETCH_OBJ_W
3511 && opline->opcode != ZEND_ASSIGN_OBJ
3512 && opline->opcode != ZEND_ASSIGN_OBJ_OP
3513 && opline->opcode != ZEND_PRE_INC_OBJ
3514 && opline->opcode != ZEND_PRE_DEC_OBJ
3515 && opline->opcode != ZEND_POST_INC_OBJ
3516 && opline->opcode != ZEND_POST_DEC_OBJ) {
3517 return 0;
3518 }
3519
3520 if (opline->op2_type != IS_CONST
3521 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
3522 || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
3523 return 0;
3524 }
3525
3526 if (opline->opcode == ZEND_ASSIGN_OBJ_OP) {
3527 if (opline->op1_type == IS_CV
3528 && (opline+1)->op1_type == IS_CV
3529 && (opline+1)->op1.var == opline->op1.var) {
3530 /* skip $a->prop += $a; */
3531 return 0;
3532 }
3533 if (!zend_jit_supported_binary_op(
3534 opline->extended_value, MAY_BE_ANY, OP1_DATA_INFO())) {
3535 return 0;
3536 }
3537 }
3538
3539 for (i = ssa->vars[var].definition; i < use; i++) {
3540 if (ssa_opcodes[i]->opcode == ZEND_DO_UCALL
3541 || ssa_opcodes[i]->opcode == ZEND_DO_FCALL_BY_NAME
3542 || ssa_opcodes[i]->opcode == ZEND_DO_FCALL
3543 || ssa_opcodes[i]->opcode == ZEND_INCLUDE_OR_EVAL) {
3544 return 0;
3545 }
3546 }
3547
3548 return 1;
3549 }
3550
zend_jit_trace_stack_needs_deoptimization(zend_jit_trace_stack * stack,uint32_t stack_size)3551 static int zend_jit_trace_stack_needs_deoptimization(zend_jit_trace_stack *stack, uint32_t stack_size)
3552 {
3553 uint32_t i;
3554
3555 for (i = 0; i < stack_size; i++) {
3556 if (STACK_REG(stack, i) != ZREG_NONE
3557 && !(STACK_FLAGS(stack, i) & (ZREG_LOAD|ZREG_STORE))) {
3558 return 1;
3559 }
3560 }
3561 return 0;
3562 }
3563
zend_jit_trace_exit_needs_deoptimization(uint32_t trace_num,uint32_t exit_num)3564 static int zend_jit_trace_exit_needs_deoptimization(uint32_t trace_num, uint32_t exit_num)
3565 {
3566 const zend_op *opline = zend_jit_traces[trace_num].exit_info[exit_num].opline;
3567 uint32_t flags = zend_jit_traces[trace_num].exit_info[exit_num].flags;
3568 uint32_t stack_size;
3569 zend_jit_trace_stack *stack;
3570
3571 if (opline || (flags & (ZEND_JIT_EXIT_RESTORE_CALL|ZEND_JIT_EXIT_FREE_OP1|ZEND_JIT_EXIT_FREE_OP2))) {
3572 return 1;
3573 }
3574
3575 stack_size = zend_jit_traces[trace_num].exit_info[exit_num].stack_size;
3576 stack = zend_jit_traces[trace_num].stack_map + zend_jit_traces[trace_num].exit_info[exit_num].stack_offset;
3577 return zend_jit_trace_stack_needs_deoptimization(stack, stack_size);
3578 }
3579
zend_jit_trace_deoptimization(dasm_State ** Dst,uint32_t flags,const zend_op * opline,zend_jit_trace_stack * parent_stack,int parent_vars_count,zend_ssa * ssa,zend_jit_trace_stack * stack,zend_lifetime_interval ** ra,bool polymorphic_side_trace)3580 static int zend_jit_trace_deoptimization(dasm_State **Dst,
3581 uint32_t flags,
3582 const zend_op *opline,
3583 zend_jit_trace_stack *parent_stack,
3584 int parent_vars_count,
3585 zend_ssa *ssa,
3586 zend_jit_trace_stack *stack,
3587 zend_lifetime_interval **ra,
3588 bool polymorphic_side_trace)
3589 {
3590 int i;
3591 bool has_constants = 0;
3592 bool has_unsaved_vars = 0;
3593
3594 // TODO: Merge this loop with the following register LOAD loop to implement parallel move ???
3595 for (i = 0; i < parent_vars_count; i++) {
3596 int8_t reg = STACK_REG(parent_stack, i);
3597
3598 if (reg != ZREG_NONE) {
3599 if (reg < ZREG_NUM) {
3600 if (ssa && ssa->vars[i].no_val) {
3601 /* pass */
3602 } else if (ra && ra[i] && ra[i]->reg == reg) {
3603 /* register already loaded by parent trace */
3604 if (stack) {
3605 SET_STACK_REG_EX(stack, i, reg, STACK_FLAGS(parent_stack, i));
3606 }
3607 has_unsaved_vars = 1;
3608 } else {
3609 uint8_t type = STACK_TYPE(parent_stack, i);
3610
3611 if (!(STACK_FLAGS(parent_stack, i) & (ZREG_LOAD|ZREG_STORE))
3612 && !zend_jit_store_var(Dst, 1 << type, i, reg,
3613 STACK_MEM_TYPE(parent_stack, i) != type)) {
3614 return 0;
3615 }
3616 if (stack) {
3617 SET_STACK_TYPE(stack, i, type, 1);
3618 }
3619 }
3620 } else {
3621 /* delay custom deoptimization instructions to prevent register clobbering */
3622 has_constants = 1;
3623 }
3624 }
3625 }
3626
3627 if (has_unsaved_vars
3628 && (has_constants
3629 || (flags & (ZEND_JIT_EXIT_RESTORE_CALL|ZEND_JIT_EXIT_FREE_OP1|ZEND_JIT_EXIT_FREE_OP2)))) {
3630 for (i = 0; i < parent_vars_count; i++) {
3631 int8_t reg = STACK_REG(parent_stack, i);
3632
3633 if (reg != ZREG_NONE) {
3634 if (reg < ZREG_NUM) {
3635 if (ssa && ssa->vars[i].no_val) {
3636 /* pass */
3637 } else if (ra && ra[i] && ra[i]->reg == reg) {
3638 uint8_t type = STACK_TYPE(parent_stack, i);
3639
3640 if (stack) {
3641 SET_STACK_TYPE(stack, i, type, 1);
3642 }
3643 if (!(STACK_FLAGS(parent_stack, i) & (ZREG_LOAD|ZREG_STORE))
3644 && !zend_jit_store_var(Dst, 1 << type, i, reg,
3645 STACK_MEM_TYPE(parent_stack, i) != type)) {
3646 return 0;
3647 }
3648 }
3649 }
3650 }
3651 }
3652 }
3653
3654 if (has_constants) {
3655 for (i = 0; i < parent_vars_count; i++) {
3656 int8_t reg = STACK_REG(parent_stack, i);
3657
3658 if (reg != ZREG_NONE) {
3659 if (reg < ZREG_NUM) {
3660 /* pass */
3661 } else if (reg == ZREG_THIS) {
3662 if (polymorphic_side_trace) {
3663 ssa->var_info[i].delayed_fetch_this = 1;
3664 if (stack) {
3665 SET_STACK_REG(stack, i, ZREG_THIS);
3666 }
3667 } else if (!zend_jit_load_this(Dst, EX_NUM_TO_VAR(i))) {
3668 return 0;
3669 }
3670 } else {
3671 if (reg == ZREG_ZVAL_COPY_GPR0
3672 &&!zend_jit_escape_if_undef_r0(Dst, i, flags, opline)) {
3673 return 0;
3674 }
3675 if (!zend_jit_store_const(Dst, i, reg)) {
3676 return 0;
3677 }
3678 }
3679 }
3680 }
3681 }
3682
3683 if (flags & ZEND_JIT_EXIT_RESTORE_CALL) {
3684 if (!zend_jit_save_call_chain(Dst, -1)) {
3685 return 0;
3686 }
3687 }
3688
3689 if (flags & ZEND_JIT_EXIT_FREE_OP2) {
3690 const zend_op *op = opline - 1;
3691
3692 if (!zend_jit_free_op(Dst, op, -1, op->op2.var)) {
3693 return 0;
3694 }
3695 }
3696
3697 if (flags & ZEND_JIT_EXIT_FREE_OP1) {
3698 const zend_op *op = opline - 1;
3699
3700 if (!zend_jit_free_op(Dst, op, -1, op->op1.var)) {
3701 return 0;
3702 }
3703 }
3704
3705 if (flags & (ZEND_JIT_EXIT_FREE_OP1|ZEND_JIT_EXIT_FREE_OP2)) {
3706 if (!zend_jit_check_exception(Dst)) {
3707 return 0;
3708 }
3709 }
3710
3711 if ((flags & ZEND_JIT_EXIT_METHOD_CALL) && !polymorphic_side_trace) {
3712 if (!zend_jit_free_trampoline(Dst)) {
3713 return 0;
3714 }
3715 }
3716
3717 return 1;
3718 }
3719
zend_jit_trace_set_var_range(zend_ssa_var_info * info,zend_long min,zend_long max)3720 static void zend_jit_trace_set_var_range(zend_ssa_var_info *info, zend_long min, zend_long max)
3721 {
3722 info->has_range = 1;
3723 info->range.min = min;
3724 info->range.max = max;
3725 info->range.underflow = 0;
3726 info->range.overflow = 0;
3727 }
3728
zend_jit_trace_update_condition_ranges(const zend_op * opline,const zend_ssa_op * ssa_op,const zend_op_array * op_array,zend_ssa * ssa,bool exit_if_true)3729 static void zend_jit_trace_update_condition_ranges(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_op_array *op_array, zend_ssa *ssa, bool exit_if_true)
3730 {
3731 zend_long op1_min, op1_max, op2_min, op2_max;
3732
3733 if ((OP1_INFO() & MAY_BE_ANY) != MAY_BE_LONG
3734 || (OP1_INFO() & MAY_BE_ANY) != MAY_BE_LONG) {
3735 return;
3736 }
3737
3738 op1_min = OP1_MIN_RANGE();
3739 op1_max = OP1_MAX_RANGE();
3740 op2_min = OP2_MIN_RANGE();
3741 op2_max = OP2_MAX_RANGE();
3742
3743 switch (opline->opcode) {
3744 case ZEND_IS_EQUAL:
3745 case ZEND_CASE:
3746 case ZEND_IS_IDENTICAL:
3747 case ZEND_CASE_STRICT:
3748 case ZEND_IS_NOT_IDENTICAL:
3749 if (!exit_if_true) {
3750 /* op1 == op2 */
3751 if (ssa_op->op1_use >= 0) {
3752 zend_jit_trace_set_var_range(
3753 &ssa->var_info[ssa_op->op1_use],
3754 MAX(op1_min, op2_min),
3755 MIN(op1_max, op2_max));
3756 }
3757 if (ssa_op->op2_use >= 0) {
3758 zend_jit_trace_set_var_range(
3759 &ssa->var_info[ssa_op->op2_use],
3760 MAX(op2_min, op1_min),
3761 MIN(op2_max, op1_max));
3762 }
3763 }
3764 break;
3765 case ZEND_IS_NOT_EQUAL:
3766 if (exit_if_true) {
3767 /* op1 == op2 */
3768 if (ssa_op->op1_use >= 0) {
3769 zend_jit_trace_set_var_range(
3770 &ssa->var_info[ssa_op->op1_use],
3771 MAX(op1_min, op2_min),
3772 MIN(op1_max, op2_max));
3773 }
3774 if (ssa_op->op2_use >= 0) {
3775 zend_jit_trace_set_var_range(
3776 &ssa->var_info[ssa_op->op2_use],
3777 MAX(op2_min, op1_min),
3778 MIN(op2_max, op1_max));
3779 }
3780 }
3781 break;
3782 case ZEND_IS_SMALLER_OR_EQUAL:
3783 if (!exit_if_true) {
3784 /* op1 <= op2 */
3785 if (ssa_op->op1_use >= 0) {
3786 zend_jit_trace_set_var_range(
3787 &ssa->var_info[ssa_op->op1_use],
3788 op1_min,
3789 MIN(op1_max, op2_max));
3790 }
3791 if (ssa_op->op2_use >= 0) {
3792 zend_jit_trace_set_var_range(
3793 &ssa->var_info[ssa_op->op2_use],
3794 MAX(op2_min, op1_min),
3795 op2_max);
3796 }
3797 } else {
3798 /* op1 > op2 */
3799 if (ssa_op->op1_use >= 0) {
3800 zend_jit_trace_set_var_range(
3801 &ssa->var_info[ssa_op->op1_use],
3802 op2_min != ZEND_LONG_MAX ? MAX(op1_min, op2_min + 1) : op1_min,
3803 op1_max);
3804 }
3805 if (ssa_op->op2_use >= 0) {
3806 zend_jit_trace_set_var_range(
3807 &ssa->var_info[ssa_op->op2_use],
3808 op2_min,
3809 op2_max != ZEND_LONG_MIN ?MIN(op2_max, op1_max - 1) : op1_max);
3810 }
3811 }
3812 break;
3813 case ZEND_IS_SMALLER:
3814 if (!exit_if_true) {
3815 /* op1 < op2 */
3816 if (ssa_op->op1_use >= 0) {
3817 zend_jit_trace_set_var_range(
3818 &ssa->var_info[ssa_op->op1_use],
3819 op1_min,
3820 op2_max != ZEND_LONG_MIN ? MIN(op1_max, op2_max - 1) : op1_max);
3821 }
3822 if (ssa_op->op2_use >= 0) {
3823 zend_jit_trace_set_var_range(
3824 &ssa->var_info[ssa_op->op2_use],
3825 op1_min != ZEND_LONG_MAX ? MAX(op2_min, op1_min + 1) : op2_min,
3826 op2_max);
3827 }
3828 } else {
3829 /* op1 >= op2 */
3830 if (ssa_op->op1_use >= 0) {
3831 zend_jit_trace_set_var_range(
3832 &ssa->var_info[ssa_op->op1_use],
3833 MAX(op1_min, op2_min),
3834 op1_max);
3835 }
3836 if (ssa_op->op2_use >= 0) {
3837 zend_jit_trace_set_var_range(
3838 &ssa->var_info[ssa_op->op2_use],
3839 op2_min,
3840 MIN(op2_max, op1_max));
3841 }
3842 }
3843 break;
3844 }
3845 }
3846
zend_jit_may_skip_comparison(const zend_op * opline,const zend_ssa_op * ssa_op,const zend_ssa * ssa,const zend_op ** ssa_opcodes,const zend_op_array * op_array)3847 static bool zend_jit_may_skip_comparison(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_ssa *ssa, const zend_op **ssa_opcodes, const zend_op_array *op_array)
3848 {
3849 zend_uchar prev_opcode;
3850
3851 if (opline->op1_type == IS_CONST
3852 && Z_TYPE_P(RT_CONSTANT(opline, opline->op1)) == IS_LONG
3853 && Z_LVAL_P(RT_CONSTANT(opline, opline->op1)) == 0) {
3854 if (ssa_op->op2_use >= 0) {
3855 if ((ssa_op-1)->op1_def == ssa_op->op2_use) {
3856 ssa_op--;
3857 opline = ssa_opcodes[ssa_op - ssa->ops];
3858 prev_opcode = opline->opcode;
3859 if (prev_opcode == ZEND_PRE_INC
3860 || prev_opcode == ZEND_PRE_DEC
3861 || prev_opcode == ZEND_POST_INC
3862 || prev_opcode == ZEND_POST_DEC) {
3863 return (OP1_INFO() & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)-MAY_BE_LONG)) == 0;
3864 }
3865 } else if ((ssa_op-1)->result_def == ssa_op->op2_use) {
3866 ssa_op--;
3867 opline = ssa_opcodes[ssa_op - ssa->ops];
3868 prev_opcode = opline->opcode;
3869 if (prev_opcode == ZEND_ADD
3870 || prev_opcode == ZEND_SUB) {
3871 return (OP1_INFO() & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)-MAY_BE_LONG)) == 0 &&
3872 (OP2_INFO() & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)-MAY_BE_LONG)) == 0;
3873 }
3874 }
3875 }
3876 } else if (opline->op2_type == IS_CONST
3877 && Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_LONG
3878 && Z_LVAL_P(RT_CONSTANT(opline, opline->op2)) == 0) {
3879 if (ssa_op->op1_use >= 0) {
3880 if ((ssa_op-1)->op1_def == ssa_op->op1_use) {
3881 ssa_op--;
3882 opline = ssa_opcodes[ssa_op - ssa->ops];
3883 prev_opcode = opline->opcode;
3884 if (prev_opcode == ZEND_PRE_INC
3885 || prev_opcode == ZEND_PRE_DEC
3886 || prev_opcode == ZEND_POST_INC
3887 || prev_opcode == ZEND_POST_DEC) {
3888 return (OP1_INFO() & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)-MAY_BE_LONG)) == 0;
3889 }
3890 } else if ((ssa_op-1)->result_def == ssa_op->op1_use) {
3891 ssa_op--;
3892 opline = ssa_opcodes[ssa_op - ssa->ops];
3893 prev_opcode = opline->opcode;
3894 if (prev_opcode == ZEND_ADD
3895 || prev_opcode == ZEND_SUB) {
3896 return (OP1_INFO() & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)-MAY_BE_LONG)) == 0 &&
3897 (OP2_INFO() & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)-MAY_BE_LONG)) == 0;
3898 }
3899 }
3900 }
3901 } else {
3902 const zend_ssa_op *prev_ssa_op = ssa_op - 1;
3903 prev_opcode = ssa_opcodes[prev_ssa_op - ssa->ops]->opcode;
3904
3905 if ((prev_opcode == ZEND_JMPZ || prev_opcode == ZEND_JMPNZ)
3906 && prev_ssa_op != ssa->ops
3907 && prev_ssa_op->op1_use >= 0
3908 && prev_ssa_op->op1_use == (prev_ssa_op-1)->result_def) {
3909 prev_ssa_op--;
3910 prev_opcode = ssa_opcodes[prev_ssa_op - ssa->ops]->opcode;
3911 }
3912
3913 if (ssa_op->op1_use == prev_ssa_op->op1_use
3914 && ssa_op->op2_use == prev_ssa_op->op2_use) {
3915 if (prev_opcode == ZEND_IS_EQUAL
3916 || prev_opcode == ZEND_IS_NOT_EQUAL
3917 || prev_opcode == ZEND_IS_SMALLER
3918 || prev_opcode == ZEND_IS_SMALLER_OR_EQUAL
3919 || prev_opcode == ZEND_CASE
3920 || prev_opcode == ZEND_IS_IDENTICAL
3921 || prev_opcode == ZEND_IS_NOT_IDENTICAL
3922 || prev_opcode == ZEND_CASE_STRICT) {
3923 if (ssa_op->op1_use < 0) {
3924 if (RT_CONSTANT(opline, opline->op1) != RT_CONSTANT(&ssa_opcodes[prev_ssa_op - ssa->ops], ssa_opcodes[prev_ssa_op - ssa->ops]->op1)) {
3925 return 0;
3926 }
3927 }
3928 if (ssa_op->op2_use < 0) {
3929 if (RT_CONSTANT(opline, opline->op2) != RT_CONSTANT(&ssa_opcodes[prev_ssa_op - ssa->ops], ssa_opcodes[prev_ssa_op - ssa->ops]->op2)) {
3930 return 0;
3931 }
3932 }
3933 return 1;
3934 }
3935 }
3936 }
3937 return 0;
3938 }
3939
zend_jit_trace_next_is_send_result(const zend_op * opline,zend_jit_trace_rec * p,zend_jit_trace_stack_frame * frame)3940 static bool zend_jit_trace_next_is_send_result(const zend_op *opline,
3941 zend_jit_trace_rec *p,
3942 zend_jit_trace_stack_frame *frame)
3943 {
3944 if (opline->result_type == IS_TMP_VAR
3945 && (p+1)->op == ZEND_JIT_TRACE_VM
3946 && (p+1)->opline == opline + 1
3947 && ((opline+1)->opcode == ZEND_SEND_VAL
3948 || ((opline+1)->opcode == ZEND_SEND_VAL_EX
3949 && frame
3950 && frame->call
3951 && frame->call->func
3952 && !ARG_MUST_BE_SENT_BY_REF(frame->call->func, (opline+1)->op2.num)))
3953 && (opline+1)->op1_type == IS_TMP_VAR
3954 && (opline+1)->op2_type != IS_CONST /* Named parameters not supported in JIT */
3955 && (opline+1)->op1.var == opline->result.var) {
3956
3957 if (frame->call && frame->call->func) {
3958 uint8_t res_type = (p+1)->op1_type;
3959
3960 if (res_type != IS_UNKNOWN && !(res_type & IS_TRACE_REFERENCE) ) {
3961 zend_jit_trace_send_type(opline+1, frame->call, res_type);
3962 }
3963 }
3964 return 1;
3965 }
3966 return 0;
3967 }
3968
zend_jit_trace(zend_jit_trace_rec * trace_buffer,uint32_t parent_trace,uint32_t exit_num)3969 static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t parent_trace, uint32_t exit_num)
3970 {
3971 const void *handler = NULL;
3972 dasm_State* dasm_state = NULL;
3973 zend_script *script = NULL;
3974 zend_lifetime_interval **ra = NULL;
3975 zend_string *name = NULL;
3976 void *checkpoint;
3977 const zend_op_array *op_array;
3978 zend_ssa *ssa, *op_array_ssa;
3979 const zend_op **ssa_opcodes;
3980 zend_jit_trace_rec *p;
3981 zend_jit_op_array_trace_extension *jit_extension;
3982 int num_op_arrays = 0;
3983 zend_jit_trace_info *t;
3984 const zend_op_array *op_arrays[ZEND_JIT_TRACE_MAX_FUNCS];
3985 zend_uchar smart_branch_opcode;
3986 const void *exit_addr;
3987 uint32_t op1_info, op1_def_info, op2_info, res_info, res_use_info, op1_data_info;
3988 bool send_result = 0;
3989 bool skip_comparison;
3990 zend_jit_addr op1_addr, op1_def_addr, op2_addr, op2_def_addr, res_addr;
3991 zend_class_entry *ce;
3992 bool ce_is_instanceof;
3993 bool on_this = 0;
3994 bool delayed_fetch_this = 0;
3995 bool avoid_refcounting = 0;
3996 bool polymorphic_side_trace =
3997 parent_trace &&
3998 (zend_jit_traces[parent_trace].exit_info[exit_num].flags & ZEND_JIT_EXIT_METHOD_CALL);
3999 uint32_t i;
4000 zend_jit_trace_stack_frame *frame, *top, *call;
4001 zend_jit_trace_stack *stack;
4002 zend_uchar res_type = IS_UNKNOWN;
4003 const zend_op *opline, *orig_opline;
4004 const zend_ssa_op *ssa_op, *orig_ssa_op;
4005 int checked_stack;
4006 int peek_checked_stack;
4007 uint32_t frame_flags = 0;
4008
4009 JIT_G(current_trace) = trace_buffer;
4010
4011 checkpoint = zend_arena_checkpoint(CG(arena));
4012
4013 ssa = zend_jit_trace_build_tssa(trace_buffer, parent_trace, exit_num, script, op_arrays, &num_op_arrays);
4014
4015 if (!ssa) {
4016 goto jit_cleanup;
4017 }
4018
4019 ssa_opcodes = ((zend_tssa*)ssa)->tssa_opcodes;
4020
4021 /* Register allocation */
4022 if ((JIT_G(opt_flags) & (ZEND_JIT_REG_ALLOC_LOCAL|ZEND_JIT_REG_ALLOC_GLOBAL))
4023 && JIT_G(opt_level) >= ZEND_JIT_LEVEL_INLINE) {
4024 ra = zend_jit_trace_allocate_registers(trace_buffer, ssa, parent_trace, exit_num);
4025 }
4026
4027 p = trace_buffer;
4028 ZEND_ASSERT(p->op == ZEND_JIT_TRACE_START);
4029 op_array = p->op_array;
4030 frame = JIT_G(current_frame);
4031 top = zend_jit_trace_call_frame(frame, op_array);
4032 TRACE_FRAME_INIT(frame, op_array, TRACE_FRAME_MASK_UNKNOWN_RETURN, -1);
4033 frame->used_stack = checked_stack = peek_checked_stack = 0;
4034 stack = frame->stack;
4035 for (i = 0; i < op_array->last_var + op_array->T; i++) {
4036 SET_STACK_TYPE(stack, i, IS_UNKNOWN, 1);
4037 }
4038
4039 opline = p[1].opline;
4040 name = zend_jit_trace_name(op_array, opline->lineno);
4041 p += ZEND_JIT_TRACE_START_REC_SIZE;
4042
4043 dasm_init(&dasm_state, DASM_MAXSECTION);
4044 dasm_setupglobal(&dasm_state, dasm_labels, zend_lb_MAX);
4045 dasm_setup(&dasm_state, dasm_actions);
4046
4047 jit_extension =
4048 (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
4049 op_array_ssa = &jit_extension->func_info.ssa;
4050
4051 dasm_growpc(&dasm_state, 2); /* =>0: loop header */
4052 /* =>1: end of code */
4053
4054 zend_jit_align_func(&dasm_state);
4055 if (!parent_trace) {
4056 zend_jit_prologue(&dasm_state);
4057 }
4058 zend_jit_trace_begin(&dasm_state, ZEND_JIT_TRACE_NUM,
4059 parent_trace ? &zend_jit_traces[parent_trace] : NULL, exit_num);
4060
4061 if (!parent_trace) {
4062 zend_jit_set_last_valid_opline(opline);
4063 zend_jit_track_last_valid_opline();
4064 } else {
4065 if (zend_jit_traces[parent_trace].exit_info[exit_num].opline == NULL) {
4066 zend_jit_trace_opline_guard(&dasm_state, opline);
4067 } else {
4068 zend_jit_reset_last_valid_opline();
4069 }
4070 }
4071
4072 if (JIT_G(opt_level) >= ZEND_JIT_LEVEL_INLINE) {
4073 int last_var;
4074 int parent_vars_count = 0;
4075 zend_jit_trace_stack *parent_stack = NULL;
4076 int used_stack = ((zend_tssa*)ssa)->used_stack;
4077
4078 if (used_stack > 0) {
4079 peek_checked_stack = used_stack;
4080 if (!zend_jit_stack_check(&dasm_state, opline, used_stack)) {
4081 goto jit_failure;
4082 }
4083 }
4084
4085 if (parent_trace) {
4086 parent_vars_count = MIN(zend_jit_traces[parent_trace].exit_info[exit_num].stack_size,
4087 op_array->last_var + op_array->T);
4088 if (parent_vars_count) {
4089 parent_stack =
4090 zend_jit_traces[parent_trace].stack_map +
4091 zend_jit_traces[parent_trace].exit_info[exit_num].stack_offset;
4092 }
4093 }
4094
4095 last_var = op_array->last_var;
4096 if (trace_buffer->start != ZEND_JIT_TRACE_START_ENTER) {
4097 last_var += op_array->T;
4098 }
4099
4100 for (i = 0; i < last_var; i++) {
4101 uint32_t info = ssa->var_info[i].type;
4102
4103 if (!(info & MAY_BE_GUARD) && has_concrete_type(info)) {
4104 uint8_t type, mem_type;
4105
4106 type = concrete_type(info);
4107 if (i < parent_vars_count
4108 && STACK_TYPE(parent_stack, i) == type) {
4109 mem_type = STACK_MEM_TYPE(parent_stack, i);
4110 if (mem_type != IS_UNKNOWN) {
4111 SET_STACK_TYPE(stack, i, mem_type, 1);
4112 }
4113 SET_STACK_TYPE(stack, i, type, 0);
4114 } else {
4115 SET_STACK_TYPE(stack, i, type, 1);
4116 }
4117 } else if (ssa->vars[i].alias != NO_ALIAS) {
4118 SET_STACK_TYPE(stack, i, IS_UNKNOWN, 1);
4119 } else if (i < parent_vars_count
4120 && STACK_TYPE(parent_stack, i) != IS_UNKNOWN) {
4121 /* This must be already handled by trace type inference */
4122 ZEND_UNREACHABLE();
4123 // SET_STACK_TYPE(stack, i, STACK_TYPE(parent_stack, i));
4124 } else if ((info & MAY_BE_GUARD) != 0
4125 && (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
4126 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
4127 || (trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET
4128 && (opline-1)->result_type == IS_VAR
4129 && EX_VAR_TO_NUM((opline-1)->result.var) == i))
4130 && (ssa->vars[i].use_chain != -1
4131 || (ssa->vars[i].phi_use_chain
4132 && !(ssa->var_info[ssa->vars[i].phi_use_chain->ssa_var].type & MAY_BE_GUARD)))) {
4133 /* Check loop-invariant variable type */
4134 if (!zend_jit_type_guard(&dasm_state, opline, EX_NUM_TO_VAR(i), concrete_type(info))) {
4135 goto jit_failure;
4136 }
4137 info &= ~MAY_BE_GUARD;
4138 ssa->var_info[i].type = info;
4139 SET_STACK_TYPE(stack, i, concrete_type(info), 1);
4140 } else if (trace_buffer->start == ZEND_JIT_TRACE_START_ENTER
4141 && op_array->function_name
4142 && i >= op_array->num_args) {
4143 /* This must be already handled by trace type inference */
4144 ZEND_UNREACHABLE();
4145 // SET_STACK_TYPE(stack, i, IS_UNDEF, 1);
4146 }
4147
4148 if ((info & MAY_BE_PACKED_GUARD) != 0
4149 && (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
4150 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
4151 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET)
4152 && (ssa->vars[i].use_chain != -1
4153 || (ssa->vars[i].phi_use_chain
4154 && !(ssa->var_info[ssa->vars[i].phi_use_chain->ssa_var].type & MAY_BE_PACKED_GUARD)))) {
4155 if (!zend_jit_packed_guard(&dasm_state, opline, EX_NUM_TO_VAR(i), info)) {
4156 goto jit_failure;
4157 }
4158 info &= ~MAY_BE_PACKED_GUARD;
4159 ssa->var_info[i].type = info;
4160 }
4161 }
4162
4163 if (parent_trace) {
4164 /* Deoptimization */
4165 if (!zend_jit_trace_deoptimization(&dasm_state,
4166 zend_jit_traces[parent_trace].exit_info[exit_num].flags,
4167 zend_jit_traces[parent_trace].exit_info[exit_num].opline,
4168 parent_stack, parent_vars_count, ssa, stack, ra,
4169 polymorphic_side_trace)) {
4170 goto jit_failure;
4171 }
4172 }
4173
4174 if (ra
4175 && trace_buffer->stop != ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
4176 && trace_buffer->stop != ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
4177 for (i = 0; i < last_var; i++) {
4178 if (ra[i]
4179 && (ra[i]->flags & ZREG_LOAD) != 0
4180 && ra[i]->reg != stack[i].reg) {
4181
4182 if ((ssa->var_info[i].type & MAY_BE_GUARD) != 0) {
4183 uint8_t op_type;
4184
4185 ssa->var_info[i].type &= ~MAY_BE_GUARD;
4186 op_type = concrete_type(ssa->var_info[i].type);
4187 if (!zend_jit_type_guard(&dasm_state, opline, EX_NUM_TO_VAR(i), op_type)) {
4188 goto jit_failure;
4189 }
4190 SET_STACK_TYPE(stack, i, op_type, 1);
4191 }
4192
4193 SET_STACK_REG_EX(stack, i, ra[i]->reg, ZREG_LOAD);
4194 if (!zend_jit_load_var(&dasm_state, ssa->var_info[i].type, i, ra[i]->reg)) {
4195 goto jit_failure;
4196 }
4197 }
4198 }
4199 }
4200 }
4201
4202 if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
4203 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
4204 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
4205
4206 zend_jit_label(&dasm_state, 0); /* start of of trace loop */
4207
4208 if (ra) {
4209 zend_ssa_phi *phi = ssa->blocks[1].phis;
4210
4211 while (phi) {
4212 zend_lifetime_interval *ival = ra[phi->ssa_var];
4213
4214 if (ival) {
4215 if (ival->flags & ZREG_LOAD) {
4216 uint32_t info = ssa->var_info[phi->ssa_var].type;
4217 ZEND_ASSERT(ival->reg != ZREG_NONE);
4218
4219 if (info & MAY_BE_GUARD) {
4220 if (!zend_jit_type_guard(&dasm_state, opline, EX_NUM_TO_VAR(phi->var), concrete_type(info))) {
4221 goto jit_failure;
4222 }
4223 info &= ~MAY_BE_GUARD;
4224 ssa->var_info[phi->ssa_var].type = info;
4225 SET_STACK_TYPE(stack, phi->var, concrete_type(info), 1);
4226 }
4227 SET_STACK_REG_EX(stack, phi->var, ival->reg, ZREG_LOAD);
4228 if (!zend_jit_load_var(&dasm_state, ssa->var_info[phi->ssa_var].type, ssa->vars[phi->ssa_var].var, ival->reg)) {
4229 goto jit_failure;
4230 }
4231 } else if (ival->flags & ZREG_STORE) {
4232 ZEND_ASSERT(ival->reg != ZREG_NONE);
4233
4234 SET_STACK_REG_EX(stack, phi->var, ival->reg, ZREG_STORE);
4235 if (!zend_jit_store_var(&dasm_state, ssa->var_info[phi->ssa_var].type, ssa->vars[phi->ssa_var].var, ival->reg,
4236 STACK_MEM_TYPE(stack, phi->var) != ssa->var_info[phi->ssa_var].type)) {
4237 goto jit_failure;
4238 }
4239 } else {
4240 /* Register has to be written back on side exit */
4241 SET_STACK_REG(stack, phi->var, ival->reg);
4242 }
4243 }
4244 phi = phi->next;
4245 }
4246 }
4247
4248 // if (trace_buffer->stop != ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
4249 // if (ra && zend_jit_trace_stack_needs_deoptimization(stack, op_array->last_var + op_array->T)) {
4250 // uint32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
4251 //
4252 // timeout_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
4253 // if (!timeout_exit_addr) {
4254 // goto jit_failure;
4255 // }
4256 // }
4257 // }
4258
4259 if (ra && trace_buffer->stop != ZEND_JIT_TRACE_STOP_LOOP) {
4260 int last_var = op_array->last_var;
4261
4262 if (trace_buffer->start != ZEND_JIT_TRACE_START_ENTER) {
4263 last_var += op_array->T;
4264 }
4265 for (i = 0; i < last_var; i++) {
4266 if (ra && ra[i] && (ra[i]->flags & ZREG_LOAD) != 0) {
4267 SET_STACK_REG_EX(stack, i, ra[i]->reg, ZREG_LOAD);
4268 if (!zend_jit_load_var(&dasm_state, ssa->var_info[i].type, i, ra[i]->reg)) {
4269 goto jit_failure;
4270 }
4271 }
4272 }
4273 }
4274 }
4275
4276 ssa_op = (JIT_G(opt_level) >= ZEND_JIT_LEVEL_INLINE) ? ssa->ops : NULL;
4277 for (;;p++) {
4278 if (p->op == ZEND_JIT_TRACE_VM) {
4279 uint8_t op1_type = p->op1_type;
4280 uint8_t op2_type = p->op2_type;
4281 uint8_t op3_type = p->op3_type;
4282 uint8_t orig_op1_type = op1_type;
4283 uint8_t orig_op2_type = op2_type;
4284 uint8_t val_type = IS_UNKNOWN;
4285 bool op1_indirect;
4286 zend_class_entry *op1_ce = NULL;
4287 zend_class_entry *op2_ce = NULL;
4288 bool gen_handler;
4289
4290 opline = p->opline;
4291 if (op1_type & (IS_TRACE_REFERENCE|IS_TRACE_INDIRECT)) {
4292 op1_type = IS_UNKNOWN;
4293 }
4294 if (op1_type != IS_UNKNOWN) {
4295 op1_type &= ~IS_TRACE_PACKED;
4296 }
4297 if (op2_type & (IS_TRACE_REFERENCE|IS_TRACE_INDIRECT)) {
4298 op2_type = IS_UNKNOWN;
4299 }
4300 if (op3_type & (IS_TRACE_REFERENCE|IS_TRACE_INDIRECT)) {
4301 op3_type = IS_UNKNOWN;
4302 }
4303
4304 if ((p+1)->op == ZEND_JIT_TRACE_OP1_TYPE) {
4305 op1_ce = (zend_class_entry*)(p+1)->ce;
4306 p++;
4307 }
4308 if ((p+1)->op == ZEND_JIT_TRACE_OP2_TYPE) {
4309 op2_ce = (zend_class_entry*)(p+1)->ce;
4310 p++;
4311 }
4312 if ((p+1)->op == ZEND_JIT_TRACE_VAL_INFO) {
4313 val_type = (p+1)->op1_type;
4314 p++;
4315 }
4316
4317 frame_flags = 0;
4318
4319 switch (opline->opcode) {
4320 case ZEND_INIT_FCALL:
4321 case ZEND_INIT_FCALL_BY_NAME:
4322 case ZEND_INIT_NS_FCALL_BY_NAME:
4323 case ZEND_INIT_METHOD_CALL:
4324 case ZEND_INIT_DYNAMIC_CALL:
4325 case ZEND_INIT_STATIC_METHOD_CALL:
4326 case ZEND_INIT_USER_CALL:
4327 case ZEND_NEW:
4328 frame->call_level++;
4329 }
4330
4331 if (JIT_G(opt_level) >= ZEND_JIT_LEVEL_INLINE) {
4332 gen_handler = 0;
4333 switch (opline->opcode) {
4334 case ZEND_PRE_INC:
4335 case ZEND_PRE_DEC:
4336 case ZEND_POST_INC:
4337 case ZEND_POST_DEC:
4338 if (opline->op1_type != IS_CV) {
4339 break;
4340 }
4341 op1_info = OP1_INFO();
4342 CHECK_OP1_TRACE_TYPE();
4343 if (!(op1_info & MAY_BE_LONG)) {
4344 break;
4345 }
4346 if (opline->result_type != IS_UNUSED) {
4347 res_use_info = zend_jit_trace_type_to_info(
4348 STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->result.var)))
4349 & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE);
4350 res_info = RES_INFO();
4351 res_addr = RES_REG_ADDR();
4352 } else {
4353 res_use_info = -1;
4354 res_info = -1;
4355 res_addr = 0;
4356 }
4357 op1_def_info = OP1_DEF_INFO();
4358 if (op1_def_info & MAY_BE_GUARD
4359 && !has_concrete_type(op1_def_info)) {
4360 op1_def_info &= ~MAY_BE_GUARD;
4361 }
4362 if (!zend_jit_inc_dec(&dasm_state, opline,
4363 op1_info, OP1_REG_ADDR(),
4364 op1_def_info, OP1_DEF_REG_ADDR(),
4365 res_use_info, res_info,
4366 res_addr,
4367 (op1_def_info & (MAY_BE_DOUBLE|MAY_BE_GUARD)) && zend_may_overflow(opline, ssa_op, op_array, ssa),
4368 zend_may_throw(opline, ssa_op, op_array, ssa))) {
4369 goto jit_failure;
4370 }
4371 if ((op1_def_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_LONG|MAY_BE_GUARD)
4372 && !(op1_info & MAY_BE_STRING)) {
4373 ssa->var_info[ssa_op->op1_def].type &= ~MAY_BE_GUARD;
4374 if (opline->result_type != IS_UNUSED) {
4375 ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
4376 }
4377 }
4378 if (opline->result_type != IS_UNUSED
4379 && (res_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_LONG|MAY_BE_GUARD)
4380 && !(op1_info & MAY_BE_STRING)) {
4381 ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
4382 }
4383 goto done;
4384 case ZEND_BW_OR:
4385 case ZEND_BW_AND:
4386 case ZEND_BW_XOR:
4387 case ZEND_SL:
4388 case ZEND_SR:
4389 case ZEND_MOD:
4390 op1_info = OP1_INFO();
4391 CHECK_OP1_TRACE_TYPE();
4392 op2_info = OP2_INFO();
4393 CHECK_OP2_TRACE_TYPE();
4394 if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
4395 break;
4396 }
4397 if (!(op1_info & MAY_BE_LONG)
4398 || !(op2_info & MAY_BE_LONG)) {
4399 break;
4400 }
4401 res_addr = RES_REG_ADDR();
4402 if (Z_MODE(res_addr) != IS_REG
4403 && zend_jit_trace_next_is_send_result(opline, p, frame)) {
4404 send_result = 1;
4405 res_use_info = -1;
4406 res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, (opline+1)->result.var);
4407 if (!zend_jit_reuse_ip(&dasm_state)) {
4408 goto jit_failure;
4409 }
4410 } else {
4411 res_use_info = zend_jit_trace_type_to_info(
4412 STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->result.var)))
4413 & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE);
4414 }
4415 res_info = RES_INFO();
4416 if (!zend_jit_long_math(&dasm_state, opline,
4417 op1_info, OP1_RANGE(), OP1_REG_ADDR(),
4418 op2_info, OP2_RANGE(), OP2_REG_ADDR(),
4419 res_use_info, res_info, res_addr,
4420 zend_may_throw(opline, ssa_op, op_array, ssa))) {
4421 goto jit_failure;
4422 }
4423 goto done;
4424 case ZEND_ADD:
4425 case ZEND_SUB:
4426 case ZEND_MUL:
4427 // case ZEND_DIV: // TODO: check for division by zero ???
4428 op1_info = OP1_INFO();
4429 op1_addr = OP1_REG_ADDR();
4430 op2_info = OP2_INFO();
4431 op2_addr = OP2_REG_ADDR();
4432 if (orig_op1_type != IS_UNKNOWN
4433 && (orig_op1_type & IS_TRACE_REFERENCE)
4434 && opline->op1_type == IS_CV
4435 && (Z_MODE(op2_addr) != IS_REG || Z_REG(op2_addr) != ZREG_FCARG1)
4436 && (orig_op2_type == IS_UNKNOWN || !(orig_op2_type & IS_TRACE_REFERENCE))) {
4437 if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr,
4438 !ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
4439 goto jit_failure;
4440 }
4441 if (ssa->vars[ssa_op->op1_use].alias == NO_ALIAS) {
4442 ssa->var_info[ssa_op->op1_use].guarded_reference = 1;
4443 }
4444 } else {
4445 CHECK_OP1_TRACE_TYPE();
4446 }
4447 if (orig_op2_type != IS_UNKNOWN
4448 && (orig_op2_type & IS_TRACE_REFERENCE)
4449 && opline->op2_type == IS_CV
4450 && (Z_MODE(op1_addr) != IS_REG || Z_REG(op1_addr) != ZREG_FCARG1)
4451 && (orig_op1_type == IS_UNKNOWN || !(orig_op1_type & IS_TRACE_REFERENCE))) {
4452 if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op2_type, &op2_info, &op2_addr,
4453 !ssa->var_info[ssa_op->op2_use].guarded_reference, 1)) {
4454 goto jit_failure;
4455 }
4456 if (ssa->vars[ssa_op->op2_use].alias == NO_ALIAS) {
4457 ssa->var_info[ssa_op->op2_use].guarded_reference = 1;
4458 }
4459 } else {
4460 CHECK_OP2_TRACE_TYPE();
4461 }
4462 if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
4463 break;
4464 }
4465 if (opline->opcode == ZEND_ADD &&
4466 (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY &&
4467 (op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) {
4468 /* pass */
4469 } else if (!(op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) ||
4470 !(op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
4471 break;
4472 }
4473 res_addr = RES_REG_ADDR();
4474 if (Z_MODE(res_addr) != IS_REG
4475 && zend_jit_trace_next_is_send_result(opline, p, frame)) {
4476 send_result = 1;
4477 res_use_info = -1;
4478 res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, (opline+1)->result.var);
4479 if (!zend_jit_reuse_ip(&dasm_state)) {
4480 goto jit_failure;
4481 }
4482 } else {
4483 res_use_info = zend_jit_trace_type_to_info(
4484 STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->result.var)))
4485 & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE);
4486 }
4487 res_info = RES_INFO();
4488 if (opline->opcode == ZEND_ADD &&
4489 (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY &&
4490 (op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) {
4491 if (!zend_jit_add_arrays(&dasm_state, opline, op1_info, op1_addr, op2_info, op2_addr, res_addr)) {
4492 goto jit_failure;
4493 }
4494 } else {
4495 if (!zend_jit_math(&dasm_state, opline,
4496 op1_info, op1_addr,
4497 op2_info, op2_addr,
4498 res_use_info, res_info, res_addr,
4499 (op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG) && (res_info & (MAY_BE_DOUBLE|MAY_BE_GUARD)) && zend_may_overflow(opline, ssa_op, op_array, ssa),
4500 zend_may_throw(opline, ssa_op, op_array, ssa))) {
4501 goto jit_failure;
4502 }
4503 if (((res_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_LONG|MAY_BE_GUARD)
4504 || (res_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_DOUBLE|MAY_BE_GUARD))
4505 && has_concrete_type(op1_info)
4506 && has_concrete_type(op2_info)) {
4507 ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
4508 }
4509 }
4510 goto done;
4511 case ZEND_CONCAT:
4512 case ZEND_FAST_CONCAT:
4513 op1_info = OP1_INFO();
4514 CHECK_OP1_TRACE_TYPE();
4515 op2_info = OP2_INFO();
4516 CHECK_OP2_TRACE_TYPE();
4517 if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
4518 break;
4519 }
4520 if (!(op1_info & MAY_BE_STRING) ||
4521 !(op2_info & MAY_BE_STRING)) {
4522 break;
4523 }
4524 res_addr = RES_REG_ADDR();
4525 if (zend_jit_trace_next_is_send_result(opline, p, frame)) {
4526 send_result = 1;
4527 res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, (opline+1)->result.var);
4528 if (!zend_jit_reuse_ip(&dasm_state)) {
4529 goto jit_failure;
4530 }
4531 }
4532 if (!zend_jit_concat(&dasm_state, opline,
4533 op1_info, op2_info, res_addr,
4534 zend_may_throw(opline, ssa_op, op_array, ssa))) {
4535 goto jit_failure;
4536 }
4537 goto done;
4538 case ZEND_ASSIGN_OP:
4539 if (opline->op1_type != IS_CV || opline->result_type != IS_UNUSED) {
4540 break;
4541 }
4542 op1_info = OP1_INFO();
4543 CHECK_OP1_TRACE_TYPE();
4544 op2_info = OP2_INFO();
4545 CHECK_OP2_TRACE_TYPE();
4546 if (!zend_jit_supported_binary_op(
4547 opline->extended_value, op1_info, op2_info)) {
4548 break;
4549 }
4550 op1_def_info = OP1_DEF_INFO();
4551 if (op1_def_info & MAY_BE_GUARD
4552 && !has_concrete_type(op1_def_info)) {
4553 op1_def_info &= ~MAY_BE_GUARD;
4554 }
4555 if (!zend_jit_assign_op(&dasm_state, opline,
4556 op1_info, op1_def_info, OP1_RANGE(),
4557 op2_info, OP2_RANGE(),
4558 (op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG) && (op1_def_info & (MAY_BE_DOUBLE|MAY_BE_GUARD)) && zend_may_overflow(opline, ssa_op, op_array, ssa),
4559 zend_may_throw(opline, ssa_op, op_array, ssa))) {
4560 goto jit_failure;
4561 }
4562 if ((op1_def_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_LONG|MAY_BE_GUARD)
4563 && has_concrete_type(op1_info)
4564 && has_concrete_type(op2_info)) {
4565 ssa->var_info[ssa_op->op1_def].type &= ~MAY_BE_GUARD;
4566 if (opline->result_type != IS_UNUSED) {
4567 ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
4568 }
4569 }
4570 goto done;
4571 case ZEND_ASSIGN_DIM_OP:
4572 if (opline->result_type != IS_UNUSED) {
4573 break;
4574 }
4575 if (!zend_jit_supported_binary_op(
4576 opline->extended_value, MAY_BE_ANY, OP1_DATA_INFO())) {
4577 break;
4578 }
4579 if (opline->op1_type == IS_CV
4580 && (opline+1)->op1_type == IS_CV
4581 && (opline+1)->op1.var == opline->op1.var) {
4582 /* skip $a[x] += $a; */
4583 break;
4584 }
4585 op1_info = OP1_INFO();
4586 op1_addr = OP1_REG_ADDR();
4587 if (opline->op1_type == IS_VAR) {
4588 if (orig_op1_type != IS_UNKNOWN
4589 && (orig_op1_type & IS_TRACE_INDIRECT)) {
4590 if (!zend_jit_fetch_indirect_var(&dasm_state, opline, orig_op1_type,
4591 &op1_info, &op1_addr, !ssa->var_info[ssa_op->op1_use].indirect_reference)) {
4592 goto jit_failure;
4593 }
4594 } else {
4595 break;
4596 }
4597 }
4598 if (orig_op1_type != IS_UNKNOWN
4599 && (orig_op1_type & IS_TRACE_REFERENCE)) {
4600 if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr,
4601 !ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
4602 goto jit_failure;
4603 }
4604 if (opline->op1_type == IS_CV
4605 && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) {
4606 ssa->var_info[ssa_op->op1_def].guarded_reference = 1;
4607 }
4608 } else {
4609 CHECK_OP1_TRACE_TYPE();
4610 }
4611 op2_info = OP2_INFO();
4612 CHECK_OP2_TRACE_TYPE();
4613 op1_data_info = OP1_DATA_INFO();
4614 CHECK_OP1_DATA_TRACE_TYPE();
4615 op1_def_info = OP1_DEF_INFO();
4616 if (!zend_jit_assign_dim_op(&dasm_state, opline,
4617 op1_info, op1_def_info, op1_addr, op2_info,
4618 op1_data_info, OP1_DATA_RANGE(), val_type,
4619 zend_may_throw_ex(opline, ssa_op, op_array, ssa, op1_info, op2_info))) {
4620 goto jit_failure;
4621 }
4622 goto done;
4623 case ZEND_PRE_INC_OBJ:
4624 case ZEND_PRE_DEC_OBJ:
4625 case ZEND_POST_INC_OBJ:
4626 case ZEND_POST_DEC_OBJ:
4627 if (opline->op2_type != IS_CONST
4628 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
4629 || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
4630 break;
4631 }
4632 ce = NULL;
4633 ce_is_instanceof = 0;
4634 on_this = delayed_fetch_this = 0;
4635 op1_indirect = 0;
4636 if (opline->op1_type == IS_UNUSED) {
4637 op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
4638 ce = op_array->scope;
4639 ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
4640 op1_addr = 0;
4641 on_this = 1;
4642 } else {
4643 if (ssa_op->op1_use >= 0) {
4644 delayed_fetch_this = ssa->var_info[ssa_op->op1_use].delayed_fetch_this;
4645 }
4646 op1_info = OP1_INFO();
4647 if (!(op1_info & MAY_BE_OBJECT)) {
4648 break;
4649 }
4650 op1_addr = OP1_REG_ADDR();
4651 if (opline->op1_type == IS_VAR) {
4652 if (orig_op1_type != IS_UNKNOWN
4653 && (orig_op1_type & IS_TRACE_INDIRECT)) {
4654 op1_indirect = 1;
4655 if (!zend_jit_fetch_indirect_var(&dasm_state, opline, orig_op1_type,
4656 &op1_info, &op1_addr, !ssa->var_info[ssa_op->op1_use].indirect_reference)) {
4657 goto jit_failure;
4658 }
4659 }
4660 }
4661 if (orig_op1_type != IS_UNKNOWN
4662 && (orig_op1_type & IS_TRACE_REFERENCE)) {
4663 if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr,
4664 !ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
4665 goto jit_failure;
4666 }
4667 if (opline->op1_type == IS_CV
4668 && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) {
4669 ssa->var_info[ssa_op->op1_def].guarded_reference = 1;
4670 }
4671 } else {
4672 CHECK_OP1_TRACE_TYPE();
4673 }
4674 if (!(op1_info & MAY_BE_OBJECT)) {
4675 break;
4676 }
4677 if (ssa->var_info && ssa->ops) {
4678 if (ssa_op->op1_use >= 0) {
4679 zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
4680 if (op1_ssa->ce && !op1_ssa->ce->create_object) {
4681 ce = op1_ssa->ce;
4682 ce_is_instanceof = op1_ssa->is_instanceof;
4683 }
4684 }
4685 }
4686 if (delayed_fetch_this) {
4687 on_this = 1;
4688 } else if (ssa_op->op1_use >= 0 && ssa->vars[ssa_op->op1_use].definition >= 0) {
4689 on_this = ssa_opcodes[ssa->vars[ssa_op->op1_use].definition]->opcode == ZEND_FETCH_THIS;
4690 } else if (op_array_ssa->ops
4691 && op_array_ssa->vars
4692 && op_array_ssa->ops[opline-op_array->opcodes].op1_use >= 0
4693 && op_array_ssa->vars[op_array_ssa->ops[opline-op_array->opcodes].op1_use].definition >= 0) {
4694 on_this = op_array->opcodes[op_array_ssa->vars[op_array_ssa->ops[opline-op_array->opcodes].op1_use].definition].opcode == ZEND_FETCH_THIS;
4695 }
4696 }
4697 if (!zend_jit_incdec_obj(&dasm_state, opline, op_array, ssa, ssa_op,
4698 op1_info, op1_addr,
4699 op1_indirect, ce, ce_is_instanceof, on_this, delayed_fetch_this, op1_ce,
4700 val_type)) {
4701 goto jit_failure;
4702 }
4703 goto done;
4704 case ZEND_ASSIGN_OBJ_OP:
4705 if (opline->result_type != IS_UNUSED) {
4706 break;
4707 }
4708 if (opline->op2_type != IS_CONST
4709 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
4710 || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
4711 break;
4712 }
4713 if (opline->op1_type == IS_CV
4714 && (opline+1)->op1_type == IS_CV
4715 && (opline+1)->op1.var == opline->op1.var) {
4716 /* skip $a->prop += $a; */
4717 break;
4718 }
4719 if (!zend_jit_supported_binary_op(
4720 opline->extended_value, MAY_BE_ANY, OP1_DATA_INFO())) {
4721 break;
4722 }
4723 ce = NULL;
4724 ce_is_instanceof = 0;
4725 on_this = delayed_fetch_this = 0;
4726 op1_indirect = 0;
4727 if (opline->op1_type == IS_UNUSED) {
4728 op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
4729 ce = op_array->scope;
4730 ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
4731 op1_addr = 0;
4732 on_this = 1;
4733 } else {
4734 if (ssa_op->op1_use >= 0) {
4735 delayed_fetch_this = ssa->var_info[ssa_op->op1_use].delayed_fetch_this;
4736 }
4737 op1_info = OP1_INFO();
4738 if (!(op1_info & MAY_BE_OBJECT)) {
4739 break;
4740 }
4741 op1_addr = OP1_REG_ADDR();
4742 if (opline->op1_type == IS_VAR) {
4743 if (orig_op1_type != IS_UNKNOWN
4744 && (orig_op1_type & IS_TRACE_INDIRECT)) {
4745 op1_indirect = 1;
4746 if (!zend_jit_fetch_indirect_var(&dasm_state, opline, orig_op1_type,
4747 &op1_info, &op1_addr, !ssa->var_info[ssa_op->op1_use].indirect_reference)) {
4748 goto jit_failure;
4749 }
4750 }
4751 }
4752 if (orig_op1_type != IS_UNKNOWN
4753 && (orig_op1_type & IS_TRACE_REFERENCE)) {
4754 if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr,
4755 !ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
4756 goto jit_failure;
4757 }
4758 if (opline->op1_type == IS_CV
4759 && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) {
4760 ssa->var_info[ssa_op->op1_def].guarded_reference = 1;
4761 }
4762 } else {
4763 CHECK_OP1_TRACE_TYPE();
4764 }
4765 if (!(op1_info & MAY_BE_OBJECT)) {
4766 break;
4767 }
4768 if (ssa->var_info && ssa->ops) {
4769 if (ssa_op->op1_use >= 0) {
4770 zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
4771 if (op1_ssa->ce && !op1_ssa->ce->create_object) {
4772 ce = op1_ssa->ce;
4773 ce_is_instanceof = op1_ssa->is_instanceof;
4774 }
4775 }
4776 }
4777 if (delayed_fetch_this) {
4778 on_this = 1;
4779 } else if (ssa_op->op1_use >= 0 && ssa->vars[ssa_op->op1_use].definition >= 0) {
4780 on_this = ssa_opcodes[ssa->vars[ssa_op->op1_use].definition]->opcode == ZEND_FETCH_THIS;
4781 } else if (op_array_ssa->ops
4782 && op_array_ssa->vars
4783 && op_array_ssa->ops[opline-op_array->opcodes].op1_use >= 0
4784 && op_array_ssa->vars[op_array_ssa->ops[opline-op_array->opcodes].op1_use].definition >= 0) {
4785 on_this = op_array->opcodes[op_array_ssa->vars[op_array_ssa->ops[opline-op_array->opcodes].op1_use].definition].opcode == ZEND_FETCH_THIS;
4786 }
4787 }
4788 op1_data_info = OP1_DATA_INFO();
4789 CHECK_OP1_DATA_TRACE_TYPE();
4790 if (!zend_jit_assign_obj_op(&dasm_state, opline, op_array, ssa, ssa_op,
4791 op1_info, op1_addr, op1_data_info, OP1_DATA_RANGE(),
4792 op1_indirect, ce, ce_is_instanceof, on_this, delayed_fetch_this, op1_ce,
4793 val_type)) {
4794 goto jit_failure;
4795 }
4796 goto done;
4797 case ZEND_ASSIGN_OBJ:
4798 if (opline->op2_type != IS_CONST
4799 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
4800 || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
4801 break;
4802 }
4803 ce = NULL;
4804 ce_is_instanceof = 0;
4805 on_this = delayed_fetch_this = 0;
4806 op1_indirect = 0;
4807 if (opline->op1_type == IS_UNUSED) {
4808 op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
4809 ce = op_array->scope;
4810 ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
4811 op1_addr = 0;
4812 on_this = 1;
4813 } else {
4814 if (ssa_op->op1_use >= 0) {
4815 delayed_fetch_this = ssa->var_info[ssa_op->op1_use].delayed_fetch_this;
4816 }
4817 op1_info = OP1_INFO();
4818 if (!(op1_info & MAY_BE_OBJECT)) {
4819 break;
4820 }
4821 op1_addr = OP1_REG_ADDR();
4822 if (opline->op1_type == IS_VAR) {
4823 if (orig_op1_type != IS_UNKNOWN
4824 && (orig_op1_type & IS_TRACE_INDIRECT)) {
4825 op1_indirect = 1;
4826 if (!zend_jit_fetch_indirect_var(&dasm_state, opline, orig_op1_type,
4827 &op1_info, &op1_addr, !ssa->var_info[ssa_op->op1_use].indirect_reference)) {
4828 goto jit_failure;
4829 }
4830 }
4831 }
4832 if (orig_op1_type != IS_UNKNOWN
4833 && (orig_op1_type & IS_TRACE_REFERENCE)) {
4834 if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr,
4835 !ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
4836 goto jit_failure;
4837 }
4838 if (opline->op1_type == IS_CV
4839 && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) {
4840 ssa->var_info[ssa_op->op1_def].guarded_reference = 1;
4841 }
4842 } else {
4843 CHECK_OP1_TRACE_TYPE();
4844 }
4845 if (!(op1_info & MAY_BE_OBJECT)) {
4846 break;
4847 }
4848 if (ssa->var_info && ssa->ops) {
4849 if (ssa_op->op1_use >= 0) {
4850 zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
4851 if (op1_ssa->ce && !op1_ssa->ce->create_object) {
4852 ce = op1_ssa->ce;
4853 ce_is_instanceof = op1_ssa->is_instanceof;
4854 }
4855 }
4856 }
4857 if (delayed_fetch_this) {
4858 on_this = 1;
4859 } else if (ssa_op->op1_use >= 0 && ssa->vars[ssa_op->op1_use].definition >= 0) {
4860 on_this = ssa_opcodes[ssa->vars[ssa_op->op1_use].definition]->opcode == ZEND_FETCH_THIS;
4861 } else if (op_array_ssa->ops
4862 && op_array_ssa->vars
4863 && op_array_ssa->ops[opline-op_array->opcodes].op1_use >= 0
4864 && op_array_ssa->vars[op_array_ssa->ops[opline-op_array->opcodes].op1_use].definition >= 0) {
4865 on_this = op_array->opcodes[op_array_ssa->vars[op_array_ssa->ops[opline-op_array->opcodes].op1_use].definition].opcode == ZEND_FETCH_THIS;
4866 }
4867 }
4868 op1_data_info = OP1_DATA_INFO();
4869 CHECK_OP1_DATA_TRACE_TYPE();
4870 if (!zend_jit_assign_obj(&dasm_state, opline, op_array, ssa, ssa_op,
4871 op1_info, op1_addr, op1_data_info,
4872 op1_indirect, ce, ce_is_instanceof, on_this, delayed_fetch_this, op1_ce,
4873 val_type,
4874 zend_may_throw(opline, ssa_op, op_array, ssa))) {
4875 goto jit_failure;
4876 }
4877 if ((opline+1)->op1_type == IS_CV
4878 && (ssa_op+1)->op1_def >= 0
4879 && ssa->vars[(ssa_op+1)->op1_def].alias == NO_ALIAS) {
4880 ssa->var_info[(ssa_op+1)->op1_def].guarded_reference = ssa->var_info[(ssa_op+1)->op1_use].guarded_reference;
4881 }
4882 goto done;
4883 case ZEND_ASSIGN_DIM:
4884 op1_info = OP1_INFO();
4885 op1_addr = OP1_REG_ADDR();
4886 if (opline->op1_type == IS_CV
4887 && (opline+1)->op1_type == IS_CV
4888 && (opline+1)->op1.var == opline->op1.var) {
4889 /* skip $a[x] = $a; */
4890 break;
4891 }
4892 if (opline->op1_type == IS_VAR) {
4893 if (orig_op1_type != IS_UNKNOWN
4894 && (orig_op1_type & IS_TRACE_INDIRECT)
4895 && opline->result_type == IS_UNUSED) {
4896 if (!zend_jit_fetch_indirect_var(&dasm_state, opline, orig_op1_type,
4897 &op1_info, &op1_addr, !ssa->var_info[ssa_op->op1_use].indirect_reference)) {
4898 goto jit_failure;
4899 }
4900 } else {
4901 break;
4902 }
4903 }
4904 if (orig_op1_type != IS_UNKNOWN
4905 && (orig_op1_type & IS_TRACE_REFERENCE)) {
4906 if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr,
4907 !ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
4908 goto jit_failure;
4909 }
4910 if (opline->op1_type == IS_CV
4911 && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) {
4912 ssa->var_info[ssa_op->op1_def].guarded_reference = 1;
4913 }
4914 } else {
4915 CHECK_OP1_TRACE_TYPE();
4916 }
4917 op2_info = OP2_INFO();
4918 CHECK_OP2_TRACE_TYPE();
4919 op1_data_info = OP1_DATA_INFO();
4920 CHECK_OP1_DATA_TRACE_TYPE();
4921 if (!zend_jit_assign_dim(&dasm_state, opline,
4922 op1_info, op1_addr, op2_info, op1_data_info, val_type,
4923 zend_may_throw_ex(opline, ssa_op, op_array, ssa, op1_info, op2_info))) {
4924 goto jit_failure;
4925 }
4926 if ((opline+1)->op1_type == IS_CV
4927 && (ssa_op+1)->op1_def >= 0
4928 && ssa->vars[(ssa_op+1)->op1_def].alias == NO_ALIAS) {
4929 ssa->var_info[(ssa_op+1)->op1_def].guarded_reference = ssa->var_info[(ssa_op+1)->op1_use].guarded_reference;
4930 }
4931 goto done;
4932 case ZEND_ASSIGN:
4933 if (opline->op1_type != IS_CV) {
4934 break;
4935 }
4936 op2_addr = OP2_REG_ADDR();
4937 op2_info = OP2_INFO();
4938
4939 if (ssa_op->op2_def < 0 || (Z_MODE(op2_addr) == IS_REG && ssa->vars[ssa_op->op2_def].no_val)) {
4940 op2_def_addr = op2_addr;
4941 } else {
4942 op2_def_addr = OP2_DEF_REG_ADDR();
4943 }
4944 CHECK_OP2_TRACE_TYPE();
4945 op1_info = OP1_INFO();
4946 op1_def_info = OP1_DEF_INFO();
4947 if (op1_type != IS_UNKNOWN && (op1_info & MAY_BE_GUARD)) {
4948 if (op1_type < IS_STRING
4949 && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) != (op1_def_info & (MAY_BE_ANY|MAY_BE_UNDEF))) {
4950 if (!zend_jit_scalar_type_guard(&dasm_state, opline, opline->op1.var)) {
4951 goto jit_failure;
4952 }
4953 op1_info &= ~(MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF|MAY_BE_GUARD);
4954 } else {
4955 CHECK_OP1_TRACE_TYPE();
4956 }
4957 }
4958 op1_addr = OP1_REG_ADDR();
4959 op1_def_addr = OP1_DEF_REG_ADDR();
4960 if (Z_MODE(op1_def_addr) != IS_REG &&
4961 STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var)) !=
4962 STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var))) {
4963 /* type may be not set */
4964 op1_info |= MAY_BE_NULL;
4965 }
4966 if (orig_op1_type != IS_UNKNOWN) {
4967 if (orig_op1_type & IS_TRACE_REFERENCE) {
4968 if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr,
4969 !ssa->var_info[ssa_op->op1_use].guarded_reference, 0)) {
4970 goto jit_failure;
4971 }
4972 if (opline->op1_type == IS_CV
4973 && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) {
4974 ssa->var_info[ssa_op->op1_def].guarded_reference = 1;
4975 }
4976 if (opline->result_type == IS_UNUSED) {
4977 res_addr = 0;
4978 } else {
4979 res_addr = RES_REG_ADDR();
4980 if (Z_MODE(res_addr) != IS_REG
4981 && zend_jit_trace_next_is_send_result(opline, p, frame)) {
4982 send_result = 1;
4983 res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, (opline+1)->result.var);
4984 if (!zend_jit_reuse_ip(&dasm_state)) {
4985 goto jit_failure;
4986 }
4987 }
4988 }
4989 if (!zend_jit_assign_to_typed_ref(&dasm_state, opline, opline->op2_type, op2_addr, res_addr, 1)) {
4990 goto jit_failure;
4991 }
4992 op1_def_addr = op1_addr;
4993 op1_def_info &= ~MAY_BE_REF;
4994 } else if (op1_info & MAY_BE_REF) {
4995 if (!zend_jit_noref_guard(&dasm_state, opline, op1_addr)) {
4996 goto jit_failure;
4997 }
4998 op1_info &= ~MAY_BE_REF;
4999 op1_def_info &= ~MAY_BE_REF;
5000 }
5001 }
5002 if (opline->result_type == IS_UNUSED) {
5003 res_addr = 0;
5004 res_info = -1;
5005 } else {
5006 res_addr = RES_REG_ADDR();
5007 res_info = RES_INFO();
5008 if (Z_MODE(res_addr) != IS_REG
5009 && zend_jit_trace_next_is_send_result(opline, p, frame)) {
5010 send_result = 1;
5011 res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, (opline+1)->result.var);
5012 if (!zend_jit_reuse_ip(&dasm_state)) {
5013 goto jit_failure;
5014 }
5015 }
5016 }
5017 if (!zend_jit_assign(&dasm_state, opline,
5018 op1_info, op1_addr,
5019 op1_def_info, op1_def_addr,
5020 op2_info, op2_addr, op2_def_addr,
5021 res_info, res_addr,
5022 zend_may_throw_ex(opline, ssa_op, op_array, ssa, op1_info, op2_info))) {
5023 goto jit_failure;
5024 }
5025 if (ssa_op->op2_def > 0
5026 && Z_MODE(op2_addr) == IS_REG
5027 && ssa->vars[ssa_op->op2_def].no_val) {
5028 uint8_t type = (op2_info & MAY_BE_LONG) ? IS_LONG : IS_DOUBLE;
5029 uint32_t var_num = EX_VAR_TO_NUM(opline->op2.var);
5030
5031 if (STACK_MEM_TYPE(stack, var_num) != type
5032 && ssa->vars[ssa_op->op2_def].use_chain < 0
5033 && !ssa->vars[ssa_op->op2_def].phi_use_chain) {
5034 if (!zend_jit_store_var_type(&dasm_state, var_num, type)) {
5035 return 0;
5036 }
5037 SET_STACK_TYPE(stack, var_num, type, 1);
5038 }
5039 }
5040 if (opline->op2_type == IS_CV
5041 && ssa_op->op2_def >= 0
5042 && ssa->vars[ssa_op->op2_def].alias == NO_ALIAS) {
5043 ssa->var_info[ssa_op->op2_def].guarded_reference = ssa->var_info[ssa_op->op2_use].guarded_reference;
5044 }
5045 goto done;
5046 case ZEND_CAST:
5047 if (opline->extended_value != op1_type) {
5048 break;
5049 }
5050 ZEND_FALLTHROUGH;
5051 case ZEND_QM_ASSIGN:
5052 op1_addr = OP1_REG_ADDR();
5053 if (ssa_op->op1_def < 0 || (Z_MODE(op1_addr) == IS_REG && ssa->vars[ssa_op->op1_def].no_val)) {
5054 op1_def_addr = op1_addr;
5055 } else {
5056 op1_def_addr = OP1_DEF_REG_ADDR();
5057 }
5058 op1_info = OP1_INFO();
5059 CHECK_OP1_TRACE_TYPE();
5060 res_info = RES_INFO();
5061 res_use_info = zend_jit_trace_type_to_info(
5062 STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->result.var)))
5063 & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE);
5064 res_addr = RES_REG_ADDR();
5065 if (Z_MODE(res_addr) != IS_REG &&
5066 STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var)) !=
5067 STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->result.var))) {
5068 /* type may be not set */
5069 res_use_info |= MAY_BE_NULL;
5070 }
5071 if (!zend_jit_qm_assign(&dasm_state, opline,
5072 op1_info, op1_addr, op1_def_addr,
5073 res_use_info, res_info, res_addr)) {
5074 goto jit_failure;
5075 }
5076 if (ssa_op->op1_def > 0
5077 && Z_MODE(op1_addr) == IS_REG
5078 && ssa->vars[ssa_op->op1_def].no_val) {
5079 uint8_t type = (op1_info & MAY_BE_LONG) ? IS_LONG : IS_DOUBLE;
5080 uint32_t var_num = EX_VAR_TO_NUM(opline->op1.var);
5081
5082 if (STACK_MEM_TYPE(stack, var_num) != type
5083 && ssa->vars[ssa_op->op1_def].use_chain < 0
5084 && !ssa->vars[ssa_op->op1_def].phi_use_chain) {
5085 if (!zend_jit_store_var_type(&dasm_state, var_num, type)) {
5086 return 0;
5087 }
5088 SET_STACK_TYPE(stack, var_num, type, 1);
5089 }
5090 }
5091 if (opline->op1_type == IS_CV
5092 && ssa_op->op1_def >= 0
5093 && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) {
5094 ssa->var_info[ssa_op->op1_def].guarded_reference = ssa->var_info[ssa_op->op1_use].guarded_reference;
5095 }
5096 goto done;
5097 case ZEND_INIT_FCALL:
5098 case ZEND_INIT_FCALL_BY_NAME:
5099 case ZEND_INIT_NS_FCALL_BY_NAME:
5100 frame_flags = TRACE_FRAME_MASK_NESTED;
5101 if (!zend_jit_init_fcall(&dasm_state, opline, op_array_ssa->cfg.map ? op_array_ssa->cfg.map[opline - op_array->opcodes] : -1, op_array, ssa, ssa_op, frame->call_level, p + 1, peek_checked_stack - checked_stack)) {
5102 goto jit_failure;
5103 }
5104 goto done;
5105 case ZEND_SEND_VAL:
5106 case ZEND_SEND_VAL_EX:
5107 if (opline->op2_type == IS_CONST) {
5108 /* Named parameters not supported in JIT */
5109 break;
5110 }
5111 if (opline->opcode == ZEND_SEND_VAL_EX
5112 && opline->op2.num > MAX_ARG_FLAG_NUM) {
5113 break;
5114 }
5115 op1_info = OP1_INFO();
5116 CHECK_OP1_TRACE_TYPE();
5117 if (!zend_jit_send_val(&dasm_state, opline,
5118 op1_info, OP1_REG_ADDR())) {
5119 goto jit_failure;
5120 }
5121 if (frame->call && frame->call->func) {
5122 if (opline->op1_type == IS_CONST) {
5123 zend_jit_trace_send_type(opline, frame->call, Z_TYPE_P(RT_CONSTANT(opline, opline->op1)));
5124 } else if (op1_type != IS_UNKNOWN) {
5125 if (op1_type == IS_UNDEF) {
5126 op1_type = IS_NULL;
5127 }
5128 zend_jit_trace_send_type(opline, frame->call, op1_type);
5129 }
5130 }
5131 goto done;
5132 case ZEND_SEND_REF:
5133 if (opline->op2_type == IS_CONST) {
5134 /* Named parameters not supported in JIT */
5135 break;
5136 }
5137 op1_info = OP1_INFO();
5138 if (!zend_jit_send_ref(&dasm_state, opline, op_array,
5139 op1_info, 0)) {
5140 goto jit_failure;
5141 }
5142 if (opline->op1_type == IS_CV
5143 && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) {
5144 ssa->var_info[ssa_op->op1_def].guarded_reference = 1;
5145 }
5146 goto done;
5147 case ZEND_SEND_VAR:
5148 case ZEND_SEND_VAR_EX:
5149 case ZEND_SEND_VAR_NO_REF:
5150 case ZEND_SEND_VAR_NO_REF_EX:
5151 case ZEND_SEND_FUNC_ARG:
5152 if (opline->op2_type == IS_CONST) {
5153 /* Named parameters not supported in JIT */
5154 break;
5155 }
5156 if ((opline->opcode == ZEND_SEND_VAR_EX
5157 || opline->opcode == ZEND_SEND_VAR_NO_REF_EX)
5158 && opline->op2.num > MAX_ARG_FLAG_NUM) {
5159 break;
5160 }
5161 op1_addr = OP1_REG_ADDR();
5162 if (ssa_op->op1_def < 0 || (Z_MODE(op1_addr) == IS_REG && ssa->vars[ssa_op->op1_def].no_val)) {
5163 op1_def_addr = op1_addr;
5164 } else {
5165 op1_def_addr = OP1_DEF_REG_ADDR();
5166 }
5167 op1_info = OP1_INFO();
5168 CHECK_OP1_TRACE_TYPE();
5169 if (!zend_jit_send_var(&dasm_state, opline, op_array,
5170 op1_info, op1_addr, op1_def_addr)) {
5171 goto jit_failure;
5172 }
5173 if (ssa_op->op1_def > 0
5174 && Z_MODE(op1_addr) == IS_REG
5175 && ssa->vars[ssa_op->op1_def].no_val) {
5176 uint8_t type = (op1_info & MAY_BE_LONG) ? IS_LONG : IS_DOUBLE;
5177 uint32_t var_num = EX_VAR_TO_NUM(opline->op1.var);
5178
5179 if (STACK_MEM_TYPE(stack, var_num) != type
5180 && ssa->vars[ssa_op->op1_def].use_chain < 0
5181 && !ssa->vars[ssa_op->op1_def].phi_use_chain) {
5182 if (!zend_jit_store_var_type(&dasm_state, var_num, type)) {
5183 return 0;
5184 }
5185 SET_STACK_TYPE(stack, var_num, type, 1);
5186 }
5187 }
5188 if (opline->op1_type == IS_CV
5189 && ssa_op->op1_def >= 0
5190 && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) {
5191 ssa->var_info[ssa_op->op1_def].guarded_reference = ssa->var_info[ssa_op->op1_use].guarded_reference;
5192 }
5193 if (frame->call && frame->call->func) {
5194 if ((opline->opcode == ZEND_SEND_VAR_EX
5195 || opline->opcode == ZEND_SEND_FUNC_ARG)
5196 && ARG_SHOULD_BE_SENT_BY_REF(frame->call->func, opline->op2.num)) {
5197 goto done;
5198 }
5199 if (op1_type != IS_UNKNOWN) {
5200 if (op1_type == IS_UNDEF) {
5201 op1_type = IS_NULL;
5202 }
5203 zend_jit_trace_send_type(opline, frame->call, op1_type);
5204 }
5205 }
5206 goto done;
5207 case ZEND_CHECK_FUNC_ARG:
5208 if (!JIT_G(current_frame)
5209 || !JIT_G(current_frame)->call
5210 || !JIT_G(current_frame)->call->func) {
5211 break;
5212 }
5213 if (opline->op2_type == IS_CONST
5214 || opline->op2.num > MAX_ARG_FLAG_NUM) {
5215 /* Named parameters not supported in JIT */
5216 TRACE_FRAME_SET_LAST_SEND_UNKNOWN(JIT_G(current_frame)->call);
5217 break;
5218 }
5219 if (!zend_jit_check_func_arg(&dasm_state, opline)) {
5220 goto jit_failure;
5221 }
5222 goto done;
5223 case ZEND_CHECK_UNDEF_ARGS:
5224 if (JIT_G(current_frame)
5225 && JIT_G(current_frame)->call) {
5226 TRACE_FRAME_SET_UNKNOWN_NUM_ARGS(JIT_G(current_frame)->call);
5227 }
5228 if (!zend_jit_check_undef_args(&dasm_state, opline)) {
5229 goto jit_failure;
5230 }
5231 goto done;
5232 case ZEND_DO_UCALL:
5233 case ZEND_DO_ICALL:
5234 case ZEND_DO_FCALL_BY_NAME:
5235 case ZEND_DO_FCALL:
5236 if (!zend_jit_do_fcall(&dasm_state, opline, op_array, op_array_ssa, frame->call_level, -1, p + 1)) {
5237 goto jit_failure;
5238 }
5239 goto done;
5240 case ZEND_IS_EQUAL:
5241 case ZEND_IS_NOT_EQUAL:
5242 case ZEND_IS_SMALLER:
5243 case ZEND_IS_SMALLER_OR_EQUAL:
5244 case ZEND_CASE:
5245 op1_info = OP1_INFO();
5246 op2_info = OP2_INFO();
5247 skip_comparison =
5248 ssa_op != ssa->ops &&
5249 (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) == MAY_BE_LONG &&
5250 (op2_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) == MAY_BE_LONG &&
5251 zend_jit_may_skip_comparison(opline, ssa_op, ssa, ssa_opcodes, op_array);
5252 CHECK_OP1_TRACE_TYPE();
5253 CHECK_OP2_TRACE_TYPE();
5254 if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
5255 bool exit_if_true = 0;
5256 const zend_op *exit_opline = zend_jit_trace_get_exit_opline(p + 1, opline + 1, &exit_if_true);
5257 uint32_t exit_point;
5258
5259 if (ra) {
5260 zend_jit_trace_clenup_stack(stack, opline, ssa_op, ssa, ra);
5261 }
5262 exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5263 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5264 if (!exit_addr) {
5265 goto jit_failure;
5266 }
5267 smart_branch_opcode = exit_if_true ? ZEND_JMPNZ : ZEND_JMPZ;
5268 if (!zend_jit_cmp(&dasm_state, opline,
5269 op1_info, OP1_RANGE(), OP1_REG_ADDR(),
5270 op2_info, OP2_RANGE(), OP2_REG_ADDR(),
5271 RES_REG_ADDR(),
5272 zend_may_throw(opline, ssa_op, op_array, ssa),
5273 smart_branch_opcode, -1, -1, exit_addr, skip_comparison)) {
5274 goto jit_failure;
5275 }
5276 zend_jit_trace_update_condition_ranges(opline, ssa_op, op_array, ssa, exit_if_true);
5277 } else {
5278 smart_branch_opcode = 0;
5279 exit_addr = NULL;
5280 if (!zend_jit_cmp(&dasm_state, opline,
5281 op1_info, OP1_RANGE(), OP1_REG_ADDR(),
5282 op2_info, OP2_RANGE(), OP2_REG_ADDR(),
5283 RES_REG_ADDR(),
5284 zend_may_throw(opline, ssa_op, op_array, ssa),
5285 smart_branch_opcode, -1, -1, exit_addr, skip_comparison)) {
5286 goto jit_failure;
5287 }
5288 }
5289 goto done;
5290 case ZEND_IS_IDENTICAL:
5291 case ZEND_IS_NOT_IDENTICAL:
5292 case ZEND_CASE_STRICT:
5293 op1_info = OP1_INFO();
5294 op2_info = OP2_INFO();
5295 skip_comparison =
5296 ssa_op != ssa->ops &&
5297 (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) == MAY_BE_LONG &&
5298 (op2_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) == MAY_BE_LONG &&
5299 zend_jit_may_skip_comparison(opline, ssa_op, ssa, ssa_opcodes, op_array);
5300 CHECK_OP1_TRACE_TYPE();
5301 CHECK_OP2_TRACE_TYPE();
5302 if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
5303 bool exit_if_true = 0;
5304 const zend_op *exit_opline = zend_jit_trace_get_exit_opline(p + 1, opline + 1, &exit_if_true);
5305 uint32_t exit_point;
5306
5307 if (ra) {
5308 zend_jit_trace_clenup_stack(stack, opline, ssa_op, ssa, ra);
5309 }
5310 exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5311 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5312 if (!exit_addr) {
5313 goto jit_failure;
5314 }
5315 if (opline->opcode == ZEND_IS_NOT_IDENTICAL) {
5316 exit_if_true = !exit_if_true;
5317 }
5318 smart_branch_opcode = exit_if_true ? ZEND_JMPNZ : ZEND_JMPZ;
5319 if (!zend_jit_identical(&dasm_state, opline,
5320 op1_info, OP1_RANGE(), OP1_REG_ADDR(),
5321 op2_info, OP2_RANGE(), OP2_REG_ADDR(),
5322 RES_REG_ADDR(),
5323 zend_may_throw(opline, ssa_op, op_array, ssa),
5324 smart_branch_opcode, -1, -1, exit_addr, skip_comparison)) {
5325 goto jit_failure;
5326 }
5327 zend_jit_trace_update_condition_ranges(opline, ssa_op, op_array, ssa, exit_if_true);
5328 } else {
5329 smart_branch_opcode = 0;
5330 exit_addr = NULL;
5331 if (!zend_jit_identical(&dasm_state, opline,
5332 op1_info, OP1_RANGE(), OP1_REG_ADDR(),
5333 op2_info, OP2_RANGE(), OP2_REG_ADDR(),
5334 RES_REG_ADDR(),
5335 zend_may_throw(opline, ssa_op, op_array, ssa),
5336 smart_branch_opcode, -1, -1, exit_addr, skip_comparison)) {
5337 goto jit_failure;
5338 }
5339 }
5340 goto done;
5341 case ZEND_DEFINED:
5342 if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
5343 bool exit_if_true = 0;
5344 const zend_op *exit_opline = zend_jit_trace_get_exit_opline(p + 1, opline + 1, &exit_if_true);
5345 uint32_t exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5346
5347 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5348 if (!exit_addr) {
5349 goto jit_failure;
5350 }
5351 smart_branch_opcode = exit_if_true ? ZEND_JMPNZ : ZEND_JMPZ;
5352 } else {
5353 smart_branch_opcode = 0;
5354 exit_addr = NULL;
5355 }
5356 if (!zend_jit_defined(&dasm_state, opline, smart_branch_opcode, -1, -1, exit_addr)) {
5357 goto jit_failure;
5358 }
5359 goto done;
5360 case ZEND_TYPE_CHECK:
5361 if (opline->extended_value == MAY_BE_RESOURCE) {
5362 // TODO: support for is_resource() ???
5363 break;
5364 }
5365 op1_info = OP1_INFO();
5366 CHECK_OP1_TRACE_TYPE();
5367 if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
5368 bool exit_if_true = 0;
5369 const zend_op *exit_opline = zend_jit_trace_get_exit_opline(p + 1, opline + 1, &exit_if_true);
5370 uint32_t exit_point;
5371
5372 if (ra) {
5373 zend_jit_trace_clenup_stack(stack, opline, ssa_op, ssa, ra);
5374 }
5375 exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5376 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5377 if (!exit_addr) {
5378 goto jit_failure;
5379 }
5380 smart_branch_opcode = exit_if_true ? ZEND_JMPNZ : ZEND_JMPZ;
5381 } else {
5382 smart_branch_opcode = 0;
5383 exit_addr = NULL;
5384 }
5385 if (!zend_jit_type_check(&dasm_state, opline, op1_info, smart_branch_opcode, -1, -1, exit_addr)) {
5386 goto jit_failure;
5387 }
5388 goto done;
5389 case ZEND_RETURN:
5390 op1_info = OP1_INFO();
5391 CHECK_OP1_TRACE_TYPE();
5392 if (opline->op1_type == IS_CONST) {
5393 res_type = Z_TYPE_P(RT_CONSTANT(opline, opline->op1));
5394 } else if (op1_type != IS_UNKNOWN) {
5395 res_type = op1_type;
5396 }
5397 if (op_array->type == ZEND_EVAL_CODE
5398 // TODO: support for top-level code
5399 || !op_array->function_name
5400 // TODO: support for IS_UNDEF ???
5401 || (op1_info & MAY_BE_UNDEF)) {
5402 if (!zend_jit_trace_handler(&dasm_state, op_array, opline, zend_may_throw(opline, ssa_op, op_array, ssa), p + 1)) {
5403 goto jit_failure;
5404 }
5405 } else {
5406 int j;
5407 int may_throw = 0;
5408 bool left_frame = 0;
5409
5410 if (!zend_jit_return(&dasm_state, opline, op_array,
5411 op1_info, OP1_REG_ADDR())) {
5412 goto jit_failure;
5413 }
5414 if (op_array->last_var > 100) {
5415 /* To many CVs to unroll */
5416 if (!zend_jit_free_cvs(&dasm_state)) {
5417 goto jit_failure;
5418 }
5419 left_frame = 1;
5420 }
5421 if (!left_frame) {
5422 for (j = 0 ; j < op_array->last_var; j++) {
5423 uint32_t info;
5424 zend_uchar type;
5425
5426 info = zend_ssa_cv_info(op_array, op_array_ssa, j);
5427 type = STACK_TYPE(stack, j);
5428 info = zend_jit_trace_type_to_info_ex(type, info);
5429 if (opline->op1_type == IS_CV
5430 && EX_VAR_TO_NUM(opline->op1.var) == j
5431 && !(op1_info & (MAY_BE_REF|MAY_BE_OBJECT))) {
5432 if (JIT_G(current_frame)
5433 && TRACE_FRAME_IS_RETURN_VALUE_USED(JIT_G(current_frame))) {
5434 continue;
5435 } else {
5436 info |= MAY_BE_NULL;
5437 }
5438 }
5439 if (info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
5440 if (!left_frame) {
5441 left_frame = 1;
5442 if (!zend_jit_leave_frame(&dasm_state)) {
5443 goto jit_failure;
5444 }
5445 }
5446 if (!zend_jit_free_cv(&dasm_state, info, j)) {
5447 goto jit_failure;
5448 }
5449 if (info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_RESOURCE)) {
5450 if (info & MAY_BE_RC1) {
5451 may_throw = 1;
5452 }
5453 }
5454 }
5455 }
5456 }
5457 if (!zend_jit_leave_func(&dasm_state, op_array, opline, op1_info, left_frame,
5458 p + 1, &zend_jit_traces[ZEND_JIT_TRACE_NUM],
5459 (op_array_ssa->cfg.flags & ZEND_FUNC_INDIRECT_VAR_ACCESS) != 0, may_throw)) {
5460 goto jit_failure;
5461 }
5462 }
5463 goto done;
5464 case ZEND_BOOL:
5465 case ZEND_BOOL_NOT:
5466 op1_info = OP1_INFO();
5467 CHECK_OP1_TRACE_TYPE();
5468 if (!zend_jit_bool_jmpznz(&dasm_state, opline,
5469 op1_info, OP1_REG_ADDR(), RES_REG_ADDR(),
5470 -1, -1,
5471 zend_may_throw(opline, ssa_op, op_array, ssa),
5472 opline->opcode, NULL)) {
5473 goto jit_failure;
5474 }
5475 goto done;
5476 case ZEND_JMPZ:
5477 case ZEND_JMPNZ:
5478 case ZEND_JMPZNZ:
5479 case ZEND_JMPZ_EX:
5480 case ZEND_JMPNZ_EX:
5481 op1_info = OP1_INFO();
5482 CHECK_OP1_TRACE_TYPE();
5483 if ((p+1)->op == ZEND_JIT_TRACE_VM || (p+1)->op == ZEND_JIT_TRACE_END) {
5484 const zend_op *exit_opline = NULL;
5485 uint32_t exit_point;
5486
5487 if ((p+1)->opline == OP_JMP_ADDR(opline, opline->op2)) {
5488 /* taken branch */
5489 if (opline->opcode == ZEND_JMPNZ_EX) {
5490 smart_branch_opcode = ZEND_JMPZ_EX;
5491 } else if (opline->opcode == ZEND_JMPZ_EX) {
5492 smart_branch_opcode = ZEND_JMPNZ_EX;
5493 } else if (opline->opcode == ZEND_JMPNZ) {
5494 smart_branch_opcode = ZEND_JMPZ;
5495 } else {
5496 smart_branch_opcode = ZEND_JMPNZ;
5497 }
5498 exit_opline = (opline->opcode == ZEND_JMPZNZ) ?
5499 ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) :
5500 opline + 1;
5501 } else if (opline->opcode == ZEND_JMPZNZ) {
5502 ZEND_ASSERT((p+1)->opline == ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value));
5503 smart_branch_opcode = ZEND_JMPZ;
5504 exit_opline = OP_JMP_ADDR(opline, opline->op2);
5505 } else if ((p+1)->opline == opline + 1) {
5506 /* not taken branch */
5507 smart_branch_opcode = opline->opcode;
5508 exit_opline = OP_JMP_ADDR(opline, opline->op2);
5509 } else {
5510 ZEND_UNREACHABLE();
5511 }
5512 if (ra) {
5513 zend_jit_trace_clenup_stack(stack, opline, ssa_op, ssa, ra);
5514 }
5515 if (!(op1_info & MAY_BE_GUARD)
5516 && has_concrete_type(op1_info)
5517 && concrete_type(op1_info) <= IS_TRUE) {
5518 /* unconditional branch */
5519 exit_addr = NULL;
5520 } else if (opline->result_type == IS_TMP_VAR) {
5521 zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
5522 uint32_t old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
5523
5524 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN, 1);
5525 exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5526 SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_info);
5527 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5528 if (!exit_addr) {
5529 goto jit_failure;
5530 }
5531 } else {
5532 exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5533 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5534 if (!exit_addr) {
5535 goto jit_failure;
5536 }
5537 }
5538 } else {
5539 ZEND_UNREACHABLE();
5540 }
5541 if (opline->result_type == IS_UNDEF) {
5542 res_addr = 0;
5543 } else {
5544 res_addr = RES_REG_ADDR();
5545 }
5546 if (!zend_jit_bool_jmpznz(&dasm_state, opline,
5547 op1_info, OP1_REG_ADDR(), res_addr,
5548 -1, -1,
5549 zend_may_throw(opline, ssa_op, op_array, ssa),
5550 smart_branch_opcode, exit_addr)) {
5551 goto jit_failure;
5552 }
5553 goto done;
5554 case ZEND_ISSET_ISEMPTY_CV:
5555 if ((opline->extended_value & ZEND_ISEMPTY)) {
5556 // TODO: support for empty() ???
5557 break;
5558 }
5559 op1_info = OP1_INFO();
5560 op1_addr = OP1_REG_ADDR();
5561 if (orig_op1_type != IS_UNKNOWN
5562 && (orig_op1_type & IS_TRACE_REFERENCE)) {
5563 if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr,
5564 !ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
5565 goto jit_failure;
5566 }
5567 if (opline->op1_type == IS_CV
5568 && ssa->vars[ssa_op->op1_use].alias == NO_ALIAS) {
5569 ssa->var_info[ssa_op->op1_use].guarded_reference = 1;
5570 }
5571 } else {
5572 CHECK_OP1_TRACE_TYPE();
5573 }
5574 if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
5575 bool exit_if_true = 0;
5576 const zend_op *exit_opline = zend_jit_trace_get_exit_opline(p + 1, opline + 1, &exit_if_true);
5577 uint32_t exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5578
5579 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5580 if (!exit_addr) {
5581 goto jit_failure;
5582 }
5583 smart_branch_opcode = exit_if_true ? ZEND_JMPNZ : ZEND_JMPZ;
5584 } else {
5585 smart_branch_opcode = 0;
5586 exit_addr = NULL;
5587 }
5588 if (!zend_jit_isset_isempty_cv(&dasm_state, opline,
5589 op1_info, op1_addr,
5590 smart_branch_opcode, -1, -1, exit_addr)) {
5591 goto jit_failure;
5592 }
5593 goto done;
5594 case ZEND_IN_ARRAY:
5595 if (opline->op1_type == IS_VAR || opline->op1_type == IS_TMP_VAR) {
5596 break;
5597 }
5598 op1_info = OP1_INFO();
5599 op1_addr = OP1_REG_ADDR();
5600 CHECK_OP1_TRACE_TYPE();
5601 if ((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != MAY_BE_STRING) {
5602 break;
5603 }
5604 if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
5605 bool exit_if_true = 0;
5606 const zend_op *exit_opline = zend_jit_trace_get_exit_opline(p + 1, opline + 1, &exit_if_true);
5607 uint32_t exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5608
5609 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5610 if (!exit_addr) {
5611 goto jit_failure;
5612 }
5613 smart_branch_opcode = exit_if_true ? ZEND_JMPNZ : ZEND_JMPZ;
5614 } else {
5615 smart_branch_opcode = 0;
5616 exit_addr = NULL;
5617 }
5618 if (!zend_jit_in_array(&dasm_state, opline,
5619 op1_info, op1_addr,
5620 smart_branch_opcode, -1, -1, exit_addr)) {
5621 goto jit_failure;
5622 }
5623 goto done;
5624 case ZEND_FETCH_DIM_FUNC_ARG:
5625 if (!JIT_G(current_frame)
5626 || !JIT_G(current_frame)->call
5627 || !JIT_G(current_frame)->call->func
5628 || !TRACE_FRAME_IS_LAST_SEND_BY_VAL(JIT_G(current_frame)->call)) {
5629 break;
5630 }
5631 ZEND_FALLTHROUGH;
5632 case ZEND_FETCH_DIM_R:
5633 case ZEND_FETCH_DIM_IS:
5634 case ZEND_FETCH_LIST_R:
5635 op1_info = OP1_INFO();
5636 op1_addr = OP1_REG_ADDR();
5637 if (orig_op1_type != IS_UNKNOWN
5638 && (orig_op1_type & IS_TRACE_REFERENCE)) {
5639 if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr,
5640 !ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
5641 goto jit_failure;
5642 }
5643 if (opline->op1_type == IS_CV
5644 && ssa->vars[ssa_op->op1_use].alias == NO_ALIAS) {
5645 ssa->var_info[ssa_op->op1_use].guarded_reference = 1;
5646 if (ssa_op->op1_def >= 0) {
5647 ssa->var_info[ssa_op->op1_def].guarded_reference = 1;
5648 }
5649 }
5650 } else {
5651 CHECK_OP1_TRACE_TYPE();
5652 }
5653 op2_info = OP2_INFO();
5654 CHECK_OP2_TRACE_TYPE();
5655 res_info = RES_INFO();
5656 avoid_refcounting =
5657 ssa_op->op1_use >= 0 &&
5658 ssa->var_info[ssa_op->op1_use].avoid_refcounting;
5659 if (op1_info & MAY_BE_PACKED_GUARD) {
5660 ssa->var_info[ssa_op->op1_use].type &= ~MAY_BE_PACKED_GUARD;
5661 } else if ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG
5662 && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY
5663 && MAY_BE_PACKED(op1_info)
5664 && MAY_BE_HASH(op1_info)
5665 && orig_op1_type != IS_UNKNOWN) {
5666 op1_info |= MAY_BE_PACKED_GUARD;
5667 if (orig_op1_type & IS_TRACE_PACKED) {
5668 op1_info &= ~(MAY_BE_ARRAY_NUMERIC_HASH|MAY_BE_ARRAY_STRING_HASH);
5669 if (op1_type != IS_UNKNOWN) {
5670 ssa->var_info[ssa_op->op1_use].type &= ~(MAY_BE_ARRAY_NUMERIC_HASH|MAY_BE_ARRAY_STRING_HASH);
5671 }
5672 } else {
5673 op1_info &= ~MAY_BE_ARRAY_PACKED;
5674 if (op1_type != IS_UNKNOWN) {
5675 ssa->var_info[ssa_op->op1_use].type &= ~MAY_BE_ARRAY_PACKED;
5676 }
5677 }
5678 }
5679 if (!zend_jit_fetch_dim_read(&dasm_state, opline, ssa, ssa_op,
5680 op1_info, op1_addr, avoid_refcounting,
5681 op2_info, res_info, RES_REG_ADDR(), val_type)) {
5682 goto jit_failure;
5683 }
5684 if (ssa_op->op1_def >= 0 && op1_type != IS_UNKNOWN) {
5685 ssa->var_info[ssa_op->op1_def].type = ssa->var_info[ssa_op->op1_use].type;
5686 }
5687 goto done;
5688 case ZEND_FETCH_DIM_W:
5689 case ZEND_FETCH_DIM_RW:
5690 // case ZEND_FETCH_DIM_UNSET:
5691 case ZEND_FETCH_LIST_W:
5692 if (opline->op1_type != IS_CV
5693 && (orig_op1_type == IS_UNKNOWN
5694 || !(orig_op1_type & IS_TRACE_INDIRECT))) {
5695 break;
5696 }
5697 op1_info = OP1_INFO();
5698 op1_addr = OP1_REG_ADDR();
5699 if (opline->op1_type == IS_VAR) {
5700 if (orig_op1_type != IS_UNKNOWN
5701 && (orig_op1_type & IS_TRACE_INDIRECT)) {
5702 if (!zend_jit_fetch_indirect_var(&dasm_state, opline, orig_op1_type,
5703 &op1_info, &op1_addr, !ssa->var_info[ssa_op->op1_use].indirect_reference)) {
5704 goto jit_failure;
5705 }
5706 } else {
5707 break;
5708 }
5709 }
5710 if (orig_op1_type != IS_UNKNOWN
5711 && (orig_op1_type & IS_TRACE_REFERENCE)) {
5712 if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr,
5713 !ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
5714 goto jit_failure;
5715 }
5716 if (opline->op1_type == IS_CV
5717 && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) {
5718 ssa->var_info[ssa_op->op1_def].guarded_reference = 1;
5719 }
5720 } else {
5721 CHECK_OP1_TRACE_TYPE();
5722 }
5723 op2_info = OP2_INFO();
5724 CHECK_OP2_TRACE_TYPE();
5725 op1_def_info = OP1_DEF_INFO();
5726 if (!zend_jit_fetch_dim(&dasm_state, opline,
5727 op1_info, op1_addr, op2_info, RES_REG_ADDR(), val_type)) {
5728 goto jit_failure;
5729 }
5730 if (ssa_op->result_def > 0
5731 && (opline->opcode == ZEND_FETCH_DIM_W || opline->opcode == ZEND_FETCH_LIST_W)
5732 && !(op1_info & (MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_STRING|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))
5733 && !(op2_info & (MAY_BE_UNDEF|MAY_BE_RESOURCE|MAY_BE_ARRAY|MAY_BE_OBJECT))) {
5734 ssa->var_info[ssa_op->result_def].indirect_reference = 1;
5735 }
5736 goto done;
5737 case ZEND_ISSET_ISEMPTY_DIM_OBJ:
5738 if ((opline->extended_value & ZEND_ISEMPTY)) {
5739 // TODO: support for empty() ???
5740 break;
5741 }
5742 op1_info = OP1_INFO();
5743 op1_addr = OP1_REG_ADDR();
5744 if (orig_op1_type != IS_UNKNOWN
5745 && (orig_op1_type & IS_TRACE_REFERENCE)) {
5746 if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr,
5747 !ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
5748 goto jit_failure;
5749 }
5750 if (opline->op1_type == IS_CV
5751 && ssa->vars[ssa_op->op1_use].alias == NO_ALIAS) {
5752 ssa->var_info[ssa_op->op1_use].guarded_reference = 1;
5753 }
5754 } else {
5755 CHECK_OP1_TRACE_TYPE();
5756 }
5757 op2_info = OP2_INFO();
5758 CHECK_OP2_TRACE_TYPE();
5759 if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
5760 bool exit_if_true = 0;
5761 const zend_op *exit_opline = zend_jit_trace_get_exit_opline(p + 1, opline + 1, &exit_if_true);
5762 uint32_t exit_point;
5763
5764 if (ra) {
5765 zend_jit_trace_clenup_stack(stack, opline, ssa_op, ssa, ra);
5766 }
5767 if (ssa_op->op1_use >= 0
5768 && ssa->var_info[ssa_op->op1_use].avoid_refcounting) {
5769 /* Temporary reset ZREG_ZVAL_TRY_ADDREF */
5770 zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
5771 uint32_t old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
5772
5773 SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
5774 exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5775 SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_info);
5776 } else {
5777 exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5778 }
5779 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5780 if (!exit_addr) {
5781 goto jit_failure;
5782 }
5783 smart_branch_opcode = exit_if_true ? ZEND_JMPNZ : ZEND_JMPZ;
5784 } else {
5785 smart_branch_opcode = 0;
5786 exit_addr = NULL;
5787 }
5788 avoid_refcounting =
5789 ssa_op->op1_use >= 0 &&
5790 ssa->var_info[ssa_op->op1_use].avoid_refcounting;
5791 if (op1_info & MAY_BE_PACKED_GUARD) {
5792 ssa->var_info[ssa_op->op1_use].type &= ~MAY_BE_PACKED_GUARD;
5793 } else if ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG
5794 && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY
5795 && MAY_BE_PACKED(op1_info)
5796 && MAY_BE_HASH(op1_info)
5797 && orig_op1_type != IS_UNKNOWN) {
5798 op1_info |= MAY_BE_PACKED_GUARD;
5799 if (orig_op1_type & IS_TRACE_PACKED) {
5800 op1_info &= ~(MAY_BE_ARRAY_NUMERIC_HASH|MAY_BE_ARRAY_STRING_HASH);
5801 } else {
5802 op1_info &= ~MAY_BE_ARRAY_PACKED;
5803 }
5804 }
5805 if (!zend_jit_isset_isempty_dim(&dasm_state, opline,
5806 op1_info, op1_addr, avoid_refcounting,
5807 op2_info, val_type,
5808 zend_may_throw_ex(opline, ssa_op, op_array, ssa, op1_info, op2_info),
5809 smart_branch_opcode, -1, -1,
5810 exit_addr)) {
5811 goto jit_failure;
5812 }
5813 goto done;
5814 case ZEND_FETCH_OBJ_FUNC_ARG:
5815 if (!JIT_G(current_frame)
5816 || !JIT_G(current_frame)->call
5817 || !JIT_G(current_frame)->call->func
5818 || !TRACE_FRAME_IS_LAST_SEND_BY_VAL(JIT_G(current_frame)->call)) {
5819 break;
5820 }
5821 ZEND_FALLTHROUGH;
5822 case ZEND_FETCH_OBJ_R:
5823 case ZEND_FETCH_OBJ_IS:
5824 case ZEND_FETCH_OBJ_W:
5825 on_this = delayed_fetch_this = 0;
5826 avoid_refcounting = 0;
5827 if (opline->op2_type != IS_CONST
5828 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
5829 || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
5830 break;
5831 }
5832 ce = NULL;
5833 ce_is_instanceof = 0;
5834 op1_indirect = 0;
5835 if (opline->op1_type == IS_UNUSED) {
5836 op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
5837 ce = op_array->scope;
5838 ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
5839 op1_addr = 0;
5840 on_this = 1;
5841 } else {
5842 op1_info = OP1_INFO();
5843 if (!(op1_info & MAY_BE_OBJECT)) {
5844 break;
5845 }
5846 op1_addr = OP1_REG_ADDR();
5847 if (opline->op1_type == IS_VAR
5848 && opline->opcode == ZEND_FETCH_OBJ_W) {
5849 if (orig_op1_type != IS_UNKNOWN
5850 && (orig_op1_type & IS_TRACE_INDIRECT)) {
5851 op1_indirect = 1;
5852 if (!zend_jit_fetch_indirect_var(&dasm_state, opline, orig_op1_type,
5853 &op1_info, &op1_addr, !ssa->var_info[ssa_op->op1_use].indirect_reference)) {
5854 goto jit_failure;
5855 }
5856 }
5857 }
5858 if (orig_op1_type != IS_UNKNOWN
5859 && (orig_op1_type & IS_TRACE_REFERENCE)) {
5860 if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr,
5861 !ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
5862 goto jit_failure;
5863 }
5864 if (opline->op1_type == IS_CV
5865 && ssa->vars[ssa_op->op1_use].alias == NO_ALIAS) {
5866 ssa->var_info[ssa_op->op1_def >= 0 ? ssa_op->op1_def : ssa_op->op1_use].guarded_reference = 1;
5867 }
5868 } else {
5869 CHECK_OP1_TRACE_TYPE();
5870 }
5871 if (!(op1_info & MAY_BE_OBJECT)) {
5872 break;
5873 }
5874 if (ssa->var_info && ssa->ops) {
5875 if (ssa_op->op1_use >= 0) {
5876 zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
5877 if (op1_ssa->ce && !op1_ssa->ce->create_object) {
5878 ce = op1_ssa->ce;
5879 ce_is_instanceof = op1_ssa->is_instanceof;
5880 }
5881 }
5882 }
5883 if (ssa_op->op1_use >= 0) {
5884 delayed_fetch_this = ssa->var_info[ssa_op->op1_use].delayed_fetch_this;
5885 avoid_refcounting = ssa->var_info[ssa_op->op1_use].avoid_refcounting;
5886 }
5887 if (delayed_fetch_this) {
5888 on_this = 1;
5889 } else if (ssa_op->op1_use >= 0 && ssa->vars[ssa_op->op1_use].definition >= 0) {
5890 on_this = ssa_opcodes[ssa->vars[ssa_op->op1_use].definition]->opcode == ZEND_FETCH_THIS;
5891 } else if (op_array_ssa->ops
5892 && op_array_ssa->vars
5893 && op_array_ssa->ops[opline-op_array->opcodes].op1_use >= 0
5894 && op_array_ssa->vars[op_array_ssa->ops[opline-op_array->opcodes].op1_use].definition >= 0) {
5895 on_this = op_array->opcodes[op_array_ssa->vars[op_array_ssa->ops[opline-op_array->opcodes].op1_use].definition].opcode == ZEND_FETCH_THIS;
5896 }
5897 }
5898 if (!zend_jit_fetch_obj(&dasm_state, opline, op_array, ssa, ssa_op,
5899 op1_info, op1_addr, op1_indirect, ce, ce_is_instanceof,
5900 on_this, delayed_fetch_this, avoid_refcounting, op1_ce, val_type,
5901 zend_may_throw_ex(opline, ssa_op, op_array, ssa, op1_info, MAY_BE_STRING))) {
5902 goto jit_failure;
5903 }
5904 goto done;
5905 case ZEND_BIND_GLOBAL:
5906 orig_opline = opline;
5907 orig_ssa_op = ssa_op;
5908 while (1) {
5909 if (!ssa->ops || !ssa->var_info) {
5910 op1_info = MAY_BE_ANY|MAY_BE_REF;
5911 } else {
5912 op1_info = OP1_INFO();
5913 }
5914 if (ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) {
5915 ssa->var_info[ssa_op->op1_def].guarded_reference = 1;
5916 }
5917 if (!zend_jit_bind_global(&dasm_state, opline, op1_info)) {
5918 goto jit_failure;
5919 }
5920 if ((opline+1)->opcode == ZEND_BIND_GLOBAL) {
5921 opline++;
5922 ssa_op++;
5923 } else {
5924 break;
5925 }
5926 }
5927 opline = orig_opline;
5928 ssa_op = orig_ssa_op;
5929 goto done;
5930 case ZEND_RECV:
5931 if (!zend_jit_recv(&dasm_state, opline, op_array)) {
5932 goto jit_failure;
5933 }
5934 goto done;
5935 case ZEND_RECV_INIT:
5936 orig_opline = opline;
5937 orig_ssa_op = ssa_op;
5938 while (1) {
5939 if (!zend_jit_recv_init(&dasm_state, opline, op_array,
5940 (opline + 1)->opcode != ZEND_RECV_INIT,
5941 zend_may_throw(opline, ssa_op, op_array, ssa))) {
5942 goto jit_failure;
5943 }
5944 if ((opline+1)->opcode == ZEND_RECV_INIT) {
5945 opline++;
5946 ssa_op++;
5947 } else {
5948 break;
5949 }
5950 }
5951 opline = orig_opline;
5952 ssa_op = orig_ssa_op;
5953 goto done;
5954 case ZEND_FREE:
5955 case ZEND_FE_FREE:
5956 op1_info = OP1_INFO();
5957 if (!zend_jit_free(&dasm_state, opline, op1_info,
5958 zend_may_throw(opline, ssa_op, op_array, ssa))) {
5959 goto jit_failure;
5960 }
5961 goto done;
5962 case ZEND_ECHO:
5963 op1_info = OP1_INFO();
5964 CHECK_OP1_TRACE_TYPE();
5965 if ((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) != MAY_BE_STRING) {
5966 break;
5967 }
5968 if (!zend_jit_echo(&dasm_state, opline, op1_info)) {
5969 goto jit_failure;
5970 }
5971 goto done;
5972 case ZEND_STRLEN:
5973 op1_info = OP1_INFO();
5974 op1_addr = OP1_REG_ADDR();
5975 if (orig_op1_type == (IS_TRACE_REFERENCE|IS_STRING)) {
5976 if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr,
5977 !ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
5978 goto jit_failure;
5979 }
5980 if (opline->op1_type == IS_CV
5981 && ssa->vars[ssa_op->op1_use].alias == NO_ALIAS) {
5982 ssa->var_info[ssa_op->op1_use].guarded_reference = 1;
5983 }
5984 } else {
5985 CHECK_OP1_TRACE_TYPE();
5986 if ((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) != MAY_BE_STRING) {
5987 break;
5988 }
5989 }
5990 if (!zend_jit_strlen(&dasm_state, opline, op1_info, op1_addr, RES_REG_ADDR())) {
5991 goto jit_failure;
5992 }
5993 goto done;
5994 case ZEND_COUNT:
5995 op1_info = OP1_INFO();
5996 op1_addr = OP1_REG_ADDR();
5997 if (orig_op1_type == (IS_TRACE_REFERENCE|IS_ARRAY)) {
5998 if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr,
5999 !ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
6000 goto jit_failure;
6001 }
6002 if (opline->op1_type == IS_CV
6003 && ssa->vars[ssa_op->op1_use].alias == NO_ALIAS) {
6004 ssa->var_info[ssa_op->op1_use].guarded_reference = 1;
6005 }
6006 } else {
6007 CHECK_OP1_TRACE_TYPE();
6008 if ((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) != MAY_BE_ARRAY) {
6009 break;
6010 }
6011 }
6012 if (!zend_jit_count(&dasm_state, opline, op1_info, op1_addr, RES_REG_ADDR(), zend_may_throw(opline, ssa_op, op_array, ssa))) {
6013 goto jit_failure;
6014 }
6015 goto done;
6016 case ZEND_FETCH_THIS:
6017 delayed_fetch_this = 0;
6018 if (ssa_op->result_def >= 0 && opline->result_type != IS_CV) {
6019 if (zend_jit_may_delay_fetch_this(op_array, ssa, ssa_opcodes, ssa_op)) {
6020 ssa->var_info[ssa_op->result_def].delayed_fetch_this = 1;
6021 delayed_fetch_this = 1;
6022 }
6023 }
6024 if (!zend_jit_fetch_this(&dasm_state, opline, op_array, delayed_fetch_this)) {
6025 goto jit_failure;
6026 }
6027 goto done;
6028 case ZEND_SWITCH_LONG:
6029 case ZEND_SWITCH_STRING:
6030 case ZEND_MATCH:
6031 if (!zend_jit_switch(&dasm_state, opline, op_array, op_array_ssa, p+1, &zend_jit_traces[ZEND_JIT_TRACE_NUM])) {
6032 goto jit_failure;
6033 }
6034 goto done;
6035 case ZEND_VERIFY_RETURN_TYPE:
6036 if (opline->op1_type == IS_UNUSED) {
6037 /* Always throws */
6038 break;
6039 }
6040 if (opline->op1_type == IS_CONST) {
6041 /* TODO Different instruction format, has return value */
6042 break;
6043 }
6044 if (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
6045 /* Not worth bothering with */
6046 break;
6047 }
6048 op1_info = OP1_INFO();
6049 CHECK_OP1_TRACE_TYPE();
6050 if (op1_info & MAY_BE_REF) {
6051 /* TODO May need reference unwrapping. */
6052 break;
6053 }
6054 if (!zend_jit_verify_return_type(&dasm_state, opline, op_array, op1_info)) {
6055 goto jit_failure;
6056 }
6057 goto done;
6058 case ZEND_FE_RESET_R:
6059 op1_info = OP1_INFO();
6060 CHECK_OP1_TRACE_TYPE();
6061 if ((op1_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) != MAY_BE_ARRAY) {
6062 break;
6063 }
6064 if (!zend_jit_fe_reset(&dasm_state, opline, op1_info)) {
6065 goto jit_failure;
6066 }
6067 goto done;
6068 case ZEND_FE_FETCH_R:
6069 op1_info = OP1_INFO();
6070 CHECK_OP1_TRACE_TYPE();
6071 if ((op1_info & MAY_BE_ANY) != MAY_BE_ARRAY) {
6072 break;
6073 }
6074 if ((p+1)->op == ZEND_JIT_TRACE_VM || (p+1)->op == ZEND_JIT_TRACE_END) {
6075 const zend_op *exit_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
6076 uint32_t exit_point;
6077
6078 if ((p+1)->opline == exit_opline) {
6079 /* taken branch (exit from loop) */
6080 exit_opline = opline;
6081 smart_branch_opcode = ZEND_NOP;
6082 } else if ((p+1)->opline == opline + 1) {
6083 /* not taken branch (loop) */
6084 smart_branch_opcode = ZEND_JMP;
6085 } else {
6086 ZEND_UNREACHABLE();
6087 }
6088 exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
6089 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
6090 if (!exit_addr) {
6091 goto jit_failure;
6092 }
6093 } else {
6094 ZEND_UNREACHABLE();
6095 }
6096 if (!zend_jit_fe_fetch(&dasm_state, opline, op1_info, OP2_INFO(),
6097 -1, smart_branch_opcode, exit_addr)) {
6098 goto jit_failure;
6099 }
6100 goto done;
6101 case ZEND_FETCH_CONSTANT:
6102 if (!zend_jit_fetch_constant(&dasm_state, opline, op_array, ssa, ssa_op, RES_REG_ADDR())) {
6103 goto jit_failure;
6104 }
6105 goto done;
6106 case ZEND_INIT_METHOD_CALL:
6107 if (opline->op2_type != IS_CONST
6108 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING) {
6109 goto generic_dynamic_call;
6110 }
6111 on_this = delayed_fetch_this = 0;
6112 ce = NULL;
6113 ce_is_instanceof = 0;
6114 if (opline->op1_type == IS_UNUSED) {
6115 op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
6116 ce = op_array->scope;
6117 ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
6118 op1_addr = 0;
6119 on_this = 1;
6120 } else {
6121 op1_info = OP1_INFO();
6122 op1_addr = OP1_REG_ADDR();
6123 if (polymorphic_side_trace) {
6124 op1_info = MAY_BE_OBJECT;
6125 op1_addr = 0;
6126 } else if (orig_op1_type != IS_UNKNOWN
6127 && (orig_op1_type & IS_TRACE_REFERENCE)) {
6128 if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr,
6129 !ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
6130 goto jit_failure;
6131 }
6132 if (opline->op1_type == IS_CV
6133 && ssa->vars[ssa_op->op1_use].alias == NO_ALIAS) {
6134 ssa->var_info[ssa_op->op1_use].guarded_reference = 1;
6135 }
6136 } else {
6137 CHECK_OP1_TRACE_TYPE();
6138 }
6139 if (ssa->var_info && ssa->ops) {
6140 if (ssa_op->op1_use >= 0) {
6141 zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
6142 if (op1_ssa->ce && !op1_ssa->ce->create_object) {
6143 ce = op1_ssa->ce;
6144 ce_is_instanceof = op1_ssa->is_instanceof;
6145 }
6146 }
6147 }
6148 if (ssa_op->op1_use >= 0) {
6149 delayed_fetch_this = ssa->var_info[ssa_op->op1_use].delayed_fetch_this;
6150 }
6151 if (delayed_fetch_this) {
6152 on_this = 1;
6153 } else if (ssa_op->op1_use >= 0 && ssa->vars[ssa_op->op1_use].definition >= 0) {
6154 on_this = ssa_opcodes[ssa->vars[ssa_op->op1_use].definition]->opcode == ZEND_FETCH_THIS;
6155 } else if (op_array_ssa->ops
6156 && op_array_ssa->vars
6157 && op_array_ssa->ops[opline-op_array->opcodes].op1_use >= 0
6158 && op_array_ssa->vars[op_array_ssa->ops[opline-op_array->opcodes].op1_use].definition >= 0) {
6159 on_this = op_array->opcodes[op_array_ssa->vars[op_array_ssa->ops[opline-op_array->opcodes].op1_use].definition].opcode == ZEND_FETCH_THIS;
6160 }
6161 }
6162 frame_flags = TRACE_FRAME_MASK_NESTED;
6163 if (!zend_jit_init_method_call(&dasm_state, opline,
6164 op_array_ssa->cfg.map ? op_array_ssa->cfg.map[opline - op_array->opcodes] : -1,
6165 op_array, ssa, ssa_op, frame->call_level,
6166 op1_info, op1_addr, ce, ce_is_instanceof, on_this, delayed_fetch_this, op1_ce,
6167 p + 1, peek_checked_stack - checked_stack, polymorphic_side_trace)) {
6168 goto jit_failure;
6169 }
6170 goto done;
6171 case ZEND_INIT_DYNAMIC_CALL:
6172 if (orig_op2_type != IS_OBJECT || op2_ce != zend_ce_closure) {
6173 goto generic_dynamic_call;
6174 }
6175 op2_info = OP2_INFO();
6176 CHECK_OP2_TRACE_TYPE();
6177 frame_flags = TRACE_FRAME_MASK_NESTED;
6178 if (!zend_jit_init_closure_call(&dasm_state, opline, op_array_ssa->cfg.map ? op_array_ssa->cfg.map[opline - op_array->opcodes] : -1, op_array, ssa, ssa_op, frame->call_level, p + 1, peek_checked_stack - checked_stack)) {
6179 goto jit_failure;
6180 }
6181 goto done;
6182 case ZEND_INIT_STATIC_METHOD_CALL:
6183 generic_dynamic_call:
6184 if (!zend_jit_trace_handler(&dasm_state, op_array, opline, zend_may_throw(opline, ssa_op, op_array, ssa), p + 1)) {
6185 goto jit_failure;
6186 }
6187 if ((p+1)->op == ZEND_JIT_TRACE_INIT_CALL && (p+1)->func
6188 && (opline->opcode != ZEND_INIT_STATIC_METHOD_CALL
6189 || opline->op1_type != IS_CONST
6190 || opline->op2_type != IS_CONST
6191 || zend_jit_may_be_modified((p+1)->func, op_array))) {
6192 if (!zend_jit_init_fcall_guard(&dasm_state, 0, (p+1)->func, opline+1)) {
6193 goto jit_failure;
6194 }
6195 }
6196 goto done;
6197 case ZEND_INIT_USER_CALL:
6198 if (!zend_jit_trace_handler(&dasm_state, op_array, opline, zend_may_throw(opline, ssa_op, op_array, ssa), p + 1)) {
6199 goto jit_failure;
6200 }
6201 if ((p+1)->op == ZEND_JIT_TRACE_INIT_CALL && (p+1)->func
6202 && (opline->op2_type != IS_CONST
6203 || zend_jit_may_be_modified((p+1)->func, op_array))) {
6204 if (!zend_jit_init_fcall_guard(&dasm_state, 0, (p+1)->func, opline+1)) {
6205 goto jit_failure;
6206 }
6207 }
6208 goto done;
6209 case ZEND_NEW:
6210 if (!zend_jit_trace_handler(&dasm_state, op_array, opline, zend_may_throw(opline, ssa_op, op_array, ssa), p + 1)) {
6211 goto jit_failure;
6212 }
6213 if ((p+1)->op == ZEND_JIT_TRACE_INIT_CALL && (p+1)->func
6214 && (opline->op1_type != IS_CONST
6215 || zend_jit_may_be_modified((p+1)->func, op_array))) {
6216 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_OBJECT, 1);
6217 if (!zend_jit_init_fcall_guard(&dasm_state, 0, (p+1)->func, opline+1)) {
6218 goto jit_failure;
6219 }
6220 }
6221 goto done;
6222 case ZEND_SEND_ARRAY:
6223 case ZEND_SEND_UNPACK:
6224 if (JIT_G(current_frame)
6225 && JIT_G(current_frame)->call) {
6226 TRACE_FRAME_SET_UNKNOWN_NUM_ARGS(JIT_G(current_frame)->call);
6227 }
6228 break;
6229 case ZEND_ROPE_INIT:
6230 case ZEND_ROPE_ADD:
6231 case ZEND_ROPE_END:
6232 op2_info = OP2_INFO();
6233 CHECK_OP2_TRACE_TYPE();
6234 if ((op2_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) != MAY_BE_STRING) {
6235 break;
6236 }
6237 if (!zend_jit_rope(&dasm_state, opline, op2_info)) {
6238 goto jit_failure;
6239 }
6240 goto done;
6241 default:
6242 break;
6243 }
6244 }
6245
6246 if (opline->opcode != ZEND_NOP && opline->opcode != ZEND_JMP) {
6247 gen_handler = 1;
6248 op1_info = OP1_INFO();
6249 op2_info = OP2_INFO();
6250 if (op1_info & MAY_BE_GUARD) {
6251 op1_info = MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
6252 }
6253 if (op2_info & MAY_BE_GUARD) {
6254 op2_info = MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
6255 }
6256 if (!zend_jit_trace_handler(&dasm_state, op_array, opline,
6257 zend_may_throw_ex(opline, ssa_op, op_array, ssa, op1_info, op2_info), p + 1)) {
6258 goto jit_failure;
6259 }
6260 }
6261
6262 done:
6263 polymorphic_side_trace = 0;
6264 switch (opline->opcode) {
6265 case ZEND_DO_FCALL:
6266 case ZEND_DO_ICALL:
6267 case ZEND_DO_UCALL:
6268 case ZEND_DO_FCALL_BY_NAME:
6269 case ZEND_CALLABLE_CONVERT:
6270 frame->call_level--;
6271 }
6272
6273 if (ra) {
6274 zend_jit_trace_clenup_stack(stack, opline, ssa_op, ssa, ra);
6275 }
6276
6277 if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
6278 && STACK_REG(stack, EX_VAR_TO_NUM(opline->op1.var)) > ZREG_NUM) {
6279 SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
6280 }
6281
6282 if (opline->opcode == ZEND_ROPE_INIT) {
6283 /* clear stack slots used by rope */
6284 uint32_t var = EX_VAR_TO_NUM(opline->result.var);
6285 uint32_t count =
6286 ((opline->extended_value * sizeof(void*)) + (sizeof(zval)-1)) / sizeof(zval);
6287
6288 do {
6289 SET_STACK_TYPE(stack, var, IS_UNKNOWN, 1);
6290 var++;
6291 count--;
6292 } while (count);
6293 }
6294
6295 if (ssa_op) {
6296 zend_ssa_range tmp;
6297
6298 /* Keep information about known types on abstract stack */
6299 if (ssa_op->result_def >= 0) {
6300 zend_uchar type = IS_UNKNOWN;
6301
6302 if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0
6303 || send_result) {
6304 /* we didn't set result variable */
6305 type = IS_UNKNOWN;
6306 } else if (!(ssa->var_info[ssa_op->result_def].type & MAY_BE_GUARD)
6307 && has_concrete_type(ssa->var_info[ssa_op->result_def].type)) {
6308 type = concrete_type(ssa->var_info[ssa_op->result_def].type);
6309 } else if (opline->opcode == ZEND_QM_ASSIGN) {
6310 if (opline->op1_type != IS_CONST) {
6311 /* copy */
6312 type = STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var));
6313 }
6314 } else if (opline->opcode == ZEND_ASSIGN) {
6315 if (opline->op2_type != IS_CONST
6316 && ssa_op->op1_use >= 0
6317 /* assignment to typed reference may cause conversion */
6318 && (ssa->var_info[ssa_op->op1_use].type & MAY_BE_REF) == 0) {
6319 /* copy */
6320 type = STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op2.var));
6321 }
6322 } else if (opline->opcode == ZEND_POST_INC
6323 || opline->opcode == ZEND_POST_DEC) {
6324 /* copy */
6325 type = STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var));
6326 }
6327 if (opline->opcode == ZEND_JMP_SET
6328 || opline->opcode == ZEND_COALESCE
6329 || opline->opcode == ZEND_JMP_NULL) {
6330 if ((p+1)->op != ZEND_JIT_TRACE_VM) {
6331 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN, 1);
6332 } else if ((p+1)->opline != (opline + 1)) {
6333 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), type, 1);
6334 }
6335 } else {
6336 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), type,
6337 (gen_handler || type == IS_UNKNOWN || !ra || !ra[ssa_op->result_def]));
6338 if (ssa->var_info[ssa_op->result_def].type & MAY_BE_INDIRECT) {
6339 RESET_STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->result.var));
6340 }
6341 if (type != IS_UNKNOWN) {
6342 ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
6343 if (opline->opcode == ZEND_FETCH_THIS
6344 && delayed_fetch_this) {
6345 SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_THIS);
6346 } else if (ssa->var_info[ssa_op->result_def].avoid_refcounting) {
6347 SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_ZVAL_TRY_ADDREF);
6348 } else if (ra && ra[ssa_op->result_def]) {
6349 SET_STACK_REG_EX(stack, EX_VAR_TO_NUM(opline->result.var), ra[ssa_op->result_def]->reg,
6350 ra[ssa_op->result_def]->flags & ZREG_STORE);
6351 }
6352 }
6353 }
6354
6355 if (type == IS_LONG
6356 && zend_inference_propagate_range(op_array, ssa, (zend_op*)opline, (zend_ssa_op*)ssa_op, ssa_op->result_def, &tmp)) {
6357 ssa->var_info[ssa_op->result_def].range.min = tmp.min;
6358 ssa->var_info[ssa_op->result_def].range.max = tmp.max;
6359 ssa->var_info[ssa_op->result_def].range.underflow = 0;
6360 ssa->var_info[ssa_op->result_def].range.overflow = 0;
6361 ssa->var_info[ssa_op->result_def].has_range = 1;
6362 }
6363 }
6364 if (ssa_op->op1_def >= 0
6365 && ((opline->opcode != ZEND_QM_ASSIGN && opline->opcode != ZEND_CAST)
6366 || opline->result_type != IS_CV
6367 || opline->result.var != opline->op1.var)) {
6368 zend_uchar type = IS_UNKNOWN;
6369
6370 if (!(ssa->var_info[ssa_op->op1_def].type & MAY_BE_GUARD)
6371 && has_concrete_type(ssa->var_info[ssa_op->op1_def].type)) {
6372 type = concrete_type(ssa->var_info[ssa_op->op1_def].type);
6373 } else if (opline->opcode == ZEND_ASSIGN) {
6374 if (!(OP1_INFO() & MAY_BE_REF)
6375 || STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var)) != IS_UNKNOWN) {
6376 if (opline->op2_type != IS_CONST) {
6377 /* copy */
6378 type = STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op2.var));
6379 }
6380 }
6381 } else if (opline->opcode == ZEND_SEND_VAR
6382 || opline->opcode == ZEND_CAST
6383 || opline->opcode == ZEND_QM_ASSIGN
6384 || opline->opcode == ZEND_JMP_SET
6385 || opline->opcode == ZEND_COALESCE
6386 || opline->opcode == ZEND_JMP_NULL
6387 || opline->opcode == ZEND_FE_RESET_R) {
6388 /* keep old value */
6389 type = STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var));
6390 }
6391 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var), type,
6392 (gen_handler || type == IS_UNKNOWN || !ra ||
6393 (!ra[ssa_op->op1_def] &&
6394 !(ssa->vars[ssa_op->op1_def].no_val &&
6395 Z_MODE(OP1_REG_ADDR()) == IS_REG &&
6396 (opline->opcode == ZEND_QM_ASSIGN ||
6397 opline->opcode == ZEND_SEND_VAR ||
6398 opline->opcode == ZEND_SEND_VAR_EX ||
6399 opline->opcode == ZEND_SEND_VAR_NO_REF ||
6400 opline->opcode == ZEND_SEND_VAR_NO_REF_EX ||
6401 opline->opcode == ZEND_SEND_FUNC_ARG)))));
6402 if (type != IS_UNKNOWN) {
6403 ssa->var_info[ssa_op->op1_def].type &= ~MAY_BE_GUARD;
6404 if (ra && ra[ssa_op->op1_def]) {
6405 uint8_t flags = ra[ssa_op->op1_def]->flags & ZREG_STORE;
6406
6407 if (ssa_op->op1_use >= 0) {
6408 if (opline->opcode == ZEND_SEND_VAR
6409 || opline->opcode == ZEND_CAST
6410 || opline->opcode == ZEND_QM_ASSIGN
6411 || opline->opcode == ZEND_JMP_SET
6412 || opline->opcode == ZEND_COALESCE
6413 || opline->opcode == ZEND_JMP_NULL
6414 || opline->opcode == ZEND_FE_RESET_R) {
6415 if (!ra[ssa_op->op1_use]) {
6416 flags |= ZREG_LOAD;
6417 }
6418 }
6419 }
6420 SET_STACK_REG_EX(stack, EX_VAR_TO_NUM(opline->op1.var), ra[ssa_op->op1_def]->reg, flags);
6421 }
6422 }
6423 if (type == IS_LONG
6424 && zend_inference_propagate_range(op_array, ssa, (zend_op*)opline, (zend_ssa_op*)ssa_op, ssa_op->op1_def, &tmp)) {
6425 ssa->var_info[ssa_op->op1_def].range.min = tmp.min;
6426 ssa->var_info[ssa_op->op1_def].range.max = tmp.max;
6427 ssa->var_info[ssa_op->op1_def].range.underflow = 0;
6428 ssa->var_info[ssa_op->op1_def].range.overflow = 0;
6429 ssa->var_info[ssa_op->op1_def].has_range = 1;
6430 }
6431 }
6432 if (ssa_op->op2_def >= 0
6433 && (opline->opcode != ZEND_ASSIGN
6434 || opline->op1_type != IS_CV
6435 || opline->op1.var != opline->op2.var)) {
6436 zend_uchar type = IS_UNKNOWN;
6437
6438 if (!(ssa->var_info[ssa_op->op2_def].type & MAY_BE_GUARD)
6439 && has_concrete_type(ssa->var_info[ssa_op->op2_def].type)) {
6440 type = concrete_type(ssa->var_info[ssa_op->op2_def].type);
6441 } else if (opline->opcode == ZEND_ASSIGN) {
6442 /* keep old value */
6443 type = STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op2.var));
6444 }
6445 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op2.var), type,
6446 (gen_handler || type == IS_UNKNOWN || !ra ||
6447 (!ra[ssa_op->op2_def] &&
6448 !(ssa->vars[ssa_op->op2_def].no_val &&
6449 Z_MODE(OP2_REG_ADDR()) == IS_REG &&
6450 opline->opcode == ZEND_ASSIGN))));
6451 if (type != IS_UNKNOWN) {
6452 ssa->var_info[ssa_op->op2_def].type &= ~MAY_BE_GUARD;
6453 if (ra && ra[ssa_op->op2_def]) {
6454 uint8_t flags = ra[ssa_op->op2_def]->flags & ZREG_STORE;
6455
6456 if (ssa_op->op2_use >= 0) {
6457 if (opline->opcode == ZEND_ASSIGN) {
6458 if (!ra[ssa_op->op2_use]
6459 || ra[ssa_op->op2_use]->reg != ra[ssa_op->op2_def]->reg) {
6460 flags |= ZREG_LOAD;
6461 }
6462 }
6463 }
6464 SET_STACK_REG_EX(stack, EX_VAR_TO_NUM(opline->op2.var), ra[ssa_op->op2_def]->reg, flags);
6465 }
6466 }
6467 if (type == IS_LONG
6468 && zend_inference_propagate_range(op_array, ssa, (zend_op*)opline, (zend_ssa_op*)ssa_op, ssa_op->op2_def, &tmp)) {
6469 ssa->var_info[ssa_op->op2_def].range.min = tmp.min;
6470 ssa->var_info[ssa_op->op2_def].range.max = tmp.max;
6471 ssa->var_info[ssa_op->op2_def].range.underflow = 0;
6472 ssa->var_info[ssa_op->op2_def].range.overflow = 0;
6473 ssa->var_info[ssa_op->op2_def].has_range = 1;
6474 }
6475 }
6476
6477 switch (opline->opcode) {
6478 case ZEND_ASSIGN_DIM:
6479 case ZEND_ASSIGN_OBJ:
6480 case ZEND_ASSIGN_STATIC_PROP:
6481 case ZEND_ASSIGN_DIM_OP:
6482 case ZEND_ASSIGN_OBJ_OP:
6483 case ZEND_ASSIGN_STATIC_PROP_OP:
6484 case ZEND_ASSIGN_OBJ_REF:
6485 case ZEND_ASSIGN_STATIC_PROP_REF:
6486 /* OP_DATA */
6487 ssa_op++;
6488 opline++;
6489 if (ssa_op->op1_def >= 0) {
6490 zend_uchar type = IS_UNKNOWN;
6491
6492 if (!(ssa->var_info[ssa_op->op1_def].type & MAY_BE_GUARD)
6493 && has_concrete_type(ssa->var_info[ssa_op->op1_def].type)) {
6494 type = concrete_type(ssa->var_info[ssa_op->op1_def].type);
6495 } else if ((opline-1)->opcode == ZEND_ASSIGN_DIM
6496 || (opline-1)->opcode == ZEND_ASSIGN_OBJ
6497 || (opline-1)->opcode == ZEND_ASSIGN_STATIC_PROP) {
6498 /* keep old value */
6499 type = STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var));
6500 }
6501 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var), type,
6502 (gen_handler || type == IS_UNKNOWN || !ra || !ra[ssa_op->op1_def]));
6503 if (type != IS_UNKNOWN) {
6504 ssa->var_info[ssa_op->op1_def].type &= ~MAY_BE_GUARD;
6505 if (ra && ra[ssa_op->op1_def]) {
6506 SET_STACK_REG_EX(stack, EX_VAR_TO_NUM(opline->op1.var), ra[ssa_op->op1_def]->reg,
6507 ra[ssa_op->op1_def]->flags & ZREG_STORE);
6508 }
6509 }
6510 if (type == IS_LONG
6511 && zend_inference_propagate_range(op_array, ssa, (zend_op*)opline, (zend_ssa_op*)ssa_op, ssa_op->op1_def, &tmp)) {
6512 ssa->var_info[ssa_op->op1_def].range.min = tmp.min;
6513 ssa->var_info[ssa_op->op1_def].range.max = tmp.max;
6514 ssa->var_info[ssa_op->op1_def].range.underflow = 0;
6515 ssa->var_info[ssa_op->op1_def].range.overflow = 0;
6516 ssa->var_info[ssa_op->op1_def].has_range = 1;
6517 }
6518 }
6519 ssa_op++;
6520 break;
6521 case ZEND_RECV_INIT:
6522 ssa_op++;
6523 opline++;
6524 while (opline->opcode == ZEND_RECV_INIT) {
6525 if (ssa_op->result_def >= 0) {
6526 zend_uchar type = IS_UNKNOWN;
6527
6528 if (!(ssa->var_info[ssa_op->result_def].type & MAY_BE_GUARD)
6529 && has_concrete_type(ssa->var_info[ssa_op->result_def].type)) {
6530 type = concrete_type(ssa->var_info[ssa_op->result_def].type);
6531 }
6532 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), type,
6533 (gen_handler || !ra || !ra[ssa_op->result_def]));
6534 if (ra && ra[ssa_op->result_def]) {
6535 SET_STACK_REG_EX(stack, EX_VAR_TO_NUM(opline->result.var), ra[ssa_op->result_def]->reg,
6536 ra[ssa_op->result_def]->flags & ZREG_STORE);
6537 }
6538 }
6539 ssa_op++;
6540 opline++;
6541 }
6542 break;
6543 case ZEND_BIND_GLOBAL:
6544 ssa_op++;
6545 opline++;
6546 while (opline->opcode == ZEND_BIND_GLOBAL) {
6547 if (ssa_op->op1_def >= 0) {
6548 zend_uchar type = IS_UNKNOWN;
6549
6550 if (!(ssa->var_info[ssa_op->op1_def].type & MAY_BE_GUARD)
6551 && has_concrete_type(ssa->var_info[ssa_op->op1_def].type)) {
6552 type = concrete_type(ssa->var_info[ssa_op->op1_def].type);
6553 }
6554 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var), type,
6555 (gen_handler || !ra || !ra[ssa_op->op1_def]));
6556 if (ra && ra[ssa_op->op1_def]) {
6557 SET_STACK_REG_EX(stack, EX_VAR_TO_NUM(opline->op1.var), ra[ssa_op->op1_def]->reg,
6558 ra[ssa_op->op1_def]->flags & ZREG_STORE);
6559 }
6560 }
6561 ssa_op++;
6562 opline++;
6563 }
6564 break;
6565 default:
6566 ssa_op += zend_jit_trace_op_len(opline);
6567 break;
6568 }
6569
6570 if (send_result) {
6571 ssa_op++;
6572 p++;
6573 if ((p+1)->op == ZEND_JIT_TRACE_OP1_TYPE) {
6574 p++;
6575 }
6576 send_result = 0;
6577 }
6578 }
6579 } else if (p->op == ZEND_JIT_TRACE_ENTER) {
6580 call = frame->call;
6581 assert(call && &call->func->op_array == p->op_array);
6582
6583 if (opline->opcode == ZEND_DO_UCALL
6584 || opline->opcode == ZEND_DO_FCALL_BY_NAME
6585 || opline->opcode == ZEND_DO_FCALL) {
6586
6587 frame->call_opline = opline;
6588
6589 /* Check if SEND_UNPACK/SEND_ARRAY may cause enter at different opline */
6590 if (opline > op_array->opcodes) {
6591 const zend_op *prev_opline = opline - 1;
6592
6593 while (prev_opline->opcode == ZEND_EXT_FCALL_BEGIN || prev_opline->opcode == ZEND_TICKS) {
6594 prev_opline--;
6595 }
6596 JIT_G(current_frame) = call;
6597 if ((prev_opline->opcode == ZEND_SEND_ARRAY
6598 || prev_opline->opcode == ZEND_SEND_UNPACK
6599 || prev_opline->opcode == ZEND_CHECK_UNDEF_ARGS)
6600 && p->op_array->num_args
6601 && (p->op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0
6602 && ((p+1)->op == ZEND_JIT_TRACE_VM
6603 || (p+1)->op == ZEND_JIT_TRACE_END)
6604 && (TRACE_FRAME_NUM_ARGS(call) < 0
6605 || TRACE_FRAME_NUM_ARGS(call) < p->op_array->num_args)
6606 && !zend_jit_trace_opline_guard(&dasm_state, (p+1)->opline)) {
6607 goto jit_failure;
6608 }
6609 JIT_G(current_frame) = frame;
6610 }
6611 }
6612
6613 if ((p+1)->op == ZEND_JIT_TRACE_END) {
6614 p++;
6615 break;
6616 }
6617 if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
6618 if (TRACE_FRAME_IS_THIS_CHECKED(frame)) {
6619 TRACE_FRAME_SET_THIS_CHECKED(call);
6620 }
6621 } else if (op_array->scope && !(op_array->fn_flags & ZEND_ACC_STATIC)) {
6622 TRACE_FRAME_SET_THIS_CHECKED(call);
6623 }
6624 op_array = (zend_op_array*)p->op_array;
6625 jit_extension =
6626 (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
6627 op_array_ssa = &jit_extension->func_info.ssa;
6628 frame->call = call->prev;
6629 call->prev = frame;
6630 if (p->info & ZEND_JIT_TRACE_RETURN_VALUE_USED) {
6631 TRACE_FRAME_SET_RETURN_VALUE_USED(call);
6632 } else {
6633 TRACE_FRAME_SET_RETURN_VALUE_UNUSED(call);
6634 }
6635 JIT_G(current_frame) = frame = call;
6636 stack = frame->stack;
6637 if (ra) {
6638 int j = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
6639
6640 for (i = 0; i < op_array->last_var; i++,j++) {
6641 if (ra[j] && (ra[j]->flags & ZREG_LOAD) != 0) {
6642 SET_STACK_REG_EX(stack, i, ra[j]->reg, ZREG_LOAD);
6643 if (!zend_jit_load_var(&dasm_state, ssa->var_info[j].type, i, ra[j]->reg)) {
6644 goto jit_failure;
6645 }
6646 }
6647 }
6648 }
6649 } else if (p->op == ZEND_JIT_TRACE_BACK) {
6650 op_array = (zend_op_array*)p->op_array;
6651 jit_extension =
6652 (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
6653 op_array_ssa = &jit_extension->func_info.ssa;
6654 top = frame;
6655 if (frame->prev) {
6656 checked_stack = frame->old_checked_stack;
6657 peek_checked_stack = frame->old_peek_checked_stack;
6658 frame = frame->prev;
6659 stack = frame->stack;
6660 ZEND_ASSERT(&frame->func->op_array == op_array);
6661 } else {
6662 frame = zend_jit_trace_ret_frame(frame, op_array);
6663 TRACE_FRAME_INIT(frame, op_array, TRACE_FRAME_MASK_UNKNOWN_RETURN, -1);
6664 frame->used_stack = checked_stack = peek_checked_stack = 0;
6665 stack = frame->stack;
6666 if (JIT_G(opt_level) >= ZEND_JIT_LEVEL_INLINE) {
6667 uint32_t j = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
6668
6669 for (i = 0; i < op_array->last_var + op_array->T; i++, j++) {
6670 /* Initialize abstract stack using SSA */
6671 if (!(ssa->var_info[j].type & MAY_BE_GUARD)
6672 && has_concrete_type(ssa->var_info[j].type)) {
6673 SET_STACK_TYPE(stack, i, concrete_type(ssa->var_info[j].type), 1);
6674 } else {
6675 SET_STACK_TYPE(stack, i, IS_UNKNOWN, 1);
6676 }
6677 }
6678 if (ra) {
6679 j = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
6680 for (i = 0; i < op_array->last_var + op_array->T; i++, j++) {
6681 if (ra[j] && (ra[j]->flags & ZREG_LOAD) != 0) {
6682 SET_STACK_REG_EX(stack, i, ra[j]->reg, ZREG_LOAD);
6683 if (!zend_jit_load_var(&dasm_state, ssa->var_info[j].type, i, ra[j]->reg)) {
6684 goto jit_failure;
6685 }
6686 }
6687 }
6688 }
6689 } else {
6690 for (i = 0; i < op_array->last_var + op_array->T; i++) {
6691 SET_STACK_TYPE(stack, i, IS_UNKNOWN, 1);
6692 }
6693 }
6694 opline = NULL;
6695 }
6696 JIT_G(current_frame) = frame;
6697 if (res_type != IS_UNKNOWN
6698 && (p+1)->op == ZEND_JIT_TRACE_VM) {
6699 const zend_op *opline = (p+1)->opline - 1;
6700 if (opline->result_type != IS_UNUSED) {
6701 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), res_type, 1);
6702 }
6703 }
6704 res_type = IS_UNKNOWN;
6705 } else if (p->op == ZEND_JIT_TRACE_END) {
6706 break;
6707 } else if (p->op == ZEND_JIT_TRACE_INIT_CALL) {
6708 const zend_op *init_opline = zend_jit_trace_find_init_fcall_op(p, op_array);
6709 int num_args = -1;
6710
6711 if (init_opline
6712 && init_opline->extended_value <= TRACE_FRAME_MAX_NUM_ARGS) {
6713 num_args = init_opline->extended_value;
6714 }
6715
6716 call = top;
6717 TRACE_FRAME_INIT(call, p->func, frame_flags, num_args);
6718 call->prev = frame->call;
6719 if (!(p->info & ZEND_JIT_TRACE_FAKE_INIT_CALL)) {
6720 TRACE_FRAME_SET_LAST_SEND_BY_VAL(call);
6721 }
6722 if (init_opline
6723 && init_opline->opcode != ZEND_NEW
6724 && (init_opline->opcode != ZEND_INIT_METHOD_CALL
6725 || init_opline->op1_type == IS_UNDEF)
6726 && (init_opline->opcode != ZEND_INIT_USER_CALL
6727 || (p->func && (!p->func->common.scope || (p->func->common.fn_flags & ZEND_ACC_STATIC))))
6728 && (init_opline->opcode != ZEND_INIT_DYNAMIC_CALL
6729 || (p->func && (!p->func->common.scope || (p->func->common.fn_flags & ZEND_ACC_STATIC))))
6730 ) {
6731 TRACE_FRAME_SET_NO_NEED_RELEASE_THIS(call);
6732 }
6733 frame->call = call;
6734 top = zend_jit_trace_call_frame(top, p->op_array);
6735 if (p->func) {
6736 if (p->func->type == ZEND_USER_FUNCTION) {
6737 if (JIT_G(opt_level) >= ZEND_JIT_LEVEL_INLINE) {
6738 zend_jit_op_array_trace_extension *jit_extension =
6739 (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(p->op_array);
6740
6741 i = 0;
6742 while (i < p->op_array->num_args) {
6743 /* Types of arguments are going to be stored in abstract stack when processing SEV instruction */
6744 SET_STACK_TYPE(call->stack, i, IS_UNKNOWN, 1);
6745 i++;
6746 }
6747 while (i < p->op_array->last_var) {
6748 if (jit_extension
6749 && zend_jit_var_may_alias(p->op_array, &jit_extension->func_info.ssa, i) != NO_ALIAS) {
6750 SET_STACK_TYPE(call->stack, i, IS_UNKNOWN, 1);
6751 } else {
6752 SET_STACK_TYPE(call->stack, i, IS_UNDEF, 1);
6753 }
6754 i++;
6755 }
6756 while (i < p->op_array->last_var + p->op_array->T) {
6757 SET_STACK_TYPE(call->stack, i, IS_UNKNOWN, 1);
6758 i++;
6759 }
6760 } else {
6761 for (i = 0; i < p->op_array->last_var + p->op_array->T; i++) {
6762 SET_STACK_TYPE(call->stack, i, IS_UNKNOWN, 1);
6763 }
6764 }
6765 } else {
6766 ZEND_ASSERT(p->func->type == ZEND_INTERNAL_FUNCTION);
6767 for (i = 0; i < p->op_array->num_args; i++) {
6768 SET_STACK_TYPE(call->stack, i, IS_UNKNOWN, 1);
6769 }
6770 }
6771 if (p->info & ZEND_JIT_TRACE_FAKE_INIT_CALL) {
6772 int skip_guard = 0;
6773
6774 if (init_opline) {
6775 zend_call_info *call_info = jit_extension->func_info.callee_info;
6776
6777 while (call_info) {
6778 if (call_info->caller_init_opline == init_opline
6779 && !call_info->is_prototype) {
6780 if (op_array->fn_flags & ZEND_ACC_TRAIT_CLONE) {
6781 if (init_opline->opcode == ZEND_INIT_STATIC_METHOD_CALL
6782 && init_opline->op1_type != IS_CONST) {
6783 break;
6784 } else if (init_opline->opcode == ZEND_INIT_METHOD_CALL) {
6785 break;
6786 }
6787 }
6788 skip_guard = 1;
6789 break;
6790 }
6791 call_info = call_info->next_callee;
6792 }
6793 if (!skip_guard
6794 && !zend_jit_may_be_polymorphic_call(init_opline)
6795 && !zend_jit_may_be_modified(p->func, op_array)) {
6796 skip_guard = 1;
6797 }
6798 }
6799
6800 if (!skip_guard) {
6801 if (!opline) {
6802 zend_jit_trace_rec *q = p + 1;
6803 while (q->op != ZEND_JIT_TRACE_VM && q->op != ZEND_JIT_TRACE_END) {
6804 q++;
6805 }
6806 opline = q->opline;
6807 ZEND_ASSERT(opline != NULL);
6808 }
6809 if (!zend_jit_init_fcall_guard(&dasm_state,
6810 ZEND_JIT_TRACE_FAKE_LEVEL(p->info), p->func, opline)) {
6811 goto jit_failure;
6812 }
6813 }
6814 }
6815 }
6816 call->old_checked_stack = checked_stack;
6817 call->old_peek_checked_stack = peek_checked_stack;
6818 if (p->info & ZEND_JIT_TRACE_FAKE_INIT_CALL) {
6819 frame->call_level++;
6820 call->used_stack = checked_stack = peek_checked_stack = 0;
6821 } else {
6822 if (p->func) {
6823 call->used_stack = zend_vm_calc_used_stack(init_opline->extended_value, (zend_function*)p->func);
6824 } else {
6825 call->used_stack = (ZEND_CALL_FRAME_SLOT + init_opline->extended_value) * sizeof(zval);
6826 }
6827 switch (init_opline->opcode) {
6828 case ZEND_INIT_FCALL:
6829 case ZEND_INIT_FCALL_BY_NAME:
6830 case ZEND_INIT_NS_FCALL_BY_NAME:
6831 case ZEND_INIT_METHOD_CALL:
6832 case ZEND_INIT_DYNAMIC_CALL:
6833 //case ZEND_INIT_STATIC_METHOD_CALL:
6834 //case ZEND_INIT_USER_CALL:
6835 //case ZEND_NEW:
6836 checked_stack += call->used_stack;
6837 if (checked_stack > peek_checked_stack) {
6838 peek_checked_stack = checked_stack;
6839 }
6840 break;
6841 default:
6842 checked_stack = peek_checked_stack = 0;
6843 }
6844 }
6845 } else if (p->op == ZEND_JIT_TRACE_DO_ICALL) {
6846 call = frame->call;
6847 if (call) {
6848 checked_stack = call->old_checked_stack;
6849 peek_checked_stack = call->old_peek_checked_stack;
6850 top = call;
6851 frame->call = call->prev;
6852 }
6853 } else {
6854 ZEND_UNREACHABLE();
6855 }
6856 }
6857
6858 ZEND_ASSERT(p->op == ZEND_JIT_TRACE_END);
6859
6860 t = &zend_jit_traces[ZEND_JIT_TRACE_NUM];
6861
6862 if (!parent_trace && zend_jit_trace_uses_initial_ip()) {
6863 t->flags |= ZEND_JIT_TRACE_USES_INITIAL_IP;
6864 }
6865
6866 if (p->stop == ZEND_JIT_TRACE_STOP_LOOP
6867 || p->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
6868 || p->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
6869 if (ra) {
6870 zend_ssa_phi *phi = ssa->blocks[1].phis;
6871
6872 while (phi) {
6873 if (ra[phi->ssa_var]
6874 && ra[phi->sources[1]]
6875 && STACK_MEM_TYPE(stack, phi->var) != STACK_TYPE(stack, phi->var)
6876 && (ra[phi->ssa_var]->flags & (ZREG_LOAD|ZREG_STORE)) == 0
6877 && (ra[phi->sources[1]]->flags & (ZREG_LOAD|ZREG_STORE)) == 0) {
6878 /* Store actual type to memory to avoid deoptimization mistakes */
6879 /* TODO: Alternatively, we may try to update alredy generated deoptimization info */
6880 zend_jit_store_var_type(&dasm_state, phi->var, STACK_TYPE(stack, phi->var));
6881 }
6882 phi = phi->next;
6883 }
6884 }
6885 if (p->stop != ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
6886 if ((t->flags & ZEND_JIT_TRACE_USES_INITIAL_IP)
6887 && !zend_jit_set_ip(&dasm_state, p->opline)) {
6888 goto jit_failure;
6889 }
6890 }
6891 t->link = ZEND_JIT_TRACE_NUM;
6892 if (p->stop != ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
6893 t->flags |= ZEND_JIT_TRACE_CHECK_INTERRUPT;
6894 }
6895 if (!(t->flags & ZEND_JIT_TRACE_LOOP)) {
6896 const void *timeout_exit_addr = NULL;
6897
6898 t->flags |= ZEND_JIT_TRACE_LOOP;
6899
6900 if (trace_buffer->stop != ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
6901 if (!(t->flags & ZEND_JIT_TRACE_USES_INITIAL_IP)
6902 || (ra
6903 && zend_jit_trace_stack_needs_deoptimization(stack, op_array->last_var + op_array->T))) {
6904 /* Deoptimize to the first instruction of the loop */
6905 uint32_t exit_point = zend_jit_trace_get_exit_point(trace_buffer[1].opline, ZEND_JIT_EXIT_TO_VM);
6906
6907 timeout_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
6908 if (!timeout_exit_addr) {
6909 goto jit_failure;
6910 }
6911 } else {
6912 timeout_exit_addr = dasm_labels[zend_lbinterrupt_handler];
6913 }
6914 }
6915
6916 zend_jit_trace_end_loop(&dasm_state, 0, timeout_exit_addr); /* jump back to start of the trace loop */
6917 }
6918 } else if (p->stop == ZEND_JIT_TRACE_STOP_LINK
6919 || p->stop == ZEND_JIT_TRACE_STOP_INTERPRETER) {
6920 if (ra
6921 && (p-1)->op != ZEND_JIT_TRACE_ENTER
6922 && (p-1)->op != ZEND_JIT_TRACE_BACK
6923 && opline->opcode != ZEND_DO_UCALL
6924 && opline->opcode != ZEND_DO_FCALL
6925 && opline->opcode != ZEND_DO_FCALL_BY_NAME
6926 && opline->opcode != ZEND_INCLUDE_OR_EVAL) {
6927 if (!zend_jit_trace_deoptimization(&dasm_state, 0, NULL,
6928 stack, op_array->last_var + op_array->T, NULL, NULL, NULL, 0)) {
6929 goto jit_failure;
6930 }
6931 for (i = 0; i < op_array->last_var; i++) {
6932 int8_t reg = STACK_REG(stack, i);
6933 uint8_t type = STACK_TYPE(stack, i);
6934
6935 if (reg == ZREG_NONE
6936 && type != IS_UNKNOWN
6937 && type != STACK_MEM_TYPE(stack, i)) {
6938 if (!zend_jit_store_var_type(&dasm_state, i, type)) {
6939 return 0;
6940 }
6941 SET_STACK_TYPE(stack, i, type, 1);
6942 }
6943 }
6944 }
6945 if (p->stop == ZEND_JIT_TRACE_STOP_LINK) {
6946 const void *timeout_exit_addr = NULL;
6947
6948 t->link = zend_jit_find_trace(p->opline->handler);
6949 if (t->link == 0) {
6950 /* this can happen if ZEND_JIT_EXIT_INVALIDATE was handled
6951 * by zend_jit_trace_exit() in another thread after this
6952 * thread set ZEND_JIT_TRACE_STOP_LINK in zend_jit_trace_execute();
6953 * ZEND_JIT_EXIT_INVALIDATE resets the opline handler to one of
6954 * the "_counter_handler" functions, and these are not registered
6955 * tracer functions */
6956 goto jit_failure;
6957 }
6958 if ((zend_jit_traces[t->link].flags & ZEND_JIT_TRACE_USES_INITIAL_IP)
6959 && !zend_jit_set_ip(&dasm_state, p->opline)) {
6960 goto jit_failure;
6961 }
6962 if (!parent_trace && zend_jit_trace_uses_initial_ip()) {
6963 t->flags |= ZEND_JIT_TRACE_USES_INITIAL_IP;
6964 }
6965 if (parent_trace
6966 && (zend_jit_traces[t->link].flags & ZEND_JIT_TRACE_CHECK_INTERRUPT)
6967 && zend_jit_traces[parent_trace].root == t->link) {
6968 if (!(zend_jit_traces[t->link].flags & ZEND_JIT_TRACE_USES_INITIAL_IP)) {
6969 uint32_t exit_point;
6970
6971 for (i = 0; i < op_array->last_var + op_array->T; i++) {
6972 SET_STACK_TYPE(stack, i, IS_UNKNOWN, 1);
6973 }
6974 exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
6975 timeout_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
6976 if (!timeout_exit_addr) {
6977 goto jit_failure;
6978 }
6979 } else {
6980 timeout_exit_addr = dasm_labels[zend_lbinterrupt_handler];
6981 }
6982 }
6983 zend_jit_trace_link_to_root(&dasm_state, &zend_jit_traces[t->link], timeout_exit_addr);
6984 } else {
6985 zend_jit_trace_return(&dasm_state, 0, NULL);
6986 }
6987 } else if (p->stop == ZEND_JIT_TRACE_STOP_RETURN) {
6988 zend_jit_trace_return(&dasm_state, 0, NULL);
6989 } else {
6990 // TODO: not implemented ???
6991 ZEND_ASSERT(0 && p->stop);
6992 }
6993
6994 if (ZEND_JIT_EXIT_COUNTERS + t->exit_count >= JIT_G(max_exit_counters)) {
6995 goto jit_failure;
6996 }
6997
6998 if (!zend_jit_trace_end(&dasm_state, t)) {
6999 goto jit_failure;
7000 }
7001
7002 handler = dasm_link_and_encode(&dasm_state, NULL, NULL, NULL, NULL, ZSTR_VAL(name), ZEND_JIT_TRACE_NUM,
7003 parent_trace ? SP_ADJ_JIT : ((zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) ? SP_ADJ_VM : SP_ADJ_RET),
7004 parent_trace ? SP_ADJ_NONE : SP_ADJ_JIT);
7005
7006 if (handler) {
7007 if (p->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL) {
7008 const zend_op_array *rec_op_array;
7009
7010 rec_op_array = op_array = trace_buffer->op_array;
7011 jit_extension =
7012 (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
7013 p = trace_buffer + ZEND_JIT_TRACE_START_REC_SIZE;
7014 for (;;p++) {
7015 if (p->op == ZEND_JIT_TRACE_VM) {
7016 opline = p->opline;
7017 } else if (p->op == ZEND_JIT_TRACE_ENTER) {
7018 if (p->op_array == rec_op_array) {
7019 zend_jit_trace_setup_ret_counter(opline, jit_extension->offset);
7020 }
7021 op_array = p->op_array;
7022 jit_extension =
7023 (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
7024 } else if (p->op == ZEND_JIT_TRACE_BACK) {
7025 op_array = p->op_array;
7026 jit_extension =
7027 (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
7028 } else if (p->op == ZEND_JIT_TRACE_END) {
7029 break;
7030 }
7031 }
7032 } else if (p->stop == ZEND_JIT_TRACE_STOP_LINK
7033 || p->stop == ZEND_JIT_TRACE_STOP_INTERPRETER) {
7034 if (opline
7035 && (opline->opcode == ZEND_DO_UCALL
7036 || opline->opcode == ZEND_DO_FCALL
7037 || opline->opcode == ZEND_DO_FCALL_BY_NAME
7038 || opline->opcode == ZEND_YIELD
7039 || opline->opcode == ZEND_YIELD_FROM
7040 || opline->opcode == ZEND_INCLUDE_OR_EVAL)) {
7041 zend_jit_trace_setup_ret_counter(opline, jit_extension->offset);
7042 }
7043 if (JIT_G(current_frame)
7044 && JIT_G(current_frame)->prev) {
7045 frame = JIT_G(current_frame)->prev;
7046 do {
7047 if (frame->call_opline) {
7048 op_array = &frame->func->op_array;
7049 jit_extension =
7050 (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
7051 zend_jit_trace_setup_ret_counter(frame->call_opline, jit_extension->offset);
7052 }
7053 frame = frame->prev;
7054 } while (frame);
7055 }
7056 }
7057 }
7058
7059 jit_failure:
7060 dasm_free(&dasm_state);
7061
7062 if (name) {
7063 zend_string_release(name);
7064 }
7065
7066 jit_cleanup:
7067 /* Clean up used op_arrays */
7068 while (num_op_arrays > 0) {
7069 op_array = op_arrays[--num_op_arrays];
7070 jit_extension =
7071 (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
7072
7073 jit_extension->func_info.num = 0;
7074 jit_extension->func_info.flags &= ZEND_FUNC_JIT_ON_FIRST_EXEC
7075 | ZEND_FUNC_JIT_ON_PROF_REQUEST
7076 | ZEND_FUNC_JIT_ON_HOT_COUNTERS
7077 | ZEND_FUNC_JIT_ON_HOT_TRACE;
7078 memset(&jit_extension->func_info.ssa, 0, sizeof(zend_func_info) - offsetof(zend_func_info, ssa));
7079 }
7080
7081 zend_arena_release(&CG(arena), checkpoint);
7082
7083 JIT_G(current_frame) = NULL;
7084 JIT_G(current_trace) = NULL;
7085
7086 return handler;
7087 }
7088
zend_jit_trace_exit_to_vm(uint32_t trace_num,uint32_t exit_num)7089 static const void *zend_jit_trace_exit_to_vm(uint32_t trace_num, uint32_t exit_num)
7090 {
7091 const void *handler = NULL;
7092 dasm_State* dasm_state = NULL;
7093 void *checkpoint;
7094 char name[32];
7095 const zend_op *opline;
7096 uint32_t stack_size;
7097 zend_jit_trace_stack *stack;
7098 bool original_handler = 0;
7099
7100 if (!zend_jit_trace_exit_needs_deoptimization(trace_num, exit_num)) {
7101 return dasm_labels[zend_lbtrace_escape];
7102 }
7103
7104 checkpoint = zend_arena_checkpoint(CG(arena));;
7105
7106 sprintf(name, "ESCAPE-%d-%d", trace_num, exit_num);
7107
7108 dasm_init(&dasm_state, DASM_MAXSECTION);
7109 dasm_setupglobal(&dasm_state, dasm_labels, zend_lb_MAX);
7110 dasm_setup(&dasm_state, dasm_actions);
7111
7112 zend_jit_align_func(&dasm_state);
7113
7114 /* Deoptimization */
7115 stack_size = zend_jit_traces[trace_num].exit_info[exit_num].stack_size;
7116 stack = zend_jit_traces[trace_num].stack_map + zend_jit_traces[trace_num].exit_info[exit_num].stack_offset;
7117
7118 if (!zend_jit_trace_deoptimization(&dasm_state,
7119 zend_jit_traces[trace_num].exit_info[exit_num].flags,
7120 zend_jit_traces[trace_num].exit_info[exit_num].opline,
7121 stack, stack_size, NULL, NULL, NULL, 0)) {
7122 goto jit_failure;
7123 }
7124
7125 opline = zend_jit_traces[trace_num].exit_info[exit_num].opline;
7126 if (opline) {
7127 if (opline == zend_jit_traces[zend_jit_traces[trace_num].root].opline) {
7128 /* prevent endless loop */
7129 original_handler = 1;
7130 }
7131 zend_jit_set_ip_ex(&dasm_state, opline, original_handler);
7132 }
7133
7134 zend_jit_trace_return(&dasm_state, original_handler, opline);
7135
7136 handler = dasm_link_and_encode(&dasm_state, NULL, NULL, NULL, NULL, name, ZEND_JIT_TRACE_NUM, SP_ADJ_JIT, SP_ADJ_NONE);
7137
7138 jit_failure:
7139 dasm_free(&dasm_state);
7140 zend_arena_release(&CG(arena), checkpoint);
7141 return handler;
7142 }
7143
zend_jit_compile_root_trace(zend_jit_trace_rec * trace_buffer,const zend_op * opline,size_t offset)7144 static zend_jit_trace_stop zend_jit_compile_root_trace(zend_jit_trace_rec *trace_buffer, const zend_op *opline, size_t offset)
7145 {
7146 zend_jit_trace_stop ret;
7147 const void *handler;
7148 uint8_t orig_trigger;
7149 zend_jit_trace_info *t = NULL;
7150 zend_jit_trace_exit_info exit_info[ZEND_JIT_TRACE_MAX_EXITS];
7151 bool do_bailout = 0;
7152
7153 zend_shared_alloc_lock();
7154
7155 /* Checks under lock */
7156 if ((ZEND_OP_TRACE_INFO(opline, offset)->trace_flags & ZEND_JIT_TRACE_JITED)) {
7157 ret = ZEND_JIT_TRACE_STOP_ALREADY_DONE;
7158 } else if (ZEND_JIT_TRACE_NUM >= JIT_G(max_root_traces)) {
7159 ret = ZEND_JIT_TRACE_STOP_TOO_MANY_TRACES;
7160 } else {
7161 zend_try {
7162 SHM_UNPROTECT();
7163 zend_jit_unprotect();
7164
7165 t = &zend_jit_traces[ZEND_JIT_TRACE_NUM];
7166
7167 t->id = ZEND_JIT_TRACE_NUM;
7168 t->root = ZEND_JIT_TRACE_NUM;
7169 t->parent = 0;
7170 t->link = 0;
7171 t->exit_count = 0;
7172 t->child_count = 0;
7173 t->stack_map_size = 0;
7174 t->flags = 0;
7175 t->polymorphism = 0;
7176 t->jmp_table_size = 0;
7177 t->op_array = trace_buffer[0].op_array;
7178 t->opline = trace_buffer[1].opline;
7179 t->exit_info = exit_info;
7180 t->stack_map = NULL;
7181
7182 orig_trigger = JIT_G(trigger);
7183 JIT_G(trigger) = ZEND_JIT_ON_HOT_TRACE;
7184
7185 handler = zend_jit_trace(trace_buffer, 0, 0);
7186
7187 JIT_G(trigger) = orig_trigger;
7188
7189 if (handler) {
7190 zend_jit_trace_exit_info *shared_exit_info = NULL;
7191
7192 t->exit_info = NULL;
7193 if (t->exit_count) {
7194 /* reallocate exit_info into shared memory */
7195 shared_exit_info = (zend_jit_trace_exit_info*)zend_shared_alloc(
7196 sizeof(zend_jit_trace_exit_info) * t->exit_count);
7197
7198 if (!shared_exit_info) {
7199 if (t->stack_map) {
7200 efree(t->stack_map);
7201 t->stack_map = NULL;
7202 }
7203 ret = ZEND_JIT_TRACE_STOP_NO_SHM;
7204 goto exit;
7205 }
7206 memcpy(shared_exit_info, exit_info,
7207 sizeof(zend_jit_trace_exit_info) * t->exit_count);
7208 t->exit_info = shared_exit_info;
7209 }
7210
7211 if (t->stack_map_size) {
7212 zend_jit_trace_stack *shared_stack_map = (zend_jit_trace_stack*)zend_shared_alloc(t->stack_map_size * sizeof(zend_jit_trace_stack));
7213 if (!shared_stack_map) {
7214 efree(t->stack_map);
7215 ret = ZEND_JIT_TRACE_STOP_NO_SHM;
7216 goto exit;
7217 }
7218 memcpy(shared_stack_map, t->stack_map, t->stack_map_size * sizeof(zend_jit_trace_stack));
7219 efree(t->stack_map);
7220 t->stack_map = shared_stack_map;
7221 }
7222
7223 t->exit_counters = ZEND_JIT_EXIT_COUNTERS;
7224 ZEND_JIT_EXIT_COUNTERS += t->exit_count;
7225
7226 ((zend_op*)opline)->handler = handler;
7227
7228 ZEND_JIT_TRACE_NUM++;
7229 ZEND_OP_TRACE_INFO(opline, offset)->trace_flags |= ZEND_JIT_TRACE_JITED;
7230
7231 ret = ZEND_JIT_TRACE_STOP_COMPILED;
7232 } else if (t->exit_count >= ZEND_JIT_TRACE_MAX_EXITS ||
7233 ZEND_JIT_EXIT_COUNTERS + t->exit_count >= JIT_G(max_exit_counters)) {
7234 if (t->stack_map) {
7235 efree(t->stack_map);
7236 t->stack_map = NULL;
7237 }
7238 ret = ZEND_JIT_TRACE_STOP_TOO_MANY_EXITS;
7239 } else {
7240 if (t->stack_map) {
7241 efree(t->stack_map);
7242 t->stack_map = NULL;
7243 }
7244 ret = ZEND_JIT_TRACE_STOP_COMPILER_ERROR;
7245 }
7246
7247 exit:;
7248 } zend_catch {
7249 do_bailout = 1;
7250 } zend_end_try();
7251
7252 zend_jit_protect();
7253 SHM_PROTECT();
7254 }
7255
7256 zend_shared_alloc_unlock();
7257
7258 if (do_bailout) {
7259 zend_bailout();
7260 }
7261
7262 if ((JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_EXIT_INFO) != 0
7263 && ret == ZEND_JIT_TRACE_STOP_COMPILED
7264 && t->exit_count > 0) {
7265 zend_jit_dump_exit_info(t);
7266 }
7267
7268 return ret;
7269 }
7270
zend_jit_blacklist_root_trace(const zend_op * opline,size_t offset)7271 static void zend_jit_blacklist_root_trace(const zend_op *opline, size_t offset)
7272 {
7273 zend_shared_alloc_lock();
7274
7275 if (!(ZEND_OP_TRACE_INFO(opline, offset)->trace_flags & ZEND_JIT_TRACE_BLACKLISTED)) {
7276 SHM_UNPROTECT();
7277 zend_jit_unprotect();
7278
7279 ((zend_op*)opline)->handler =
7280 ZEND_OP_TRACE_INFO(opline, offset)->orig_handler;
7281
7282 ZEND_OP_TRACE_INFO(opline, offset)->trace_flags |= ZEND_JIT_TRACE_BLACKLISTED;
7283
7284 zend_jit_protect();
7285 SHM_PROTECT();
7286 }
7287
7288 zend_shared_alloc_unlock();
7289 }
7290
zend_jit_trace_is_bad_root(const zend_op * opline,zend_jit_trace_stop stop,size_t offset)7291 static bool zend_jit_trace_is_bad_root(const zend_op *opline, zend_jit_trace_stop stop, size_t offset)
7292 {
7293 const zend_op **cache_opline = JIT_G(bad_root_cache_opline);
7294 uint8_t *cache_count = JIT_G(bad_root_cache_count);
7295 uint8_t *cache_stop = JIT_G(bad_root_cache_stop);
7296 uint32_t cache_slot = JIT_G(bad_root_slot);
7297 uint32_t i;
7298
7299 for (i = 0; i < ZEND_JIT_TRACE_BAD_ROOT_SLOTS; i++) {
7300 if (cache_opline[i] == opline) {
7301 if (cache_count[i] >= JIT_G(blacklist_root_trace) - 1) {
7302 cache_opline[i] = NULL;
7303 return 1;
7304 } else {
7305 #if 0
7306 if (ZEND_OP_TRACE_INFO(opline, offset)->counter) {
7307 *ZEND_OP_TRACE_INFO(opline, offset)->counter =
7308 random() % ZEND_JIT_TRACE_COUNTER_MAX;
7309 }
7310 #endif
7311 cache_count[i]++;
7312 cache_stop[i] = stop;
7313 return 0;
7314 }
7315 }
7316 }
7317 i = cache_slot;
7318 cache_opline[i] = opline;
7319 cache_count[i] = 1;
7320 cache_stop[i] = stop;
7321 cache_slot = (i + 1) % ZEND_JIT_TRACE_BAD_ROOT_SLOTS;
7322 JIT_G(bad_root_slot) = cache_slot;
7323 return 0;
7324 }
7325
zend_jit_dump_trace(zend_jit_trace_rec * trace_buffer,zend_ssa * tssa)7326 static void zend_jit_dump_trace(zend_jit_trace_rec *trace_buffer, zend_ssa *tssa)
7327 {
7328 zend_jit_trace_rec *p = trace_buffer;
7329 const zend_op_array *op_array;
7330 const zend_op *opline;
7331 uint32_t level = 1 + trace_buffer[0].level;
7332 int idx, len, i, v, vars_count, call_level;
7333
7334 ZEND_ASSERT(p->op == ZEND_JIT_TRACE_START);
7335 op_array = p->op_array;
7336 p += ZEND_JIT_TRACE_START_REC_SIZE;
7337 idx = 0;
7338 call_level = 0;
7339
7340 if (tssa && tssa->var_info) {
7341 if (trace_buffer->start == ZEND_JIT_TRACE_START_ENTER) {
7342 vars_count = op_array->last_var;
7343 } else {
7344 vars_count = op_array->last_var + op_array->T;
7345 }
7346 for (i = 0; i < vars_count; i++) {
7347 if (tssa->vars[i].use_chain >= 0 || tssa->vars[i].phi_use_chain) {
7348 fprintf(stderr, " %*c;", level, ' ');
7349 zend_dump_ssa_var(op_array, tssa, i, 0, i, ZEND_DUMP_RC_INFERENCE);
7350 fprintf(stderr, "\n");
7351 }
7352 }
7353 if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
7354 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
7355 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
7356 zend_ssa_phi *p = tssa->blocks[1].phis;
7357
7358 fprintf(stderr, "LOOP:\n");
7359
7360 while (p) {
7361 fprintf(stderr, " ;");
7362 zend_dump_ssa_var(op_array, tssa, p->ssa_var, 0, p->var, ZEND_DUMP_RC_INFERENCE);
7363 fprintf(stderr, " = Phi(");
7364 zend_dump_ssa_var(op_array, tssa, p->sources[0], 0, p->var, ZEND_DUMP_RC_INFERENCE);
7365 fprintf(stderr, ", ");
7366 zend_dump_ssa_var(op_array, tssa, p->sources[1], 0, p->var, ZEND_DUMP_RC_INFERENCE);
7367 fprintf(stderr, ")\n");
7368 p = p->next;
7369 }
7370 }
7371 }
7372
7373 while (1) {
7374 if (p->op == ZEND_JIT_TRACE_VM) {
7375 uint8_t op1_type, op2_type, op3_type;
7376
7377 opline = p->opline;
7378 fprintf(stderr, "%04d%*c",
7379 (int)(opline - op_array->opcodes),
7380 level, ' ');
7381 zend_dump_op(op_array, NULL, opline, ZEND_DUMP_RC_INFERENCE, tssa, (tssa && tssa->ops) ? tssa->ops + idx : NULL);
7382
7383 op1_type = p->op1_type;
7384 op2_type = p->op2_type;
7385 op3_type = p->op3_type;
7386 if (op1_type != IS_UNKNOWN || op2_type != IS_UNKNOWN || op3_type != IS_UNKNOWN) {
7387 fprintf(stderr, " ;");
7388 if (op1_type != IS_UNKNOWN) {
7389 const char *ref = (op1_type & IS_TRACE_INDIRECT) ?
7390 ((op1_type & IS_TRACE_REFERENCE) ? "*&" : "*") :
7391 ((op1_type & IS_TRACE_REFERENCE) ? "&" : "");
7392 if ((p+1)->op == ZEND_JIT_TRACE_OP1_TYPE) {
7393 p++;
7394 fprintf(stderr, " op1(%sobject of class %s)", ref,
7395 ZSTR_VAL(p->ce->name));
7396 } else {
7397 const char *type = ((op1_type & ~IS_TRACE_INDIRECT) == 0) ? "undef" : zend_get_type_by_const(op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED));
7398 fprintf(stderr, " op1(%s%s%s)", ref, (op1_type & IS_TRACE_PACKED) ? "packed " : "", type);
7399 }
7400 }
7401 if (op2_type != IS_UNKNOWN) {
7402 const char *ref = (op2_type & IS_TRACE_INDIRECT) ?
7403 ((op2_type & IS_TRACE_REFERENCE) ? "*&" : "*") :
7404 ((op2_type & IS_TRACE_REFERENCE) ? "&" : "");
7405 if ((p+1)->op == ZEND_JIT_TRACE_OP2_TYPE) {
7406 p++;
7407 fprintf(stderr, " op2(%sobject of class %s)", ref,
7408 ZSTR_VAL(p->ce->name));
7409 } else {
7410 const char *type = ((op2_type & ~IS_TRACE_INDIRECT) == 0) ? "undef" : zend_get_type_by_const(op2_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT));
7411 fprintf(stderr, " op2(%s%s)", ref, type);
7412 }
7413 }
7414 if (op3_type != IS_UNKNOWN) {
7415 const char *ref = (op3_type & IS_TRACE_INDIRECT) ?
7416 ((op3_type & IS_TRACE_REFERENCE) ? "*&" : "*") :
7417 ((op3_type & IS_TRACE_REFERENCE) ? "&" : "");
7418 const char *type = ((op3_type & ~IS_TRACE_INDIRECT) == 0) ? "undef" : zend_get_type_by_const(op3_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT));
7419 fprintf(stderr, " op3(%s%s)", ref, type);
7420 }
7421 }
7422 if ((p+1)->op == ZEND_JIT_TRACE_VAL_INFO) {
7423 uint8_t val_type;
7424 const char *type;
7425
7426 if (op1_type == IS_UNKNOWN && op2_type == IS_UNKNOWN && op3_type == IS_UNKNOWN) {
7427 fprintf(stderr, " ;");
7428 }
7429 p++;
7430 val_type = p->op1_type;
7431
7432 if (val_type == IS_UNDEF) {
7433 type = "undef";
7434 } else if (val_type == IS_REFERENCE) {
7435 type = "ref";
7436 } else {
7437 type = zend_get_type_by_const(val_type);
7438 }
7439 fprintf(stderr, " val(%s)", type);
7440 }
7441 fprintf(stderr, "\n");
7442 idx++;
7443
7444 len = zend_jit_trace_op_len(opline);
7445 while (len > 1) {
7446 opline++;
7447 fprintf(stderr, "%04d%*c;",
7448 (int)(opline - op_array->opcodes),
7449 level, ' ');
7450 zend_dump_op(op_array, NULL, opline, ZEND_DUMP_RC_INFERENCE, tssa, (tssa && tssa->ops) ? tssa->ops + idx : NULL);
7451 idx++;
7452 len--;
7453 fprintf(stderr, "\n");
7454 }
7455 } else if (p->op == ZEND_JIT_TRACE_ENTER) {
7456 op_array = p->op_array;
7457 fprintf(stderr, " %*c>enter %s%s%s\n",
7458 level, ' ',
7459 op_array->scope ? ZSTR_VAL(op_array->scope->name) : "",
7460 op_array->scope ? "::" : "",
7461 op_array->function_name ?
7462 ZSTR_VAL(op_array->function_name) :
7463 ZSTR_VAL(op_array->filename));
7464 level++;
7465 if (tssa && tssa->var_info) {
7466 call_level++;
7467 v = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
7468 vars_count = op_array->last_var;
7469 for (i = 0; i < vars_count; i++, v++) {
7470 if (tssa->vars[v].use_chain >= 0 || tssa->vars[v].phi_use_chain) {
7471 fprintf(stderr, " %*c;", level, ' ');
7472 zend_dump_ssa_var(op_array, tssa, v, 0, i, ZEND_DUMP_RC_INFERENCE);
7473 fprintf(stderr, "\n");
7474 }
7475 }
7476 }
7477 } else if (p->op == ZEND_JIT_TRACE_BACK) {
7478 op_array = p->op_array;
7479 level--;
7480 fprintf(stderr, " %*c<back %s%s%s\n",
7481 level, ' ',
7482 op_array->scope ? ZSTR_VAL(op_array->scope->name) : "",
7483 op_array->scope ? "::" : "",
7484 op_array->function_name ?
7485 ZSTR_VAL(op_array->function_name) :
7486 ZSTR_VAL(op_array->filename));
7487 if (tssa && tssa->var_info) {
7488 if (call_level == 0) {
7489 v = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
7490 vars_count = op_array->last_var + op_array->T;
7491 for (i = 0; i < vars_count; i++, v++) {
7492 if (tssa->vars[v].use_chain >= 0 || tssa->vars[v].phi_use_chain) {
7493 fprintf(stderr, " %*c;", level, ' ');
7494 zend_dump_ssa_var(op_array, tssa, v, 0, i, ZEND_DUMP_RC_INFERENCE);
7495 fprintf(stderr, "\n");
7496 }
7497 }
7498 } else {
7499 call_level--;
7500 }
7501 }
7502 } else if (p->op == ZEND_JIT_TRACE_INIT_CALL) {
7503 if (p->func != (zend_function*)&zend_pass_function) {
7504 fprintf(stderr, (p->info & ZEND_JIT_TRACE_FAKE_INIT_CALL) ? " %*c>fake_init %s%s%s\n" : " %*c>init %s%s%s\n",
7505 level, ' ',
7506 (p->func && p->func->common.scope) ? ZSTR_VAL(p->func->common.scope->name) : "",
7507 (p->func && p->func->common.scope) ? "::" : "",
7508 p->func ? ZSTR_VAL(p->func->common.function_name) : "???");
7509 } else {
7510 fprintf(stderr, " %*c>skip\n",
7511 level, ' ');
7512 }
7513 } else if (p->op == ZEND_JIT_TRACE_DO_ICALL) {
7514 if (p->func != (zend_function*)&zend_pass_function) {
7515 fprintf(stderr, " %*c>call %s%s%s\n",
7516 level, ' ',
7517 p->func->common.scope ? ZSTR_VAL(p->func->common.scope->name) : "",
7518 p->func->common.scope ? "::" : "",
7519 ZSTR_VAL(p->func->common.function_name));
7520 } else {
7521 fprintf(stderr, " %*c>skip\n",
7522 level, ' ');
7523 }
7524 } else if (p->op == ZEND_JIT_TRACE_END) {
7525 break;
7526 }
7527 p++;
7528 }
7529 }
7530
zend_jit_dump_exit_info(zend_jit_trace_info * t)7531 static void zend_jit_dump_exit_info(zend_jit_trace_info *t)
7532 {
7533 int i, j;
7534
7535 fprintf(stderr, "---- TRACE %d exit info\n", t->id);
7536 for (i = 0; i < t->exit_count; i++) {
7537 const zend_op_array *op_array = t->exit_info[i].op_array;
7538 uint32_t stack_size = t->exit_info[i].stack_size;
7539 zend_jit_trace_stack *stack = t->stack_map + t->exit_info[i].stack_offset;
7540
7541 fprintf(stderr, " exit_%d:", i);
7542 if (t->exit_info[i].opline) {
7543 fprintf(stderr, " %04d/", (int)(t->exit_info[i].opline - op_array->opcodes));
7544 } else {
7545 fprintf(stderr, " ----/");
7546 }
7547 if (t->exit_info[i].stack_size) {
7548 fprintf(stderr, "%04d/%d", t->exit_info[i].stack_offset, t->exit_info[i].stack_size);
7549 } else {
7550 fprintf(stderr, "----/0");
7551 }
7552 if (t->exit_info[i].flags & ZEND_JIT_EXIT_TO_VM) {
7553 fprintf(stderr, "/VM");
7554 }
7555 if (t->exit_info[i].flags & ZEND_JIT_EXIT_RESTORE_CALL) {
7556 fprintf(stderr, "/CALL");
7557 }
7558 if (t->exit_info[i].flags & (ZEND_JIT_EXIT_POLYMORPHISM|ZEND_JIT_EXIT_METHOD_CALL|ZEND_JIT_EXIT_CLOSURE_CALL)) {
7559 fprintf(stderr, "/POLY");
7560 }
7561 if (t->exit_info[i].flags & ZEND_JIT_EXIT_FREE_OP1) {
7562 fprintf(stderr, "/FREE_OP1");
7563 }
7564 if (t->exit_info[i].flags & ZEND_JIT_EXIT_FREE_OP2) {
7565 fprintf(stderr, "/FREE_OP2");
7566 }
7567 for (j = 0; j < stack_size; j++) {
7568 zend_uchar type = STACK_TYPE(stack, j);
7569 if (type != IS_UNKNOWN) {
7570 fprintf(stderr, " ");
7571 zend_dump_var(op_array, (j < op_array->last_var) ? IS_CV : 0, j);
7572 fprintf(stderr, ":");
7573 if (type == IS_UNDEF) {
7574 fprintf(stderr, "undef");
7575 } else {
7576 fprintf(stderr, "%s", zend_get_type_by_const(type));
7577 }
7578 if (STACK_REG(stack, j) != ZREG_NONE) {
7579 if (STACK_REG(stack, j) < ZREG_NUM) {
7580 fprintf(stderr, "(%s)", zend_reg_name[STACK_REG(stack, j)]);
7581 } else if (STACK_REG(stack, j) == ZREG_THIS) {
7582 fprintf(stderr, "(this)");
7583 } else if (STACK_REG(stack, j) == ZREG_ZVAL_TRY_ADDREF) {
7584 fprintf(stderr, "(zval_try_addref)");
7585 } else {
7586 fprintf(stderr, "(const_%d)", STACK_REG(stack, j) - ZREG_NUM);
7587 }
7588 }
7589 } else if (STACK_REG(stack, j) == ZREG_ZVAL_TRY_ADDREF) {
7590 fprintf(stderr, " ");
7591 zend_dump_var(op_array, (j < op_array->last_var) ? IS_CV : 0, j);
7592 fprintf(stderr, ":unknown(zval_try_addref)");
7593 } else if (STACK_REG(stack, j) == ZREG_ZVAL_COPY_GPR0) {
7594 fprintf(stderr, " ");
7595 zend_dump_var(op_array, (j < op_array->last_var) ? IS_CV : 0, j);
7596 fprintf(stderr, ":unknown(zval_copy(%s))", zend_reg_name[ZREG_COPY]);
7597 }
7598 }
7599 fprintf(stderr, "\n");
7600 }
7601 }
7602
zend_jit_trace_hot_root(zend_execute_data * execute_data,const zend_op * opline)7603 int ZEND_FASTCALL zend_jit_trace_hot_root(zend_execute_data *execute_data, const zend_op *opline)
7604 {
7605 const zend_op *orig_opline;
7606 zend_jit_trace_stop stop;
7607 int ret = 0;
7608 zend_op_array *op_array;
7609 zend_jit_op_array_trace_extension *jit_extension;
7610 size_t offset;
7611 uint32_t trace_num;
7612 zend_jit_trace_rec trace_buffer[ZEND_JIT_TRACE_MAX_LENGTH];
7613
7614 ZEND_ASSERT(EX(func)->type == ZEND_USER_FUNCTION);
7615 ZEND_ASSERT(opline >= EX(func)->op_array.opcodes &&
7616 opline < EX(func)->op_array.opcodes + EX(func)->op_array.last);
7617
7618 repeat:
7619 trace_num = ZEND_JIT_TRACE_NUM;
7620 orig_opline = opline;
7621 op_array = &EX(func)->op_array;
7622 jit_extension = (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
7623 offset = jit_extension->offset;
7624
7625 EX(opline) = opline;
7626
7627 /* Lock-free check if the root trace was already JIT-ed or blacklist-ed in another process */
7628 if (ZEND_OP_TRACE_INFO(opline, offset)->trace_flags & (ZEND_JIT_TRACE_JITED|ZEND_JIT_TRACE_BLACKLISTED)) {
7629 return 0;
7630 }
7631
7632 if (JIT_G(tracing)) {
7633 ++(*ZEND_OP_TRACE_INFO(opline, offset)->counter);
7634 return 0;
7635 }
7636
7637 if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_START) {
7638 fprintf(stderr, "---- TRACE %d start (%s) %s%s%s() %s:%d\n",
7639 trace_num,
7640 zend_jit_trace_star_desc(ZEND_OP_TRACE_INFO(opline, offset)->trace_flags),
7641 EX(func)->op_array.scope ? ZSTR_VAL(EX(func)->op_array.scope->name) : "",
7642 EX(func)->op_array.scope ? "::" : "",
7643 EX(func)->op_array.function_name ?
7644 ZSTR_VAL(EX(func)->op_array.function_name) : "$main",
7645 ZSTR_VAL(EX(func)->op_array.filename),
7646 opline->lineno);
7647 }
7648
7649 if (ZEND_JIT_TRACE_NUM >= JIT_G(max_root_traces)) {
7650 stop = ZEND_JIT_TRACE_STOP_TOO_MANY_TRACES;
7651 goto abort;
7652 }
7653
7654 JIT_G(tracing) = 1;
7655 stop = zend_jit_trace_execute(execute_data, opline, trace_buffer,
7656 ZEND_OP_TRACE_INFO(opline, offset)->trace_flags & ZEND_JIT_TRACE_START_MASK, 0);
7657 JIT_G(tracing) = 0;
7658
7659 if (stop & ZEND_JIT_TRACE_HALT) {
7660 ret = -1;
7661 }
7662 stop &= ~ZEND_JIT_TRACE_HALT;
7663
7664 if (UNEXPECTED(trace_buffer[1].opline != orig_opline)) {
7665 orig_opline = trace_buffer[1].opline;
7666 op_array = (zend_op_array*)trace_buffer[0].op_array;
7667 jit_extension = (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
7668 offset = jit_extension->offset;
7669 if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_START) {
7670 const zend_op_array *op_array = trace_buffer[0].op_array;
7671 const zend_op *opline = trace_buffer[1].opline;
7672 zend_jit_op_array_trace_extension *jit_extension =
7673 (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
7674 size_t offset = jit_extension->offset;
7675
7676 fprintf(stderr, "---- TRACE %d start (%s) %s%s%s() %s:%d\n",
7677 trace_num,
7678 zend_jit_trace_star_desc(ZEND_OP_TRACE_INFO(opline, offset)->trace_flags),
7679 op_array->scope ? ZSTR_VAL(op_array->scope->name) : "",
7680 op_array->scope ? "::" : "",
7681 op_array->function_name ?
7682 ZSTR_VAL(op_array->function_name) : "$main",
7683 ZSTR_VAL(op_array->filename),
7684 opline->lineno);
7685 }
7686 }
7687
7688 if (UNEXPECTED(JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_BYTECODE)) {
7689 zend_jit_dump_trace(trace_buffer, NULL);
7690 }
7691
7692 if (ZEND_JIT_TRACE_STOP_OK(stop)) {
7693 if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_STOP) {
7694 if (stop == ZEND_JIT_TRACE_STOP_LINK) {
7695 uint32_t idx = trace_buffer[1].last;
7696 uint32_t link_to = zend_jit_find_trace(trace_buffer[idx].opline->handler);
7697 fprintf(stderr, "---- TRACE %d stop (link to %d)\n",
7698 trace_num,
7699 link_to);
7700 } else {
7701 fprintf(stderr, "---- TRACE %d stop (%s)\n",
7702 trace_num,
7703 zend_jit_trace_stop_description[stop]);
7704 }
7705 }
7706 stop = zend_jit_compile_root_trace(trace_buffer, orig_opline, offset);
7707 if (EXPECTED(ZEND_JIT_TRACE_STOP_DONE(stop))) {
7708 if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_COMPILED) {
7709 fprintf(stderr, "---- TRACE %d %s\n",
7710 trace_num,
7711 zend_jit_trace_stop_description[stop]);
7712 }
7713 } else {
7714 goto abort;
7715 }
7716 } else {
7717 abort:
7718 if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_ABORT) {
7719 fprintf(stderr, "---- TRACE %d abort (%s)\n",
7720 trace_num,
7721 zend_jit_trace_stop_description[stop]);
7722 }
7723 if (!ZEND_JIT_TRACE_STOP_MAY_RECOVER(stop)
7724 || zend_jit_trace_is_bad_root(orig_opline, stop, offset)) {
7725 if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_BLACKLIST) {
7726 fprintf(stderr, "---- TRACE %d blacklisted\n",
7727 trace_num);
7728 }
7729 zend_jit_blacklist_root_trace(orig_opline, offset);
7730 }
7731 if (ZEND_JIT_TRACE_STOP_REPEAT(stop)) {
7732 execute_data = EG(current_execute_data);
7733 opline = EX(opline);
7734 goto repeat;
7735 }
7736 }
7737
7738 if (JIT_G(debug) & (ZEND_JIT_DEBUG_TRACE_STOP|ZEND_JIT_DEBUG_TRACE_ABORT|ZEND_JIT_DEBUG_TRACE_COMPILED|ZEND_JIT_DEBUG_TRACE_BLACKLIST)) {
7739 fprintf(stderr, "\n");
7740 }
7741
7742 return ret;
7743 }
7744
zend_jit_blacklist_trace_exit(uint32_t trace_num,uint32_t exit_num)7745 static void zend_jit_blacklist_trace_exit(uint32_t trace_num, uint32_t exit_num)
7746 {
7747 const void *handler;
7748 bool do_bailout = 0;
7749
7750 zend_shared_alloc_lock();
7751
7752 if (!(zend_jit_traces[trace_num].exit_info[exit_num].flags & (ZEND_JIT_EXIT_JITED|ZEND_JIT_EXIT_BLACKLISTED))) {
7753 SHM_UNPROTECT();
7754 zend_jit_unprotect();
7755
7756 zend_try {
7757 handler = zend_jit_trace_exit_to_vm(trace_num, exit_num);
7758
7759 if (handler) {
7760 zend_jit_link_side_trace(
7761 zend_jit_traces[trace_num].code_start,
7762 zend_jit_traces[trace_num].code_size,
7763 zend_jit_traces[trace_num].jmp_table_size,
7764 exit_num,
7765 handler);
7766 }
7767 zend_jit_traces[trace_num].exit_info[exit_num].flags |= ZEND_JIT_EXIT_BLACKLISTED;
7768 } zend_catch {
7769 do_bailout = 1;
7770 } zend_end_try();
7771
7772 zend_jit_protect();
7773 SHM_PROTECT();
7774 }
7775
7776 zend_shared_alloc_unlock();
7777
7778 if (do_bailout) {
7779 zend_bailout();
7780 }
7781 }
7782
zend_jit_trace_exit_is_bad(uint32_t trace_num,uint32_t exit_num)7783 static bool zend_jit_trace_exit_is_bad(uint32_t trace_num, uint32_t exit_num)
7784 {
7785 uint8_t *counter = JIT_G(exit_counters) +
7786 zend_jit_traces[trace_num].exit_counters + exit_num;
7787
7788 if (*counter + 1 >= JIT_G(hot_side_exit) + JIT_G(blacklist_side_trace)) {
7789 return 1;
7790 }
7791 (*counter)++;
7792 return 0;
7793 }
7794
zend_jit_trace_exit_is_hot(uint32_t trace_num,uint32_t exit_num)7795 static bool zend_jit_trace_exit_is_hot(uint32_t trace_num, uint32_t exit_num)
7796 {
7797 uint8_t *counter = JIT_G(exit_counters) +
7798 zend_jit_traces[trace_num].exit_counters + exit_num;
7799
7800 if (*counter + 1 >= JIT_G(hot_side_exit)) {
7801 return 1;
7802 }
7803 (*counter)++;
7804 return 0;
7805 }
7806
zend_jit_compile_side_trace(zend_jit_trace_rec * trace_buffer,uint32_t parent_num,uint32_t exit_num,uint32_t polymorphism)7807 static zend_jit_trace_stop zend_jit_compile_side_trace(zend_jit_trace_rec *trace_buffer, uint32_t parent_num, uint32_t exit_num, uint32_t polymorphism)
7808 {
7809 zend_jit_trace_stop ret;
7810 const void *handler;
7811 uint8_t orig_trigger;
7812 zend_jit_trace_info *t;
7813 zend_jit_trace_exit_info exit_info[ZEND_JIT_TRACE_MAX_EXITS];
7814 bool do_bailout = 0;
7815
7816 zend_shared_alloc_lock();
7817
7818 /* Checks under lock */
7819 if (zend_jit_traces[parent_num].exit_info[exit_num].flags & (ZEND_JIT_EXIT_JITED|ZEND_JIT_EXIT_BLACKLISTED)) {
7820 ret = ZEND_JIT_TRACE_STOP_ALREADY_DONE;
7821 } else if (ZEND_JIT_TRACE_NUM >= JIT_G(max_root_traces)) {
7822 ret = ZEND_JIT_TRACE_STOP_TOO_MANY_TRACES;
7823 } else if (zend_jit_traces[zend_jit_traces[parent_num].root].child_count >= JIT_G(max_side_traces)) {
7824 ret = ZEND_JIT_TRACE_STOP_TOO_MANY_CHILDREN;
7825 } else {
7826 SHM_UNPROTECT();
7827 zend_jit_unprotect();
7828
7829 zend_try {
7830 t = &zend_jit_traces[ZEND_JIT_TRACE_NUM];
7831
7832 t->id = ZEND_JIT_TRACE_NUM;
7833 t->root = zend_jit_traces[parent_num].root;
7834 t->parent = parent_num;
7835 t->link = 0;
7836 t->exit_count = 0;
7837 t->child_count = 0;
7838 t->stack_map_size = 0;
7839 t->flags = 0;
7840 t->polymorphism = polymorphism;
7841 t->jmp_table_size = 0;
7842 t->opline = NULL;
7843 t->exit_info = exit_info;
7844 t->stack_map = NULL;
7845
7846 orig_trigger = JIT_G(trigger);
7847 JIT_G(trigger) = ZEND_JIT_ON_HOT_TRACE;
7848
7849 handler = zend_jit_trace(trace_buffer, parent_num, exit_num);
7850
7851 JIT_G(trigger) = orig_trigger;
7852
7853 if (handler) {
7854 zend_jit_trace_exit_info *shared_exit_info = NULL;
7855
7856 t->exit_info = NULL;
7857 if (t->exit_count) {
7858 /* reallocate exit_info into shared memory */
7859 shared_exit_info = (zend_jit_trace_exit_info*)zend_shared_alloc(
7860 sizeof(zend_jit_trace_exit_info) * t->exit_count);
7861
7862 if (!shared_exit_info) {
7863 if (t->stack_map) {
7864 efree(t->stack_map);
7865 t->stack_map = NULL;
7866 }
7867 ret = ZEND_JIT_TRACE_STOP_NO_SHM;
7868 goto exit;
7869 }
7870 memcpy(shared_exit_info, exit_info,
7871 sizeof(zend_jit_trace_exit_info) * t->exit_count);
7872 t->exit_info = shared_exit_info;
7873 }
7874
7875 if (t->stack_map_size) {
7876 zend_jit_trace_stack *shared_stack_map = (zend_jit_trace_stack*)zend_shared_alloc(t->stack_map_size * sizeof(zend_jit_trace_stack));
7877 if (!shared_stack_map) {
7878 efree(t->stack_map);
7879 ret = ZEND_JIT_TRACE_STOP_NO_SHM;
7880 goto exit;
7881 }
7882 memcpy(shared_stack_map, t->stack_map, t->stack_map_size * sizeof(zend_jit_trace_stack));
7883 efree(t->stack_map);
7884 t->stack_map = shared_stack_map;
7885 }
7886
7887 zend_jit_link_side_trace(
7888 zend_jit_traces[parent_num].code_start,
7889 zend_jit_traces[parent_num].code_size,
7890 zend_jit_traces[parent_num].jmp_table_size,
7891 exit_num,
7892 handler);
7893
7894 t->exit_counters = ZEND_JIT_EXIT_COUNTERS;
7895 ZEND_JIT_EXIT_COUNTERS += t->exit_count;
7896
7897 zend_jit_traces[zend_jit_traces[parent_num].root].child_count++;
7898 ZEND_JIT_TRACE_NUM++;
7899 zend_jit_traces[parent_num].exit_info[exit_num].flags |= ZEND_JIT_EXIT_JITED;
7900
7901 ret = ZEND_JIT_TRACE_STOP_COMPILED;
7902 } else if (t->exit_count >= ZEND_JIT_TRACE_MAX_EXITS ||
7903 ZEND_JIT_EXIT_COUNTERS + t->exit_count >= JIT_G(max_exit_counters)) {
7904 if (t->stack_map) {
7905 efree(t->stack_map);
7906 t->stack_map = NULL;
7907 }
7908 ret = ZEND_JIT_TRACE_STOP_TOO_MANY_EXITS;
7909 } else {
7910 if (t->stack_map) {
7911 efree(t->stack_map);
7912 t->stack_map = NULL;
7913 }
7914 ret = ZEND_JIT_TRACE_STOP_COMPILER_ERROR;
7915 }
7916
7917 exit:;
7918 } zend_catch {
7919 do_bailout = 1;
7920 } zend_end_try();
7921
7922 zend_jit_protect();
7923 SHM_PROTECT();
7924 }
7925
7926 zend_shared_alloc_unlock();
7927
7928 if (do_bailout) {
7929 zend_bailout();
7930 }
7931
7932 if ((JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_EXIT_INFO) != 0
7933 && ret == ZEND_JIT_TRACE_STOP_COMPILED
7934 && t->exit_count > 0) {
7935 zend_jit_dump_exit_info(t);
7936 }
7937
7938 return ret;
7939 }
7940
zend_jit_trace_hot_side(zend_execute_data * execute_data,uint32_t parent_num,uint32_t exit_num)7941 int ZEND_FASTCALL zend_jit_trace_hot_side(zend_execute_data *execute_data, uint32_t parent_num, uint32_t exit_num)
7942 {
7943 zend_jit_trace_stop stop;
7944 int ret = 0;
7945 uint32_t trace_num;
7946 zend_jit_trace_rec trace_buffer[ZEND_JIT_TRACE_MAX_LENGTH];
7947 uint32_t is_megamorphic = 0;
7948 uint32_t polymorphism = 0;
7949
7950 trace_num = ZEND_JIT_TRACE_NUM;
7951
7952 /* Lock-free check if the side trace was already JIT-ed or blacklist-ed in another process */
7953 if (zend_jit_traces[parent_num].exit_info[exit_num].flags & (ZEND_JIT_EXIT_JITED|ZEND_JIT_EXIT_BLACKLISTED)) {
7954 return 0;
7955 }
7956
7957 if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_START) {
7958 fprintf(stderr, "---- TRACE %d start (side trace %d/%d) %s%s%s() %s:%d\n",
7959 trace_num, parent_num, exit_num,
7960 EX(func)->op_array.scope ? ZSTR_VAL(EX(func)->op_array.scope->name) : "",
7961 EX(func)->op_array.scope ? "::" : "",
7962 EX(func)->op_array.function_name ?
7963 ZSTR_VAL(EX(func)->op_array.function_name) : "$main",
7964 ZSTR_VAL(EX(func)->op_array.filename),
7965 EX(opline)->lineno);
7966 }
7967
7968 if (ZEND_JIT_TRACE_NUM >= JIT_G(max_root_traces)) {
7969 stop = ZEND_JIT_TRACE_STOP_TOO_MANY_TRACES;
7970 goto abort;
7971 }
7972
7973 if (zend_jit_traces[zend_jit_traces[parent_num].root].child_count >= JIT_G(max_side_traces)) {
7974 stop = ZEND_JIT_TRACE_STOP_TOO_MANY_CHILDREN;
7975 goto abort;
7976 }
7977
7978 if (JIT_G(max_polymorphic_calls) > 0) {
7979 if ((zend_jit_traces[parent_num].exit_info[exit_num].flags & (ZEND_JIT_EXIT_METHOD_CALL|ZEND_JIT_EXIT_CLOSURE_CALL))
7980 || ((zend_jit_traces[parent_num].exit_info[exit_num].flags & ZEND_JIT_EXIT_POLYMORPHISM)
7981 && EX(call))) {
7982 if (zend_jit_traces[parent_num].polymorphism >= JIT_G(max_polymorphic_calls) - 1) {
7983 is_megamorphic = zend_jit_traces[parent_num].exit_info[exit_num].flags &
7984 (ZEND_JIT_EXIT_METHOD_CALL | ZEND_JIT_EXIT_CLOSURE_CALL | ZEND_JIT_EXIT_POLYMORPHISM);
7985 } else if (!zend_jit_traces[parent_num].polymorphism) {
7986 polymorphism = 1;
7987 } else if (exit_num == 0) {
7988 polymorphism = zend_jit_traces[parent_num].polymorphism + 1;
7989 }
7990 }
7991 }
7992
7993 JIT_G(tracing) = 1;
7994 stop = zend_jit_trace_execute(execute_data, EX(opline), trace_buffer, ZEND_JIT_TRACE_START_SIDE, is_megamorphic);
7995 JIT_G(tracing) = 0;
7996
7997 if (stop & ZEND_JIT_TRACE_HALT) {
7998 ret = -1;
7999 }
8000 stop &= ~ZEND_JIT_TRACE_HALT;
8001
8002 if (UNEXPECTED(trace_buffer->start != ZEND_JIT_TRACE_START_SIDE)) {
8003 if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_START) {
8004 const zend_op_array *op_array = trace_buffer[0].op_array;
8005 const zend_op *opline = trace_buffer[1].opline;
8006 zend_jit_op_array_trace_extension *jit_extension =
8007 (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
8008 size_t offset = jit_extension->offset;
8009
8010 fprintf(stderr, "---- TRACE %d start (%s) %s%s%s() %s:%d\n",
8011 trace_num,
8012 zend_jit_trace_star_desc(ZEND_OP_TRACE_INFO(opline, offset)->trace_flags),
8013 op_array->scope ? ZSTR_VAL(op_array->scope->name) : "",
8014 op_array->scope ? "::" : "",
8015 op_array->function_name ?
8016 ZSTR_VAL(op_array->function_name) : "$main",
8017 ZSTR_VAL(op_array->filename),
8018 opline->lineno);
8019 }
8020 }
8021
8022 if (UNEXPECTED(JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_BYTECODE)) {
8023 zend_jit_dump_trace(trace_buffer, NULL);
8024 }
8025
8026 if (ZEND_JIT_TRACE_STOP_OK(stop)) {
8027 if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_STOP) {
8028 if (stop == ZEND_JIT_TRACE_STOP_LINK) {
8029 uint32_t idx = trace_buffer[1].last;
8030 uint32_t link_to = zend_jit_find_trace(trace_buffer[idx].opline->handler);;
8031 fprintf(stderr, "---- TRACE %d stop (link to %d)\n",
8032 trace_num,
8033 link_to);
8034 } else {
8035 fprintf(stderr, "---- TRACE %d stop (%s)\n",
8036 trace_num,
8037 zend_jit_trace_stop_description[stop]);
8038 }
8039 }
8040 if (EXPECTED(trace_buffer->start == ZEND_JIT_TRACE_START_SIDE)) {
8041 stop = zend_jit_compile_side_trace(trace_buffer, parent_num, exit_num, polymorphism);
8042 } else {
8043 const zend_op_array *op_array = trace_buffer[0].op_array;
8044 zend_jit_op_array_trace_extension *jit_extension =
8045 (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
8046 const zend_op *opline = trace_buffer[1].opline;
8047
8048 stop = zend_jit_compile_root_trace(trace_buffer, opline, jit_extension->offset);
8049 }
8050 if (EXPECTED(ZEND_JIT_TRACE_STOP_DONE(stop))) {
8051 if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_COMPILED) {
8052 fprintf(stderr, "---- TRACE %d %s\n",
8053 trace_num,
8054 zend_jit_trace_stop_description[stop]);
8055 }
8056 } else {
8057 goto abort;
8058 }
8059 } else {
8060 abort:
8061 if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_ABORT) {
8062 fprintf(stderr, "---- TRACE %d abort (%s)\n",
8063 trace_num,
8064 zend_jit_trace_stop_description[stop]);
8065 }
8066 if (!ZEND_JIT_TRACE_STOP_MAY_RECOVER(stop)
8067 || zend_jit_trace_exit_is_bad(parent_num, exit_num)) {
8068 zend_jit_blacklist_trace_exit(parent_num, exit_num);
8069 if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_BLACKLIST) {
8070 fprintf(stderr, "---- EXIT %d/%d blacklisted\n",
8071 parent_num, exit_num);
8072 }
8073 }
8074 if (ZEND_JIT_TRACE_STOP_REPEAT(stop)) {
8075 execute_data = EG(current_execute_data);
8076 return zend_jit_trace_hot_root(execute_data, EX(opline));
8077 }
8078 }
8079
8080 if (JIT_G(debug) & (ZEND_JIT_DEBUG_TRACE_STOP|ZEND_JIT_DEBUG_TRACE_ABORT|ZEND_JIT_DEBUG_TRACE_COMPILED|ZEND_JIT_DEBUG_TRACE_BLACKLIST)) {
8081 fprintf(stderr, "\n");
8082 }
8083
8084 return ret;
8085 }
8086
zend_jit_trace_exit(uint32_t exit_num,zend_jit_registers_buf * regs)8087 int ZEND_FASTCALL zend_jit_trace_exit(uint32_t exit_num, zend_jit_registers_buf *regs)
8088 {
8089 uint32_t trace_num = EG(jit_trace_num);
8090 zend_execute_data *execute_data = EG(current_execute_data);
8091 const zend_op *orig_opline = EX(opline);
8092 const zend_op *opline;
8093 zend_jit_trace_info *t = &zend_jit_traces[trace_num];
8094 int repeat_last_opline = 0;
8095
8096 /* Deoptimizatoion of VM stack state */
8097 uint32_t i;
8098 uint32_t stack_size = t->exit_info[exit_num].stack_size;
8099 zend_jit_trace_stack *stack = t->stack_map + t->exit_info[exit_num].stack_offset;
8100
8101 if (t->exit_info[exit_num].flags & ZEND_JIT_EXIT_RESTORE_CALL) {
8102 zend_execute_data *call = (zend_execute_data *)regs->gpr[ZREG_RX];
8103 call->prev_execute_data = EX(call);
8104 EX(call) = call;
8105 }
8106
8107 for (i = 0; i < stack_size; i++) {
8108 if (STACK_REG(stack, i) != ZREG_NONE) {
8109 if (STACK_TYPE(stack, i) == IS_LONG) {
8110 zend_long val;
8111
8112 if (STACK_REG(stack, i) < ZREG_NUM) {
8113 val = regs->gpr[STACK_REG(stack, i)];
8114 } else if (STACK_REG(stack, i) == ZREG_LONG_MIN) {
8115 val = ZEND_LONG_MIN;
8116 } else if (STACK_REG(stack, i) == ZREG_LONG_MAX) {
8117 val = ZEND_LONG_MAX;
8118 } else {
8119 ZEND_UNREACHABLE();
8120 }
8121 ZVAL_LONG(EX_VAR_NUM(i), val);
8122 } else if (STACK_TYPE(stack, i) == IS_DOUBLE) {
8123 double val;
8124
8125 if (STACK_REG(stack, i) < ZREG_NUM) {
8126 val = regs->fpr[STACK_REG(stack, i) - ZREG_FIRST_FPR];
8127 } else if (STACK_REG(stack, i) == ZREG_LONG_MIN_MINUS_1) {
8128 val = (double)ZEND_LONG_MIN - 1.0;
8129 } else if (STACK_REG(stack, i) == ZREG_LONG_MAX_PLUS_1) {
8130 val = (double)ZEND_LONG_MAX + 1.0;
8131 } else {
8132 ZEND_UNREACHABLE();
8133 }
8134 ZVAL_DOUBLE(EX_VAR_NUM(i), val);
8135 } else if (STACK_REG(stack, i) == ZREG_THIS) {
8136 zend_object *obj = Z_OBJ(EX(This));
8137
8138 GC_ADDREF(obj);
8139 ZVAL_OBJ(EX_VAR_NUM(i), obj);
8140 } else if (STACK_REG(stack, i) == ZREG_NULL) {
8141 ZVAL_NULL(EX_VAR_NUM(i));
8142 } else if (STACK_REG(stack, i) == ZREG_ZVAL_TRY_ADDREF) {
8143 Z_TRY_ADDREF_P(EX_VAR_NUM(i));
8144 } else if (STACK_REG(stack, i) == ZREG_ZVAL_COPY_GPR0) {
8145 zval *val = (zval*)regs->gpr[ZREG_COPY];
8146
8147 if (UNEXPECTED(Z_TYPE_P(val) == IS_UNDEF)) {
8148 /* Undefined array index or property */
8149 repeat_last_opline = 1;
8150 } else {
8151 ZVAL_COPY(EX_VAR_NUM(i), val);
8152 }
8153 } else {
8154 ZEND_UNREACHABLE();
8155 }
8156 }
8157 }
8158
8159 if (repeat_last_opline) {
8160 EX(opline) = t->exit_info[exit_num].opline - 1;
8161 if ((EX(opline)->op1_type & (IS_VAR|IS_TMP_VAR))
8162 && !(t->exit_info[exit_num].flags & ZEND_JIT_EXIT_FREE_OP1)
8163 && EX(opline)->opcode != ZEND_FETCH_LIST_R) {
8164 Z_TRY_ADDREF_P(EX_VAR(EX(opline)->op1.var));
8165 }
8166 return 1;
8167 }
8168
8169 opline = t->exit_info[exit_num].opline;
8170
8171 if (opline) {
8172 if (t->exit_info[exit_num].flags & ZEND_JIT_EXIT_FREE_OP2) {
8173 ZEND_ASSERT((opline-1)->opcode == ZEND_FETCH_DIM_R
8174 || (opline-1)->opcode == ZEND_FETCH_DIM_IS
8175 || (opline-1)->opcode == ZEND_FETCH_LIST_R
8176 || (opline-1)->opcode == ZEND_FETCH_DIM_FUNC_ARG);
8177 EX(opline) = opline-1;
8178 zval_ptr_dtor_nogc(EX_VAR((opline-1)->op2.var));
8179 }
8180 if (t->exit_info[exit_num].flags & ZEND_JIT_EXIT_FREE_OP1) {
8181 ZEND_ASSERT((opline-1)->opcode == ZEND_FETCH_DIM_R
8182 || (opline-1)->opcode == ZEND_FETCH_DIM_IS
8183 || (opline-1)->opcode == ZEND_FETCH_DIM_FUNC_ARG
8184 || (opline-1)->opcode == ZEND_FETCH_OBJ_R
8185 || (opline-1)->opcode == ZEND_FETCH_OBJ_IS
8186 || (opline-1)->opcode == ZEND_FETCH_OBJ_FUNC_ARG);
8187 EX(opline) = opline-1;
8188 zval_ptr_dtor_nogc(EX_VAR((opline-1)->op1.var));
8189 }
8190 if (t->exit_info[exit_num].flags & (ZEND_JIT_EXIT_FREE_OP1|ZEND_JIT_EXIT_FREE_OP2)) {
8191 if (EG(exception)) {
8192 return 1;
8193 }
8194 }
8195 if (t->exit_info[exit_num].flags & ZEND_JIT_EXIT_METHOD_CALL) {
8196 zend_function *func = (zend_function*)regs->gpr[ZREG_COPY];
8197
8198 if (UNEXPECTED(func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
8199 zend_string_release_ex(func->common.function_name, 0);
8200 zend_free_trampoline(func);
8201 EX(opline) = opline;
8202 return 1;
8203 }
8204 }
8205
8206 /* Set VM opline to continue interpretation */
8207 EX(opline) = opline;
8208 }
8209
8210 if (EG(vm_interrupt) || JIT_G(tracing)) {
8211 return 1;
8212 /* Lock-free check if the side trace was already JIT-ed or blacklist-ed in another process */
8213 } else if (t->exit_info[exit_num].flags & (ZEND_JIT_EXIT_JITED|ZEND_JIT_EXIT_BLACKLISTED)) {
8214 return 0;
8215 }
8216
8217 ZEND_ASSERT(EX(func)->type == ZEND_USER_FUNCTION);
8218 ZEND_ASSERT(EX(opline) >= EX(func)->op_array.opcodes &&
8219 EX(opline) < EX(func)->op_array.opcodes + EX(func)->op_array.last);
8220
8221 if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_EXIT) {
8222 fprintf(stderr, " TRACE %d exit %d %s%s%s() %s:%d\n",
8223 trace_num,
8224 exit_num,
8225 EX(func)->op_array.scope ? ZSTR_VAL(EX(func)->op_array.scope->name) : "",
8226 EX(func)->op_array.scope ? "::" : "",
8227 EX(func)->op_array.function_name ?
8228 ZSTR_VAL(EX(func)->op_array.function_name) : "$main",
8229 ZSTR_VAL(EX(func)->op_array.filename),
8230 EX(opline)->lineno);
8231 }
8232
8233 if (t->exit_info[exit_num].flags & ZEND_JIT_EXIT_INVALIDATE) {
8234 zend_jit_op_array_trace_extension *jit_extension;
8235 uint32_t num = trace_num;
8236
8237 while (t->root != num) {
8238 num = t->root;
8239 t = &zend_jit_traces[num];
8240 }
8241
8242 zend_shared_alloc_lock();
8243
8244 jit_extension = (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(t->op_array);
8245
8246 /* Checks under lock, just in case something has changed while we were waiting for the lock */
8247 if (!(ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->trace_flags & (ZEND_JIT_TRACE_JITED|ZEND_JIT_TRACE_BLACKLISTED))) {
8248 /* skip: not JIT-ed nor blacklisted */
8249 } else if (ZEND_JIT_TRACE_NUM >= JIT_G(max_root_traces)) {
8250 /* skip: too many root traces */
8251 } else {
8252 SHM_UNPROTECT();
8253 zend_jit_unprotect();
8254
8255 if (ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->trace_flags & ZEND_JIT_TRACE_START_LOOP) {
8256 ((zend_op*)(t->opline))->handler = (const void*)zend_jit_loop_trace_counter_handler;
8257 } else if (ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->trace_flags & ZEND_JIT_TRACE_START_ENTER) {
8258 ((zend_op*)(t->opline))->handler = (const void*)zend_jit_func_trace_counter_handler;
8259 } else if (ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->trace_flags & ZEND_JIT_TRACE_START_RETURN) {
8260 ((zend_op*)(t->opline))->handler = (const void*)zend_jit_ret_trace_counter_handler;
8261 }
8262 ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->trace_flags &=
8263 ZEND_JIT_TRACE_START_LOOP|ZEND_JIT_TRACE_START_ENTER|ZEND_JIT_TRACE_START_RETURN;
8264
8265 zend_jit_protect();
8266 SHM_PROTECT();
8267 }
8268
8269 zend_shared_alloc_unlock();
8270
8271 return 0;
8272 }
8273
8274 if (t->exit_info[exit_num].flags & ZEND_JIT_EXIT_TO_VM) {
8275 if (zend_jit_trace_exit_is_bad(trace_num, exit_num)) {
8276 zend_jit_blacklist_trace_exit(trace_num, exit_num);
8277 if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_BLACKLIST) {
8278 fprintf(stderr, "---- EXIT %d/%d blacklisted\n",
8279 trace_num, exit_num);
8280 }
8281 return 0;
8282 }
8283 } else if (JIT_G(hot_side_exit) && zend_jit_trace_exit_is_hot(trace_num, exit_num)) {
8284 return zend_jit_trace_hot_side(execute_data, trace_num, exit_num);
8285 }
8286
8287 /* Return 1 to call original handler instead of the same JIT-ed trace */
8288 return (orig_opline == t->opline && EX(opline) == orig_opline);
8289 }
8290
zend_jit_trace_supported(const zend_op * opline)8291 static zend_always_inline uint8_t zend_jit_trace_supported(const zend_op *opline)
8292 {
8293 switch (opline->opcode) {
8294 case ZEND_CATCH:
8295 case ZEND_FAST_CALL:
8296 case ZEND_FAST_RET:
8297 return ZEND_JIT_TRACE_UNSUPPORTED;
8298 default:
8299 return ZEND_JIT_TRACE_SUPPORTED;
8300 }
8301 }
8302
zend_jit_restart_hot_trace_counters(zend_op_array * op_array)8303 static int zend_jit_restart_hot_trace_counters(zend_op_array *op_array)
8304 {
8305 zend_jit_op_array_trace_extension *jit_extension;
8306 uint32_t i;
8307
8308 jit_extension = (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
8309 for (i = 0; i < op_array->last; i++) {
8310 jit_extension->trace_info[i].trace_flags &=
8311 ZEND_JIT_TRACE_START_LOOP | ZEND_JIT_TRACE_START_ENTER | ZEND_JIT_TRACE_UNSUPPORTED;
8312 if (jit_extension->trace_info[i].trace_flags == ZEND_JIT_TRACE_START_LOOP) {
8313 op_array->opcodes[i].handler = (const void*)zend_jit_loop_trace_counter_handler;
8314 } else if (jit_extension->trace_info[i].trace_flags == ZEND_JIT_TRACE_START_ENTER) {
8315 op_array->opcodes[i].handler = (const void*)zend_jit_func_trace_counter_handler;
8316 } else {
8317 op_array->opcodes[i].handler = jit_extension->trace_info[i].orig_handler;
8318 }
8319 }
8320 return SUCCESS;
8321 }
8322
zend_jit_setup_hot_trace_counters(zend_op_array * op_array)8323 static int zend_jit_setup_hot_trace_counters(zend_op_array *op_array)
8324 {
8325 zend_op *opline;
8326 zend_jit_op_array_trace_extension *jit_extension;
8327 uint32_t i;
8328
8329 ZEND_ASSERT(sizeof(zend_op_trace_info) == sizeof(zend_op));
8330
8331 jit_extension = (zend_jit_op_array_trace_extension*)zend_shared_alloc(sizeof(zend_jit_op_array_trace_extension) + (op_array->last - 1) * sizeof(zend_op_trace_info));
8332 if (!jit_extension) {
8333 return FAILURE;
8334 }
8335 memset(&jit_extension->func_info, 0, sizeof(zend_func_info));
8336 jit_extension->func_info.flags = ZEND_FUNC_JIT_ON_HOT_TRACE;
8337 jit_extension->op_array = op_array;
8338 jit_extension->offset = (char*)jit_extension->trace_info - (char*)op_array->opcodes;
8339 for (i = 0; i < op_array->last; i++) {
8340 jit_extension->trace_info[i].orig_handler = op_array->opcodes[i].handler;
8341 jit_extension->trace_info[i].call_handler = zend_get_opcode_handler_func(&op_array->opcodes[i]);
8342 jit_extension->trace_info[i].counter = NULL;
8343 jit_extension->trace_info[i].trace_flags =
8344 zend_jit_trace_supported(&op_array->opcodes[i]);
8345 }
8346 ZEND_SET_FUNC_INFO(op_array, (void*)jit_extension);
8347
8348 if (JIT_G(hot_loop)) {
8349 zend_cfg cfg;
8350
8351 ZEND_ASSERT(zend_jit_loop_trace_counter_handler != NULL);
8352
8353 if (zend_jit_build_cfg(op_array, &cfg) != SUCCESS) {
8354 return FAILURE;
8355 }
8356
8357 for (i = 0; i < cfg.blocks_count; i++) {
8358 if (cfg.blocks[i].flags & ZEND_BB_REACHABLE) {
8359 if (cfg.blocks[i].flags & ZEND_BB_LOOP_HEADER) {
8360 /* loop header */
8361 opline = op_array->opcodes + cfg.blocks[i].start;
8362 if (!(ZEND_OP_TRACE_INFO(opline, jit_extension->offset)->trace_flags & ZEND_JIT_TRACE_UNSUPPORTED)) {
8363 opline->handler = (const void*)zend_jit_loop_trace_counter_handler;
8364 if (!ZEND_OP_TRACE_INFO(opline, jit_extension->offset)->counter) {
8365 ZEND_OP_TRACE_INFO(opline, jit_extension->offset)->counter =
8366 &zend_jit_hot_counters[ZEND_JIT_COUNTER_NUM];
8367 ZEND_JIT_COUNTER_NUM = (ZEND_JIT_COUNTER_NUM + 1) % ZEND_HOT_COUNTERS_COUNT;
8368 }
8369 ZEND_OP_TRACE_INFO(opline, jit_extension->offset)->trace_flags |=
8370 ZEND_JIT_TRACE_START_LOOP;
8371 }
8372 }
8373 }
8374 }
8375 }
8376
8377 if (JIT_G(hot_func)) {
8378 ZEND_ASSERT(zend_jit_func_trace_counter_handler != NULL);
8379 opline = op_array->opcodes;
8380 if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
8381 while (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT) {
8382 opline++;
8383 }
8384 }
8385
8386 if (!ZEND_OP_TRACE_INFO(opline, jit_extension->offset)->trace_flags) {
8387 /* function entry */
8388 opline->handler = (const void*)zend_jit_func_trace_counter_handler;
8389 ZEND_OP_TRACE_INFO(opline, jit_extension->offset)->counter =
8390 &zend_jit_hot_counters[ZEND_JIT_COUNTER_NUM];
8391 ZEND_JIT_COUNTER_NUM = (ZEND_JIT_COUNTER_NUM + 1) % ZEND_HOT_COUNTERS_COUNT;
8392 ZEND_OP_TRACE_INFO(opline, jit_extension->offset)->trace_flags |=
8393 ZEND_JIT_TRACE_START_ENTER;
8394 }
8395 }
8396
8397 zend_shared_alloc_register_xlat_entry(op_array->opcodes, jit_extension);
8398
8399 return SUCCESS;
8400 }
8401
zend_jit_trace_init_caches(void)8402 static void zend_jit_trace_init_caches(void)
8403 {
8404 memset(ZEND_VOIDP(JIT_G(bad_root_cache_opline)), 0, sizeof(JIT_G(bad_root_cache_opline)));
8405 memset(JIT_G(bad_root_cache_count), 0, sizeof(JIT_G(bad_root_cache_count)));
8406 memset(JIT_G(bad_root_cache_stop), 0, sizeof(JIT_G(bad_root_cache_count)));
8407 JIT_G(bad_root_slot) = 0;
8408
8409 if (JIT_G(exit_counters)) {
8410 memset(JIT_G(exit_counters), 0, JIT_G(max_exit_counters));
8411 }
8412 }
8413
zend_jit_trace_reset_caches(void)8414 static void zend_jit_trace_reset_caches(void)
8415 {
8416 JIT_G(tracing) = 0;
8417 #ifdef ZTS
8418 if (!JIT_G(exit_counters)) {
8419 JIT_G(exit_counters) = calloc(JIT_G(max_exit_counters), 1);
8420 }
8421 #endif
8422 }
8423
zend_jit_trace_free_caches(zend_jit_globals * jit_globals)8424 static void zend_jit_trace_free_caches(zend_jit_globals *jit_globals)
8425 {
8426 if (jit_globals->exit_counters) {
8427 free(jit_globals->exit_counters);
8428 }
8429 }
8430
zend_jit_trace_restart(void)8431 static void zend_jit_trace_restart(void)
8432 {
8433 ZEND_JIT_TRACE_NUM = 1;
8434 ZEND_JIT_COUNTER_NUM = 0;
8435 ZEND_JIT_EXIT_NUM = 0;
8436 ZEND_JIT_EXIT_COUNTERS = 0;
8437
8438 zend_jit_trace_init_caches();
8439 }
8440