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