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