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