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