xref: /PHP-8.0/ext/opcache/jit/zend_jit_x86.dasc (revision 5ca41133)
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 *  | http://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 *  |          Xinchen Hui <laruence@php.net>                              |
17 *  +----------------------------------------------------------------------+
18 */
19
20|.if X64
21 |.arch x64
22|.else
23 |.arch x86
24|.endif
25
26|.if X64WIN
27 |.define FP,      r14
28 |.define IP,      r15
29 |.define IPl,     r15d
30 |.define RX,      r15       // the same as VM IP reused as a general purpose reg
31 |.define CARG1,   rcx       // x64/POSIX C call arguments.
32 |.define CARG2,   rdx
33 |.define CARG3,   r8
34 |.define CARG4,   r9
35 |.define CARG1d,  ecx
36 |.define CARG2d,  edx
37 |.define CARG3d,  r8d
38 |.define CARG4d,  r9d
39 |.define FCARG1a, CARG1     // Simulate x86 fastcall.
40 |.define FCARG2a, CARG2
41 |.define FCARG1d, CARG1d
42 |.define FCARG2d, CARG2d
43 |.define SPAD,    0x58      // padding for CPU stack alignment
44 |.define NR_SPAD, 0x58      // padding for CPU stack alignment
45 |.define T3,      [r4+0x50] // Used to store old value of IP
46 |.define T2,      [r4+0x48] // Used to store old value of FP
47 |.define T1,      [r4+0x40]
48 |.define A6,      [r4+0x28] // preallocated slot for 6-th argument
49 |.define A5,      [r4+0x20] // preallocated slot for 5-th argument
50|.elif X64
51 |.define FP,      r14
52 |.define IP,      r15
53 |.define IPl,     r15d
54 |.define RX,      r15       // the same as VM IP reused as a general purpose reg
55 |.define CARG1,   rdi       // x64/POSIX C call arguments.
56 |.define CARG2,   rsi
57 |.define CARG3,   rdx
58 |.define CARG4,   rcx
59 |.define CARG5,   r8
60 |.define CARG6,   r9
61 |.define CARG1d,  edi
62 |.define CARG2d,  esi
63 |.define CARG3d,  edx
64 |.define CARG4d,  ecx
65 |.define CARG5d,  r8d
66 |.define CARG6d,  r9d
67 |.define FCARG1a, CARG1     // Simulate x86 fastcall.
68 |.define FCARG2a, CARG2
69 |.define FCARG1d, CARG1d
70 |.define FCARG2d, CARG2d
71 |.define SPAD,    0x18      // padding for CPU stack alignment
72 |.define NR_SPAD, 0x28      // padding for CPU stack alignment
73 |.define T3,      [r4+0x20] // Used to store old value of IP (CALL VM only)
74 |.define T2,      [r4+0x18] // Used to store old value of FP (CALL VM only)
75 |.define T1,      [r4]
76|.else
77 |.define FP,      esi
78 |.define IP,      edi
79 |.define IPl,     edi
80 |.define RX,      edi       // the same as VM IP reused as a general purpose reg
81 |.define FCARG1a, ecx       // x86 fastcall arguments.
82 |.define FCARG2a, edx
83 |.define FCARG1d, ecx
84 |.define FCARG2d, edx
85 |.define SPAD,    0x1c      // padding for CPU stack alignment
86 |.define NR_SPAD, 0x1c      // padding for CPU stack alignment
87 |.define T3,      [r4+0x18] // Used to store old value of IP (CALL VM only)
88 |.define T2,      [r4+0x14] // Used to store old value of FP (CALL VM only)
89 |.define T1,      [r4]
90 |.define A4,      [r4+0xC]  // preallocated slots for arguments of "cdecl" functions (intersect with T1)
91 |.define A3,      [r4+0x8]
92 |.define A2,      [r4+0x4]
93 |.define A1,      [r4]
94|.endif
95
96|.define HYBRID_SPAD, 16     // padding for stack alignment
97
98#ifdef _WIN64
99# define TMP_ZVAL_OFFSET 0x20
100#else
101# define TMP_ZVAL_OFFSET 0
102#endif
103
104#define DASM_ALIGNMENT 16
105
106/* According to x86 and x86_64 ABI, CPU stack has to be 16 byte aligned to
107 * guarantee proper alignment of 128-bit SSE data allocated on stack.
108 * With broken alignment any execution of SSE code, including calls to
109 * memcpy() and others, may lead to crash.
110 */
111
112#include "Zend/zend_cpuinfo.h"
113#include "jit/zend_jit_x86.h"
114
115#ifdef HAVE_VALGRIND
116# include <valgrind/valgrind.h>
117#endif
118
119/* The generated code may contain tautological comparisons, ignore them. */
120#if defined(__clang__)
121# pragma clang diagnostic push
122# pragma clang diagnostic ignored "-Wtautological-compare"
123# pragma clang diagnostic ignored "-Wstring-compare"
124#endif
125
126const char* zend_reg_name[] = {
127#if defined(__x86_64__) || defined(_M_X64)
128	"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
129	"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
130	"xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
131	"xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"
132#else
133	"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
134	"xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
135#endif
136};
137
138#ifdef HAVE_GCC_GLOBAL_REGS
139# define GCC_GLOBAL_REGS 1
140#else
141# define GCC_GLOBAL_REGS 0
142#endif
143
144#if ZTS
145static size_t tsrm_ls_cache_tcb_offset = 0;
146static size_t tsrm_tls_index;
147static size_t tsrm_tls_offset;
148#endif
149
150/* By default avoid JITing inline handlers if it does not seem profitable due to lack of
151 * type information. Disabling this option allows testing some JIT handlers in the
152 * presence of try/catch blocks, which prevent SSA construction. */
153#ifndef PROFITABILITY_CHECKS
154# define PROFITABILITY_CHECKS 1
155#endif
156
157|.type EX, zend_execute_data, FP
158|.type OP, zend_op
159|.type ZVAL, zval
160
161|.actionlist dasm_actions
162
163|.globals zend_lb
164static void* dasm_labels[zend_lb_MAX];
165
166|.section code, cold_code, jmp_table
167
168#define IS_32BIT(addr) (((uintptr_t)(addr)) <= 0x7fffffff)
169
170#define IS_SIGNED_32BIT(val) ((((intptr_t)(val)) <= 0x7fffffff) && (((intptr_t)(val)) >= (-2147483647 - 1)))
171
172#define BP_JIT_IS 6
173
174
175#define CAN_USE_AVX() (JIT_G(opt_flags) & allowed_opt_flags & ZEND_JIT_CPU_AVX)
176
177|.macro ADD_HYBRID_SPAD
178||#ifndef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE
179|		add r4, HYBRID_SPAD
180||#endif
181|.endmacro
182
183|.macro SUB_HYBRID_SPAD
184||#ifndef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE
185|		sub r4, HYBRID_SPAD
186||#endif
187|.endmacro
188
189|.macro LOAD_ADDR, reg, addr
190|	.if X64
191||		if (IS_SIGNED_32BIT(addr)) {
192|			mov reg, ((ptrdiff_t)addr)    // 0x48 0xc7 0xc0 <imm-32-bit>
193||		} else {
194|			mov64 reg, ((ptrdiff_t)addr)  // 0x48 0xb8 <imm-64-bit>
195||		}
196|	.else
197|		mov reg, ((ptrdiff_t)addr)
198|	.endif
199|.endmacro
200
201|.macro LOAD_TSRM_CACHE, reg
202|	.if X64WIN
203|		gs
204|		mov reg, aword [0x58]
205|		mov reg, aword [reg+tsrm_tls_index]
206|		mov reg, aword [reg+tsrm_tls_offset]
207|	.elif WIN
208|		fs
209|		mov reg, aword [0x2c]
210|		mov reg, aword [reg+tsrm_tls_index]
211|		mov reg, aword [reg+tsrm_tls_offset]
212|	.elif X64APPLE
213|		gs
214||		if (tsrm_ls_cache_tcb_offset) {
215|			mov reg, aword [tsrm_ls_cache_tcb_offset]
216||		} else {
217|			mov reg, aword [tsrm_tls_index]
218|			mov reg, aword [reg+tsrm_tls_offset]
219||		}
220|	.elif X64
221|		fs
222||		if (tsrm_ls_cache_tcb_offset) {
223|			mov reg, aword [tsrm_ls_cache_tcb_offset]
224||		} else {
225|			mov reg, [0x8]
226|			mov reg, aword [reg+tsrm_tls_index]
227|			mov reg, aword [reg+tsrm_tls_offset]
228||		}
229|	.else
230|		gs
231||		if (tsrm_ls_cache_tcb_offset) {
232|			mov reg, aword [tsrm_ls_cache_tcb_offset]
233||		} else {
234|			mov reg, [0x4]
235|			mov reg, aword [reg+tsrm_tls_index]
236|			mov reg, aword [reg+tsrm_tls_offset]
237||		}
238|	.endif
239|.endmacro
240
241|.macro LOAD_ADDR_ZTS, reg, struct, field
242|	.if ZTS
243|		LOAD_TSRM_CACHE reg
244|		lea reg, aword [reg + (struct.._offset + offsetof(zend_..struct, field))]
245|	.else
246|		LOAD_ADDR reg, &struct.field
247|	.endif
248|.endmacro
249
250|.macro ADDR_OP1, addr_ins, addr, tmp_reg
251|	.if X64
252||		if (IS_SIGNED_32BIT(addr)) {
253|			addr_ins ((ptrdiff_t)addr)
254||		} else {
255|			mov64 tmp_reg, ((ptrdiff_t)addr)
256|			addr_ins tmp_reg
257||		}
258|	.else
259|		addr_ins ((ptrdiff_t)addr)
260|	.endif
261|.endmacro
262
263|.macro ADDR_OP2_2, addr_ins, op1, addr, tmp_reg
264|	.if X64
265||		if (IS_SIGNED_32BIT(addr)) {
266|			addr_ins op1, ((ptrdiff_t)addr)
267||		} else {
268|			mov64 tmp_reg, ((ptrdiff_t)addr)
269|			addr_ins op1, tmp_reg
270||		}
271|	.else
272|		addr_ins op1, ((ptrdiff_t)addr)
273|	.endif
274|.endmacro
275
276|.macro PUSH_ADDR, addr, tmp_reg
277|	ADDR_OP1 push, addr, tmp_reg
278|.endmacro
279
280|.macro PUSH_ADDR_ZTS, struct, field, tmp_reg
281|	.if ZTS
282|		LOAD_TSRM_CACHE tmp_reg
283|		lea tmp_reg, aword [tmp_reg + (struct.._offset + offsetof(zend_..struct, field))]
284|		push tmp_reg
285|	.else
286|		ADDR_OP1 push, &struct.field, tmp_reg
287|	.endif
288|.endmacro
289
290|.macro MEM_OP1, mem_ins, prefix, addr, tmp_reg
291|	.if X64
292||		if (IS_SIGNED_32BIT(addr)) {
293|			mem_ins prefix [addr]
294||		} else {
295|			mov64 tmp_reg, ((ptrdiff_t)addr)
296|			mem_ins prefix [tmp_reg]
297||		}
298|	.else
299|		mem_ins prefix [addr]
300|	.endif
301|.endmacro
302
303|.macro MEM_OP2_1, mem_ins, prefix, addr, op2, tmp_reg
304|	.if X64
305||		if (IS_SIGNED_32BIT(addr)) {
306|			mem_ins prefix [addr], op2
307||		} else {
308|			mov64 tmp_reg, ((ptrdiff_t)addr)
309|			mem_ins prefix [tmp_reg], op2
310||		}
311|	.else
312|		mem_ins prefix [addr], op2
313|	.endif
314|.endmacro
315
316|.macro MEM_OP2_2, mem_ins, op1, prefix, addr, tmp_reg
317|	.if X64
318||		if (IS_SIGNED_32BIT(addr)) {
319|			mem_ins op1, prefix [addr]
320||		} else {
321|			mov64 tmp_reg, ((ptrdiff_t)addr)
322|			mem_ins op1, prefix [tmp_reg]
323||		}
324|	.else
325|		mem_ins op1, prefix [addr]
326|	.endif
327|.endmacro
328
329|.macro MEM_OP2_1_ZTS, mem_ins, prefix, struct, field, op2, tmp_reg
330|	.if ZTS
331|		LOAD_TSRM_CACHE tmp_reg
332|		mem_ins prefix [tmp_reg+(struct.._offset+offsetof(zend_..struct, field))], op2
333|	.else
334|		MEM_OP2_1 mem_ins, prefix, &struct.field, op2, tmp_reg
335|	.endif
336|.endmacro
337
338|.macro MEM_OP2_2_ZTS, mem_ins, op1, prefix, struct, field, tmp_reg
339|	.if ZTS
340|		LOAD_TSRM_CACHE tmp_reg
341|		mem_ins op1, prefix [tmp_reg+(struct.._offset+offsetof(zend_..struct, field))]
342|	.else
343|		MEM_OP2_2 mem_ins, op1, prefix, &struct.field, tmp_reg
344|	.endif
345|.endmacro
346
347|.macro MEM_OP3_3, mem_ins, op1, op2, prefix, addr, tmp_reg
348|	.if X64
349||		if (IS_SIGNED_32BIT(addr)) {
350|			mem_ins op1, op2, prefix [addr]
351||		} else {
352|			mov64 tmp_reg, ((ptrdiff_t)addr)
353|			mem_ins op1, op2, prefix [tmp_reg]
354||		}
355|	.else
356|		mem_ins op1, op2, prefix [addr]
357|	.endif
358|.endmacro
359
360|.macro LOAD_BASE_ADDR, reg, base, offset
361||	if (offset) {
362|		lea reg, qword [Ra(base)+offset]
363||	} else {
364|		mov reg, Ra(base)
365||	}
366|.endmacro
367
368|.macro PUSH_BASE_ADDR, base, offset, tmp_reg
369||	if (offset) {
370|		lea tmp_reg, qword [Ra(base)+offset]
371|		push tmp_reg
372||	} else {
373|		push Ra(base)
374||	}
375|.endmacro
376
377|.macro EXT_CALL, func, tmp_reg
378|	.if X64
379||		if (IS_32BIT(dasm_end) && IS_32BIT(func)) {
380|			call qword &func
381||		} else {
382|			LOAD_ADDR tmp_reg, func
383|			call tmp_reg
384||		}
385|	.else
386|		call dword &func
387|	.endif
388|.endmacro
389
390|.macro EXT_JMP, func, tmp_reg
391|	.if X64
392||		if (IS_32BIT(dasm_end) && IS_32BIT(func)) {
393|			jmp qword &func
394||		} else {
395|			LOAD_ADDR tmp_reg, func
396|			jmp tmp_reg
397||		}
398|	.else
399|		jmp dword &func
400|	.endif
401|.endmacro
402
403|.macro SAVE_IP
404||	if (GCC_GLOBAL_REGS) {
405|		mov aword EX->opline, IP
406||	}
407|.endmacro
408
409|.macro LOAD_IP
410||	if (GCC_GLOBAL_REGS) {
411|		mov IP, aword EX->opline
412||	}
413|.endmacro
414
415|.macro LOAD_IP_ADDR, addr
416||	if (GCC_GLOBAL_REGS) {
417|		LOAD_ADDR IP, addr
418||	} else {
419|		ADDR_OP2_2 mov, aword EX->opline, addr, RX
420||	}
421|.endmacro
422
423|.macro LOAD_IP_ADDR_ZTS, struct, field
424|	.if ZTS
425||		if (GCC_GLOBAL_REGS) {
426|			LOAD_TSRM_CACHE IP
427|			mov IP, aword [IP + (struct.._offset + offsetof(zend_..struct, field))]
428||		} else {
429|			LOAD_TSRM_CACHE RX
430|			lea RX, aword [RX + (struct.._offset + offsetof(zend_..struct, field))]
431|			mov aword EX->opline, RX
432||		}
433|	.else
434|		LOAD_IP_ADDR &struct.field
435|	.endif
436|.endmacro
437
438|.macro GET_IP, reg
439||	if (GCC_GLOBAL_REGS) {
440|		mov reg, IP
441||	} else {
442|		mov reg, aword EX->opline
443||	}
444|.endmacro
445
446|.macro ADD_IP, val
447||	if (GCC_GLOBAL_REGS) {
448|		add IP, val
449||	} else {
450|		add aword EX->opline, val
451||	}
452|.endmacro
453
454|.macro JMP_IP
455||	if (GCC_GLOBAL_REGS) {
456|		jmp aword [IP]
457||	} else {
458|		mov r0, aword EX:FCARG1a->opline
459|		jmp aword [r0]
460||	}
461|.endmacro
462
463/* In 64-bit build we compare only low 32-bits.
464 * x86_64 cmp instruction doesn't support immediate 64-bit operand, and full
465 * comparison would require an additional load of 64-bit address into register.
466 * This is not a problem at all, while JIT buffer size is less than 4GB.
467 */
468|.macro CMP_IP, addr
469||	if (GCC_GLOBAL_REGS) {
470|		cmp IPl, addr
471||	} else {
472|		cmp dword EX->opline, addr
473||	}
474|.endmacro
475
476|.macro LOAD_ZVAL_ADDR, reg, addr
477||	if (Z_MODE(addr) == IS_CONST_ZVAL) {
478|		LOAD_ADDR reg, Z_ZV(addr)
479||	} else if (Z_MODE(addr) == IS_MEM_ZVAL) {
480|		LOAD_BASE_ADDR reg, Z_REG(addr), Z_OFFSET(addr)
481||	} else {
482||		ZEND_UNREACHABLE();
483||	}
484|.endmacro
485
486|.macro PUSH_ZVAL_ADDR, addr, tmp_reg
487||	if (Z_MODE(addr) == IS_CONST_ZVAL) {
488|		PUSH_ADDR Z_ZV(addr), tmp_reg
489||	} else if (Z_MODE(addr) == IS_MEM_ZVAL) {
490|		PUSH_BASE_ADDR Z_REG(addr), Z_OFFSET(addr), tmp_reg
491||	} else {
492||		ZEND_UNREACHABLE();
493||	}
494|.endmacro
495
496|.macro GET_Z_TYPE_INFO, reg, zv
497|	mov reg, dword [zv+offsetof(zval,u1.type_info)]
498|.endmacro
499
500|.macro SET_Z_TYPE_INFO, zv, type
501|	mov dword [zv+offsetof(zval,u1.type_info)], type
502|.endmacro
503
504|.macro GET_ZVAL_TYPE, reg, addr
505||	ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
506|	mov reg, byte [Ra(Z_REG(addr))+Z_OFFSET(addr)+offsetof(zval,u1.v.type)]
507|.endmacro
508
509|.macro GET_ZVAL_TYPE_INFO, reg, addr
510||	ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
511|	mov reg, dword [Ra(Z_REG(addr))+Z_OFFSET(addr)+offsetof(zval,u1.type_info)]
512|.endmacro
513
514|.macro SET_ZVAL_TYPE_INFO, addr, type
515||	ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
516|	mov dword [Ra(Z_REG(addr))+Z_OFFSET(addr)+offsetof(zval,u1.type_info)], type
517|.endmacro
518
519|.macro GET_Z_PTR, reg, zv
520|	mov reg, aword [zv]
521|.endmacro
522
523|.macro SET_Z_PTR, zv, val
524|	mov aword [zv], val
525|.endmacro
526
527|.macro GET_Z_W2, reg, zv
528|	mov reg, dword [zv+4]
529|.endmacro
530
531|.macro SET_Z_W2, zv, reg
532|	mov dword [zv+4], reg
533|.endmacro
534
535|.macro GET_ZVAL_PTR, reg, addr
536||	ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
537|	mov reg, aword [Ra(Z_REG(addr))+Z_OFFSET(addr)]
538|.endmacro
539
540|.macro SET_ZVAL_PTR, addr, val
541||	ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
542|	mov aword [Ra(Z_REG(addr))+Z_OFFSET(addr)], val
543|.endmacro
544
545|.macro GET_ZVAL_W2, reg, addr
546||	ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
547|	mov reg, dword [Ra(Z_REG(addr))+Z_OFFSET(addr)+4]
548|.endmacro
549
550|.macro SET_ZVAL_W2, addr, val
551||	ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
552|	mov dword [Ra(Z_REG(addr))+Z_OFFSET(addr)+4], val
553|.endmacro
554
555|.macro UNDEF_OPLINE_RESULT
556|	mov r0, EX->opline
557|	mov eax, dword OP:r0->result.var
558|	SET_Z_TYPE_INFO FP + r0, IS_UNDEF
559|.endmacro
560
561|.macro UNDEF_OPLINE_RESULT_IF_USED
562|	test byte OP:RX->result_type, (IS_TMP_VAR|IS_VAR)
563|	jz >1
564|	mov eax, dword OP:RX->result.var
565|	SET_Z_TYPE_INFO FP + r0, IS_UNDEF
566|1:
567|.endmacro
568
569|.macro SSE_AVX_INS, sse_ins, avx_ins, op1, op2
570||	if (CAN_USE_AVX()) {
571|		avx_ins op1, op2
572||	} else {
573|		sse_ins op1, op2
574||	}
575|.endmacro
576
577|.macro SSE_OP, sse_ins, reg, addr, tmp_reg
578||	if (Z_MODE(addr) == IS_CONST_ZVAL) {
579|		MEM_OP2_2 sse_ins, xmm(reg-ZREG_XMM0), qword, Z_ZV(addr), tmp_reg
580||	} else if (Z_MODE(addr) == IS_MEM_ZVAL) {
581|		sse_ins xmm(reg-ZREG_XMM0), qword [Ra(Z_REG(addr))+Z_OFFSET(addr)]
582||	} else if (Z_MODE(addr) == IS_REG) {
583|		sse_ins xmm(reg-ZREG_XMM0), xmm(Z_REG(addr)-ZREG_XMM0)
584||	} else {
585||		ZEND_UNREACHABLE();
586||	}
587|.endmacro
588
589|.macro SSE_AVX_OP, sse_ins, avx_ins, reg, addr
590||	if (Z_MODE(addr) == IS_CONST_ZVAL) {
591|		.if X64
592||			if (IS_SIGNED_32BIT(Z_ZV(addr))) {
593|				SSE_AVX_INS sse_ins, avx_ins, xmm(reg-ZREG_XMM0), qword [Z_ZV(addr)]
594||			} else {
595|				LOAD_ADDR r0, Z_ZV(addr)
596|				SSE_AVX_INS sse_ins, avx_ins, xmm(reg-ZREG_XMM0), qword [r0]
597||			}
598|		.else
599|			SSE_AVX_INS sse_ins, avx_ins, xmm(reg-ZREG_XMM0), qword [Z_ZV(addr)]
600|		.endif
601||	} else if (Z_MODE(addr) == IS_MEM_ZVAL) {
602|		SSE_AVX_INS sse_ins, avx_ins, xmm(reg-ZREG_XMM0), qword [Ra(Z_REG(addr))+Z_OFFSET(addr)]
603||	} else if (Z_MODE(addr) == IS_REG) {
604|		SSE_AVX_INS sse_ins, avx_ins, xmm(reg-ZREG_XMM0), xmm(Z_REG(addr)-ZREG_XMM0)
605||	} else {
606||		ZEND_UNREACHABLE();
607||	}
608|.endmacro
609
610|.macro SSE_GET_LONG, reg, lval, tmp_reg
611||		if (lval == 0) {
612||			if (CAN_USE_AVX()) {
613|				vxorps xmm(reg-ZREG_XMM0), xmm(reg-ZREG_XMM0), xmm(reg-ZREG_XMM0)
614||			} else {
615|				xorps xmm(reg-ZREG_XMM0), xmm(reg-ZREG_XMM0)
616||			}
617||		} else {
618|.if X64
619||			if (!IS_SIGNED_32BIT(lval)) {
620|				mov64 Ra(tmp_reg), lval
621||			} else {
622|				mov Ra(tmp_reg), lval
623||			}
624|.else
625|			mov Ra(tmp_reg), lval
626|.endif
627||			if (CAN_USE_AVX()) {
628|				vxorps xmm(reg-ZREG_XMM0), xmm(reg-ZREG_XMM0), xmm(reg-ZREG_XMM0)
629|				vcvtsi2sd, xmm(reg-ZREG_XMM0), xmm(reg-ZREG_XMM0), Ra(tmp_reg)
630||			} else {
631|				xorps xmm(reg-ZREG_XMM0), xmm(reg-ZREG_XMM0)
632|				cvtsi2sd, xmm(reg-ZREG_XMM0), Ra(tmp_reg)
633||			}
634||		}
635|.endmacro
636
637|.macro SSE_GET_ZVAL_LVAL, reg, addr, tmp_reg
638||	if (Z_MODE(addr) == IS_CONST_ZVAL) {
639|		SSE_GET_LONG reg, Z_LVAL_P(Z_ZV(addr)), tmp_reg
640||	} else if (Z_MODE(addr) == IS_MEM_ZVAL) {
641||		if (CAN_USE_AVX()) {
642|			vxorps xmm(reg-ZREG_XMM0), xmm(reg-ZREG_XMM0), xmm(reg-ZREG_XMM0)
643|			vcvtsi2sd xmm(reg-ZREG_XMM0), xmm(reg-ZREG_XMM0), aword [Ra(Z_REG(addr))+Z_OFFSET(addr)]
644||		} else {
645|			xorps xmm(reg-ZREG_XMM0), xmm(reg-ZREG_XMM0)
646|			cvtsi2sd xmm(reg-ZREG_XMM0), aword [Ra(Z_REG(addr))+Z_OFFSET(addr)]
647||		}
648||	} else if (Z_MODE(addr) == IS_REG) {
649||		if (CAN_USE_AVX()) {
650|			vxorps xmm(reg-ZREG_XMM0), xmm(reg-ZREG_XMM0), xmm(reg-ZREG_XMM0)
651|			vcvtsi2sd xmm(reg-ZREG_XMM0), xmm(reg-ZREG_XMM0), Ra(Z_REG(addr))
652||		} else {
653|			xorps xmm(reg-ZREG_XMM0), xmm(reg-ZREG_XMM0)
654|			cvtsi2sd xmm(reg-ZREG_XMM0), Ra(Z_REG(addr))
655||		}
656||	} else {
657||		ZEND_UNREACHABLE();
658||	}
659|.endmacro
660
661|.macro SSE_GET_ZVAL_DVAL, reg, addr
662||	if (Z_MODE(addr) != IS_REG || reg != Z_REG(addr)) {
663||		if (Z_MODE(addr) == IS_CONST_ZVAL) {
664|			.if X64
665||				if (IS_SIGNED_32BIT(Z_ZV(addr))) {
666|					SSE_AVX_INS movsd, vmovsd, xmm(reg-ZREG_XMM0), qword [Z_ZV(addr)]
667||				} else {
668|					LOAD_ADDR r0, Z_ZV(addr)
669|					SSE_AVX_INS movsd, vmovsd, xmm(reg-ZREG_XMM0), qword [r0]
670||				}
671|			.else
672|				SSE_AVX_INS movsd, vmovsd, xmm(reg-ZREG_XMM0), qword [Z_ZV(addr)]
673|			.endif
674||		} else if (Z_MODE(addr) == IS_MEM_ZVAL) {
675|			SSE_AVX_INS movsd, vmovsd, xmm(reg-ZREG_XMM0), qword [Ra(Z_REG(addr))+Z_OFFSET(addr)]
676||		} else if (Z_MODE(addr) == IS_REG) {
677|			SSE_AVX_INS movaps, vmovaps, xmm(reg-ZREG_XMM0), xmm(Z_REG(addr)-ZREG_XMM0)
678||		} else {
679||			ZEND_UNREACHABLE();
680||		}
681||	}
682|.endmacro
683
684|.macro SSE_MATH, opcode, reg, addr, tmp_reg
685||	switch (opcode) {
686||		case ZEND_ADD:
687|			SSE_OP addsd, reg, addr, tmp_reg
688||			break;
689||		case ZEND_SUB:
690|			SSE_OP subsd, reg, addr, tmp_reg
691||			break;
692||		case ZEND_MUL:
693|			SSE_OP mulsd, reg, addr, tmp_reg
694||			break;
695||		case ZEND_DIV:
696|			SSE_OP divsd, reg, addr, tmp_reg
697||			break;
698||	}
699|.endmacro
700
701|.macro SSE_MATH_REG, opcode, dst_reg, src_reg
702||	switch (opcode) {
703||		case ZEND_ADD:
704|			addsd xmm(dst_reg-ZREG_XMM0), xmm(src_reg-ZREG_XMM0)
705||			break;
706||		case ZEND_SUB:
707|			subsd xmm(dst_reg-ZREG_XMM0), xmm(src_reg-ZREG_XMM0)
708||			break;
709||		case ZEND_MUL:
710|			mulsd xmm(dst_reg-ZREG_XMM0), xmm(src_reg-ZREG_XMM0)
711||			break;
712||		case ZEND_DIV:
713|			divsd xmm(dst_reg-ZREG_XMM0), xmm(src_reg-ZREG_XMM0)
714||			break;
715||	}
716|.endmacro
717
718|.macro SSE_SET_ZVAL_DVAL, addr, reg
719||	if (Z_MODE(addr) == IS_REG) {
720||		if (reg != Z_REG(addr)) {
721|			SSE_AVX_INS movaps, vmovaps, xmm(Z_REG(addr)-ZREG_XMM0), xmm(reg-ZREG_XMM0)
722||		}
723||	} else {
724||		ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
725|		SSE_AVX_INS movsd, vmovsd, qword [Ra(Z_REG(addr))+Z_OFFSET(addr)], xmm(reg-ZREG_XMM0)
726||	}
727|.endmacro
728
729|.macro AVX_OP, avx_ins, reg, op1_reg, addr, tmp_reg
730||	if (Z_MODE(addr) == IS_CONST_ZVAL) {
731|		MEM_OP3_3 avx_ins, xmm(reg-ZREG_XMM0), xmm(op1_reg-ZREG_XMM0), qword, Z_ZV(addr), tmp_reg
732||	} else if (Z_MODE(addr) == IS_MEM_ZVAL) {
733|		avx_ins xmm(reg-ZREG_XMM0), xmm(op1_reg-ZREG_XMM0), qword [Ra(Z_REG(addr))+Z_OFFSET(addr)]
734||	} else if (Z_MODE(addr) == IS_REG) {
735|		avx_ins xmm(reg-ZREG_XMM0), xmm(op1_reg-ZREG_XMM0), xmm(Z_REG(addr)-ZREG_XMM0)
736||	} else {
737||		ZEND_UNREACHABLE();
738||	}
739|.endmacro
740
741|.macro AVX_MATH, opcode, reg, op1_reg, addr, tmp_reg
742||	switch (opcode) {
743||		case ZEND_ADD:
744|			AVX_OP vaddsd, reg, op1_reg, addr, tmp_reg
745||			break;
746||		case ZEND_SUB:
747|			AVX_OP vsubsd, reg, op1_reg, addr, tmp_reg
748||			break;
749||		case ZEND_MUL:
750|			AVX_OP vmulsd, reg, op1_reg, addr, tmp_reg
751||			break;
752||		case ZEND_DIV:
753|			AVX_OP vdivsd, reg, op1_reg, addr, tmp_reg
754||			break;
755||	}
756|.endmacro
757
758|.macro AVX_MATH_REG, opcode, dst_reg, op1_reg, src_reg
759||	switch (opcode) {
760||		case ZEND_ADD:
761|			vaddsd xmm(dst_reg-ZREG_XMM0), xmm(op1_reg-ZREG_XMM0), xmm(src_reg-ZREG_XMM0)
762||			break;
763||		case ZEND_SUB:
764|			vsubsd xmm(dst_reg-ZREG_XMM0), xmm(op1_reg-ZREG_XMM0), xmm(src_reg-ZREG_XMM0)
765||			break;
766||		case ZEND_MUL:
767|			vmulsd xmm(dst_reg-ZREG_XMM0), xmm(op1_reg-ZREG_XMM0), xmm(src_reg-ZREG_XMM0)
768||			break;
769||		case ZEND_DIV:
770|			vdivsd xmm(dst_reg-ZREG_XMM0), xmm(op1_reg-ZREG_XMM0), xmm(src_reg-ZREG_XMM0)
771||			break;
772||	}
773|.endmacro
774
775|.macro LONG_OP, long_ins, reg, addr, tmp_reg
776||	if (Z_MODE(addr) == IS_CONST_ZVAL) {
777|		.if X64
778||			if (!IS_SIGNED_32BIT(Z_LVAL_P(Z_ZV(addr)))) {
779|				mov64 tmp_reg, Z_LVAL_P(Z_ZV(addr))
780|				long_ins Ra(reg), tmp_reg
781||			} else {
782|				long_ins Ra(reg), Z_LVAL_P(Z_ZV(addr))
783||			}
784|		.else
785|			long_ins Ra(reg), Z_LVAL_P(Z_ZV(addr))
786|		.endif
787||	} else if (Z_MODE(addr) == IS_MEM_ZVAL) {
788|		long_ins Ra(reg), aword [Ra(Z_REG(addr))+Z_OFFSET(addr)]
789||	} else if (Z_MODE(addr) == IS_REG) {
790|		long_ins Ra(reg), Ra(Z_REG(addr))
791||	} else {
792||		ZEND_UNREACHABLE();
793||	}
794|.endmacro
795
796|.macro LONG_OP_WITH_32BIT_CONST, long_ins, op1_addr, lval
797||	if (Z_MODE(op1_addr) == IS_MEM_ZVAL) {
798|		long_ins aword [Ra(Z_REG(op1_addr))+Z_OFFSET(op1_addr)], lval
799||	} else if (Z_MODE(op1_addr) == IS_REG) {
800|		long_ins Ra(Z_REG(op1_addr)), lval
801||	} else {
802||		ZEND_UNREACHABLE();
803||	}
804|.endmacro
805
806|.macro LONG_OP_WITH_CONST, long_ins, op1_addr, lval
807||	if (Z_MODE(op1_addr) == IS_MEM_ZVAL) {
808|	   .if X64
809||			if (!IS_SIGNED_32BIT(lval)) {
810|				mov64 r0, lval
811|				long_ins aword [Ra(Z_REG(op1_addr))+Z_OFFSET(op1_addr)], r0
812||			} else {
813|				long_ins aword [Ra(Z_REG(op1_addr))+Z_OFFSET(op1_addr)], lval
814||			}
815|		.else
816|			long_ins aword [Ra(Z_REG(op1_addr))+Z_OFFSET(op1_addr)], lval
817|		.endif
818||	} else if (Z_MODE(op1_addr) == IS_REG) {
819|	   .if X64
820||			if (!IS_SIGNED_32BIT(lval)) {
821|				mov64 r0, lval
822|				long_ins Ra(Z_REG(op1_addr)), r0
823||			} else {
824|				long_ins Ra(Z_REG(op1_addr)), lval
825||			}
826|		.else
827|			long_ins Ra(Z_REG(op1_addr)), lval
828|		.endif
829||	} else {
830||		ZEND_UNREACHABLE();
831||	}
832|.endmacro
833
834|.macro GET_ZVAL_LVAL, reg, addr
835||	if (Z_MODE(addr) == IS_CONST_ZVAL) {
836||		if (Z_LVAL_P(Z_ZV(addr)) == 0) {
837|			xor Ra(reg), Ra(reg)
838||		} else {
839|			.if X64
840||				if (!IS_SIGNED_32BIT(Z_LVAL_P(Z_ZV(addr)))) {
841|					mov64 Ra(reg), Z_LVAL_P(Z_ZV(addr))
842||				} else {
843|					mov Ra(reg), Z_LVAL_P(Z_ZV(addr))
844||				}
845|			.else
846|				mov Ra(reg), Z_LVAL_P(Z_ZV(addr))
847|			.endif
848||		}
849||	} else if (Z_MODE(addr) == IS_MEM_ZVAL) {
850|		mov Ra(reg), aword [Ra(Z_REG(addr))+Z_OFFSET(addr)]
851||	} else if (Z_MODE(addr) == IS_REG) {
852||		if (reg != Z_REG(addr)) {
853|			mov Ra(reg), Ra(Z_REG(addr))
854||		}
855||	} else {
856||		ZEND_UNREACHABLE();
857||	}
858|.endmacro
859
860|.macro LONG_MATH, opcode, reg, addr, tmp_reg
861||	switch (opcode) {
862||		case ZEND_ADD:
863|			LONG_OP add, reg, addr, Ra(tmp_reg)
864||			break;
865||		case ZEND_SUB:
866|			LONG_OP sub, reg, addr, Ra(tmp_reg)
867||			break;
868||		case ZEND_MUL:
869|			LONG_OP imul, reg, addr, Ra(tmp_reg)
870||			break;
871||		case ZEND_BW_OR:
872|			LONG_OP or, reg, addr, Ra(tmp_reg)
873||			break;
874||		case ZEND_BW_AND:
875|			LONG_OP and, reg, addr, Ra(tmp_reg)
876||			break;
877||		case ZEND_BW_XOR:
878|			LONG_OP xor, reg, addr, Ra(tmp_reg)
879||			break;
880||		default:
881||			ZEND_UNREACHABLE();
882||	}
883|.endmacro
884
885|.macro LONG_MATH_REG, opcode, dst_reg, src_reg
886||	switch (opcode) {
887||		case ZEND_ADD:
888|			add dst_reg, src_reg
889||			break;
890||		case ZEND_SUB:
891|			sub dst_reg, src_reg
892||			break;
893||		case ZEND_MUL:
894|			imul dst_reg, src_reg
895||			break;
896||		case ZEND_BW_OR:
897|			or dst_reg, src_reg
898||			break;
899||		case ZEND_BW_AND:
900|			and dst_reg, src_reg
901||			break;
902||		case ZEND_BW_XOR:
903|			xor dst_reg, src_reg
904||			break;
905||		default:
906||			ZEND_UNREACHABLE();
907||	}
908|.endmacro
909
910|.macro SET_ZVAL_LVAL, addr, lval
911||	if (Z_MODE(addr) == IS_REG) {
912|		mov Ra(Z_REG(addr)), lval
913||	} else {
914||		ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
915|		mov aword [Ra(Z_REG(addr))+Z_OFFSET(addr)], lval
916||	}
917|.endmacro
918
919|.macro ZVAL_COPY_CONST, dst_addr, dst_info, dst_def_info, zv, tmp_reg
920||	if (Z_TYPE_P(zv) > IS_TRUE) {
921||		if (Z_TYPE_P(zv) == IS_DOUBLE) {
922||			zend_reg dst_reg = (Z_MODE(dst_addr) == IS_REG) ? Z_REG(dst_addr) : ZREG_XMM0;
923||			if (Z_DVAL_P(zv) == 0.0 && !is_signed(Z_DVAL_P(zv))) {
924||				if (CAN_USE_AVX()) {
925|					vxorps xmm(dst_reg-ZREG_XMM0), xmm(dst_reg-ZREG_XMM0), xmm(dst_reg-ZREG_XMM0)
926||				} else {
927|					xorps xmm(dst_reg-ZREG_XMM0), xmm(dst_reg-ZREG_XMM0)
928||				}
929|			.if X64
930||			} else if (!IS_SIGNED_32BIT(zv)) {
931|				mov64 Ra(tmp_reg), ((uintptr_t)zv)
932|				SSE_AVX_INS movsd, vmovsd, xmm(dst_reg-ZREG_XMM0), qword [Ra(tmp_reg)]
933|			.endif
934||			} else {
935|				SSE_AVX_INS movsd, vmovsd, xmm(dst_reg-ZREG_XMM0), qword [((uint32_t)(uintptr_t)zv)]
936||			}
937|			SSE_SET_ZVAL_DVAL dst_addr, dst_reg
938||		} else if (Z_TYPE_P(zv) == IS_LONG && dst_def_info == MAY_BE_DOUBLE) {
939||			zend_reg dst_reg = (Z_MODE(dst_addr) == IS_REG) ? Z_REG(dst_addr) : ZREG_XMM0;
940|			SSE_GET_LONG dst_reg, Z_LVAL_P(zv), ZREG_R0
941|			SSE_SET_ZVAL_DVAL dst_addr, dst_reg
942||		} else if (Z_LVAL_P(zv) == 0 && Z_MODE(dst_addr) == IS_REG) {
943|			xor Ra(Z_REG(dst_addr)), Ra(Z_REG(dst_addr))
944||		} else {
945|			.if X64
946||				if (!IS_SIGNED_32BIT(Z_LVAL_P(zv))) {
947||					if (Z_MODE(dst_addr) == IS_REG) {
948|						mov64 Ra(Z_REG(dst_addr)), ((uintptr_t)Z_LVAL_P(zv))
949||					} else {
950|						mov64 Ra(tmp_reg), ((uintptr_t)Z_LVAL_P(zv))
951|						SET_ZVAL_LVAL dst_addr, Ra(tmp_reg)
952||					}
953||				} else {
954|					SET_ZVAL_LVAL dst_addr, Z_LVAL_P(zv)
955||				}
956|			.else
957|				SET_ZVAL_LVAL dst_addr, Z_LVAL_P(zv)
958|			.endif
959||		}
960||	}
961||	if (Z_MODE(dst_addr) == IS_MEM_ZVAL) {
962||		if (dst_def_info == MAY_BE_DOUBLE) {
963||			if ((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
964|				SET_ZVAL_TYPE_INFO dst_addr, IS_DOUBLE
965||			}
966||		} else if (((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != (1<<Z_TYPE_P(zv))) || (dst_info & (MAY_BE_STRING|MAY_BE_ARRAY)) != 0) {
967|			SET_ZVAL_TYPE_INFO dst_addr, Z_TYPE_INFO_P(zv)
968||		}
969||	}
970|.endmacro
971
972|.macro ZVAL_COPY_CONST_2, dst_addr, res_addr, dst_info, dst_def_info, zv, tmp_reg
973||	if (Z_TYPE_P(zv) > IS_TRUE) {
974||		if (Z_TYPE_P(zv) == IS_DOUBLE) {
975||			zend_reg dst_reg = (Z_MODE(dst_addr) == IS_REG) ?
976||				Z_REG(dst_addr) : ((Z_MODE(res_addr) == IS_REG) ? Z_REG(res_addr) : ZREG_XMM0);
977||			if (Z_DVAL_P(zv) == 0.0 && !is_signed(Z_DVAL_P(zv))) {
978||				if (CAN_USE_AVX()) {
979|					vxorps xmm(dst_reg-ZREG_XMM0), xmm(dst_reg-ZREG_XMM0), xmm(dst_reg-ZREG_XMM0)
980||				} else {
981|					xorps xmm(dst_reg-ZREG_XMM0), xmm(dst_reg-ZREG_XMM0)
982||				}
983|			.if X64
984||			} else if (!IS_SIGNED_32BIT(zv)) {
985|				mov64 Ra(tmp_reg), ((uintptr_t)zv)
986|				SSE_AVX_INS movsd, vmovsd, xmm(dst_reg-ZREG_XMM0), qword [Ra(tmp_reg)]
987|			.endif
988||			} else {
989|				SSE_AVX_INS movsd, vmovsd, xmm(dst_reg-ZREG_XMM0), qword [((uint32_t)(uintptr_t)zv)]
990||			}
991|			SSE_SET_ZVAL_DVAL dst_addr, ZREG_XMM0
992|			SSE_SET_ZVAL_DVAL res_addr, ZREG_XMM0
993||		} else if (Z_TYPE_P(zv) == IS_LONG && dst_def_info == MAY_BE_DOUBLE) {
994||			if (Z_MODE(dst_addr) == IS_REG) {
995|				SSE_GET_LONG Z_REG(dst_addr), Z_LVAL_P(zv), ZREG_R0
996|				SSE_SET_ZVAL_DVAL res_addr, Z_REG(dst_addr)
997||			} else if (Z_MODE(res_addr) == IS_REG) {
998|				SSE_GET_LONG Z_REG(res_addr), Z_LVAL_P(zv), ZREG_R0
999|				SSE_SET_ZVAL_DVAL dst_addr, Z_REG(res_addr)
1000||			} else {
1001|				SSE_GET_LONG ZREG_XMM0, Z_LVAL_P(zv), ZREG_R0
1002|				SSE_SET_ZVAL_DVAL dst_addr, ZREG_XMM0
1003|				SSE_SET_ZVAL_DVAL res_addr, ZREG_XMM0
1004||			}
1005||		} else if (Z_LVAL_P(zv) == 0 && (Z_MODE(dst_addr) == IS_REG || Z_MODE(res_addr) == IS_REG)) {
1006||				if (Z_MODE(dst_addr) == IS_REG) {
1007|					xor Ra(Z_REG(dst_addr)), Ra(Z_REG(dst_addr))
1008|					SET_ZVAL_LVAL res_addr, Ra(Z_REG(dst_addr))
1009||				} else {
1010|					xor Ra(Z_REG(res_addr)), Ra(Z_REG(res_addr))
1011|					SET_ZVAL_LVAL dst_addr, Ra(Z_REG(res_addr))
1012||				}
1013||		} else {
1014|			.if X64
1015||				if (!IS_SIGNED_32BIT(Z_LVAL_P(zv))) {
1016||					if (Z_MODE(dst_addr) == IS_REG) {
1017|						mov64 Ra(Z_REG(dst_addr)), ((uintptr_t)Z_LVAL_P(zv))
1018|						SET_ZVAL_LVAL res_addr, Ra(Z_REG(dst_addr))
1019||					} else if (Z_MODE(res_addr) == IS_REG) {
1020|						mov64 Ra(Z_REG(res_addr)), ((uintptr_t)Z_LVAL_P(zv))
1021|						SET_ZVAL_LVAL dst_addr, Ra(Z_REG(res_addr))
1022||					} else {
1023|						mov64 Ra(tmp_reg), ((uintptr_t)Z_LVAL_P(zv))
1024|						SET_ZVAL_LVAL dst_addr, Ra(tmp_reg)
1025|						SET_ZVAL_LVAL res_addr, Ra(tmp_reg)
1026||					}
1027||				} else if (Z_MODE(dst_addr) == IS_REG) {
1028|					SET_ZVAL_LVAL dst_addr, Z_LVAL_P(zv)
1029|					SET_ZVAL_LVAL res_addr, Ra(Z_REG(dst_addr))
1030||				} else if (Z_MODE(res_addr) == IS_REG) {
1031|					SET_ZVAL_LVAL res_addr, Z_LVAL_P(zv)
1032|					SET_ZVAL_LVAL dst_addr, Ra(Z_REG(res_addr))
1033||				} else {
1034|					SET_ZVAL_LVAL dst_addr, Z_LVAL_P(zv)
1035|					SET_ZVAL_LVAL res_addr, Z_LVAL_P(zv)
1036||				}
1037|			.else
1038||				if (Z_MODE(dst_addr) == IS_REG) {
1039|					SET_ZVAL_LVAL dst_addr, Z_LVAL_P(zv)
1040|					SET_ZVAL_LVAL res_addr, Ra(Z_REG(dst_addr))
1041||				} else if (Z_MODE(res_addr) == IS_REG) {
1042|					SET_ZVAL_LVAL res_addr, Z_LVAL_P(zv)
1043|					SET_ZVAL_LVAL dst_addr, Ra(Z_REG(res_addr))
1044||				} else {
1045|					SET_ZVAL_LVAL dst_addr, Z_LVAL_P(zv)
1046|					SET_ZVAL_LVAL res_addr, Z_LVAL_P(zv)
1047||				}
1048|			.endif
1049||		}
1050||	}
1051||	if (Z_MODE(dst_addr) == IS_MEM_ZVAL) {
1052||		if (dst_def_info == MAY_BE_DOUBLE) {
1053||			if ((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
1054|				SET_ZVAL_TYPE_INFO dst_addr, IS_DOUBLE
1055||			}
1056||		} else if (((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != (1<<Z_TYPE_P(zv))) || (dst_info & (MAY_BE_STRING|MAY_BE_ARRAY)) != 0) {
1057|			SET_ZVAL_TYPE_INFO dst_addr, Z_TYPE_INFO_P(zv)
1058||		}
1059||	}
1060||	if (Z_MODE(res_addr) == IS_MEM_ZVAL) {
1061||		if (dst_def_info == MAY_BE_DOUBLE) {
1062|			SET_ZVAL_TYPE_INFO res_addr, IS_DOUBLE
1063||		} else {
1064|			SET_ZVAL_TYPE_INFO res_addr, Z_TYPE_INFO_P(zv)
1065||		}
1066||	}
1067|.endmacro
1068
1069/* the same as above, but "src" may overlap with "tmp_reg1" */
1070|.macro ZVAL_COPY_VALUE, dst_addr, dst_info, src_addr, src_info, tmp_reg1, tmp_reg2
1071|	ZVAL_COPY_VALUE_V dst_addr, dst_info, src_addr, src_info, tmp_reg1, tmp_reg2
1072||	if ((src_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE)) &&
1073||      !(src_info & MAY_BE_GUARD) &&
1074||		has_concrete_type(src_info & MAY_BE_ANY)) {
1075||		if (Z_MODE(dst_addr) == IS_MEM_ZVAL) {
1076||			if ((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != (src_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD))) {
1077||				zend_uchar type = concrete_type(src_info);
1078|				SET_ZVAL_TYPE_INFO dst_addr, type
1079||			}
1080||		}
1081||	} else {
1082|		GET_ZVAL_TYPE_INFO Rd(tmp_reg1), src_addr
1083|		SET_ZVAL_TYPE_INFO dst_addr, Rd(tmp_reg1)
1084||	}
1085|.endmacro
1086
1087|.macro ZVAL_COPY_VALUE_V, dst_addr, dst_info, src_addr, src_info, tmp_reg1, tmp_reg2
1088||	if (src_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) {
1089||		if ((src_info & (MAY_BE_ANY|MAY_BE_GUARD)) == MAY_BE_LONG) {
1090||			if (Z_MODE(src_addr) == IS_REG) {
1091||				if (Z_MODE(dst_addr) != IS_REG || Z_REG(dst_addr) != Z_REG(src_addr)) {
1092|					SET_ZVAL_LVAL dst_addr, Ra(Z_REG(src_addr))
1093||				}
1094||			} else if (Z_MODE(dst_addr) == IS_REG) {
1095|				GET_ZVAL_LVAL Z_REG(dst_addr), src_addr
1096||			} else {
1097|				GET_ZVAL_LVAL tmp_reg2, src_addr
1098|				SET_ZVAL_LVAL dst_addr, Ra(tmp_reg2)
1099||			}
1100||		} else if ((src_info & (MAY_BE_ANY|MAY_BE_GUARD)) == MAY_BE_DOUBLE) {
1101||			if (Z_MODE(src_addr) == IS_REG) {
1102|				SSE_SET_ZVAL_DVAL dst_addr, Z_REG(src_addr)
1103||			} else if (Z_MODE(dst_addr) == IS_REG) {
1104|				SSE_GET_ZVAL_DVAL Z_REG(dst_addr), src_addr
1105||			} else {
1106|				SSE_GET_ZVAL_DVAL ZREG_XMM0, src_addr
1107|				SSE_SET_ZVAL_DVAL dst_addr, ZREG_XMM0
1108||			}
1109||		} else if (!(src_info & (MAY_BE_DOUBLE|MAY_BE_GUARD))) {
1110|			GET_ZVAL_PTR Ra(tmp_reg2), src_addr
1111|			SET_ZVAL_PTR dst_addr, Ra(tmp_reg2)
1112||		} else {
1113|			.if X64
1114|				GET_ZVAL_PTR Ra(tmp_reg2), src_addr
1115|				SET_ZVAL_PTR dst_addr, Ra(tmp_reg2)
1116|			.else
1117||				if ((tmp_reg1 == tmp_reg2 || tmp_reg1 == Z_REG(src_addr))) {
1118|					GET_ZVAL_W2 Ra(tmp_reg2), src_addr
1119|					SET_ZVAL_W2 dst_addr, Ra(tmp_reg2)
1120|					GET_ZVAL_PTR Ra(tmp_reg2), src_addr
1121|					SET_ZVAL_PTR dst_addr, Ra(tmp_reg2)
1122||				} else {
1123|					GET_ZVAL_PTR Ra(tmp_reg2), src_addr
1124|					GET_ZVAL_W2 Ra(tmp_reg1), src_addr
1125|					SET_ZVAL_PTR dst_addr, Ra(tmp_reg2)
1126|					SET_ZVAL_W2 dst_addr, Ra(tmp_reg1)
1127||				}
1128|			.endif
1129||		}
1130||	}
1131|.endmacro
1132
1133|.macro ZVAL_COPY_VALUE_2, dst_addr, dst_info, res_addr, src_addr, src_info, tmp_reg1, tmp_reg2
1134||	if (src_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) {
1135||		if ((src_info & MAY_BE_ANY) == MAY_BE_LONG) {
1136||			if (Z_MODE(src_addr) == IS_REG) {
1137||				if (Z_MODE(dst_addr) != IS_REG || Z_REG(dst_addr) != Z_REG(src_addr)) {
1138|					SET_ZVAL_LVAL dst_addr, Ra(Z_REG(src_addr))
1139||				}
1140||				if (Z_MODE(res_addr) != IS_REG || Z_REG(res_addr) != Z_REG(src_addr)) {
1141|					SET_ZVAL_LVAL res_addr, Ra(Z_REG(src_addr))
1142||				}
1143||			} else if (Z_MODE(dst_addr) == IS_REG) {
1144|				GET_ZVAL_LVAL Z_REG(dst_addr), src_addr
1145||				if (Z_MODE(res_addr) != IS_REG || Z_REG(res_addr) != Z_REG(dst_addr)) {
1146|					SET_ZVAL_LVAL res_addr, Ra(Z_REG(dst_addr))
1147||				}
1148||			} else if (Z_MODE(res_addr) == IS_REG) {
1149|				GET_ZVAL_LVAL Z_REG(res_addr), src_addr
1150|				SET_ZVAL_LVAL dst_addr, Ra(Z_REG(res_addr))
1151||			} else {
1152|				GET_ZVAL_LVAL tmp_reg2, src_addr
1153|				SET_ZVAL_LVAL dst_addr, Ra(tmp_reg2)
1154|				SET_ZVAL_LVAL res_addr, Ra(tmp_reg2)
1155||			}
1156||		} else if ((src_info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
1157||			if (Z_MODE(src_addr) == IS_REG) {
1158|				SSE_SET_ZVAL_DVAL dst_addr, Z_REG(src_addr)
1159|				SSE_SET_ZVAL_DVAL res_addr, Z_REG(src_addr)
1160||			} else if (Z_MODE(dst_addr) == IS_REG) {
1161|				SSE_GET_ZVAL_DVAL Z_REG(dst_addr), src_addr
1162|				SSE_SET_ZVAL_DVAL res_addr, Z_REG(dst_addr)
1163||			} else if (Z_MODE(res_addr) == IS_REG) {
1164|				SSE_GET_ZVAL_DVAL Z_REG(res_addr), src_addr
1165|				SSE_SET_ZVAL_DVAL dst_addr, Z_REG(res_addr)
1166||			} else {
1167|				SSE_GET_ZVAL_DVAL ZREG_XMM0, src_addr
1168|				SSE_SET_ZVAL_DVAL dst_addr, ZREG_XMM0
1169|				SSE_SET_ZVAL_DVAL res_addr, ZREG_XMM0
1170||			}
1171||		} else if (!(src_info & MAY_BE_DOUBLE)) {
1172|			GET_ZVAL_PTR Ra(tmp_reg2), src_addr
1173|			SET_ZVAL_PTR dst_addr, Ra(tmp_reg2)
1174|			SET_ZVAL_PTR res_addr, Ra(tmp_reg2)
1175||		} else {
1176|			.if X64
1177|				GET_ZVAL_PTR Ra(tmp_reg2), src_addr
1178|				SET_ZVAL_PTR dst_addr, Ra(tmp_reg2)
1179|				SET_ZVAL_PTR res_addr, Ra(tmp_reg2)
1180|			.else
1181||				if (tmp_reg1 == tmp_reg2 || tmp_reg1 == Z_REG(src_addr)) {
1182|					GET_ZVAL_W2 Ra(tmp_reg2), src_addr
1183|					SET_ZVAL_W2 dst_addr, Ra(tmp_reg2)
1184|					SET_ZVAL_W2 res_addr, Ra(tmp_reg2)
1185|					GET_ZVAL_PTR Ra(tmp_reg2), src_addr
1186|					SET_ZVAL_PTR dst_addr, Ra(tmp_reg2)
1187|					SET_ZVAL_PTR res_addr, Ra(tmp_reg2)
1188||				} else {
1189|					GET_ZVAL_PTR Ra(tmp_reg2), src_addr
1190|					GET_ZVAL_W2 Ra(tmp_reg1), src_addr
1191|					SET_ZVAL_PTR dst_addr, Ra(tmp_reg2)
1192|					SET_ZVAL_PTR res_addr, Ra(tmp_reg2)
1193|					SET_ZVAL_W2 dst_addr, Ra(tmp_reg1)
1194|					SET_ZVAL_W2 res_addr, Ra(tmp_reg1)
1195||				}
1196|			.endif
1197||		}
1198||	}
1199||	if ((src_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE)) &&
1200||	    has_concrete_type(src_info & MAY_BE_ANY)) {
1201||		zend_uchar type = concrete_type(src_info);
1202||		if (Z_MODE(dst_addr) == IS_MEM_ZVAL) {
1203||			if ((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != (src_info & (MAY_BE_ANY|MAY_BE_UNDEF))) {
1204|				SET_ZVAL_TYPE_INFO dst_addr, type
1205||			}
1206||		}
1207||		if (Z_MODE(res_addr) == IS_MEM_ZVAL) {
1208|			SET_ZVAL_TYPE_INFO res_addr, type
1209||		}
1210||	} else {
1211|		GET_ZVAL_TYPE_INFO Rd(tmp_reg1), src_addr
1212|		SET_ZVAL_TYPE_INFO dst_addr, Rd(tmp_reg1)
1213|		SET_ZVAL_TYPE_INFO res_addr, Rd(tmp_reg1)
1214||	}
1215|.endmacro
1216
1217|.macro IF_UNDEF, type_reg, label
1218|	test type_reg, type_reg
1219|	je label
1220|.endmacro
1221
1222|.macro IF_TYPE, type, val, label
1223|	cmp type, val
1224|	je label
1225|.endmacro
1226
1227|.macro IF_NOT_TYPE, type, val, label
1228|	cmp type, val
1229|	jne label
1230|.endmacro
1231
1232|.macro IF_Z_TYPE, zv, val, label
1233|	IF_TYPE byte [zv+offsetof(zval, u1.v.type)], val, label
1234|.endmacro
1235
1236|.macro IF_NOT_Z_TYPE, zv, val, label
1237|	IF_NOT_TYPE byte [zv+offsetof(zval, u1.v.type)], val, label
1238|.endmacro
1239
1240|.macro CMP_ZVAL_TYPE, addr, val
1241||	ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
1242|	cmp byte [Ra(Z_REG(addr))+Z_OFFSET(addr)+offsetof(zval, u1.v.type)], val
1243|.endmacro
1244
1245|.macro IF_ZVAL_TYPE, addr, val, label
1246||	ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
1247|	IF_TYPE byte [Ra(Z_REG(addr))+Z_OFFSET(addr)+offsetof(zval, u1.v.type)], val, label
1248|.endmacro
1249
1250|.macro IF_NOT_ZVAL_TYPE, addr, val, label
1251||	ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
1252|	IF_NOT_TYPE byte [Ra(Z_REG(addr))+Z_OFFSET(addr)+offsetof(zval, u1.v.type)], val, label
1253|.endmacro
1254
1255|.macro IF_FLAGS, type_flags, mask, label
1256|	test type_flags, mask
1257|	jnz label
1258|.endmacro
1259
1260|.macro IF_NOT_FLAGS, type_flags, mask, label
1261|	test type_flags, mask
1262|	jz label
1263|.endmacro
1264
1265|.macro IF_REFCOUNTED, type_flags, label
1266|	IF_FLAGS type_flags, IS_TYPE_REFCOUNTED, label
1267|.endmacro
1268
1269|.macro IF_NOT_REFCOUNTED, type_flags, label
1270|	//IF_NOT_FLAGS type_flags, IS_TYPE_REFCOUNTED, label
1271|	test type_flags, type_flags
1272|	jz label
1273|.endmacro
1274
1275|.macro IF_ZVAL_FLAGS, addr, mask, label
1276||	ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
1277|	IF_FLAGS byte [Ra(Z_REG(addr))+Z_OFFSET(addr)+offsetof(zval, u1.v.type_flags)], mask, label
1278|.endmacro
1279
1280|.macro IF_NOT_ZVAL_FLAGS, addr, mask, label
1281||	ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
1282|	IF_NOT_FLAGS byte [Ra(Z_REG(addr))+Z_OFFSET(addr)+offsetof(zval, u1.v.type_flags)], mask, label
1283|.endmacro
1284
1285|.macro IF_ZVAL_REFCOUNTED, addr, label
1286|	IF_ZVAL_FLAGS addr, IS_TYPE_REFCOUNTED, label
1287|.endmacro
1288
1289|.macro IF_NOT_ZVAL_REFCOUNTED, addr, label
1290|	IF_NOT_ZVAL_FLAGS addr, IS_TYPE_REFCOUNTED, label
1291|.endmacro
1292
1293|.macro IF_NOT_ZVAL_COLLECTABLE, addr, label
1294|	IF_NOT_ZVAL_FLAGS addr, IS_TYPE_COLLECTABLE, label
1295|.endmacro
1296
1297|.macro GC_ADDREF, zv
1298|	add dword [zv], 1
1299|.endmacro
1300
1301|.macro GC_DELREF, zv
1302|	sub dword [zv], 1
1303|.endmacro
1304
1305|.macro IF_GC_MAY_NOT_LEAK, ptr, label
1306|	test dword [ptr+4],(GC_INFO_MASK | (GC_NOT_COLLECTABLE << GC_FLAGS_SHIFT))
1307|	jne label
1308|.endmacro
1309
1310|.macro ADDREF_CONST, zv, tmp_reg
1311|	.if X64
1312||		if (!IS_SIGNED_32BIT(Z_LVAL_P(zv))) {
1313|			mov64 tmp_reg, ((uintptr_t)Z_LVAL_P(zv))
1314|			add dword [tmp_reg], 1
1315||		} else {
1316|			add dword [Z_LVAL_P(zv)], 1
1317||		}
1318|	.else
1319|		add dword [Z_LVAL_P(zv)], 1
1320|	.endif
1321|.endmacro
1322
1323|.macro ADDREF_CONST_2, zv, tmp_reg
1324|	.if X64
1325||		if (!IS_SIGNED_32BIT(Z_LVAL_P(zv))) {
1326|			mov64 tmp_reg, ((uintptr_t)Z_LVAL_P(zv))
1327|			add dword [tmp_reg], 2
1328||		} else {
1329|			add dword [Z_LVAL_P(zv)], 2
1330||		}
1331|	.else
1332|		add dword [Z_LVAL_P(zv)], 2
1333|	.endif
1334|.endmacro
1335
1336|.macro TRY_ADDREF, val_info, type_flags_reg, value_ptr_reg
1337||	if (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
1338||		if (val_info & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1339|			IF_NOT_REFCOUNTED type_flags_reg, >1
1340||		}
1341|		GC_ADDREF value_ptr_reg
1342|1:
1343||	}
1344|.endmacro
1345
1346|.macro TRY_ADDREF_2, val_info, type_flags_reg, value_ptr_reg
1347||	if (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
1348||		if (val_info & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1349|			IF_NOT_REFCOUNTED type_flags_reg, >1
1350||		}
1351|		add dword [value_ptr_reg], 2
1352|1:
1353||	}
1354|.endmacro
1355
1356|.macro ZVAL_DEREF, reg, info
1357||	if (info & MAY_BE_REF) {
1358|		IF_NOT_Z_TYPE, reg, IS_REFERENCE, >1
1359|		GET_Z_PTR reg, reg
1360|		add reg, offsetof(zend_reference, val)
1361|1:
1362||	}
1363|.endmacro
1364
1365|.macro SET_EX_OPLINE, op, tmp_reg
1366||	if (op == last_valid_opline) {
1367||		zend_jit_use_last_valid_opline();
1368|		SAVE_IP
1369||	} else {
1370|		ADDR_OP2_2 mov, aword EX->opline, op, tmp_reg
1371||		if (!GCC_GLOBAL_REGS) {
1372||			zend_jit_reset_last_valid_opline();
1373||		}
1374||	}
1375|.endmacro
1376
1377// zval should be in FCARG1a
1378|.macro ZVAL_DTOR_FUNC, var_info, opline // arg1 must be in FCARG1a
1379||	do {
1380||		if (!((var_info) & MAY_BE_GUARD)
1381||		 && has_concrete_type((var_info) & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1382||			zend_uchar type = concrete_type((var_info) & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
1383||			if (type == IS_STRING && !ZEND_DEBUG) {
1384|				EXT_CALL _efree, r0
1385||				break;
1386||			} else if (type == IS_ARRAY) {
1387||				if ((var_info) & (MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_STRING|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_REF)) {
1388||					if (opline && ((var_info) & (MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_REF))) {
1389|						SET_EX_OPLINE opline, r0
1390||					}
1391|					EXT_CALL zend_array_destroy, r0
1392||				} else {
1393|					EXT_CALL zend_jit_array_free, r0
1394||				}
1395||				break;
1396||			} else if (type == IS_OBJECT) {
1397||				if (opline) {
1398|					SET_EX_OPLINE opline, r0
1399||				}
1400|				EXT_CALL zend_objects_store_del, r0
1401||				break;
1402||			}
1403||		}
1404||		if (opline) {
1405|			SET_EX_OPLINE opline, r0
1406||		}
1407|		EXT_CALL rc_dtor_func, r0
1408||	} while(0);
1409|.endmacro
1410
1411|.macro ZVAL_PTR_DTOR, addr, op_info, gc, cold, opline
1412||	if ((op_info) & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF|MAY_BE_GUARD)) {
1413||		if ((op_info) & ((MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_INDIRECT|MAY_BE_GUARD)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1414|			// if (Z_REFCOUNTED_P(cv)) {
1415||			if (cold) {
1416|				IF_ZVAL_REFCOUNTED addr, >1
1417|.cold_code
1418|1:
1419||			} else {
1420|				IF_NOT_ZVAL_REFCOUNTED addr, >4
1421||			}
1422||		}
1423|		// if (!Z_DELREF_P(cv)) {
1424|		GET_ZVAL_PTR FCARG1a, addr
1425|		GC_DELREF FCARG1a
1426||		if (((op_info) & MAY_BE_GUARD) || RC_MAY_BE_1(op_info)) {
1427||			if (((op_info) & MAY_BE_GUARD) || RC_MAY_BE_N(op_info)) {
1428||				if (gc && (((op_info) & MAY_BE_GUARD) || (RC_MAY_BE_N(op_info) && ((op_info) & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT)) != 0))) {
1429|					jnz >3
1430||				} else {
1431|					jnz >4
1432||				}
1433||			}
1434|			// zval_dtor_func(r);
1435|			ZVAL_DTOR_FUNC op_info, opline
1436||			if (gc && (((op_info) & MAY_BE_GUARD) || (RC_MAY_BE_N(op_info) && ((op_info) & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT)) != 0))) {
1437|				jmp >4
1438||			}
1439|3:
1440||		}
1441||		if (gc && (((op_info) & MAY_BE_GUARD) || (RC_MAY_BE_N(op_info) && ((op_info) & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT)) != 0))) {
1442||			if ((op_info) & (MAY_BE_REF|MAY_BE_GUARD)) {
1443||				zend_jit_addr ref_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, offsetof(zend_reference, val));
1444|				IF_NOT_ZVAL_TYPE addr, IS_REFERENCE, >1
1445|				IF_NOT_ZVAL_COLLECTABLE ref_addr, >4
1446|				GET_ZVAL_PTR FCARG1a, ref_addr
1447|1:
1448||			}
1449|			IF_GC_MAY_NOT_LEAK FCARG1a, >4
1450|			// gc_possible_root(Z_COUNTED_P(z))
1451|			EXT_CALL gc_possible_root, r0
1452||		}
1453||		if (cold && ((op_info) & ((MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_INDIRECT|MAY_BE_GUARD)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) != 0) {
1454|			jmp >4
1455|.code
1456||		}
1457|4:
1458||	}
1459|.endmacro
1460
1461|.macro FREE_OP, op_type, op, op_info, cold, opline
1462||	if (op_type & (IS_VAR|IS_TMP_VAR)) {
1463|		ZVAL_PTR_DTOR ZEND_ADDR_MEM_ZVAL(ZREG_FP, op.var), op_info, 0, cold, opline
1464||	}
1465|.endmacro
1466
1467|.macro SEPARATE_ARRAY, addr, op_info, cold
1468||	if (RC_MAY_BE_N(op_info)) {
1469||		if (Z_REG(addr) != ZREG_FP) {
1470|			GET_ZVAL_LVAL ZREG_R0, addr
1471||			if (RC_MAY_BE_1(op_info)) {
1472|				cmp dword [r0], 1 // if (GC_REFCOUNT() > 1)
1473|				jbe >2
1474||			}
1475||			if (Z_REG(addr) != ZREG_FCARG1a || Z_OFFSET(addr) != 0) {
1476|				LOAD_ZVAL_ADDR FCARG1a, addr
1477||			}
1478|			EXT_CALL zend_jit_zval_array_dup, r0
1479|2:
1480|			mov FCARG1a, r0
1481||		} else {
1482|			GET_ZVAL_LVAL ZREG_FCARG1a, addr
1483||			if (RC_MAY_BE_1(op_info)) {
1484|				cmp dword [FCARG1a], 1 // if (GC_REFCOUNT() > 1)
1485||				if (cold) {
1486|					ja >1
1487|.cold_code
1488|1:
1489||				} else {
1490|					jbe >2
1491||				}
1492||			}
1493|			IF_NOT_ZVAL_REFCOUNTED addr, >1
1494|			GC_DELREF FCARG1a
1495|1:
1496|			EXT_CALL zend_array_dup, r0
1497|			SET_ZVAL_PTR addr, r0
1498|			SET_ZVAL_TYPE_INFO addr, IS_ARRAY_EX
1499|			mov FCARG1a, r0
1500||			if (RC_MAY_BE_1(op_info)) {
1501||				if (cold) {
1502|					jmp >2
1503|.code
1504||				}
1505||			}
1506|2:
1507||		}
1508||	} else {
1509|		GET_ZVAL_LVAL ZREG_FCARG1a, addr
1510||	}
1511|.endmacro
1512
1513|.macro EFREE_REG_REFERENCE
1514||#if ZEND_DEBUG
1515|		xor FCARG2a, FCARG2a // filename
1516|		.if X64WIN
1517|			xor CARG3d, CARG3d // lineno
1518|			xor CARG4, CARG4
1519|			mov aword A5, 0
1520|			EXT_CALL _efree, r0
1521|		.elif X64
1522|			xor CARG3d, CARG3d // lineno
1523|			xor CARG4, CARG4
1524|			xor CARG5, CARG5
1525|			EXT_CALL _efree, r0
1526|		.else
1527|			sub r4, 4
1528|			push 0
1529|			push 0
1530|			push 0 // lineno
1531|			EXT_CALL _efree, r0
1532|			add r4, 4
1533|		.endif
1534||#else
1535||#ifdef HAVE_BUILTIN_CONSTANT_P
1536|		EXT_CALL _efree_32, r0
1537||#else
1538|		EXT_CALL _efree, r0
1539||#endif
1540||#endif
1541|.endmacro
1542
1543|.macro EFREE_REFERENCE, ptr
1544|	mov FCARG1a, ptr
1545|	EFREE_REG_REFERENCE
1546|.endmacro
1547
1548|.macro EMALLOC, size, op_array, opline
1549||#if ZEND_DEBUG
1550||		const char *filename = op_array->filename ? op_array->filename->val : NULL;
1551|		mov FCARG1a, size
1552|		LOAD_ADDR FCARG2a, filename
1553|		.if X64WIN
1554|			mov CARG3d, opline->lineno
1555|			xor CARG4, CARG4
1556|			mov aword A5, 0
1557|			EXT_CALL _emalloc, r0
1558|		.elif X64
1559|			mov CARG3d, opline->lineno
1560|			xor CARG4, CARG4
1561|			xor CARG5, CARG5
1562|			EXT_CALL _emalloc, r0
1563|		.else
1564|			sub r4, 4
1565|			push 0
1566|			push 0
1567|			push opline->lineno
1568|			EXT_CALL _emalloc, r0
1569|			add r4, 4
1570|		.endif
1571||#else
1572||#ifdef HAVE_BUILTIN_CONSTANT_P
1573||	if (size > 24 && size <= 32) {
1574|		EXT_CALL _emalloc_32, r0
1575||	} else {
1576|		mov FCARG1a, size
1577|		EXT_CALL _emalloc, r0
1578||	}
1579||#else
1580|		mov FCARG1a, size
1581|		EXT_CALL _emalloc, r0
1582||#endif
1583||#endif
1584|.endmacro
1585
1586|.macro OBJ_RELEASE, reg, exit_label
1587|	GC_DELREF Ra(reg)
1588|	jne >1
1589|	// zend_objects_store_del(obj);
1590||	if (reg != ZREG_FCARG1a) {
1591|		mov FCARG1a, Ra(reg)
1592||	}
1593|	EXT_CALL zend_objects_store_del, r0
1594|	jmp exit_label
1595|1:
1596|	IF_GC_MAY_NOT_LEAK Ra(reg), >1
1597|	// gc_possible_root(obj)
1598||	if (reg != ZREG_FCARG1a) {
1599|		mov FCARG1a, Ra(reg)
1600||	}
1601|	EXT_CALL gc_possible_root, r0
1602|1:
1603|.endmacro
1604
1605|.macro UNDEFINED_OFFSET, opline
1606||	if (opline == last_valid_opline) {
1607||		zend_jit_use_last_valid_opline();
1608|		call ->undefined_offset_ex
1609||	} else {
1610|		SET_EX_OPLINE  opline, r0
1611|		call ->undefined_offset
1612||	}
1613|.endmacro
1614
1615|.macro UNDEFINED_INDEX, opline
1616||	if (opline == last_valid_opline) {
1617||		zend_jit_use_last_valid_opline();
1618|		call ->undefined_index_ex
1619||	} else {
1620|		SET_EX_OPLINE opline, r0
1621|		call ->undefined_index
1622||	}
1623|.endmacro
1624
1625|.macro CANNOT_ADD_ELEMENT, opline
1626||	if (opline == last_valid_opline) {
1627||		zend_jit_use_last_valid_opline();
1628|		call ->cannot_add_element_ex
1629||	} else {
1630|		SET_EX_OPLINE opline, r0
1631|		call ->cannot_add_element
1632||	}
1633|.endmacro
1634
1635static zend_bool reuse_ip = 0;
1636static zend_bool delayed_call_chain = 0;
1637static uint32_t  delayed_call_level = 0;
1638static const zend_op *last_valid_opline = NULL;
1639static zend_bool use_last_vald_opline = 0;
1640static zend_bool track_last_valid_opline = 0;
1641static int jit_return_label = -1;
1642static uint32_t current_trace_num = 0;
1643static uint32_t allowed_opt_flags = 0;
1644
1645static void zend_jit_track_last_valid_opline(void)
1646{
1647	use_last_vald_opline = 0;
1648	track_last_valid_opline = 1;
1649}
1650
1651static void zend_jit_use_last_valid_opline(void)
1652{
1653	if (track_last_valid_opline) {
1654		use_last_vald_opline = 1;
1655		track_last_valid_opline = 0;
1656	}
1657}
1658
1659static zend_bool zend_jit_trace_uses_initial_ip(void)
1660{
1661	return use_last_vald_opline;
1662}
1663
1664static void zend_jit_set_last_valid_opline(const zend_op *target_opline)
1665{
1666	if (!reuse_ip) {
1667		track_last_valid_opline = 0;
1668		last_valid_opline = target_opline;
1669	}
1670}
1671
1672static void zend_jit_reset_last_valid_opline(void)
1673{
1674	track_last_valid_opline = 0;
1675	last_valid_opline = NULL;
1676}
1677
1678static void zend_jit_start_reuse_ip(void)
1679{
1680	zend_jit_reset_last_valid_opline();
1681	reuse_ip = 1;
1682}
1683
1684static int zend_jit_reuse_ip(dasm_State **Dst)
1685{
1686	if (!reuse_ip) {
1687		zend_jit_start_reuse_ip();
1688		|	// call = EX(call);
1689		|	mov RX, EX->call
1690	}
1691	return 1;
1692}
1693
1694static void zend_jit_stop_reuse_ip(void)
1695{
1696	reuse_ip = 0;
1697}
1698
1699/* bit helpers */
1700
1701/* from http://aggregate.org/MAGIC/ */
1702static uint32_t ones32(uint32_t x)
1703{
1704	x -= ((x >> 1) & 0x55555555);
1705	x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
1706	x = (((x >> 4) + x) & 0x0f0f0f0f);
1707	x += (x >> 8);
1708	x += (x >> 16);
1709	return x & 0x0000003f;
1710}
1711
1712static uint32_t floor_log2(uint32_t x)
1713{
1714	ZEND_ASSERT(x != 0);
1715	x |= (x >> 1);
1716	x |= (x >> 2);
1717	x |= (x >> 4);
1718	x |= (x >> 8);
1719	x |= (x >> 16);
1720	return ones32(x) - 1;
1721}
1722
1723static zend_bool is_power_of_two(uint32_t x)
1724{
1725	return !(x & (x - 1)) && x != 0;
1726}
1727
1728static zend_bool has_concrete_type(uint32_t value_type)
1729{
1730	return is_power_of_two (value_type & (MAY_BE_ANY|MAY_BE_UNDEF));
1731}
1732
1733static uint32_t concrete_type(uint32_t value_type)
1734{
1735	return floor_log2(value_type & (MAY_BE_ANY|MAY_BE_UNDEF));
1736}
1737
1738static inline zend_bool is_signed(double d)
1739{
1740	return (((unsigned char*)&d)[sizeof(double)-1] & 0x80) != 0;
1741}
1742
1743static int zend_jit_interrupt_handler_stub(dasm_State **Dst)
1744{
1745	|->interrupt_handler:
1746	|	SAVE_IP
1747	|	//EG(vm_interrupt) = 0;
1748	|	MEM_OP2_1_ZTS mov, byte, executor_globals, vm_interrupt, 0, r0
1749	|	//if (EG(timed_out)) {
1750	|	MEM_OP2_1_ZTS cmp, byte, executor_globals, timed_out, 0, r0
1751	|	je >1
1752	|	//zend_timeout();
1753	|	EXT_CALL zend_timeout, r0
1754	|1:
1755	|	//} else if (zend_interrupt_function) {
1756	if (zend_interrupt_function) {
1757		|	//zend_interrupt_function(execute_data);
1758		|.if X64
1759			|	mov CARG1, FP
1760			|	EXT_CALL zend_interrupt_function, r0
1761		|.else
1762			|	mov aword A1, FP
1763			|	EXT_CALL zend_interrupt_function, r0
1764		|.endif
1765		|	MEM_OP2_1_ZTS cmp, aword, executor_globals, exception, 0, r0
1766		|	je >1
1767		|	EXT_CALL zend_jit_exception_in_interrupt_handler_helper, r0
1768		|1:
1769		|	//ZEND_VM_ENTER();
1770		|	//execute_data = EG(current_execute_data);
1771		|	MEM_OP2_2_ZTS mov, FP, aword, executor_globals, current_execute_data, r0
1772		|	LOAD_IP
1773	}
1774	|	//ZEND_VM_CONTINUE()
1775	if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
1776		|	ADD_HYBRID_SPAD
1777		|	JMP_IP
1778	} else if (GCC_GLOBAL_REGS) {
1779		|	add r4, SPAD // stack alignment
1780		|	JMP_IP
1781	} else {
1782		|	mov FP, aword T2 // restore FP
1783		|	mov RX, aword T3 // restore IP
1784		|	add r4, NR_SPAD // stack alignment
1785		|	mov r0, 1 // ZEND_VM_ENTER
1786		|	ret
1787	}
1788
1789	return 1;
1790}
1791
1792static int zend_jit_exception_handler_stub(dasm_State **Dst)
1793{
1794	|->exception_handler:
1795	if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
1796		const void *handler = zend_get_opcode_handler_func(EG(exception_op));
1797
1798		|	ADD_HYBRID_SPAD
1799		|	EXT_CALL handler, r0
1800		|	JMP_IP
1801	} else {
1802		const void *handler = EG(exception_op)->handler;
1803
1804		if (GCC_GLOBAL_REGS) {
1805			|	add r4, SPAD // stack alignment
1806			|	EXT_JMP handler, r0
1807		} else {
1808			|	mov FCARG1a, FP
1809			|	EXT_CALL handler, r0
1810			|	mov FP, aword T2 // restore FP
1811			|	mov RX, aword T3 // restore IP
1812			|	add r4, NR_SPAD // stack alignment
1813			|	test eax, eax
1814			|	jl >1
1815			|	mov r0, 1 // ZEND_VM_ENTER
1816			|1:
1817			|	ret
1818		}
1819	}
1820
1821	return 1;
1822}
1823
1824static int zend_jit_exception_handler_undef_stub(dasm_State **Dst)
1825{
1826	|->exception_handler_undef:
1827	|	MEM_OP2_2_ZTS mov, r0, aword, executor_globals, opline_before_exception, r0
1828	|	test byte OP:r0->result_type, (IS_TMP_VAR|IS_VAR)
1829	|	jz >1
1830	|	mov eax, dword OP:r0->result.var
1831	|	SET_Z_TYPE_INFO FP + r0, IS_UNDEF
1832	|1:
1833	|	jmp ->exception_handler
1834
1835	return 1;
1836}
1837
1838
1839static int zend_jit_exception_handler_free_op1_op2_stub(dasm_State **Dst)
1840{
1841	|->exception_handler_free_op1_op2:
1842	|	UNDEF_OPLINE_RESULT_IF_USED
1843	|	test byte OP:RX->op1_type, (IS_TMP_VAR|IS_VAR)
1844	|	je >9
1845	|	mov eax, dword OP:RX->op1.var
1846	|	add r0, FP
1847	|	ZVAL_PTR_DTOR ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0), MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, 0, NULL
1848	|9:
1849	|	test byte OP:RX->op2_type, (IS_TMP_VAR|IS_VAR)
1850	|	je >9
1851	|	mov eax, dword OP:RX->op2.var
1852	|	add r0, FP
1853	|	ZVAL_PTR_DTOR ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0), MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, 0, NULL
1854	|9:
1855	|	jmp ->exception_handler
1856	return 1;
1857}
1858
1859static int zend_jit_exception_handler_free_op2_stub(dasm_State **Dst)
1860{
1861	|->exception_handler_free_op2:
1862	|	MEM_OP2_2_ZTS mov, RX, aword, executor_globals, opline_before_exception, r0
1863	|	UNDEF_OPLINE_RESULT_IF_USED
1864	|	test byte OP:RX->op2_type, (IS_TMP_VAR|IS_VAR)
1865	|	je >9
1866	|	mov eax, dword OP:RX->op2.var
1867	|	add r0, FP
1868	|	ZVAL_PTR_DTOR ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0), MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, 0, NULL
1869	|9:
1870	|	jmp ->exception_handler
1871	return 1;
1872}
1873
1874static int zend_jit_leave_function_stub(dasm_State **Dst)
1875{
1876	|->leave_function_handler:
1877	if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
1878		|	test FCARG1d, ZEND_CALL_TOP
1879		|	jnz >1
1880		|	EXT_CALL zend_jit_leave_nested_func_helper, r0
1881		|	ADD_HYBRID_SPAD
1882		|	JMP_IP
1883		|1:
1884		|	EXT_CALL zend_jit_leave_top_func_helper, r0
1885		|	ADD_HYBRID_SPAD
1886		|	JMP_IP
1887	} else {
1888		if (GCC_GLOBAL_REGS) {
1889			|	add r4, SPAD
1890		} else {
1891			|	mov FCARG2a, FP
1892			|	mov FP, aword T2 // restore FP
1893			|	mov RX, aword T3 // restore IP
1894			|	add r4, NR_SPAD
1895		}
1896		|	test FCARG1d, ZEND_CALL_TOP
1897		|	jnz >1
1898		|	EXT_JMP zend_jit_leave_nested_func_helper, r0
1899		|1:
1900		|	EXT_JMP zend_jit_leave_top_func_helper, r0
1901	}
1902
1903	return 1;
1904}
1905
1906static int zend_jit_leave_throw_stub(dasm_State **Dst)
1907{
1908	|->leave_throw_handler:
1909	|	// if (opline->opcode != ZEND_HANDLE_EXCEPTION) {
1910	if (GCC_GLOBAL_REGS) {
1911		|	cmp byte OP:IP->opcode, ZEND_HANDLE_EXCEPTION
1912		|	je >5
1913		|	// EG(opline_before_exception) = opline;
1914		|	MEM_OP2_1_ZTS mov, aword, executor_globals, opline_before_exception, IP, r0
1915		|5:
1916		|	// opline = EG(exception_op);
1917		|	LOAD_IP_ADDR_ZTS executor_globals, exception_op
1918		|	// HANDLE_EXCEPTION()
1919		|	jmp ->exception_handler
1920	} else {
1921		|	GET_IP FCARG1a
1922		|	cmp byte OP:FCARG1a->opcode, ZEND_HANDLE_EXCEPTION
1923		|	je >5
1924		|	// EG(opline_before_exception) = opline;
1925		|	MEM_OP2_1_ZTS mov, aword, executor_globals, opline_before_exception, FCARG1a, r0
1926		|5:
1927		|	// opline = EG(exception_op);
1928		|	LOAD_IP_ADDR_ZTS executor_globals, exception_op
1929		|	mov FP, aword T2 // restore FP
1930		|	mov RX, aword T3 // restore IP
1931		|	add r4, NR_SPAD // stack alignment
1932		|	mov r0, 2 // ZEND_VM_LEAVE
1933		|	ret
1934	}
1935
1936	return 1;
1937}
1938
1939static int zend_jit_icall_throw_stub(dasm_State **Dst)
1940{
1941	|->icall_throw_handler:
1942	|	// zend_rethrow_exception(zend_execute_data *execute_data)
1943	|	mov IP, aword EX->opline
1944	|	// if (EX(opline)->opcode != ZEND_HANDLE_EXCEPTION) {
1945	|	cmp byte OP:IP->opcode, ZEND_HANDLE_EXCEPTION
1946	|	je >1
1947	|	// EG(opline_before_exception) = opline;
1948	|	MEM_OP2_1_ZTS mov, aword, executor_globals, opline_before_exception, IP, r0
1949	|1:
1950	|	// opline = EG(exception_op);
1951	|	LOAD_IP_ADDR_ZTS executor_globals, exception_op
1952	||	if (GCC_GLOBAL_REGS) {
1953	|		mov aword EX->opline, IP
1954	||	}
1955	|	// HANDLE_EXCEPTION()
1956	|	jmp ->exception_handler
1957
1958	return 1;
1959}
1960
1961static int zend_jit_throw_cannot_pass_by_ref_stub(dasm_State **Dst)
1962{
1963	|->throw_cannot_pass_by_ref:
1964	|	mov r0, EX->opline
1965	|	mov ecx, dword OP:r0->result.var
1966	|	SET_Z_TYPE_INFO RX+r1, IS_UNDEF
1967	|	// last EX(call) frame may be delayed
1968	|	cmp RX, EX->call
1969	|	je >1
1970	|	mov r1, EX->call
1971	|	mov EX:RX->prev_execute_data, r1
1972	|	mov EX->call, RX
1973	|1:
1974	|	mov RX, r0
1975	|	mov FCARG1d, dword OP:r0->op2.num
1976	|	EXT_CALL zend_cannot_pass_by_reference, r0
1977	|	cmp byte OP:RX->op1_type, IS_TMP_VAR
1978	|	jne >9
1979	|	mov eax, dword OP:RX->op1.var
1980	|	add r0, FP
1981	|	ZVAL_PTR_DTOR ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0), MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, 0, NULL
1982	|9:
1983	|	jmp ->exception_handler
1984
1985	return 1;
1986}
1987
1988static int zend_jit_undefined_offset_ex_stub(dasm_State **Dst)
1989{
1990	|->undefined_offset_ex:
1991	|	SAVE_IP
1992	|	jmp ->undefined_offset
1993
1994	return 1;
1995}
1996
1997static int zend_jit_undefined_offset_stub(dasm_State **Dst)
1998{
1999	|->undefined_offset:
2000	|.if X64WIN
2001		|	sub r4, 0x28
2002	|.elif X64
2003		|	sub r4, 8
2004	|.else
2005		|	sub r4, 12
2006	|.endif
2007	|	mov r0, EX->opline
2008	|	mov ecx, dword OP:r0->result.var
2009	|	cmp byte OP:r0->op2_type, IS_CONST
2010	|	SET_Z_TYPE_INFO FP + r1, IS_NULL
2011	|	jne >2
2012	|.if X64
2013		|	movsxd r1, dword OP:r0->op2.constant
2014		|	add r0, r1
2015	|.else
2016		|	mov r0, aword OP:r0->op2.zv
2017	|.endif
2018	|	jmp >3
2019	|2:
2020	|	mov eax, dword OP:r0->op2.var
2021	|	add r0, FP
2022	|3:
2023	|.if X64WIN
2024		|	mov CARG1, E_WARNING
2025		|	LOAD_ADDR CARG2, "Undefined array key " ZEND_LONG_FMT
2026		|	mov CARG3, aword [r0]
2027		|	EXT_CALL zend_error, r0
2028		|	add r4, 0x28 // stack alignment
2029	|.elif X64
2030		|	mov CARG1, E_WARNING
2031		|	LOAD_ADDR CARG2, "Undefined array key " ZEND_LONG_FMT
2032		|	mov CARG3, aword [r0]
2033		|	EXT_CALL zend_error, r0
2034		|	add r4, 8 // stack alignment
2035	|.else
2036		|	sub r4, 4
2037		|	push aword [r0]
2038		|	push "Undefined array key " ZEND_LONG_FMT
2039		|	push E_WARNING
2040		|	EXT_CALL zend_error, r0
2041		|	add r4, 28
2042	|.endif
2043	|	ret
2044
2045	return 1;
2046}
2047
2048static int zend_jit_undefined_index_ex_stub(dasm_State **Dst)
2049{
2050	|->undefined_index_ex:
2051	|	SAVE_IP
2052	|	jmp ->undefined_index
2053
2054	return 1;
2055}
2056
2057static int zend_jit_undefined_index_stub(dasm_State **Dst)
2058{
2059	|->undefined_index:
2060	|.if X64WIN
2061		|	sub r4, 0x28
2062	|.elif X64
2063		|	sub r4, 8
2064	|.else
2065		|	sub r4, 12
2066	|.endif
2067	|	mov r0, EX->opline
2068	|	mov ecx, dword OP:r0->result.var
2069	|	cmp byte OP:r0->op2_type, IS_CONST
2070	|	SET_Z_TYPE_INFO FP + r1, IS_NULL
2071	|	jne >2
2072	|.if X64
2073		|	movsxd r1, dword OP:r0->op2.constant
2074		|   add r0, r1
2075	|.else
2076		|	mov r0, aword OP:r0->op2.zv
2077	|.endif
2078	|	jmp >3
2079	|2:
2080	|	mov eax, dword OP:r0->op2.var
2081	|	add r0, FP
2082	|3:
2083	|.if X64WIN
2084		|	mov CARG1, E_WARNING
2085		|	LOAD_ADDR CARG2, "Undefined array key \"%s\""
2086		|	mov CARG3, aword [r0]
2087		|	add CARG3, offsetof(zend_string, val)
2088		|	EXT_CALL zend_error, r0
2089		|	add r4, 0x28
2090	|.elif X64
2091		|	mov CARG1, E_WARNING
2092		|	LOAD_ADDR CARG2, "Undefined array key \"%s\""
2093		|	mov CARG3, aword [r0]
2094		|	add CARG3, offsetof(zend_string, val)
2095		|	EXT_CALL zend_error, r0
2096		|	add r4, 8
2097	|.else
2098		|	sub r4, 4
2099		|	mov r0, aword [r0]
2100		|	add r0, offsetof(zend_string, val)
2101		|	push r0
2102		|	push "Undefined array key \"%s\""
2103		|	push E_WARNING
2104		|	EXT_CALL zend_error, r0
2105		|	add r4, 28
2106	|.endif
2107	|	ret
2108
2109	return 1;
2110}
2111
2112static int zend_jit_cannot_add_element_ex_stub(dasm_State **Dst)
2113{
2114	|->cannot_add_element_ex:
2115	|	SAVE_IP
2116	|	jmp ->cannot_add_element
2117
2118	return 1;
2119}
2120
2121static int zend_jit_cannot_add_element_stub(dasm_State **Dst)
2122{
2123	|->cannot_add_element:
2124	|.if X64WIN
2125		|	sub r4, 0x28
2126	|.elif X64
2127		|	sub r4, 8
2128	|.else
2129		|	sub r4, 12
2130	|.endif
2131	|	mov r0, EX->opline
2132	|	cmp byte OP:r0->result_type, IS_UNUSED
2133	|	jz >1
2134	|	mov eax, dword OP:r0->result.var
2135	|	SET_Z_TYPE_INFO FP + r0, IS_NULL
2136	|1:
2137	|.if X64WIN
2138		|	xor CARG1, CARG1
2139		|	LOAD_ADDR CARG2, "Cannot add element to the array as the next element is already occupied"
2140		|	EXT_CALL zend_throw_error, r0
2141		|	add r4, 0x28
2142	|.elif X64
2143		|	xor CARG1, CARG1
2144		|	LOAD_ADDR CARG2, "Cannot add element to the array as the next element is already occupied"
2145		|	EXT_CALL zend_throw_error, r0
2146		|	add r4, 8
2147	|.else
2148		|	sub r4, 8
2149		|	push "Cannot add element to the array as the next element is already occupied"
2150		|	push 0
2151		|	EXT_CALL zend_throw_error, r0
2152		|	add r4, 28
2153	|.endif
2154	|	ret
2155
2156	return 1;
2157}
2158
2159static int zend_jit_undefined_function_stub(dasm_State **Dst)
2160{
2161	|->undefined_function:
2162	|	mov r0, aword EX->opline
2163	|.if X64
2164		|	xor CARG1, CARG1
2165		|	LOAD_ADDR CARG2, "Call to undefined function %s()"
2166		|	movsxd CARG3, dword [r0 + offsetof(zend_op, op2.constant)]
2167		|	mov CARG3, aword [r0 + CARG3]
2168		|	add CARG3, offsetof(zend_string, val)
2169		|	EXT_CALL zend_throw_error, r0
2170	|.else
2171		|	mov r0, aword [r0 + offsetof(zend_op, op2.zv)]
2172		|	mov r0, aword [r0]
2173		|	add r0, offsetof(zend_string, val)
2174		|	mov aword A3, r0
2175		|	mov aword A2, "Call to undefined function %s()"
2176		|	mov aword A1, 0
2177		|	EXT_CALL zend_throw_error, r0
2178	|.endif
2179	|	jmp ->exception_handler
2180	return 1;
2181}
2182
2183static int zend_jit_negative_shift_stub(dasm_State **Dst)
2184{
2185	|->negative_shift:
2186	|	mov RX, EX->opline
2187	|.if X64
2188		|.if WIN
2189		|	LOAD_ADDR CARG1, &zend_ce_arithmetic_error
2190		|	mov CARG1, aword [CARG1]
2191		|.else
2192		|	LOAD_ADDR CARG1, zend_ce_arithmetic_error
2193		|.endif
2194		|	LOAD_ADDR CARG2, "Bit shift by negative number"
2195		|	EXT_CALL zend_throw_error, r0
2196	|.else
2197		|	sub r4, 8
2198		|	push "Bit shift by negative number"
2199		|.if WIN
2200		|	LOAD_ADDR r0, &zend_ce_arithmetic_error
2201		|	push aword [r0]
2202		|.else
2203		|	PUSH_ADDR zend_ce_arithmetic_error, r0
2204		|.endif
2205		|	EXT_CALL zend_throw_error, r0
2206		|	add r4, 16
2207	|.endif
2208	|	jmp ->exception_handler_free_op1_op2
2209	return 1;
2210}
2211
2212static int zend_jit_mod_by_zero_stub(dasm_State **Dst)
2213{
2214	|->mod_by_zero:
2215	|	mov RX, EX->opline
2216	|.if X64
2217		|.if WIN
2218		|	LOAD_ADDR CARG1, &zend_ce_division_by_zero_error
2219		|	mov CARG1, aword [CARG1]
2220		|.else
2221		|	LOAD_ADDR CARG1, zend_ce_division_by_zero_error
2222		|.endif
2223		|	LOAD_ADDR CARG2, "Modulo by zero"
2224		|	EXT_CALL zend_throw_error, r0
2225	|.else
2226		|	sub r4, 8
2227		|	push "Modulo by zero"
2228		|.if WIN
2229		|	LOAD_ADDR r0, &zend_ce_division_by_zero_error
2230		|	push aword [r0]
2231		|.else
2232		|	PUSH_ADDR zend_ce_division_by_zero_error, r0
2233		|.endif
2234		|	EXT_CALL zend_throw_error, r0
2235		|	add r4, 16
2236	|.endif
2237	|	jmp ->exception_handler_free_op1_op2
2238	return 1;
2239}
2240
2241static int zend_jit_invalid_this_stub(dasm_State **Dst)
2242{
2243	|->invalid_this:
2244	|	UNDEF_OPLINE_RESULT
2245	|.if X64
2246		|	xor CARG1, CARG1
2247		|	LOAD_ADDR CARG2, "Using $this when not in object context"
2248		|	EXT_CALL zend_throw_error, r0
2249	|.else
2250		|	sub r4, 8
2251		|	push "Using $this when not in object context"
2252		|	push 0
2253		|	EXT_CALL zend_throw_error, r0
2254		|	add r4, 16
2255	|.endif
2256	|	jmp ->exception_handler
2257	return 1;
2258}
2259
2260static int zend_jit_double_one_stub(dasm_State **Dst)
2261{
2262	|->one:
2263	|.dword 0, 0x3ff00000
2264	return 1;
2265}
2266
2267static int zend_jit_hybrid_runtime_jit_stub(dasm_State **Dst)
2268{
2269	if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID) {
2270		return 1;
2271	}
2272
2273	|->hybrid_runtime_jit:
2274	|	EXT_CALL zend_runtime_jit, r0
2275	|	JMP_IP
2276	return 1;
2277}
2278
2279static int zend_jit_hybrid_profile_jit_stub(dasm_State **Dst)
2280{
2281	if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID) {
2282		return 1;
2283	}
2284
2285	|->hybrid_profile_jit:
2286	|	// ++zend_jit_profile_counter;
2287	|	.if X64
2288	|		LOAD_ADDR r0, &zend_jit_profile_counter
2289	|		inc aword [r0]
2290	|	.else
2291	|		inc aword [&zend_jit_profile_counter]
2292	|	.endif
2293	|	// op_array = (zend_op_array*)EX(func);
2294	|	mov r0, EX->func
2295	|	// run_time_cache = EX(run_time_cache);
2296	|	mov r2, EX->run_time_cache
2297	|	// jit_extension = (const void*)ZEND_FUNC_INFO(op_array);
2298	|	mov r0, aword [r0 + offsetof(zend_op_array, reserved[zend_func_info_rid])]
2299	|	// ++ZEND_COUNTER_INFO(op_array)
2300	|	inc aword [r2 + zend_jit_profile_counter_rid * sizeof(void*)]
2301	|	// return ((zend_vm_opcode_handler_t)jit_extension->orig_handler)()
2302	|	jmp aword [r0 + offsetof(zend_jit_op_array_extension, orig_handler)]
2303	return 1;
2304}
2305
2306static int zend_jit_hybrid_hot_code_stub(dasm_State **Dst)
2307{
2308	if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID) {
2309		return 1;
2310	}
2311
2312	|->hybrid_hot_code:
2313	|	mov word [r2], ZEND_JIT_COUNTER_INIT
2314	|	mov FCARG1a, FP
2315	|	GET_IP FCARG2a
2316	|	EXT_CALL zend_jit_hot_func, r0
2317	|	JMP_IP
2318	return 1;
2319}
2320
2321/*
2322 * This code is based Mike Pall's "Hashed profile counters" idea, implemented
2323 * in LuaJIT. The full description may be found in "LuaJIT 2.0 intellectual
2324 * property disclosure and research opportunities" email
2325 * at http://lua-users.org/lists/lua-l/2009-11/msg00089.html
2326 *
2327 * In addition we use a variation of Knuth's multiplicative hash function
2328 * described at https://code.i-harness.com/en/q/a21ce
2329 *
2330 * uint64_t hash(uint64_t x) {
2331 *    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
2332 *    x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
2333 *    x = x ^ (x >> 31);
2334 *    return x;
2335 * }
2336 *
2337 * uint_32_t hash(uint32_t x) {
2338 *    x = ((x >> 16) ^ x) * 0x45d9f3b;
2339 *    x = ((x >> 16) ^ x) * 0x45d9f3b;
2340 *    x = (x >> 16) ^ x;
2341 *    return x;
2342 * }
2343 *
2344 */
2345static int zend_jit_hybrid_hot_counter_stub(dasm_State **Dst, uint32_t cost)
2346{
2347	|	mov r0, EX->func
2348	|	mov r1, aword [r0 + offsetof(zend_op_array, reserved[zend_func_info_rid])]
2349	|	mov r2, aword [r1 + offsetof(zend_jit_op_array_hot_extension, counter)]
2350	|	sub word [r2], cost
2351	|	jle ->hybrid_hot_code
2352	|	GET_IP r2
2353	|	sub r2, aword [r0 + offsetof(zend_op_array, opcodes)]
2354	|	// divide by sizeof(zend_op)
2355	|	.if X64
2356	||		ZEND_ASSERT(sizeof(zend_op) == 32);
2357	|		sar r2, 2
2358	|	.else
2359	||		ZEND_ASSERT(sizeof(zend_op) == 28);
2360	|		imul r2, 0xb6db6db7
2361	|	.endif
2362	|	.if X64
2363	|		jmp aword [r1+r2+offsetof(zend_jit_op_array_hot_extension, orig_handlers)]
2364	|	.else
2365	|		jmp aword [r1+r2+offsetof(zend_jit_op_array_hot_extension, orig_handlers)]
2366	|	.endif
2367	return 1;
2368}
2369
2370static int zend_jit_hybrid_func_hot_counter_stub(dasm_State **Dst)
2371{
2372	if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID || !JIT_G(hot_func)) {
2373		return 1;
2374	}
2375
2376	|->hybrid_func_hot_counter:
2377
2378	return zend_jit_hybrid_hot_counter_stub(Dst,
2379		((ZEND_JIT_COUNTER_INIT + JIT_G(hot_func) - 1) / JIT_G(hot_func)));
2380}
2381
2382static int zend_jit_hybrid_loop_hot_counter_stub(dasm_State **Dst)
2383{
2384	if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID || !JIT_G(hot_loop)) {
2385		return 1;
2386	}
2387
2388	|->hybrid_loop_hot_counter:
2389
2390	return zend_jit_hybrid_hot_counter_stub(Dst,
2391		((ZEND_JIT_COUNTER_INIT + JIT_G(hot_loop) - 1) / JIT_G(hot_loop)));
2392}
2393
2394static int zend_jit_hybrid_hot_trace_stub(dasm_State **Dst)
2395{
2396	if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID) {
2397		return 1;
2398	}
2399
2400	|->hybrid_hot_trace:
2401	|	mov word [r2], ZEND_JIT_COUNTER_INIT
2402	|	mov FCARG1a, FP
2403	|	GET_IP FCARG2a
2404	|	EXT_CALL zend_jit_trace_hot_root, r0
2405	|	test eax, eax // TODO : remove this check at least for HYBRID VM ???
2406	|	jl >1
2407	|	MEM_OP2_2_ZTS mov, FP, aword, executor_globals, current_execute_data, r0
2408	|	LOAD_IP
2409	|	JMP_IP
2410	|1:
2411	|	EXT_JMP zend_jit_halt_op->handler, r0
2412	return 1;
2413}
2414
2415static int zend_jit_hybrid_trace_counter_stub(dasm_State **Dst, uint32_t cost)
2416{
2417	|	mov r0, EX->func
2418	|	mov r1, aword [r0 + offsetof(zend_op_array, reserved[zend_func_info_rid])]
2419	|	mov r1, aword [r1 + offsetof(zend_jit_op_array_trace_extension, offset)]
2420	|	mov r2, aword [IP + r1 + offsetof(zend_op_trace_info, counter)]
2421	|	sub word [r2], cost
2422	|	jle ->hybrid_hot_trace
2423	|	jmp aword [IP + r1]
2424	return 1;
2425}
2426
2427static int zend_jit_hybrid_func_trace_counter_stub(dasm_State **Dst)
2428{
2429	if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID || !JIT_G(hot_func)) {
2430		return 1;
2431	}
2432
2433	|->hybrid_func_trace_counter:
2434
2435	return zend_jit_hybrid_trace_counter_stub(Dst,
2436		((ZEND_JIT_COUNTER_INIT + JIT_G(hot_func) - 1)  / JIT_G(hot_func)));
2437}
2438
2439static int zend_jit_hybrid_ret_trace_counter_stub(dasm_State **Dst)
2440{
2441	if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID || !JIT_G(hot_return)) {
2442		return 1;
2443	}
2444
2445	|->hybrid_ret_trace_counter:
2446
2447	return zend_jit_hybrid_trace_counter_stub(Dst,
2448		((ZEND_JIT_COUNTER_INIT + JIT_G(hot_return) - 1) / JIT_G(hot_return)));
2449}
2450
2451static int zend_jit_hybrid_loop_trace_counter_stub(dasm_State **Dst)
2452{
2453	if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID || !JIT_G(hot_loop)) {
2454		return 1;
2455	}
2456
2457	|->hybrid_loop_trace_counter:
2458
2459	return zend_jit_hybrid_trace_counter_stub(Dst,
2460		((ZEND_JIT_COUNTER_INIT + JIT_G(hot_loop) - 1) / JIT_G(hot_loop)));
2461}
2462
2463static int zend_jit_trace_halt_stub(dasm_State **Dst)
2464{
2465	|->trace_halt:
2466	if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
2467		|	ADD_HYBRID_SPAD
2468		|	EXT_JMP zend_jit_halt_op->handler, r0
2469	} else if (GCC_GLOBAL_REGS) {
2470		|	add r4, SPAD // stack alignment
2471		|	xor IP, IP // PC must be zero
2472		|	ret
2473	} else {
2474		|	mov FP, aword T2 // restore FP
2475		|	mov RX, aword T3 // restore IP
2476		|	add r4, NR_SPAD // stack alignment
2477		|	mov r0, -1 // ZEND_VM_RETURN
2478		|	ret
2479	}
2480	return 1;
2481}
2482
2483static int zend_jit_trace_exit_stub(dasm_State **Dst)
2484{
2485	|->trace_exit:
2486	|
2487	|	// Save CPU registers
2488	|.if X64
2489	|	sub r4, 16*8+16*8-8 /* CPU regs + SSE regs */
2490	|	mov aword [r4+15*8], r15
2491	|	mov aword [r4+11*8], r11
2492	|	mov aword [r4+10*8], r10
2493	|	mov aword [r4+9*8], r9
2494	|	mov aword [r4+8*8], r8
2495	|	mov aword [r4+7*8], rdi
2496	|	mov aword [r4+6*8], rsi
2497	|	mov aword [r4+2*8], rdx
2498	|	mov aword [r4+1*8], rcx
2499	|	mov aword [r4+0*8], rax
2500	|	mov FCARG1a, aword [r4+16*8+16*8-8] // exit_num = POP
2501	|	mov FCARG2a, r4
2502	|	movsd qword [r4+16*8+15*8], xmm15
2503	|	movsd qword [r4+16*8+14*8], xmm14
2504	|	movsd qword [r4+16*8+13*8], xmm13
2505	|	movsd qword [r4+16*8+12*8], xmm12
2506	|	movsd qword [r4+16*8+11*8], xmm11
2507	|	movsd qword [r4+16*8+10*8], xmm10
2508	|	movsd qword [r4+16*8+9*8], xmm9
2509	|	movsd qword [r4+16*8+8*8], xmm8
2510	|	movsd qword [r4+16*8+7*8], xmm7
2511	|	movsd qword [r4+16*8+6*8], xmm6
2512	|	movsd qword [r4+16*8+5*8], xmm5
2513	|	movsd qword [r4+16*8+4*8], xmm4
2514	|	movsd qword [r4+16*8+3*8], xmm3
2515	|	movsd qword [r4+16*8+2*8], xmm2
2516	|	movsd qword [r4+16*8+1*8], xmm1
2517	|	movsd qword [r4+16*8+0*8], xmm0
2518	|.if X64WIN
2519	|	sub r4, 32 /* shadow space */
2520	|.endif
2521	|.else
2522	|	sub r4, 8*4+8*8-4 /* CPU regs + SSE regs */
2523	|	mov aword [r4+7*4], edi
2524	|	mov aword [r4+2*4], edx
2525	|	mov aword [r4+1*4], ecx
2526	|	mov aword [r4+0*4], eax
2527	|	mov FCARG1a, aword [r4+8*4+8*8-4] // exit_num = POP
2528	|	mov FCARG2a, r4
2529	|	movsd qword [r4+8*4+7*8], xmm7
2530	|	movsd qword [r4+8*4+6*8], xmm6
2531	|	movsd qword [r4+8*4+5*8], xmm5
2532	|	movsd qword [r4+8*4+4*8], xmm4
2533	|	movsd qword [r4+8*4+3*8], xmm3
2534	|	movsd qword [r4+8*4+2*8], xmm2
2535	|	movsd qword [r4+8*4+1*8], xmm1
2536	|	movsd qword [r4+8*4+0*8], xmm0
2537	|.endif
2538	|
2539	|	// EX(opline) = opline
2540	|	SAVE_IP
2541	|	// zend_jit_trace_exit(trace_num, exit_num)
2542	|	EXT_CALL zend_jit_trace_exit, r0
2543	|.if X64WIN
2544	|	add r4, 16*8+16*8+32 /* CPU regs + SSE regs + shadow space */
2545	|.elif X64
2546	|	add r4, 16*8+16*8 /* CPU regs + SSE regs */
2547	|.else
2548	|	add r4, 8*4+8*8 /* CPU regs + SSE regs */
2549	|.endif
2550
2551	|	test eax, eax
2552	|	jne >1
2553
2554	|	// execute_data = EG(current_execute_data)
2555	|	MEM_OP2_2_ZTS mov, FP, aword, executor_globals, current_execute_data, r0
2556	|	// opline = EX(opline)
2557	|	LOAD_IP
2558
2559	if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
2560		|	ADD_HYBRID_SPAD
2561		|	JMP_IP
2562	} else if (GCC_GLOBAL_REGS) {
2563		|	add r4, SPAD // stack alignment
2564		|	JMP_IP
2565	} else {
2566		|	mov FP, aword T2 // restore FP
2567		|	mov RX, aword T3 // restore IP
2568		|	add r4, NR_SPAD // stack alignment
2569		|	mov r0, 1 // ZEND_VM_ENTER
2570		|	ret
2571	}
2572
2573	|1:
2574	|	jl ->trace_halt
2575
2576	|	// execute_data = EG(current_execute_data)
2577	|	MEM_OP2_2_ZTS mov, FP, aword, executor_globals, current_execute_data, r0
2578	|	// opline = EX(opline)
2579	|	LOAD_IP
2580
2581	|	// check for interrupt (try to avoid this ???)
2582	|	MEM_OP2_1_ZTS cmp, byte, executor_globals, vm_interrupt, 0, r0
2583	|	jne ->interrupt_handler
2584
2585	if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
2586		|	ADD_HYBRID_SPAD
2587		|	mov r0, EX->func
2588		|	mov r0, aword [r0 + offsetof(zend_op_array, reserved[zend_func_info_rid])]
2589		|	mov r0, aword [r0 + offsetof(zend_jit_op_array_trace_extension, offset)]
2590		|	jmp aword [IP + r0]
2591	} else if (GCC_GLOBAL_REGS) {
2592		|	add r4, SPAD // stack alignment
2593		|	mov r0, EX->func
2594		|	mov r0, aword [r0 + offsetof(zend_op_array, reserved[zend_func_info_rid])]
2595		|	mov r0, aword [r0 + offsetof(zend_jit_op_array_trace_extension, offset)]
2596		|	jmp aword [IP + r0]
2597	} else {
2598		|	mov IP, aword EX->opline
2599		|	mov FCARG1a, FP
2600		|	mov r0, EX->func
2601		|	mov r0, aword [r0 + offsetof(zend_op_array, reserved[zend_func_info_rid])]
2602		|	mov r0, aword [r0 + offsetof(zend_jit_op_array_trace_extension, offset)]
2603		|	call aword [IP + r0]
2604		|	test eax, eax
2605		|	jl ->trace_halt
2606		|	mov FP, aword T2 // restore FP
2607		|	mov RX, aword T3 // restore IP
2608		|	add r4, NR_SPAD // stack alignment
2609		|	mov r0, 1 // ZEND_VM_ENTER
2610		|	ret
2611	}
2612
2613	return 1;
2614}
2615
2616static int zend_jit_trace_escape_stub(dasm_State **Dst)
2617{
2618	|->trace_escape:
2619	|
2620	if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
2621		|	ADD_HYBRID_SPAD
2622		|	JMP_IP
2623	} else if (GCC_GLOBAL_REGS) {
2624		|	add r4, SPAD // stack alignment
2625		|	JMP_IP
2626	} else {
2627		|	mov FP, aword T2 // restore FP
2628		|	mov RX, aword T3 // restore IP
2629		|	add r4, NR_SPAD // stack alignment
2630		|	mov r0, 1 // ZEND_VM_ENTER
2631		|	ret
2632	}
2633
2634	return 1;
2635}
2636
2637/* Keep 32 exit points in a single code block */
2638#define ZEND_JIT_EXIT_POINTS_SPACING   4  // push byte + short jmp = bytes
2639#define ZEND_JIT_EXIT_POINTS_PER_GROUP 32 // number of continuous exit points
2640
2641static int zend_jit_trace_exit_group_stub(dasm_State **Dst, uint32_t n)
2642{
2643	uint32_t i;
2644
2645	for (i = 0; i < ZEND_JIT_EXIT_POINTS_PER_GROUP - 1; i++) {
2646		|	push byte i
2647		|	.byte 0xeb, (4*(ZEND_JIT_EXIT_POINTS_PER_GROUP-i)-6) // jmp >1
2648	}
2649	|	push byte i
2650	|// 1:
2651	|	add aword [r4], n
2652	|	jmp ->trace_exit
2653
2654	return 1;
2655}
2656
2657#ifdef CONTEXT_THREADED_JIT
2658static int zend_jit_context_threaded_call_stub(dasm_State **Dst)
2659{
2660	|->context_threaded_call:
2661	|	pop r0
2662	if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
2663		|	ADD_HYBRID_SPAD
2664		|	jmp aword [IP]
2665	} else if (GCC_GLOBAL_REGS) {
2666		|	add r4, SPAD // stack alignment
2667		|	jmp aword [IP]
2668	} else {
2669		ZEND_UNREACHABLE();
2670		// TODO: context threading can't work without GLOBAL REGS because we have to change
2671		//       the value of execute_data in execute_ex()
2672		|	mov FCARG1a, FP
2673		|	mov r0, aword [FP]
2674		|	mov FP, aword T2 // restore FP
2675		|	mov RX, aword T3 // restore IP
2676		|	add r4, NR_SPAD // stack alignment
2677		|	jmp aword [r0]
2678	}
2679	return 1;
2680}
2681#endif
2682
2683static int zend_jit_assign_to_variable(dasm_State    **Dst,
2684                                       const zend_op  *opline,
2685                                       zend_jit_addr   var_use_addr,
2686                                       zend_jit_addr   var_addr,
2687                                       uint32_t        var_info,
2688                                       uint32_t        var_def_info,
2689                                       zend_uchar      val_type,
2690                                       zend_jit_addr   val_addr,
2691                                       uint32_t        val_info,
2692                                       zend_jit_addr   res_addr,
2693                                       zend_bool       check_exception);
2694
2695static int zend_jit_assign_const_stub(dasm_State **Dst)
2696{
2697	zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
2698	zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG2a, 0);
2699	uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN;
2700
2701	|->assign_const:
2702	|.if X64WIN
2703	|	sub r4, 0x28
2704	|.elif X64
2705	|	sub r4, 8
2706	|.else
2707	|	sub r4, 12
2708	|.endif
2709	if (!zend_jit_assign_to_variable(
2710			Dst, NULL,
2711			var_addr, var_addr, -1, -1,
2712			IS_CONST, val_addr, val_info,
2713			0, 0)) {
2714		return 0;
2715	}
2716	|.if X64WIN
2717	|	add r4, 0x28
2718	|.elif X64
2719	|	add r4, 8
2720	|.else
2721	|	add r4, 12
2722	|.endif
2723	|	ret
2724	return 1;
2725}
2726
2727static int zend_jit_assign_tmp_stub(dasm_State **Dst)
2728{
2729	zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
2730	zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG2a, 0);
2731	uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN;
2732
2733	|->assign_tmp:
2734	|.if X64WIN
2735	|	sub r4, 0x28
2736	|.elif X64
2737	|	sub r4, 8
2738	|.else
2739	|	sub r4, 12
2740	|.endif
2741	if (!zend_jit_assign_to_variable(
2742			Dst, NULL,
2743			var_addr, var_addr, -1, -1,
2744			IS_TMP_VAR, val_addr, val_info,
2745			0, 0)) {
2746		return 0;
2747	}
2748	|.if X64WIN
2749	|	add r4, 0x28
2750	|.elif X64
2751	|	add r4, 8
2752	|.else
2753	|	add r4, 12
2754	|.endif
2755	|	ret
2756	return 1;
2757}
2758
2759static int zend_jit_assign_var_stub(dasm_State **Dst)
2760{
2761	zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
2762	zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG2a, 0);
2763	uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF;
2764
2765	|->assign_var:
2766	|.if X64WIN
2767	|	sub r4, 0x28
2768	|.elif X64
2769	|	sub r4, 8
2770	|.else
2771	|	sub r4, 12
2772	|.endif
2773	if (!zend_jit_assign_to_variable(
2774			Dst, NULL,
2775			var_addr, var_addr, -1, -1,
2776			IS_VAR, val_addr, val_info,
2777			0, 0)) {
2778		return 0;
2779	}
2780	|.if X64WIN
2781	|	add r4, 0x28
2782	|.elif X64
2783	|	add r4, 8
2784	|.else
2785	|	add r4, 12
2786	|.endif
2787	|	ret
2788	return 1;
2789}
2790
2791static int zend_jit_assign_cv_noref_stub(dasm_State **Dst)
2792{
2793	zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
2794	zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG2a, 0);
2795	uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN/*|MAY_BE_UNDEF*/;
2796
2797	|->assign_cv_noref:
2798	|.if X64WIN
2799	|	sub r4, 0x28
2800	|.elif X64
2801	|	sub r4, 8
2802	|.else
2803	|	sub r4, 12
2804	|.endif
2805	if (!zend_jit_assign_to_variable(
2806			Dst, NULL,
2807			var_addr, var_addr, -1, -1,
2808			IS_CV, val_addr, val_info,
2809			0, 0)) {
2810		return 0;
2811	}
2812	|.if X64WIN
2813	|	add r4, 0x28
2814	|.elif X64
2815	|	add r4, 8
2816	|.else
2817	|	add r4, 12
2818	|.endif
2819	|	ret
2820	return 1;
2821}
2822
2823static int zend_jit_assign_cv_stub(dasm_State **Dst)
2824{
2825	zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
2826	zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG2a, 0);
2827	uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF/*|MAY_BE_UNDEF*/;
2828
2829	|->assign_cv:
2830	|.if X64WIN
2831	|	sub r4, 0x28
2832	|.elif X64
2833	|	sub r4, 8
2834	|.else
2835	|	sub r4, 12
2836	|.endif
2837	if (!zend_jit_assign_to_variable(
2838			Dst, NULL,
2839			var_addr, var_addr, -1, -1,
2840			IS_CV, val_addr, val_info,
2841			0, 0)) {
2842		return 0;
2843	}
2844	|.if X64WIN
2845	|	add r4, 0x28
2846	|.elif X64
2847	|	add r4, 8
2848	|.else
2849	|	add r4, 12
2850	|.endif
2851	|	ret
2852	return 1;
2853}
2854
2855static const zend_jit_stub zend_jit_stubs[] = {
2856	JIT_STUB(interrupt_handler),
2857	JIT_STUB(exception_handler),
2858	JIT_STUB(exception_handler_undef),
2859	JIT_STUB(exception_handler_free_op1_op2),
2860	JIT_STUB(exception_handler_free_op2),
2861	JIT_STUB(leave_function),
2862	JIT_STUB(leave_throw),
2863	JIT_STUB(icall_throw),
2864	JIT_STUB(throw_cannot_pass_by_ref),
2865	JIT_STUB(undefined_offset),
2866	JIT_STUB(undefined_index),
2867	JIT_STUB(cannot_add_element),
2868	JIT_STUB(undefined_offset_ex),
2869	JIT_STUB(undefined_index_ex),
2870	JIT_STUB(cannot_add_element_ex),
2871	JIT_STUB(undefined_function),
2872	JIT_STUB(negative_shift),
2873	JIT_STUB(mod_by_zero),
2874	JIT_STUB(invalid_this),
2875	JIT_STUB(trace_halt),
2876	JIT_STUB(trace_exit),
2877	JIT_STUB(trace_escape),
2878	JIT_STUB(hybrid_runtime_jit),
2879	JIT_STUB(hybrid_profile_jit),
2880	JIT_STUB(hybrid_hot_code),
2881	JIT_STUB(hybrid_func_hot_counter),
2882	JIT_STUB(hybrid_loop_hot_counter),
2883	JIT_STUB(hybrid_hot_trace),
2884	JIT_STUB(hybrid_func_trace_counter),
2885	JIT_STUB(hybrid_ret_trace_counter),
2886	JIT_STUB(hybrid_loop_trace_counter),
2887	JIT_STUB(assign_const),
2888	JIT_STUB(assign_tmp),
2889	JIT_STUB(assign_var),
2890	JIT_STUB(assign_cv_noref),
2891	JIT_STUB(assign_cv),
2892	JIT_STUB(double_one),
2893#ifdef CONTEXT_THREADED_JIT
2894	JIT_STUB(context_threaded_call),
2895#endif
2896};
2897
2898#if ZTS && defined(ZEND_WIN32)
2899extern uint32_t _tls_index;
2900extern char *_tls_start;
2901extern char *_tls_end;
2902#endif
2903
2904static int zend_jit_setup(void)
2905{
2906	if (!zend_cpu_supports_sse2()) {
2907		zend_error(E_CORE_ERROR, "CPU doesn't support SSE2");
2908		return FAILURE;
2909	}
2910	allowed_opt_flags = 0;
2911	if (zend_cpu_supports_avx()) {
2912		allowed_opt_flags |= ZEND_JIT_CPU_AVX;
2913	}
2914
2915#if ZTS
2916# ifdef _WIN64
2917	tsrm_tls_index  = _tls_index * sizeof(void*);
2918
2919	/* To find offset of "_tsrm_ls_cache" in TLS segment we perform a linear scan of local TLS memory */
2920	/* Probably, it might be better solution */
2921	do {
2922		void ***tls_mem = ((void**)__readgsqword(0x58))[_tls_index];
2923		void *val = _tsrm_ls_cache;
2924		size_t offset = 0;
2925		size_t size = (char*)&_tls_end - (char*)&_tls_start;
2926
2927		while (offset < size) {
2928			if (*tls_mem == val) {
2929				tsrm_tls_offset = offset;
2930				break;
2931			}
2932			tls_mem++;
2933			offset += sizeof(void*);
2934		}
2935		if (offset >= size) {
2936			// TODO: error message ???
2937			return FAILURE;
2938		}
2939	} while(0);
2940# elif ZEND_WIN32
2941	tsrm_tls_index  = _tls_index * sizeof(void*);
2942
2943	/* To find offset of "_tsrm_ls_cache" in TLS segment we perform a linear scan of local TLS memory */
2944	/* Probably, it might be better solution */
2945	do {
2946		void ***tls_mem = ((void***)__readfsdword(0x2c))[_tls_index];
2947		void *val = _tsrm_ls_cache;
2948		size_t offset = 0;
2949		size_t size = (char*)&_tls_end - (char*)&_tls_start;
2950
2951		while (offset < size) {
2952			if (*tls_mem == val) {
2953				tsrm_tls_offset = offset;
2954				break;
2955			}
2956			tls_mem++;
2957			offset += sizeof(void*);
2958		}
2959		if (offset >= size) {
2960			// TODO: error message ???
2961			return FAILURE;
2962		}
2963	} while(0);
2964# elif defined(__APPLE__) && defined(__x86_64__)
2965	tsrm_ls_cache_tcb_offset = tsrm_get_ls_cache_tcb_offset();
2966	if (tsrm_ls_cache_tcb_offset == 0) {
2967		size_t *ti;
2968		__asm__(
2969			"leaq __tsrm_ls_cache(%%rip),%0"
2970			: "=r" (ti));
2971		tsrm_tls_offset = ti[2];
2972		tsrm_tls_index = ti[1] * 8;
2973	}
2974# elif defined(__GNUC__) && defined(__x86_64__)
2975	tsrm_ls_cache_tcb_offset = tsrm_get_ls_cache_tcb_offset();
2976	if (tsrm_ls_cache_tcb_offset == 0) {
2977#if defined(__has_attribute) && __has_attribute(tls_model) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__MUSL__)
2978		size_t ret;
2979
2980		asm ("movq _tsrm_ls_cache@gottpoff(%%rip),%0"
2981			: "=r" (ret));
2982		tsrm_ls_cache_tcb_offset = ret;
2983#else
2984		size_t *ti;
2985
2986		__asm__(
2987			"leaq _tsrm_ls_cache@tlsgd(%%rip), %0\n"
2988			: "=a" (ti));
2989		tsrm_tls_offset = ti[1];
2990		tsrm_tls_index = ti[0] * 16;
2991#endif
2992	}
2993# elif defined(__GNUC__) && defined(__i386__)
2994	tsrm_ls_cache_tcb_offset = tsrm_get_ls_cache_tcb_offset();
2995	if (tsrm_ls_cache_tcb_offset == 0) {
2996#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__MUSL__)
2997		size_t ret;
2998
2999		asm ("leal _tsrm_ls_cache@ntpoff,%0\n"
3000			: "=a" (ret));
3001		tsrm_ls_cache_tcb_offset = ret;
3002#else
3003		size_t *ti, _ebx, _ecx, _edx;
3004
3005		__asm__(
3006			"call 1f\n"
3007			".subsection 1\n"
3008			"1:\tmovl (%%esp), %%ebx\n\t"
3009			"ret\n"
3010			".previous\n\t"
3011			"addl $_GLOBAL_OFFSET_TABLE_, %%ebx\n\t"
3012			"leal _tsrm_ls_cache@tlsldm(%%ebx), %0\n\t"
3013			"call ___tls_get_addr@plt\n\t"
3014			"leal _tsrm_ls_cache@tlsldm(%%ebx), %0\n"
3015			: "=a" (ti), "=&b" (_ebx), "=&c" (_ecx), "=&d" (_edx));
3016		tsrm_tls_offset = ti[1];
3017		tsrm_tls_index = ti[0] * 8;
3018#endif
3019	}
3020# endif
3021#endif
3022
3023	return SUCCESS;
3024}
3025
3026static ZEND_ATTRIBUTE_UNUSED int zend_jit_trap(dasm_State **Dst)
3027{
3028	|	int3
3029	return 1;
3030}
3031
3032static int zend_jit_align_func(dasm_State **Dst)
3033{
3034	reuse_ip = 0;
3035	delayed_call_chain = 0;
3036	last_valid_opline = NULL;
3037	use_last_vald_opline = 0;
3038	track_last_valid_opline = 0;
3039	jit_return_label = -1;
3040	|.align 16
3041	return 1;
3042}
3043
3044static int zend_jit_prologue(dasm_State **Dst)
3045{
3046	if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
3047		|	SUB_HYBRID_SPAD
3048	} else if (GCC_GLOBAL_REGS) {
3049		|	sub r4, SPAD // stack alignment
3050	} else {
3051		|	sub r4, NR_SPAD // stack alignment
3052		|	mov aword T2, FP // save FP
3053		|	mov aword T3, RX // save IP
3054		|	mov FP, FCARG1a
3055	}
3056	return 1;
3057}
3058
3059static int zend_jit_label(dasm_State **Dst, unsigned int label)
3060{
3061	|=>label:
3062	return 1;
3063}
3064
3065static int zend_jit_save_call_chain(dasm_State **Dst, uint32_t call_level)
3066{
3067	|	// call->prev_execute_data = EX(call);
3068	if (call_level == 1) {
3069		|	mov aword EX:RX->prev_execute_data, 0
3070	} else {
3071		|	mov r0, EX->call
3072		|	mov EX:RX->prev_execute_data, r0
3073	}
3074	|	// EX(call) = call;
3075	|	mov EX->call, RX
3076
3077	delayed_call_chain = 0;
3078
3079	return 1;
3080}
3081
3082static int zend_jit_set_ip(dasm_State **Dst, const zend_op *opline)
3083{
3084	if (last_valid_opline == opline) {
3085		zend_jit_use_last_valid_opline();
3086	} else if (GCC_GLOBAL_REGS && last_valid_opline) {
3087		zend_jit_use_last_valid_opline();
3088		|	ADD_IP (opline - last_valid_opline) * sizeof(zend_op);
3089	} else {
3090		|	LOAD_IP_ADDR opline
3091	}
3092	zend_jit_set_last_valid_opline(opline);
3093
3094	return 1;
3095}
3096
3097static int zend_jit_set_ip_ex(dasm_State **Dst, const zend_op *opline, bool set_ip_reg)
3098{
3099	if (last_valid_opline == opline) {
3100		zend_jit_use_last_valid_opline();
3101	} else if (GCC_GLOBAL_REGS && last_valid_opline) {
3102		zend_jit_use_last_valid_opline();
3103		|	ADD_IP (opline - last_valid_opline) * sizeof(zend_op);
3104	} else if (!GCC_GLOBAL_REGS && set_ip_reg) {
3105		|	LOAD_ADDR RX, opline
3106		|	mov aword EX->opline, RX
3107	} else {
3108		|	LOAD_IP_ADDR opline
3109	}
3110	zend_jit_set_last_valid_opline(opline);
3111
3112	return 1;
3113}
3114
3115static int zend_jit_set_valid_ip(dasm_State **Dst, const zend_op *opline)
3116{
3117	if (delayed_call_chain) {
3118		if (!zend_jit_save_call_chain(Dst, delayed_call_level)) {
3119			return 0;
3120		}
3121	}
3122	if (!zend_jit_set_ip(Dst, opline)) {
3123		return 0;
3124	}
3125	reuse_ip = 0;
3126	return 1;
3127}
3128
3129static int zend_jit_check_timeout(dasm_State **Dst, const zend_op *opline, const void *exit_addr)
3130{
3131#if 0
3132	if (!zend_jit_set_valid_ip(Dst, opline)) {
3133		return 0;
3134	}
3135	|	MEM_OP2_1_ZTS cmp, byte, executor_globals, vm_interrupt, 0, r0
3136	|	jne ->interrupt_handler
3137#else
3138	|	MEM_OP2_1_ZTS cmp, byte, executor_globals, vm_interrupt, 0, r0
3139	if (exit_addr) {
3140		|	jne &exit_addr
3141	} else if (last_valid_opline == opline) {
3142		||		zend_jit_use_last_valid_opline();
3143		|	jne ->interrupt_handler
3144	} else {
3145		|	jne >1
3146		|.cold_code
3147		|1:
3148		|	LOAD_IP_ADDR opline
3149		|	jmp ->interrupt_handler
3150		|.code
3151	}
3152#endif
3153	return 1;
3154}
3155
3156static int zend_jit_trace_end_loop(dasm_State **Dst, int loop_label, const void *timeout_exit_addr)
3157{
3158	if (timeout_exit_addr) {
3159		|	MEM_OP2_1_ZTS cmp, byte, executor_globals, vm_interrupt, 0, r0
3160		|	je =>loop_label
3161		|	jmp &timeout_exit_addr
3162	} else {
3163		|	jmp =>loop_label
3164	}
3165	return 1;
3166}
3167
3168static int zend_jit_check_exception(dasm_State **Dst)
3169{
3170	|	MEM_OP2_1_ZTS cmp, aword, executor_globals, exception, 0, r0
3171	|	jne ->exception_handler
3172	return 1;
3173}
3174
3175static int zend_jit_check_exception_undef_result(dasm_State **Dst, const zend_op *opline)
3176{
3177	if (opline->result_type & (IS_TMP_VAR|IS_VAR)) {
3178		|	MEM_OP2_1_ZTS cmp, aword, executor_globals, exception, 0, r0
3179		|	jne ->exception_handler_undef
3180		return 1;
3181	}
3182	return zend_jit_check_exception(Dst);
3183}
3184
3185static int zend_jit_trace_begin(dasm_State **Dst, uint32_t trace_num, zend_jit_trace_info *parent, uint32_t exit_num)
3186{
3187	zend_regset regset = ZEND_REGSET_SCRATCH;
3188
3189#if ZTS
3190	if (1) {
3191#else
3192	if ((sizeof(void*) == 8 && !IS_SIGNED_32BIT(&EG(jit_trace_num)))) {
3193#endif
3194		/* assignment to EG(jit_trace_num) shouldn't clober CPU register used by deoptimizer */
3195		if (parent) {
3196			int i;
3197			int parent_vars_count = parent->exit_info[exit_num].stack_size;
3198			zend_jit_trace_stack *parent_stack =
3199				parent->stack_map +
3200				parent->exit_info[exit_num].stack_offset;
3201
3202			for (i = 0; i < parent_vars_count; i++) {
3203				if (STACK_REG(parent_stack, i) != ZREG_NONE) {
3204					if (STACK_REG(parent_stack, i) < ZREG_NUM) {
3205						ZEND_REGSET_EXCL(regset, STACK_REG(parent_stack, i));
3206					} else if (STACK_REG(parent_stack, i) == ZREG_ZVAL_COPY_R0) {
3207						ZEND_REGSET_EXCL(regset, ZREG_R0);
3208					}
3209				}
3210			}
3211		}
3212	}
3213
3214	if (parent && parent->exit_info[exit_num].flags & ZEND_JIT_EXIT_METHOD_CALL) {
3215		ZEND_REGSET_EXCL(regset, ZREG_R0);
3216	}
3217
3218	current_trace_num = trace_num;
3219
3220	|	// EG(jit_trace_num) = trace_num;
3221	if (regset == ZEND_REGSET_EMPTY) {
3222		|	push r0
3223		|	MEM_OP2_1_ZTS mov, dword, executor_globals, jit_trace_num, trace_num, r0
3224		|	pop r0
3225	} else {
3226		zend_reg tmp = ZEND_REGSET_FIRST(regset);
3227
3228		|	MEM_OP2_1_ZTS mov, dword, executor_globals, jit_trace_num, trace_num, Ra(tmp)
3229		(void)tmp;
3230	}
3231
3232	return 1;
3233}
3234
3235/* This taken from LuaJIT. Thanks to Mike Pall. */
3236static uint32_t _asm_x86_inslen(const uint8_t* p)
3237{
3238	static const uint8_t map_op1[256] = {
3239		0x92,0x92,0x92,0x92,0x52,0x45,0x51,0x51,0x92,0x92,0x92,0x92,0x52,0x45,0x51,0x20,
3240		0x92,0x92,0x92,0x92,0x52,0x45,0x51,0x51,0x92,0x92,0x92,0x92,0x52,0x45,0x51,0x51,
3241		0x92,0x92,0x92,0x92,0x52,0x45,0x10,0x51,0x92,0x92,0x92,0x92,0x52,0x45,0x10,0x51,
3242		0x92,0x92,0x92,0x92,0x52,0x45,0x10,0x51,0x92,0x92,0x92,0x92,0x52,0x45,0x10,0x51,
3243#if defined(__x86_64__) || defined(_M_X64)
3244		0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,
3245#else
3246		0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,
3247#endif
3248		0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,
3249		0x51,0x51,0x92,0x92,0x10,0x10,0x12,0x11,0x45,0x86,0x52,0x93,0x51,0x51,0x51,0x51,
3250		0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,
3251		0x93,0x86,0x93,0x93,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,
3252		0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x47,0x51,0x51,0x51,0x51,0x51,
3253#if defined(__x86_64__) || defined(_M_X64)
3254		0x59,0x59,0x59,0x59,0x51,0x51,0x51,0x51,0x52,0x45,0x51,0x51,0x51,0x51,0x51,0x51,
3255#else
3256		0x55,0x55,0x55,0x55,0x51,0x51,0x51,0x51,0x52,0x45,0x51,0x51,0x51,0x51,0x51,0x51,
3257#endif
3258		0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,
3259		0x93,0x93,0x53,0x51,0x70,0x71,0x93,0x86,0x54,0x51,0x53,0x51,0x51,0x52,0x51,0x51,
3260		0x92,0x92,0x92,0x92,0x52,0x52,0x51,0x51,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,
3261		0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x45,0x45,0x47,0x52,0x51,0x51,0x51,0x51,
3262		0x10,0x51,0x10,0x10,0x51,0x51,0x63,0x66,0x51,0x51,0x51,0x51,0x51,0x51,0x92,0x92
3263	};
3264	static const uint8_t map_op2[256] = {
3265		0x93,0x93,0x93,0x93,0x52,0x52,0x52,0x52,0x52,0x52,0x51,0x52,0x51,0x93,0x52,0x94,
3266		0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,
3267		0x53,0x53,0x53,0x53,0x53,0x53,0x53,0x53,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,
3268		0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x34,0x51,0x35,0x51,0x51,0x51,0x51,0x51,
3269		0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,
3270		0x53,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,
3271		0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,
3272		0x94,0x54,0x54,0x54,0x93,0x93,0x93,0x52,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,
3273		0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,
3274		0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,
3275		0x52,0x52,0x52,0x93,0x94,0x93,0x51,0x51,0x52,0x52,0x52,0x93,0x94,0x93,0x93,0x93,
3276		0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x94,0x93,0x93,0x93,0x93,0x93,
3277		0x93,0x93,0x94,0x93,0x94,0x94,0x94,0x93,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,
3278		0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,
3279		0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,
3280		0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x52
3281	};
3282	uint32_t result = 0;
3283	uint32_t prefixes = 0;
3284	uint32_t x = map_op1[*p];
3285
3286	for (;;) {
3287		switch (x >> 4) {
3288			case 0:
3289				return result + x + (prefixes & 4);
3290			case 1:
3291				prefixes |= x;
3292				x = map_op1[*++p];
3293				result++;
3294				break;
3295			case 2:
3296				x = map_op2[*++p];
3297				break;
3298			case 3:
3299				p++;
3300				goto mrm;
3301			case 4:
3302				result -= (prefixes & 2);
3303				/* fallthrough */
3304			case 5:
3305				return result + (x & 15);
3306			case 6: /* Group 3. */
3307				if (p[1] & 0x38) {
3308					x = 2;
3309				} else if ((prefixes & 2) && (x == 0x66)) {
3310					x = 4;
3311				}
3312				goto mrm;
3313			case 7: /* VEX c4/c5. */
3314#if !defined(__x86_64__) && !defined(_M_X64)
3315				if (p[1] < 0xc0) {
3316					x = 2;
3317					goto mrm;
3318				}
3319#endif
3320				if (x == 0x70) {
3321					x = *++p & 0x1f;
3322					result++;
3323					if (x >= 2) {
3324						p += 2;
3325						result += 2;
3326						goto mrm;
3327					}
3328				}
3329				p++;
3330				result++;
3331				x = map_op2[*++p];
3332				break;
3333			case 8:
3334				result -= (prefixes & 2);
3335				/* fallthrough */
3336			case 9:
3337mrm:
3338				/* ModR/M and possibly SIB. */
3339				result += (x & 15);
3340				x = *++p;
3341				switch (x >> 6) {
3342					case 0:
3343						if ((x & 7) == 5) {
3344							return result + 4;
3345						}
3346						break;
3347					case 1:
3348						result++;
3349						break;
3350					case 2:
3351						result += 4;
3352						break;
3353					case 3:
3354						return result;
3355				}
3356				if ((x & 7) == 4) {
3357					result++;
3358					if (x < 0x40 && (p[1] & 7) == 5) {
3359						result += 4;
3360					}
3361				}
3362				return result;
3363		}
3364	}
3365}
3366
3367typedef ZEND_SET_ALIGNED(1, uint16_t unaligned_uint16_t);
3368typedef ZEND_SET_ALIGNED(1, int32_t unaligned_int32_t);
3369
3370static int zend_jit_patch(const void *code, size_t size, uint32_t jmp_table_size, const void *from_addr, const void *to_addr)
3371{
3372	int ret = 0;
3373	uint8_t *p, *end;
3374
3375	if (jmp_table_size) {
3376		const void **jmp_slot = (const void **)((char*)code + size);
3377
3378		size -= jmp_table_size * sizeof(void*);
3379		do {
3380			jmp_slot--;
3381			if (*jmp_slot == from_addr) {
3382				*jmp_slot = to_addr;
3383				ret++;
3384			}
3385		} while (--jmp_table_size);
3386	}
3387
3388	p = (uint8_t*)code;
3389	end = p + size - 5;
3390	while (p < end) {
3391		if ((*(unaligned_uint16_t*)p & 0xf0ff) == 0x800f && p + *(unaligned_int32_t*)(p+2) == (uint8_t*)from_addr - 6) {
3392			*(unaligned_int32_t*)(p+2) = ((uint8_t*)to_addr - (p + 6));
3393			ret++;
3394		} else if (*p == 0xe9 && p + *(unaligned_int32_t*)(p+1) == (uint8_t*)from_addr - 5) {
3395			*(unaligned_int32_t*)(p+1) = ((uint8_t*)to_addr - (p + 5));
3396			ret++;
3397		}
3398		p += _asm_x86_inslen(p);
3399	}
3400#ifdef HAVE_VALGRIND
3401	VALGRIND_DISCARD_TRANSLATIONS(code, size);
3402#endif
3403	return ret;
3404}
3405
3406static int zend_jit_link_side_trace(const void *code, size_t size, uint32_t jmp_table_size, uint32_t exit_num, const void *addr)
3407{
3408	return zend_jit_patch(code, size, jmp_table_size, zend_jit_trace_get_exit_addr(exit_num), addr);
3409}
3410
3411static int zend_jit_trace_link_to_root(dasm_State **Dst, zend_jit_trace_info *t, const void *timeout_exit_addr)
3412{
3413	const void *link_addr;
3414	size_t prologue_size;
3415
3416	/* Skip prologue. */
3417	// TODO: don't hardcode this ???
3418	if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
3419#ifdef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE
3420		prologue_size = 0;
3421#elif defined(__x86_64__) || defined(_M_X64)
3422		// sub r4, HYBRID_SPAD
3423		prologue_size = 4;
3424#else
3425		// sub r4, HYBRID_SPAD
3426		prologue_size = 3;
3427#endif
3428	} else if (GCC_GLOBAL_REGS) {
3429		// sub r4, SPAD // stack alignment
3430#if defined(__x86_64__) || defined(_M_X64)
3431		prologue_size = 4;
3432#else
3433		prologue_size = 3;
3434#endif
3435	} else {
3436		// sub r4, NR_SPAD // stack alignment
3437		// mov aword T2, FP // save FP
3438		// mov aword T3, RX // save IP
3439		// mov FP, FCARG1a
3440#if defined(__x86_64__) || defined(_M_X64)
3441		prologue_size = 17;
3442#else
3443		prologue_size = 13;
3444#endif
3445	}
3446	link_addr = (const void*)((const char*)t->code_start + prologue_size);
3447
3448	if (timeout_exit_addr) {
3449		/* Check timeout for links to LOOP */
3450		|	MEM_OP2_1_ZTS cmp, byte, executor_globals, vm_interrupt, 0, r0
3451		|	je &link_addr
3452		|	jmp &timeout_exit_addr
3453	} else {
3454		|	jmp &link_addr
3455	}
3456	return 1;
3457}
3458
3459static int zend_jit_trace_return(dasm_State **Dst, zend_bool original_handler, const zend_op *opline)
3460{
3461#if 0
3462	|	jmp ->trace_escape
3463#else
3464	if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
3465		|	ADD_HYBRID_SPAD
3466		if (!original_handler) {
3467			|	JMP_IP
3468		} else {
3469			|	mov r0, EX->func
3470			|	mov r0, aword [r0 + offsetof(zend_op_array, reserved[zend_func_info_rid])]
3471			|	mov r0, aword [r0 + offsetof(zend_jit_op_array_trace_extension, offset)]
3472			|	jmp aword [IP + r0]
3473		}
3474	} else if (GCC_GLOBAL_REGS) {
3475		|	add r4, SPAD // stack alignment
3476		if (!original_handler) {
3477			|	JMP_IP
3478		} else {
3479			|	mov r0, EX->func
3480			|	mov r0, aword [r0 + offsetof(zend_op_array, reserved[zend_func_info_rid])]
3481			|	mov r0, aword [r0 + offsetof(zend_jit_op_array_trace_extension, offset)]
3482			|	jmp aword [IP + r0]
3483		}
3484	} else {
3485		if (original_handler) {
3486			|	mov FCARG1a, FP
3487			|	mov r0, EX->func
3488			|	mov r0, aword [r0 + offsetof(zend_op_array, reserved[zend_func_info_rid])]
3489			|	mov r0, aword [r0 + offsetof(zend_jit_op_array_trace_extension, offset)]
3490			|	call aword [IP + r0]
3491		}
3492		|	mov FP, aword T2 // restore FP
3493		|	mov RX, aword T3 // restore IP
3494		|	add r4, NR_SPAD // stack alignment
3495		if (!original_handler || !opline ||
3496		    (opline->opcode != ZEND_RETURN
3497		  && opline->opcode != ZEND_RETURN_BY_REF
3498		  && opline->opcode != ZEND_GENERATOR_RETURN
3499		  && opline->opcode != ZEND_GENERATOR_CREATE
3500		  && opline->opcode != ZEND_YIELD
3501		  && opline->opcode != ZEND_YIELD_FROM)) {
3502			|	mov r0, 2 // ZEND_VM_LEAVE
3503		}
3504		|	ret
3505	}
3506#endif
3507	return 1;
3508}
3509
3510static int zend_jit_type_guard(dasm_State **Dst, const zend_op *opline, uint32_t var, uint8_t type)
3511{
3512	int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
3513	const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
3514
3515	if (!exit_addr) {
3516		return 0;
3517	}
3518	|	IF_NOT_Z_TYPE FP + var, type, &exit_addr
3519
3520	return 1;
3521}
3522
3523static int zend_jit_packed_guard(dasm_State **Dst, const zend_op *opline, uint32_t var, uint32_t op_info)
3524{
3525	int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_PACKED_GUARD);
3526	const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
3527
3528	if (!exit_addr) {
3529		return 0;
3530	}
3531
3532	|	GET_ZVAL_LVAL ZREG_FCARG1a, ZEND_ADDR_MEM_ZVAL(ZREG_FP, var)
3533	if (op_info & MAY_BE_ARRAY_PACKED) {
3534		|	test dword [FCARG1a + offsetof(zend_array, u.flags)], HASH_FLAG_PACKED
3535		|	jz &exit_addr
3536	} else {
3537		|	test dword [FCARG1a + offsetof(zend_array, u.flags)], HASH_FLAG_PACKED
3538		|	jnz &exit_addr
3539	}
3540
3541	return 1;
3542}
3543
3544static int zend_jit_trace_handler(dasm_State **Dst, const zend_op_array *op_array, const zend_op *opline, int may_throw, zend_jit_trace_rec *trace)
3545{
3546	zend_jit_op_array_trace_extension *jit_extension =
3547		(zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
3548	size_t offset = jit_extension->offset;
3549	const void *handler =
3550		(zend_vm_opcode_handler_t)ZEND_OP_TRACE_INFO(opline, offset)->call_handler;
3551
3552	if (!zend_jit_set_valid_ip(Dst, opline)) {
3553		return 0;
3554	}
3555	if (!GCC_GLOBAL_REGS) {
3556		|	mov FCARG1a, FP
3557	}
3558	|	EXT_CALL handler, r0
3559	if (may_throw
3560	 && opline->opcode != ZEND_RETURN
3561	 && opline->opcode != ZEND_RETURN_BY_REF) {
3562		|	MEM_OP2_1_ZTS cmp, aword, executor_globals, exception, 0, r1
3563		|	jne ->exception_handler
3564	}
3565
3566	while (trace->op != ZEND_JIT_TRACE_VM && trace->op != ZEND_JIT_TRACE_END) {
3567		trace++;
3568	}
3569
3570	if (!GCC_GLOBAL_REGS
3571	 && (trace->op != ZEND_JIT_TRACE_END || trace->stop != ZEND_JIT_TRACE_STOP_RETURN)) {
3572		if (opline->opcode == ZEND_RETURN ||
3573		    opline->opcode == ZEND_RETURN_BY_REF ||
3574		    opline->opcode == ZEND_DO_UCALL ||
3575		    opline->opcode == ZEND_DO_FCALL_BY_NAME ||
3576		    opline->opcode == ZEND_DO_FCALL ||
3577		    opline->opcode == ZEND_GENERATOR_CREATE) {
3578			|	MEM_OP2_2_ZTS mov, FP, aword, executor_globals, current_execute_data, r1
3579		}
3580	}
3581
3582	if (zend_jit_trace_may_exit(op_array, opline)) {
3583		if (opline->opcode == ZEND_RETURN ||
3584		    opline->opcode == ZEND_RETURN_BY_REF ||
3585		    opline->opcode == ZEND_GENERATOR_CREATE) {
3586
3587			if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
3588#if 0
3589				/* this check should be handled by the following OPLINE guard or jmp [IP] */
3590				|	cmp IP, zend_jit_halt_op
3591				|	je ->trace_halt
3592#endif
3593			} else if (GCC_GLOBAL_REGS) {
3594				|	test IP, IP
3595				|	je ->trace_halt
3596			} else {
3597				|	test eax, eax
3598				|	jl ->trace_halt
3599			}
3600		} else if (opline->opcode == ZEND_EXIT ||
3601		           opline->opcode == ZEND_GENERATOR_RETURN ||
3602		           opline->opcode == ZEND_YIELD ||
3603		           opline->opcode == ZEND_YIELD_FROM) {
3604			|	jmp ->trace_halt
3605		}
3606		if (trace->op != ZEND_JIT_TRACE_END ||
3607		    (trace->stop != ZEND_JIT_TRACE_STOP_RETURN &&
3608		     trace->stop != ZEND_JIT_TRACE_STOP_INTERPRETER)) {
3609
3610			const zend_op *next_opline = trace->opline;
3611			const zend_op *exit_opline = NULL;
3612			uint32_t exit_point;
3613			const void *exit_addr;
3614			uint32_t old_info = 0;
3615			uint32_t old_res_info = 0;
3616			zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
3617
3618			if (zend_is_smart_branch(opline)) {
3619				zend_bool exit_if_true = 0;
3620				exit_opline = zend_jit_trace_get_exit_opline(trace, opline + 1, &exit_if_true);
3621			} else {
3622				switch (opline->opcode) {
3623					case ZEND_JMPZ:
3624					case ZEND_JMPNZ:
3625					case ZEND_JMPZ_EX:
3626					case ZEND_JMPNZ_EX:
3627					case ZEND_JMP_SET:
3628					case ZEND_COALESCE:
3629					case ZEND_JMP_NULL:
3630					case ZEND_FE_RESET_R:
3631					case ZEND_FE_RESET_RW:
3632						exit_opline = (trace->opline == opline + 1) ?
3633							OP_JMP_ADDR(opline, opline->op2) :
3634							opline + 1;
3635						break;
3636					case ZEND_JMPZNZ:
3637						exit_opline = (trace->opline == OP_JMP_ADDR(opline, opline->op2)) ?
3638							ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) :
3639							OP_JMP_ADDR(opline, opline->op2);
3640						break;
3641					case ZEND_FE_FETCH_R:
3642					case ZEND_FE_FETCH_RW:
3643						exit_opline = (trace->opline == opline + 1) ?
3644							ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) :
3645							opline + 1;
3646						break;
3647
3648				}
3649			}
3650
3651			switch (opline->opcode) {
3652				case ZEND_FE_FETCH_R:
3653				case ZEND_FE_FETCH_RW:
3654					if (opline->op2_type != IS_UNUSED) {
3655						old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op2.var));
3656						SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op2.var), IS_UNKNOWN, 1);
3657					}
3658					break;
3659			}
3660
3661			if (opline->result_type == IS_VAR || opline->result_type == IS_TMP_VAR) {
3662				old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
3663				SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN, 1);
3664			}
3665			exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
3666			exit_addr = zend_jit_trace_get_exit_addr(exit_point);
3667
3668			if (opline->result_type == IS_VAR || opline->result_type == IS_TMP_VAR) {
3669				SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
3670			}
3671			switch (opline->opcode) {
3672				case ZEND_FE_FETCH_R:
3673				case ZEND_FE_FETCH_RW:
3674					if (opline->op2_type != IS_UNUSED) {
3675						SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op2.var), old_info);
3676					}
3677					break;
3678			}
3679
3680			if (!exit_addr) {
3681				return 0;
3682			}
3683			|	CMP_IP next_opline
3684			|	jne &exit_addr
3685		}
3686	}
3687
3688	zend_jit_set_last_valid_opline(trace->opline);
3689
3690	return 1;
3691}
3692
3693static int zend_jit_handler(dasm_State **Dst, const zend_op *opline, int may_throw)
3694{
3695	const void *handler;
3696
3697	if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
3698		handler = zend_get_opcode_handler_func(opline);
3699	} else {
3700		handler = opline->handler;
3701	}
3702
3703	if (!zend_jit_set_valid_ip(Dst, opline)) {
3704		return 0;
3705	}
3706	if (!GCC_GLOBAL_REGS) {
3707		|	mov FCARG1a, FP
3708	}
3709	|	EXT_CALL handler, r0
3710	if (may_throw) {
3711		zend_jit_check_exception(Dst);
3712	}
3713
3714	/* Skip the following OP_DATA */
3715	switch (opline->opcode) {
3716		case ZEND_ASSIGN_DIM:
3717		case ZEND_ASSIGN_OBJ:
3718		case ZEND_ASSIGN_STATIC_PROP:
3719		case ZEND_ASSIGN_DIM_OP:
3720		case ZEND_ASSIGN_OBJ_OP:
3721		case ZEND_ASSIGN_STATIC_PROP_OP:
3722		case ZEND_ASSIGN_STATIC_PROP_REF:
3723		case ZEND_ASSIGN_OBJ_REF:
3724			zend_jit_set_last_valid_opline(opline + 2);
3725			break;
3726		default:
3727			zend_jit_set_last_valid_opline(opline + 1);
3728			break;
3729	}
3730
3731	return 1;
3732}
3733
3734static int zend_jit_tail_handler(dasm_State **Dst, const zend_op *opline)
3735{
3736	if (!zend_jit_set_valid_ip(Dst, opline)) {
3737		return 0;
3738	}
3739	if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
3740		if (opline->opcode == ZEND_DO_UCALL ||
3741		    opline->opcode == ZEND_DO_FCALL_BY_NAME ||
3742		    opline->opcode == ZEND_DO_FCALL ||
3743		    opline->opcode == ZEND_RETURN) {
3744
3745			/* Use inlined HYBRID VM handler */
3746			const void *handler = opline->handler;
3747
3748			|	ADD_HYBRID_SPAD
3749			|	EXT_JMP handler, r0
3750		} else {
3751			const void *handler = zend_get_opcode_handler_func(opline);
3752
3753			|	EXT_CALL handler, r0
3754			|	ADD_HYBRID_SPAD
3755			|	JMP_IP
3756		}
3757	} else {
3758		const void *handler = opline->handler;
3759
3760		if (GCC_GLOBAL_REGS) {
3761			|	add r4, SPAD // stack alignment
3762		} else {
3763			|	mov FCARG1a, FP
3764			|	mov FP, aword T2 // restore FP
3765			|	mov RX, aword T3 // restore IP
3766			|	add r4, NR_SPAD // stack alignment
3767		}
3768		|	EXT_JMP handler, r0
3769	}
3770	zend_jit_reset_last_valid_opline();
3771	return 1;
3772}
3773
3774static int zend_jit_trace_opline_guard(dasm_State **Dst, const zend_op *opline)
3775{
3776	uint32_t exit_point = zend_jit_trace_get_exit_point(NULL, 0);
3777	const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
3778
3779	if (!exit_addr) {
3780		return 0;
3781	}
3782	|	CMP_IP opline
3783	|	jne &exit_addr
3784
3785	zend_jit_set_last_valid_opline(opline);
3786
3787	return 1;
3788}
3789
3790static int zend_jit_jmp(dasm_State **Dst, unsigned int target_label)
3791{
3792	|	jmp =>target_label
3793	return 1;
3794}
3795
3796static int zend_jit_cond_jmp(dasm_State **Dst, const zend_op *next_opline, unsigned int target_label)
3797{
3798	|	CMP_IP next_opline
3799	|	jne =>target_label
3800
3801	zend_jit_set_last_valid_opline(next_opline);
3802
3803	return 1;
3804}
3805
3806#ifdef CONTEXT_THREADED_JIT
3807static int zend_jit_context_threaded_call(dasm_State **Dst, const zend_op *opline, unsigned int next_block)
3808{
3809	if (!zend_jit_handler(Dst, opline, 1)) return 0;
3810	if (opline->opcode == ZEND_DO_UCALL) {
3811		|	call ->context_threaded_call
3812	} else {
3813		const zend_op *next_opline = opline + 1;
3814
3815		|	CMP_IP next_opline
3816		|	je =>next_block
3817		|	call ->context_threaded_call
3818	}
3819	return 1;
3820}
3821#endif
3822
3823static int zend_jit_call(dasm_State **Dst, const zend_op *opline, unsigned int next_block)
3824{
3825#ifdef CONTEXT_THREADED_JIT
3826	return zend_jit_context_threaded_call(Dst, opline, next_block);
3827#else
3828	return zend_jit_tail_handler(Dst, opline);
3829#endif
3830}
3831
3832static int zend_jit_spill_store(dasm_State **Dst, zend_jit_addr src, zend_jit_addr dst, uint32_t info, zend_bool set_type)
3833{
3834	ZEND_ASSERT(Z_MODE(src) == IS_REG);
3835	ZEND_ASSERT(Z_MODE(dst) == IS_MEM_ZVAL);
3836
3837	if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
3838		|	SET_ZVAL_LVAL dst, Ra(Z_REG(src))
3839		if (set_type) {
3840			|	SET_ZVAL_TYPE_INFO dst, IS_LONG
3841		}
3842	} else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
3843		|	SSE_SET_ZVAL_DVAL dst, Z_REG(src)
3844		if (set_type) {
3845			|	SET_ZVAL_TYPE_INFO dst, IS_DOUBLE
3846		}
3847	} else {
3848		ZEND_UNREACHABLE();
3849	}
3850	return 1;
3851}
3852
3853static int zend_jit_load_reg(dasm_State **Dst, zend_jit_addr src, zend_jit_addr dst, uint32_t info)
3854{
3855	ZEND_ASSERT(Z_MODE(src) == IS_MEM_ZVAL);
3856	ZEND_ASSERT(Z_MODE(dst) == IS_REG);
3857
3858	if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
3859		|	GET_ZVAL_LVAL Z_REG(dst), src
3860	} else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
3861		|	SSE_GET_ZVAL_DVAL Z_REG(dst), src
3862	} else {
3863		ZEND_UNREACHABLE();
3864	}
3865	return 1;
3866}
3867
3868static int zend_jit_store_var(dasm_State **Dst, uint32_t info, int var, zend_reg reg, zend_bool set_type)
3869{
3870	zend_jit_addr src = ZEND_ADDR_REG(reg);
3871	zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
3872
3873	return zend_jit_spill_store(Dst, src, dst, info, set_type);
3874}
3875
3876static int zend_jit_store_var_type(dasm_State **Dst, int var, uint8_t type)
3877{
3878	zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
3879
3880	|	SET_ZVAL_TYPE_INFO dst, type
3881	return 1;
3882}
3883
3884static int zend_jit_store_var_if_necessary(dasm_State **Dst, int var, zend_jit_addr src, uint32_t info)
3885{
3886	if (Z_MODE(src) == IS_REG && Z_STORE(src)) {
3887		zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
3888		return zend_jit_spill_store(Dst, src, dst, info, 1);
3889	}
3890	return 1;
3891}
3892
3893static int zend_jit_store_var_if_necessary_ex(dasm_State **Dst, int var, zend_jit_addr src, uint32_t info, zend_jit_addr old, uint32_t old_info)
3894{
3895	if (Z_MODE(src) == IS_REG && Z_STORE(src)) {
3896		zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
3897		zend_bool set_type = 1;
3898
3899		if ((info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) ==
3900		    (old_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF))) {
3901			if (Z_MODE(old) != IS_REG || Z_LOAD(old) || Z_STORE(old)) {
3902				set_type = 0;
3903			}
3904		}
3905		return zend_jit_spill_store(Dst, src, dst, info, set_type);
3906	}
3907	return 1;
3908}
3909
3910static int zend_jit_load_var(dasm_State **Dst, uint32_t info, int var, zend_reg reg)
3911{
3912	zend_jit_addr src = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
3913	zend_jit_addr dst = ZEND_ADDR_REG(reg);
3914
3915	return zend_jit_load_reg(Dst, src, dst, info);
3916}
3917
3918static int zend_jit_invalidate_var_if_necessary(dasm_State **Dst, zend_uchar op_type, zend_jit_addr addr, znode_op op)
3919{
3920	if ((op_type & (IS_TMP_VAR|IS_VAR)) && Z_MODE(addr) == IS_REG && !Z_LOAD(addr) && !Z_STORE(addr)) {
3921		zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op.var);
3922		|	SET_ZVAL_TYPE_INFO dst, IS_UNDEF
3923	}
3924	return 1;
3925}
3926
3927static int zend_jit_update_regs(dasm_State **Dst, uint32_t var, zend_jit_addr src, zend_jit_addr dst, uint32_t info)
3928{
3929	if (!zend_jit_same_addr(src, dst)) {
3930		if (Z_MODE(src) == IS_REG) {
3931			if (Z_MODE(dst) == IS_REG) {
3932				if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
3933					|	mov Ra(Z_REG(dst)), Ra(Z_REG(src))
3934				} else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
3935					|	SSE_AVX_INS movaps, vmovaps, xmm(Z_REG(dst)-ZREG_XMM0), xmm(Z_REG(src)-ZREG_XMM0)
3936				} else {
3937					ZEND_UNREACHABLE();
3938				}
3939				if (!Z_LOAD(src) && !Z_STORE(src) && Z_STORE(dst)) {
3940					zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
3941
3942					if (!zend_jit_spill_store(Dst, dst, var_addr, info,
3943							JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
3944							JIT_G(current_frame) == NULL ||
3945							STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var)) == IS_UNKNOWN ||
3946							(1 << STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var))) != (info & MAY_BE_ANY)
3947					)) {
3948						return 0;
3949					}
3950				}
3951			} else if (Z_MODE(dst) == IS_MEM_ZVAL) {
3952				if (!Z_LOAD(src) && !Z_STORE(src)) {
3953					if (!zend_jit_spill_store(Dst, src, dst, info,
3954							JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
3955							JIT_G(current_frame) == NULL ||
3956							STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var)) == IS_UNKNOWN ||
3957							(1 << STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var))) != (info & MAY_BE_ANY)
3958					)) {
3959						return 0;
3960					}
3961				}
3962			} else {
3963				ZEND_UNREACHABLE();
3964			}
3965		} else if (Z_MODE(src) == IS_MEM_ZVAL) {
3966			if (Z_MODE(dst) == IS_REG) {
3967				if (!zend_jit_load_reg(Dst, src, dst, info)) {
3968					return 0;
3969				}
3970			} else {
3971				ZEND_UNREACHABLE();
3972			}
3973		} else {
3974			ZEND_UNREACHABLE();
3975		}
3976	} else if (Z_MODE(dst) == IS_REG && Z_STORE(dst)) {
3977		dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
3978		if (!zend_jit_spill_store(Dst, src, dst, info,
3979				JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
3980				JIT_G(current_frame) == NULL ||
3981				STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var)) == IS_UNKNOWN ||
3982				(1 << STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var))) != (info & MAY_BE_ANY)
3983		)) {
3984			return 0;
3985		}
3986	}
3987	return 1;
3988}
3989
3990static int zend_jit_escape_if_undef_r0(dasm_State **Dst, int var, uint32_t flags, const zend_op *opline)
3991{
3992	zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0);
3993
3994	|	IF_NOT_ZVAL_TYPE val_addr, IS_UNDEF, >1
3995
3996	if (flags & ZEND_JIT_EXIT_RESTORE_CALL) {
3997		if (!zend_jit_save_call_chain(Dst, -1)) {
3998			return 0;
3999		}
4000	}
4001
4002	ZEND_ASSERT(opline);
4003
4004	if ((opline-1)->opcode != ZEND_FETCH_CONSTANT
4005	 && (opline-1)->opcode != ZEND_FETCH_LIST_R
4006	 && ((opline-1)->op1_type & (IS_VAR|IS_TMP_VAR))
4007	 && !(flags & ZEND_JIT_EXIT_FREE_OP1)) {
4008		val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline-1)->op1.var);
4009
4010		|	IF_NOT_ZVAL_REFCOUNTED val_addr, >2
4011		|	GET_ZVAL_PTR r0, val_addr
4012		|	GC_ADDREF r0
4013		|2:
4014	}
4015
4016	|	LOAD_IP_ADDR (opline - 1)
4017	|	jmp ->trace_escape
4018	|1:
4019
4020	return 1;
4021}
4022
4023static int zend_jit_store_const(dasm_State **Dst, int var, zend_reg reg)
4024{
4025	zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4026
4027	if (reg == ZREG_LONG_MIN_MINUS_1) {
4028		|.if X64
4029			|	SET_ZVAL_LVAL dst, 0x00000000
4030			|	SET_ZVAL_W2 dst, 0xc3e00000
4031		|.else
4032			|	SET_ZVAL_LVAL dst, 0x00200000
4033			|	SET_ZVAL_W2 dst, 0xc1e00000
4034		|.endif
4035		|	SET_ZVAL_TYPE_INFO dst, IS_DOUBLE
4036	} else if (reg == ZREG_LONG_MIN) {
4037		|.if X64
4038			|	SET_ZVAL_LVAL dst, 0x00000000
4039			|	SET_ZVAL_W2 dst, 0x80000000
4040		|.else
4041			|	SET_ZVAL_LVAL dst, ZEND_LONG_MIN
4042		|.endif
4043		|	SET_ZVAL_TYPE_INFO dst, IS_LONG
4044	} else if (reg == ZREG_LONG_MAX) {
4045		|.if X64
4046			|	SET_ZVAL_LVAL dst, 0xffffffff
4047			|	SET_ZVAL_W2 dst, 0x7fffffff
4048		|.else
4049			|	SET_ZVAL_LVAL dst, ZEND_LONG_MAX
4050		|.endif
4051		|	SET_ZVAL_TYPE_INFO dst, IS_LONG
4052	} else if (reg == ZREG_LONG_MAX_PLUS_1) {
4053		|.if X64
4054			|	SET_ZVAL_LVAL dst, 0
4055			|	SET_ZVAL_W2 dst, 0x43e00000
4056		|.else
4057			|	SET_ZVAL_LVAL dst, 0
4058			|	SET_ZVAL_W2 dst, 0x41e00000
4059		|.endif
4060		|	SET_ZVAL_TYPE_INFO dst, IS_DOUBLE
4061	} else if (reg == ZREG_NULL) {
4062		|	SET_ZVAL_TYPE_INFO dst, IS_NULL
4063	} else if (reg == ZREG_ZVAL_TRY_ADDREF) {
4064		|	IF_NOT_ZVAL_REFCOUNTED dst, >1
4065		|	GET_ZVAL_PTR r1, dst
4066		|	GC_ADDREF r1
4067		|1:
4068	} else if (reg == ZREG_ZVAL_COPY_R0) {
4069		zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0);
4070
4071		|	ZVAL_COPY_VALUE dst, -1, val_addr, -1, ZREG_R1, ZREG_R2
4072		|	TRY_ADDREF -1, ch, r2
4073	} else {
4074		ZEND_UNREACHABLE();
4075	}
4076	return 1;
4077}
4078
4079static int zend_jit_free_trampoline(dasm_State **Dst)
4080{
4081	|	/// if (UNEXPECTED(func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))
4082	|	test dword [r0 + offsetof(zend_function, common.fn_flags)], ZEND_ACC_CALL_VIA_TRAMPOLINE
4083	|	jz >1
4084	|	mov FCARG1a, r0
4085	|	EXT_CALL zend_jit_free_trampoline_helper, r0
4086	|1:
4087	return 1;
4088}
4089
4090static int zend_jit_inc_dec(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint32_t op1_def_info, zend_jit_addr op1_def_addr, uint32_t res_use_info, uint32_t res_info, zend_jit_addr res_addr, int may_overflow, int may_throw)
4091{
4092	if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)-MAY_BE_LONG)) {
4093		|	IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >2
4094	}
4095	if (opline->opcode == ZEND_POST_INC || opline->opcode == ZEND_POST_DEC) {
4096		|	ZVAL_COPY_VALUE res_addr, res_use_info, op1_addr, MAY_BE_LONG, ZREG_R0, ZREG_R1
4097	}
4098	if (!zend_jit_update_regs(Dst, opline->op1.var, op1_addr, op1_def_addr, MAY_BE_LONG)) {
4099		return 0;
4100	}
4101	if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
4102		|	LONG_OP_WITH_32BIT_CONST add, op1_def_addr, Z_L(1)
4103	} else {
4104		|	LONG_OP_WITH_32BIT_CONST sub, op1_def_addr, Z_L(1)
4105	}
4106
4107	if (may_overflow &&
4108	    (((op1_def_info & MAY_BE_GUARD) && (op1_def_info & MAY_BE_LONG)) ||
4109	     ((opline->result_type != IS_UNUSED && (res_info & MAY_BE_GUARD) && (res_info & MAY_BE_LONG))))) {
4110		int32_t exit_point;
4111		const void *exit_addr;
4112		zend_jit_trace_stack *stack;
4113		uint32_t old_op1_info, old_res_info = 0;
4114
4115		stack = JIT_G(current_frame)->stack;
4116		old_op1_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
4117		SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var), IS_DOUBLE, 0);
4118		if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
4119			SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_LONG_MAX_PLUS_1);
4120		} else {
4121			SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_LONG_MIN_MINUS_1);
4122		}
4123		if (opline->result_type != IS_UNUSED) {
4124			old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
4125			if (opline->opcode == ZEND_PRE_INC) {
4126				SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
4127				SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_LONG_MAX_PLUS_1);
4128			} else if (opline->opcode == ZEND_PRE_DEC) {
4129				SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
4130				SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_LONG_MIN_MINUS_1);
4131			} else if (opline->opcode == ZEND_POST_INC) {
4132				SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_LONG, 0);
4133				SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_LONG_MAX);
4134			} else if (opline->opcode == ZEND_POST_DEC) {
4135				SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_LONG, 0);
4136				SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_LONG_MIN);
4137			}
4138		}
4139
4140		exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
4141		exit_addr = zend_jit_trace_get_exit_addr(exit_point);
4142		|	jo &exit_addr
4143
4144		if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4145		    opline->result_type != IS_UNUSED) {
4146			|	ZVAL_COPY_VALUE res_addr, res_use_info, op1_def_addr, MAY_BE_LONG, ZREG_R0, ZREG_R1
4147		}
4148
4149		SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_op1_info);
4150		if (opline->result_type != IS_UNUSED) {
4151			SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
4152		}
4153	} else if (may_overflow) {
4154		|	jo >1
4155		if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4156		    opline->result_type != IS_UNUSED) {
4157			|	ZVAL_COPY_VALUE res_addr, res_use_info, op1_def_addr, MAY_BE_LONG, ZREG_R0, ZREG_R1
4158		}
4159		|.cold_code
4160		|1:
4161		if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
4162			|.if X64
4163				|	mov64 rax, 0x43e0000000000000
4164				|	SET_ZVAL_LVAL op1_def_addr, rax
4165			|.else
4166				|	SET_ZVAL_LVAL op1_def_addr, 0
4167				|	SET_ZVAL_W2 op1_def_addr, 0x41e00000
4168			|.endif
4169		} else {
4170			|.if X64
4171				|	mov64 rax, 0xc3e0000000000000
4172				|	SET_ZVAL_LVAL op1_def_addr, rax
4173			|.else
4174				|	SET_ZVAL_LVAL op1_def_addr, 0x00200000
4175				|	SET_ZVAL_W2 op1_def_addr, 0xc1e00000
4176			|.endif
4177		}
4178		if (Z_MODE(op1_def_addr) == IS_MEM_ZVAL) {
4179			|	SET_ZVAL_TYPE_INFO op1_def_addr, IS_DOUBLE
4180		}
4181		if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4182		    opline->result_type != IS_UNUSED) {
4183			|	ZVAL_COPY_VALUE res_addr, res_use_info, op1_def_addr, MAY_BE_DOUBLE, ZREG_R0, ZREG_R1
4184		}
4185		|	jmp >3
4186		|.code
4187	} else {
4188		if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4189		    opline->result_type != IS_UNUSED) {
4190			|	ZVAL_COPY_VALUE res_addr, res_use_info, op1_def_addr, MAY_BE_LONG, ZREG_R0, ZREG_R1
4191		}
4192	}
4193	if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
4194		|.cold_code
4195		|2:
4196		if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
4197			|	SET_EX_OPLINE opline, r0
4198			if (op1_info & MAY_BE_UNDEF) {
4199				|	IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >2
4200				|	// zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var))));
4201				|	mov FCARG1d, opline->op1.var
4202				|	SET_ZVAL_TYPE_INFO op1_addr, IS_NULL
4203				|	EXT_CALL zend_jit_undefined_op_helper, r0
4204				op1_info |= MAY_BE_NULL;
4205			}
4206			|2:
4207			|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
4208
4209			|	// ZVAL_DEREF(var_ptr);
4210			if (op1_info & MAY_BE_REF) {
4211				|	IF_NOT_Z_TYPE, FCARG1a, IS_REFERENCE, >2
4212				|	GET_Z_PTR FCARG1a, FCARG1a
4213				|	cmp aword [FCARG1a + offsetof(zend_reference, sources.ptr)], 0
4214				|	jz >1
4215				if (RETURN_VALUE_USED(opline)) {
4216					|	LOAD_ZVAL_ADDR FCARG2a, res_addr
4217				} else {
4218					|	xor FCARG2a, FCARG2a
4219				}
4220				if (opline->opcode == ZEND_PRE_INC) {
4221					|	EXT_CALL zend_jit_pre_inc_typed_ref, r0
4222				} else if (opline->opcode == ZEND_PRE_DEC) {
4223					|	EXT_CALL zend_jit_pre_dec_typed_ref, r0
4224				} else if (opline->opcode == ZEND_POST_INC) {
4225					|	EXT_CALL zend_jit_post_inc_typed_ref, r0
4226				} else if (opline->opcode == ZEND_POST_DEC) {
4227					|	EXT_CALL zend_jit_post_dec_typed_ref, r0
4228				} else {
4229					ZEND_UNREACHABLE();
4230				}
4231				zend_jit_check_exception(Dst);
4232				|	jmp >3
4233				|1:
4234				|	lea FCARG1a, [FCARG1a + offsetof(zend_reference, val)]
4235				|2:
4236			}
4237
4238			if (opline->opcode == ZEND_POST_INC || opline->opcode == ZEND_POST_DEC) {
4239				zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
4240
4241				|	ZVAL_COPY_VALUE res_addr, res_use_info, val_addr, op1_info, ZREG_R0, ZREG_R2
4242				|	TRY_ADDREF op1_info, ah, r2
4243			}
4244			if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
4245				if (opline->opcode == ZEND_PRE_INC && opline->result_type != IS_UNUSED) {
4246					|	LOAD_ZVAL_ADDR FCARG2a, res_addr
4247					|	EXT_CALL zend_jit_pre_inc, r0
4248				} else {
4249					|	EXT_CALL increment_function, r0
4250				}
4251			} else {
4252				if (opline->opcode == ZEND_PRE_DEC && opline->result_type != IS_UNUSED) {
4253					|	LOAD_ZVAL_ADDR FCARG2a, res_addr
4254					|	EXT_CALL zend_jit_pre_dec, r0
4255				} else {
4256					|	EXT_CALL decrement_function, r0
4257				}
4258			}
4259			if (may_throw) {
4260				zend_jit_check_exception(Dst);
4261			}
4262		} else {
4263			zend_reg tmp_reg;
4264
4265			if (opline->opcode == ZEND_POST_INC || opline->opcode == ZEND_POST_DEC) {
4266				|	ZVAL_COPY_VALUE res_addr, res_use_info, op1_addr, MAY_BE_DOUBLE, ZREG_R0, ZREG_R2
4267			}
4268			if (Z_MODE(op1_def_addr) == IS_REG) {
4269				tmp_reg = Z_REG(op1_def_addr);
4270			} else if (Z_MODE(op1_addr) == IS_REG && Z_LAST_USE(op1_addr)) {
4271				tmp_reg = Z_REG(op1_addr);
4272			} else {
4273				tmp_reg = ZREG_XMM0;
4274			}
4275			|	SSE_GET_ZVAL_DVAL tmp_reg, op1_addr
4276			if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
4277				if (CAN_USE_AVX()) {
4278					|	vaddsd xmm(tmp_reg-ZREG_XMM0), xmm(tmp_reg-ZREG_XMM0), qword [->one]
4279				} else {
4280					|	addsd xmm(tmp_reg-ZREG_XMM0), qword [->one]
4281				}
4282			} else {
4283				if (CAN_USE_AVX()) {
4284					|	vsubsd xmm(tmp_reg-ZREG_XMM0), xmm(tmp_reg-ZREG_XMM0), qword [->one]
4285				} else {
4286					|	subsd xmm(tmp_reg-ZREG_XMM0), qword [->one]
4287				}
4288			}
4289			|	SSE_SET_ZVAL_DVAL op1_def_addr, tmp_reg
4290			if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4291			    opline->result_type != IS_UNUSED) {
4292				|	ZVAL_COPY_VALUE res_addr, res_use_info, op1_addr, op1_def_info, ZREG_R0, ZREG_R1
4293				|	TRY_ADDREF op1_def_info, ah, r1
4294			}
4295		}
4296		|	jmp >3
4297		|.code
4298	}
4299	|3:
4300	if (!zend_jit_store_var_if_necessary_ex(Dst, opline->op1.var, op1_def_addr, op1_def_info, op1_addr, op1_info)) {
4301		return 0;
4302	}
4303	if (opline->result_type != IS_UNUSED) {
4304		if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, res_info)) {
4305			return 0;
4306		}
4307	}
4308	return 1;
4309}
4310
4311static int zend_jit_opline_uses_reg(const zend_op  *opline, int8_t reg)
4312{
4313	if ((opline+1)->opcode == ZEND_OP_DATA
4314	 && ((opline+1)->op1_type & (IS_VAR|IS_TMP_VAR|IS_CV))
4315	 && JIT_G(current_frame)->stack[EX_VAR_TO_NUM((opline+1)->op1.var)].reg == reg) {
4316		return 1;
4317	}
4318	return
4319		((opline->result_type & (IS_VAR|IS_TMP_VAR|IS_CV)) &&
4320			JIT_G(current_frame)->stack[EX_VAR_TO_NUM(opline->result.var)].reg == reg) ||
4321		((opline->op1_type & (IS_VAR|IS_TMP_VAR|IS_CV)) &&
4322			JIT_G(current_frame)->stack[EX_VAR_TO_NUM(opline->op1.var)].reg == reg) ||
4323		((opline->op2_type & (IS_VAR|IS_TMP_VAR|IS_CV)) &&
4324			JIT_G(current_frame)->stack[EX_VAR_TO_NUM(opline->op2.var)].reg == reg);
4325}
4326
4327static int zend_jit_math_long_long(dasm_State    **Dst,
4328                                   const zend_op  *opline,
4329                                   zend_uchar      opcode,
4330                                   zend_jit_addr   op1_addr,
4331                                   zend_jit_addr   op2_addr,
4332                                   zend_jit_addr   res_addr,
4333                                   uint32_t        res_info,
4334                                   uint32_t        res_use_info,
4335                                   int             may_overflow)
4336{
4337	zend_bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
4338	zend_reg result_reg;
4339	zend_reg tmp_reg = ZREG_R0;
4340
4341	if (Z_MODE(res_addr) == IS_REG && (res_info & MAY_BE_LONG)) {
4342		if (may_overflow && (res_info & MAY_BE_GUARD)
4343		 && JIT_G(current_frame)
4344		 && zend_jit_opline_uses_reg(opline, Z_REG(res_addr))) {
4345			result_reg = ZREG_R0;
4346		} else {
4347			result_reg = Z_REG(res_addr);
4348		}
4349	} else if (Z_MODE(op1_addr) == IS_REG && Z_LAST_USE(op1_addr) && !may_overflow) {
4350		result_reg = Z_REG(op1_addr);
4351	} else if (Z_REG(res_addr) != ZREG_R0) {
4352		result_reg = ZREG_R0;
4353	} else {
4354		/* ASSIGN_DIM_OP */
4355		result_reg = ZREG_FCARG1a;
4356		tmp_reg = ZREG_FCARG1a;
4357	}
4358
4359	if (opcode == ZEND_MUL &&
4360			Z_MODE(op2_addr) == IS_CONST_ZVAL &&
4361			Z_LVAL_P(Z_ZV(op2_addr)) == 2) {
4362		if (Z_MODE(op1_addr) == IS_REG && !may_overflow) {
4363			|	lea Ra(result_reg), [Ra(Z_REG(op1_addr))+Ra(Z_REG(op1_addr))]
4364		} else {
4365			|	GET_ZVAL_LVAL result_reg, op1_addr
4366			|	add Ra(result_reg), Ra(result_reg)
4367		}
4368	} else if (opcode == ZEND_MUL &&
4369			Z_MODE(op2_addr) == IS_CONST_ZVAL &&
4370			!may_overflow &&
4371			Z_LVAL_P(Z_ZV(op2_addr)) > 0 &&
4372			zend_long_is_power_of_two(Z_LVAL_P(Z_ZV(op2_addr)))) {
4373		|	GET_ZVAL_LVAL result_reg, op1_addr
4374		|	shl Ra(result_reg), zend_long_floor_log2(Z_LVAL_P(Z_ZV(op2_addr)))
4375	} else if (opcode == ZEND_MUL &&
4376			Z_MODE(op1_addr) == IS_CONST_ZVAL &&
4377			Z_LVAL_P(Z_ZV(op1_addr)) == 2) {
4378		if (Z_MODE(op2_addr) == IS_REG && !may_overflow) {
4379			|	lea Ra(result_reg), [Ra(Z_REG(op2_addr))+Ra(Z_REG(op2_addr))]
4380		} else {
4381			|	GET_ZVAL_LVAL result_reg, op2_addr
4382			|	add Ra(result_reg), Ra(result_reg)
4383		}
4384	} else if (opcode == ZEND_MUL &&
4385			Z_MODE(op1_addr) == IS_CONST_ZVAL &&
4386			!may_overflow &&
4387			Z_LVAL_P(Z_ZV(op1_addr)) > 0 &&
4388			zend_long_is_power_of_two(Z_LVAL_P(Z_ZV(op1_addr)))) {
4389		|	GET_ZVAL_LVAL result_reg, op2_addr
4390		|	shl Ra(result_reg), zend_long_floor_log2(Z_LVAL_P(Z_ZV(op1_addr)))
4391	} else if (opcode == ZEND_DIV &&
4392			(Z_MODE(op2_addr) == IS_CONST_ZVAL &&
4393			zend_long_is_power_of_two(Z_LVAL_P(Z_ZV(op2_addr))))) {
4394		|	GET_ZVAL_LVAL result_reg, op1_addr
4395		|	shr Ra(result_reg), zend_long_floor_log2(Z_LVAL_P(Z_ZV(op2_addr)))
4396	} else if (opcode == ZEND_ADD &&
4397			!may_overflow &&
4398			Z_MODE(op1_addr) == IS_REG &&
4399			Z_MODE(op2_addr) == IS_CONST_ZVAL &&
4400			IS_SIGNED_32BIT(Z_LVAL_P(Z_ZV(op2_addr)))) {
4401		|	lea Ra(result_reg), [Ra(Z_REG(op1_addr))+Z_LVAL_P(Z_ZV(op2_addr))]
4402	} else if (opcode == ZEND_ADD &&
4403			!may_overflow &&
4404			Z_MODE(op2_addr) == IS_REG &&
4405			Z_MODE(op1_addr) == IS_CONST_ZVAL &&
4406			IS_SIGNED_32BIT(Z_LVAL_P(Z_ZV(op1_addr)))) {
4407		|	lea Ra(result_reg), [Ra(Z_REG(op2_addr))+Z_LVAL_P(Z_ZV(op1_addr))]
4408	} else if (opcode == ZEND_SUB &&
4409			!may_overflow &&
4410			Z_MODE(op1_addr) == IS_REG &&
4411			Z_MODE(op2_addr) == IS_CONST_ZVAL &&
4412			IS_SIGNED_32BIT(-Z_LVAL_P(Z_ZV(op2_addr)))) {
4413		|	lea Ra(result_reg), [Ra(Z_REG(op1_addr))-Z_LVAL_P(Z_ZV(op2_addr))]
4414	} else {
4415		|	GET_ZVAL_LVAL result_reg, op1_addr
4416		if ((opcode == ZEND_ADD || opcode == ZEND_SUB)
4417		 && Z_MODE(op2_addr) == IS_CONST_ZVAL
4418		 && Z_LVAL_P(Z_ZV(op2_addr)) == 0) {
4419			/* +/- 0 */
4420			may_overflow = 0;
4421		} else if (same_ops && opcode != ZEND_DIV) {
4422			|	LONG_MATH_REG opcode, Ra(result_reg), Ra(result_reg)
4423		} else {
4424			zend_reg tmp_reg;
4425
4426			if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_R0) {
4427				tmp_reg = ZREG_R1;
4428			} else if (result_reg != ZREG_R0) {
4429				tmp_reg = ZREG_R0;
4430			} else {
4431				tmp_reg = ZREG_R1;
4432			}
4433			|	LONG_MATH opcode, result_reg, op2_addr, tmp_reg
4434			(void)tmp_reg;
4435		}
4436	}
4437	if (may_overflow) {
4438		if (res_info & MAY_BE_GUARD) {
4439			int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
4440			const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
4441			if ((res_info & MAY_BE_ANY) == MAY_BE_LONG) {
4442				|	jo &exit_addr
4443				if (Z_MODE(res_addr) == IS_REG && result_reg != Z_REG(res_addr)) {
4444					|	mov Ra(Z_REG(res_addr)), Ra(result_reg)
4445				}
4446			} else if ((res_info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4447				|	jno &exit_addr
4448			} else {
4449				ZEND_UNREACHABLE();
4450			}
4451		} else {
4452			if (res_info & MAY_BE_LONG) {
4453				|	jo >1
4454			} else {
4455				|	jno >1
4456			}
4457		}
4458	}
4459
4460	if (Z_MODE(res_addr) == IS_MEM_ZVAL && (res_info & MAY_BE_LONG)) {
4461		|	SET_ZVAL_LVAL res_addr, Ra(result_reg)
4462		if (Z_MODE(op1_addr) != IS_MEM_ZVAL || Z_REG(op1_addr) != Z_REG(res_addr) || Z_OFFSET(op1_addr) != Z_OFFSET(res_addr)) {
4463			if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_LONG) {
4464				|	SET_ZVAL_TYPE_INFO res_addr, IS_LONG
4465			}
4466		}
4467	}
4468
4469	if (may_overflow && (!(res_info & MAY_BE_GUARD) || (res_info & MAY_BE_ANY) == MAY_BE_DOUBLE)) {
4470		zend_reg tmp_reg1 = ZREG_XMM0;
4471		zend_reg tmp_reg2 = ZREG_XMM1;
4472
4473		if (res_info & MAY_BE_LONG) {
4474			|.cold_code
4475			|1:
4476		}
4477
4478		do {
4479			if ((sizeof(void*) == 8 || Z_MODE(res_addr) != IS_REG) &&
4480			    ((Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op1_addr)) == 1) ||
4481			     (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 1))) {
4482				if (opcode == ZEND_ADD) {
4483					|.if X64
4484						|	mov64 Ra(tmp_reg), 0x43e0000000000000
4485						if (Z_MODE(res_addr) == IS_REG) {
4486							|	movd xmm(Z_REG(res_addr)-ZREG_XMM0), Ra(tmp_reg)
4487						} else {
4488							|	SET_ZVAL_LVAL res_addr, Ra(tmp_reg)
4489						}
4490					|.else
4491						|	SET_ZVAL_LVAL res_addr, 0
4492						|	SET_ZVAL_W2 res_addr, 0x41e00000
4493					|.endif
4494					break;
4495				} else if (opcode == ZEND_SUB) {
4496					|.if X64
4497						|	mov64 Ra(tmp_reg), 0xc3e0000000000000
4498						if (Z_MODE(res_addr) == IS_REG) {
4499							|	movd xmm(Z_REG(res_addr)-ZREG_XMM0), Ra(tmp_reg)
4500						} else {
4501							|	SET_ZVAL_LVAL res_addr, Ra(tmp_reg)
4502						}
4503					|.else
4504						|	SET_ZVAL_LVAL res_addr, 0x00200000
4505						|	SET_ZVAL_W2 res_addr, 0xc1e00000
4506					|.endif
4507					break;
4508				}
4509			}
4510
4511			|	SSE_GET_ZVAL_LVAL tmp_reg1, op1_addr, tmp_reg
4512			|	SSE_GET_ZVAL_LVAL tmp_reg2, op2_addr, tmp_reg
4513			if (CAN_USE_AVX()) {
4514				|	AVX_MATH_REG opcode, tmp_reg1, tmp_reg1, tmp_reg2
4515			} else {
4516				|	SSE_MATH_REG opcode, tmp_reg1, tmp_reg2
4517			}
4518			|	SSE_SET_ZVAL_DVAL res_addr, tmp_reg1
4519		} while (0);
4520
4521		if (Z_MODE(res_addr) == IS_MEM_ZVAL
4522		 && (res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
4523			|	SET_ZVAL_TYPE_INFO res_addr, IS_DOUBLE
4524		}
4525		if (res_info & MAY_BE_LONG) {
4526			|	jmp >2
4527			|.code
4528		}
4529		|2:
4530	}
4531
4532	return 1;
4533}
4534
4535static int zend_jit_math_long_double(dasm_State    **Dst,
4536                                     zend_uchar      opcode,
4537                                     zend_jit_addr   op1_addr,
4538                                     zend_jit_addr   op2_addr,
4539                                     zend_jit_addr   res_addr,
4540                                     uint32_t        res_use_info)
4541{
4542	zend_reg result_reg =
4543		(Z_MODE(res_addr) == IS_REG) ? Z_REG(res_addr) : ZREG_XMM0;
4544	zend_reg tmp_reg;
4545
4546	if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_R0) {
4547		/* ASSIGN_DIM_OP */
4548		tmp_reg = ZREG_R1;
4549	} else {
4550		tmp_reg = ZREG_R0;
4551	}
4552
4553	|	SSE_GET_ZVAL_LVAL result_reg, op1_addr, tmp_reg
4554
4555	if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_R0) {
4556		/* ASSIGN_DIM_OP */
4557		if (CAN_USE_AVX()) {
4558			|	AVX_MATH opcode, result_reg, result_reg, op2_addr, r1
4559		} else {
4560			|	SSE_MATH opcode, result_reg, op2_addr, r1
4561		}
4562	} else {
4563		if (CAN_USE_AVX()) {
4564			|	AVX_MATH opcode, result_reg, result_reg, op2_addr, r0
4565		} else {
4566			|	SSE_MATH opcode, result_reg, op2_addr, r0
4567		}
4568	}
4569	|	SSE_SET_ZVAL_DVAL res_addr, result_reg
4570
4571	if (Z_MODE(res_addr) == IS_MEM_ZVAL) {
4572		if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
4573			|	SET_ZVAL_TYPE_INFO res_addr, IS_DOUBLE
4574		}
4575	}
4576
4577	return 1;
4578}
4579
4580static int zend_jit_math_double_long(dasm_State    **Dst,
4581                                     zend_uchar      opcode,
4582                                     zend_jit_addr   op1_addr,
4583                                     zend_jit_addr   op2_addr,
4584                                     zend_jit_addr   res_addr,
4585                                     uint32_t        res_use_info)
4586{
4587	zend_reg result_reg, tmp_reg_gp;
4588
4589	if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_R0) {
4590		/* ASSIGN_DIM_OP */
4591		tmp_reg_gp = ZREG_R1;
4592	} else {
4593		tmp_reg_gp = ZREG_R0;
4594	}
4595
4596	if (zend_is_commutative(opcode)
4597	 && (Z_MODE(res_addr) != IS_REG || Z_MODE(op1_addr) != IS_REG || Z_REG(res_addr) != Z_REG(op1_addr))) {
4598		if (Z_MODE(res_addr) == IS_REG) {
4599			result_reg = Z_REG(res_addr);
4600		} else {
4601			result_reg = ZREG_XMM0;
4602		}
4603		|	SSE_GET_ZVAL_LVAL result_reg, op2_addr, tmp_reg_gp
4604		if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_R0) {
4605			/* ASSIGN_DIM_OP */
4606			if (CAN_USE_AVX()) {
4607				|	AVX_MATH opcode, result_reg, result_reg, op1_addr, r1
4608			} else {
4609				|	SSE_MATH opcode, result_reg, op1_addr, r1
4610			}
4611		} else {
4612			if (CAN_USE_AVX()) {
4613				|	AVX_MATH opcode, result_reg, result_reg, op1_addr, r0
4614			} else {
4615				|	SSE_MATH opcode, result_reg, op1_addr, r0
4616			}
4617		}
4618	} else {
4619		zend_reg tmp_reg;
4620
4621		if (Z_MODE(res_addr) == IS_REG) {
4622			result_reg = Z_REG(res_addr);
4623			tmp_reg = (result_reg == ZREG_XMM0) ? ZREG_XMM1 : ZREG_XMM0;
4624		} else if (Z_MODE(op1_addr) == IS_REG && Z_LAST_USE(op1_addr)) {
4625			result_reg = Z_REG(op1_addr);
4626			tmp_reg = ZREG_XMM0;
4627		} else {
4628			result_reg = ZREG_XMM0;
4629			tmp_reg = ZREG_XMM1;
4630		}
4631		if (CAN_USE_AVX()) {
4632			zend_reg op1_reg;
4633
4634			if (Z_MODE(op1_addr) == IS_REG) {
4635				op1_reg = Z_REG(op1_addr);
4636			} else {
4637				|	SSE_GET_ZVAL_DVAL result_reg, op1_addr
4638				op1_reg = result_reg;
4639			}
4640			if ((opcode == ZEND_ADD || opcode == ZEND_SUB)
4641			 && Z_MODE(op2_addr) == IS_CONST_ZVAL
4642			 && Z_LVAL_P(Z_ZV(op2_addr)) == 0) {
4643				/* +/- 0 */
4644			} else {
4645				|	SSE_GET_ZVAL_LVAL tmp_reg, op2_addr, tmp_reg_gp
4646				|	AVX_MATH_REG opcode, result_reg, op1_reg, tmp_reg
4647			}
4648		} else {
4649			|	SSE_GET_ZVAL_DVAL result_reg, op1_addr
4650			if ((opcode == ZEND_ADD || opcode == ZEND_SUB)
4651			 && Z_MODE(op2_addr) == IS_CONST_ZVAL
4652			 && Z_LVAL_P(Z_ZV(op2_addr)) == 0) {
4653				/* +/- 0 */
4654			} else {
4655				|	SSE_GET_ZVAL_LVAL tmp_reg, op2_addr, tmp_reg_gp
4656				|	SSE_MATH_REG opcode, result_reg, tmp_reg
4657			}
4658		}
4659	}
4660	|	SSE_SET_ZVAL_DVAL res_addr, result_reg
4661
4662	if (Z_MODE(res_addr) == IS_MEM_ZVAL) {
4663		if (Z_MODE(op1_addr) != IS_MEM_ZVAL || Z_REG(op1_addr) != Z_REG(res_addr) || Z_OFFSET(op1_addr) != Z_OFFSET(res_addr)) {
4664			if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
4665				|	SET_ZVAL_TYPE_INFO res_addr, IS_DOUBLE
4666			}
4667		}
4668	}
4669
4670	return 1;
4671}
4672
4673static int zend_jit_math_double_double(dasm_State    **Dst,
4674                                       zend_uchar      opcode,
4675                                       zend_jit_addr   op1_addr,
4676                                       zend_jit_addr   op2_addr,
4677                                       zend_jit_addr   res_addr,
4678                                       uint32_t        res_use_info)
4679{
4680	zend_bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
4681	zend_reg result_reg;
4682
4683	if (Z_MODE(res_addr) == IS_REG) {
4684		result_reg = Z_REG(res_addr);
4685	} else if (Z_MODE(op1_addr) == IS_REG && Z_LAST_USE(op1_addr)) {
4686		result_reg = Z_REG(op1_addr);
4687	} else if (zend_is_commutative(opcode) && Z_MODE(op2_addr) == IS_REG && Z_LAST_USE(op2_addr)) {
4688		result_reg = Z_REG(op2_addr);
4689	} else {
4690		result_reg = ZREG_XMM0;
4691	}
4692
4693	if (CAN_USE_AVX()) {
4694		zend_reg op1_reg;
4695		zend_jit_addr val_addr;
4696
4697		if (Z_MODE(op1_addr) == IS_REG) {
4698			op1_reg = Z_REG(op1_addr);
4699			val_addr = op2_addr;
4700		} else if (Z_MODE(op2_addr) == IS_REG && zend_is_commutative(opcode)) {
4701			op1_reg = Z_REG(op2_addr);
4702			val_addr = op1_addr;
4703		} else {
4704			|	SSE_GET_ZVAL_DVAL result_reg, op1_addr
4705			op1_reg = result_reg;
4706			val_addr = op2_addr;
4707		}
4708		if ((opcode == ZEND_MUL) &&
4709			Z_MODE(val_addr) == IS_CONST_ZVAL && Z_DVAL_P(Z_ZV(val_addr)) == 2.0) {
4710			|	AVX_MATH_REG ZEND_ADD, result_reg, op1_reg, op1_reg
4711		} else if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_R0) {
4712			/* ASSIGN_DIM_OP */
4713			|	AVX_MATH opcode, result_reg, op1_reg, val_addr, r1
4714		} else {
4715			|	AVX_MATH opcode, result_reg, op1_reg, val_addr, r0
4716		}
4717	} else {
4718		zend_jit_addr val_addr;
4719
4720		if (Z_MODE(op1_addr) != IS_REG && Z_MODE(op2_addr) == IS_REG && zend_is_commutative(opcode)) {
4721			|	SSE_GET_ZVAL_DVAL result_reg, op2_addr
4722			val_addr = op1_addr;
4723		} else {
4724			|	SSE_GET_ZVAL_DVAL result_reg, op1_addr
4725			val_addr = op2_addr;
4726		}
4727		if (same_ops) {
4728			|	SSE_MATH_REG opcode, result_reg, result_reg
4729		} else if ((opcode == ZEND_MUL) &&
4730			Z_MODE(val_addr) == IS_CONST_ZVAL && Z_DVAL_P(Z_ZV(val_addr)) == 2.0) {
4731			|	SSE_MATH_REG ZEND_ADD, result_reg, result_reg
4732		} else if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_R0) {
4733			/* ASSIGN_DIM_OP */
4734			|	SSE_MATH opcode, result_reg, val_addr, r1
4735		} else {
4736			|	SSE_MATH opcode, result_reg, val_addr, r0
4737		}
4738	}
4739	|	SSE_SET_ZVAL_DVAL res_addr, result_reg
4740
4741	if (Z_MODE(res_addr) == IS_MEM_ZVAL) {
4742		if (Z_MODE(op1_addr) != IS_MEM_ZVAL || Z_REG(op1_addr) != Z_REG(res_addr) || Z_OFFSET(op1_addr) != Z_OFFSET(res_addr)) {
4743			if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
4744				|	SET_ZVAL_TYPE_INFO res_addr, IS_DOUBLE
4745			}
4746		}
4747	}
4748
4749	return 1;
4750}
4751
4752static int zend_jit_math_helper(dasm_State    **Dst,
4753                                const zend_op  *opline,
4754                                zend_uchar      opcode,
4755                                zend_uchar      op1_type,
4756                                znode_op        op1,
4757                                zend_jit_addr   op1_addr,
4758                                uint32_t        op1_info,
4759                                zend_uchar      op2_type,
4760                                znode_op        op2,
4761                                zend_jit_addr   op2_addr,
4762                                uint32_t        op2_info,
4763                                uint32_t        res_var,
4764                                zend_jit_addr   res_addr,
4765                                uint32_t        res_info,
4766                                uint32_t        res_use_info,
4767                                int             may_overflow,
4768                                int             may_throw)
4769/* Labels: 1,2,3,4,5,6 */
4770{
4771	zend_bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
4772
4773	if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG) && (res_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
4774		if (op1_info & (MAY_BE_ANY-MAY_BE_LONG)) {
4775			if (op1_info & MAY_BE_DOUBLE) {
4776				|	IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >3
4777			} else {
4778				|	IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >6
4779			}
4780		}
4781		if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_LONG))) {
4782			if (op2_info & MAY_BE_DOUBLE) {
4783				|	IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >1
4784				|.cold_code
4785				|1:
4786				if (op2_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
4787					|	IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >6
4788				}
4789				if (!zend_jit_math_long_double(Dst, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
4790					return 0;
4791				}
4792				|	jmp >5
4793				|.code
4794			} else {
4795				|	IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >6
4796			}
4797		}
4798		if (!zend_jit_math_long_long(Dst, opline, opcode, op1_addr, op2_addr, res_addr, res_info, res_use_info, may_overflow)) {
4799			return 0;
4800		}
4801		if (op1_info & MAY_BE_DOUBLE) {
4802			|.cold_code
4803			|3:
4804			if (op1_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
4805				|	IF_NOT_ZVAL_TYPE op1_addr, IS_DOUBLE, >6
4806			}
4807			if (op2_info & MAY_BE_DOUBLE) {
4808				if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_DOUBLE))) {
4809					if (!same_ops) {
4810						|	IF_NOT_ZVAL_TYPE, op2_addr, IS_DOUBLE, >1
4811					} else {
4812						|	IF_NOT_ZVAL_TYPE, op2_addr, IS_DOUBLE, >6
4813					}
4814				}
4815				if (!zend_jit_math_double_double(Dst, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
4816					return 0;
4817				}
4818				|	jmp >5
4819			}
4820			if (!same_ops) {
4821				|1:
4822				if (op2_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
4823					|	IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >6
4824				}
4825				if (!zend_jit_math_double_long(Dst, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
4826					return 0;
4827				}
4828				|	jmp >5
4829			}
4830			|.code
4831		}
4832	} else if ((op1_info & MAY_BE_DOUBLE) &&
4833	           !(op1_info & MAY_BE_LONG) &&
4834	           (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
4835	           (res_info & MAY_BE_DOUBLE)) {
4836		if (op1_info & (MAY_BE_ANY-MAY_BE_DOUBLE)) {
4837			|	IF_NOT_ZVAL_TYPE op1_addr, IS_DOUBLE, >6
4838		}
4839		if (op2_info & MAY_BE_DOUBLE) {
4840			if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_DOUBLE))) {
4841				if (!same_ops && (op2_info & MAY_BE_LONG)) {
4842					|	IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >1
4843				} else {
4844					|	IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >6
4845				}
4846			}
4847			if (!zend_jit_math_double_double(Dst, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
4848				return 0;
4849			}
4850		}
4851		if (!same_ops && (op2_info & MAY_BE_LONG)) {
4852			if (op2_info & MAY_BE_DOUBLE) {
4853				|.cold_code
4854			}
4855		    |1:
4856			if (op2_info & (MAY_BE_ANY-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
4857				|	IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >6
4858			}
4859			if (!zend_jit_math_double_long(Dst, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
4860				return 0;
4861			}
4862			if (op2_info & MAY_BE_DOUBLE) {
4863				|	jmp >5
4864				|.code
4865			}
4866		}
4867	} else if ((op2_info & MAY_BE_DOUBLE) &&
4868	           !(op2_info & MAY_BE_LONG) &&
4869	           (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
4870	           (res_info & MAY_BE_DOUBLE)) {
4871		if (op2_info & (MAY_BE_ANY-MAY_BE_DOUBLE)) {
4872			|	IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >6
4873		}
4874		if (op1_info & MAY_BE_DOUBLE) {
4875			if (!same_ops && (op1_info & (MAY_BE_ANY-MAY_BE_DOUBLE))) {
4876				if (!same_ops && (op1_info & MAY_BE_LONG)) {
4877					|	IF_NOT_ZVAL_TYPE op1_addr, IS_DOUBLE, >1
4878				} else {
4879					|	IF_NOT_ZVAL_TYPE op1_addr, IS_DOUBLE, >6
4880				}
4881			}
4882			if (!zend_jit_math_double_double(Dst, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
4883				return 0;
4884			}
4885		}
4886		if (!same_ops && (op1_info & MAY_BE_LONG)) {
4887			if (op1_info & MAY_BE_DOUBLE) {
4888				|.cold_code
4889			}
4890			|1:
4891			if (op1_info & (MAY_BE_ANY-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
4892				|	IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >6
4893			}
4894			if (!zend_jit_math_long_double(Dst, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
4895				return 0;
4896			}
4897			if (op1_info & MAY_BE_DOUBLE) {
4898				|	jmp >5
4899				|.code
4900			}
4901		}
4902	}
4903
4904	|5:
4905
4906	if ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) ||
4907		(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)))) {
4908		if ((op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
4909		    (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
4910		    (res_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
4911			|.cold_code
4912		}
4913		|6:
4914		if (Z_MODE(res_addr) == IS_REG) {
4915			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var);
4916			|	LOAD_ZVAL_ADDR FCARG1a, real_addr
4917		} else if (Z_REG(res_addr) != ZREG_FCARG1a || Z_OFFSET(res_addr) != 0) {
4918			|	LOAD_ZVAL_ADDR FCARG1a, res_addr
4919		}
4920		if (Z_MODE(op1_addr) == IS_REG) {
4921			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op1.var);
4922			if (!zend_jit_spill_store(Dst, op1_addr, real_addr, op1_info, 1)) {
4923				return 0;
4924			}
4925			op1_addr = real_addr;
4926		}
4927		|	LOAD_ZVAL_ADDR FCARG2a, op1_addr
4928		if (Z_MODE(op2_addr) == IS_REG) {
4929			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op2.var);
4930			if (!zend_jit_spill_store(Dst, op2_addr, real_addr, op2_info, 1)) {
4931				return 0;
4932			}
4933			op2_addr = real_addr;
4934		}
4935		|.if X64
4936			|	LOAD_ZVAL_ADDR CARG3, op2_addr
4937		|.else
4938			|	sub r4, 12
4939			|	PUSH_ZVAL_ADDR op2_addr, r0
4940		|.endif
4941		|	SET_EX_OPLINE opline, r0
4942		if (opcode == ZEND_ADD) {
4943			|	EXT_CALL add_function, r0
4944		} else if (opcode == ZEND_SUB) {
4945			|	EXT_CALL sub_function, r0
4946		} else if (opcode == ZEND_MUL) {
4947			|	EXT_CALL mul_function, r0
4948		} else if (opcode == ZEND_DIV) {
4949			|	EXT_CALL div_function, r0
4950		} else {
4951			ZEND_UNREACHABLE();
4952		}
4953		|.if not(X64)
4954		|	add r4, 12
4955		|.endif
4956		|	FREE_OP op1_type, op1, op1_info, 0, opline
4957		|	FREE_OP op2_type, op2, op2_info, 0, opline
4958		if (may_throw) {
4959			if (opline->opcode == ZEND_ASSIGN_DIM_OP && (opline->op2_type & (IS_VAR|IS_TMP_VAR))) {
4960				|	MEM_OP2_1_ZTS cmp, aword, executor_globals, exception, 0, r0
4961				|	jne ->exception_handler_free_op2
4962			} else if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RX) {
4963				zend_jit_check_exception_undef_result(Dst, opline);
4964			} else {
4965				zend_jit_check_exception(Dst);
4966			}
4967		}
4968		if (Z_MODE(res_addr) == IS_REG) {
4969			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var);
4970			if (!zend_jit_load_reg(Dst, real_addr, res_addr, res_info)) {
4971				return 0;
4972			}
4973		}
4974		if ((op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
4975		    (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
4976		    (res_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
4977			|	jmp <5
4978			|.code
4979		}
4980	}
4981
4982	return 1;
4983}
4984
4985static int zend_jit_math(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint32_t op2_info, zend_jit_addr op2_addr, uint32_t res_use_info, uint32_t res_info, zend_jit_addr res_addr, int may_overflow, int may_throw)
4986{
4987	ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF));
4988	ZEND_ASSERT((op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
4989	    (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE)));
4990
4991	if (!zend_jit_math_helper(Dst, opline, opline->opcode, opline->op1_type, opline->op1, op1_addr, op1_info, opline->op2_type, opline->op2, op2_addr, op2_info, opline->result.var, res_addr, res_info, res_use_info, may_overflow, may_throw)) {
4992		return 0;
4993	}
4994	if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, res_info)) {
4995		return 0;
4996	}
4997	return 1;
4998}
4999
5000static int zend_jit_add_arrays(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, uint32_t op2_info, zend_jit_addr res_addr)
5001{
5002	zend_jit_addr op1_addr = OP1_ADDR();
5003	zend_jit_addr op2_addr = OP2_ADDR();
5004
5005	|	GET_ZVAL_LVAL ZREG_FCARG1a, op1_addr
5006	|	GET_ZVAL_LVAL ZREG_FCARG2a, op2_addr
5007	|	EXT_CALL zend_jit_add_arrays_helper, r0
5008	|	SET_ZVAL_PTR res_addr, r0
5009	|	SET_ZVAL_TYPE_INFO res_addr, IS_ARRAY_EX
5010	|	FREE_OP opline->op1_type, opline->op1, op1_info, 0, opline
5011	|	FREE_OP opline->op2_type, opline->op2, op2_info, 0, opline
5012	return 1;
5013}
5014
5015static int zend_jit_long_math_helper(dasm_State    **Dst,
5016                                     const zend_op  *opline,
5017                                     zend_uchar      opcode,
5018                                     zend_uchar      op1_type,
5019                                     znode_op        op1,
5020                                     zend_jit_addr   op1_addr,
5021                                     uint32_t        op1_info,
5022                                     zend_ssa_range *op1_range,
5023                                     zend_uchar      op2_type,
5024                                     znode_op        op2,
5025                                     zend_jit_addr   op2_addr,
5026                                     uint32_t        op2_info,
5027                                     zend_ssa_range *op2_range,
5028                                     uint32_t        res_var,
5029                                     zend_jit_addr   res_addr,
5030                                     uint32_t        res_info,
5031                                     uint32_t        res_use_info,
5032                                     int             may_throw)
5033/* Labels: 6 */
5034{
5035	zend_bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
5036	zend_reg result_reg;
5037
5038	if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
5039		|	IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >6
5040	}
5041	if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))) {
5042		|	IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >6
5043	}
5044
5045	if (opcode == ZEND_MOD) {
5046		result_reg = ZREG_RAX;
5047	} else if (Z_MODE(res_addr) == IS_REG) {
5048		if ((opline->opcode == ZEND_SL || opline->opcode == ZEND_SR)
5049		 && opline->op2_type != IS_CONST) {
5050			result_reg = ZREG_R0;
5051		} else {
5052			result_reg = Z_REG(res_addr);
5053		}
5054	} else if (Z_MODE(op1_addr) == IS_REG && Z_LAST_USE(op1_addr)) {
5055		result_reg = Z_REG(op1_addr);
5056	} else if (Z_REG(res_addr) != ZREG_R0) {
5057		result_reg = ZREG_R0;
5058	} else {
5059		/* ASSIGN_DIM_OP */
5060		if (sizeof(void*) == 4
5061		 && (opcode == ZEND_SL || opcode == ZEND_SR)
5062		 && Z_MODE(op2_addr) != IS_CONST_ZVAL) {
5063			result_reg = ZREG_R2;
5064		} else {
5065			result_reg = ZREG_FCARG1a;
5066		}
5067	}
5068
5069	if (opcode == ZEND_SL) {
5070		if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
5071			zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr));
5072
5073			if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
5074				if (EXPECTED(op2_lval > 0)) {
5075					|	xor Ra(result_reg), Ra(result_reg)
5076				} else {
5077					zend_jit_invalidate_var_if_necessary(Dst, op1_type, op1_addr, op1);
5078					zend_jit_invalidate_var_if_necessary(Dst, op2_type, op2_addr, op2);
5079					|	SET_EX_OPLINE opline, r0
5080					|	jmp ->negative_shift
5081				}
5082			} else if (Z_MODE(op1_addr) == IS_REG && op2_lval == 1) {
5083				|	lea Ra(result_reg), [Ra(Z_REG(op1_addr))+Ra(Z_REG(op1_addr))]
5084			} else {
5085				|	GET_ZVAL_LVAL result_reg, op1_addr
5086				|	shl Ra(result_reg), op2_lval
5087			}
5088		} else {
5089			if (Z_MODE(op2_addr) != IS_REG || Z_REG(op2_addr) != ZREG_RCX) {
5090				|	GET_ZVAL_LVAL ZREG_RCX, op2_addr
5091			}
5092			if (!op2_range ||
5093			     op2_range->min < 0 ||
5094			     op2_range->max >= SIZEOF_ZEND_LONG * 8) {
5095				|	cmp r1, (SIZEOF_ZEND_LONG*8)
5096				|	jae >1
5097				|.cold_code
5098				|1:
5099				|	cmp r1, 0
5100				|	mov Ra(result_reg), 0
5101				|	jg >1
5102				zend_jit_invalidate_var_if_necessary(Dst, op1_type, op1_addr, op1);
5103				zend_jit_invalidate_var_if_necessary(Dst, op2_type, op2_addr, op2);
5104				|	SET_EX_OPLINE opline, r0
5105				|	jmp ->negative_shift
5106				|.code
5107			}
5108			|	GET_ZVAL_LVAL result_reg, op1_addr
5109			|	shl Ra(result_reg), cl
5110			|1:
5111		}
5112	} else if (opcode == ZEND_SR) {
5113		|	GET_ZVAL_LVAL result_reg, op1_addr
5114		if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
5115			zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr));
5116
5117			if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
5118				if (EXPECTED(op2_lval > 0)) {
5119					|	sar Ra(result_reg), (SIZEOF_ZEND_LONG * 8) - 1
5120				} else {
5121					zend_jit_invalidate_var_if_necessary(Dst, op1_type, op1_addr, op1);
5122					zend_jit_invalidate_var_if_necessary(Dst, op2_type, op2_addr, op2);
5123					|	SET_EX_OPLINE opline, r0
5124					|	jmp ->negative_shift
5125				}
5126			} else {
5127				|	sar Ra(result_reg), op2_lval
5128			}
5129		} else {
5130			if (Z_MODE(op2_addr) != IS_REG || Z_REG(op2_addr) != ZREG_RCX) {
5131				|	GET_ZVAL_LVAL ZREG_RCX, op2_addr
5132			}
5133			if (!op2_range ||
5134			     op2_range->min < 0 ||
5135			     op2_range->max >= SIZEOF_ZEND_LONG * 8) {
5136				|	cmp r1, (SIZEOF_ZEND_LONG*8)
5137				|	jae >1
5138				|.cold_code
5139				|1:
5140				|	cmp r1, 0
5141				|	mov r1, (SIZEOF_ZEND_LONG * 8) - 1
5142				|	jg >1
5143				zend_jit_invalidate_var_if_necessary(Dst, op1_type, op1_addr, op1);
5144				zend_jit_invalidate_var_if_necessary(Dst, op2_type, op2_addr, op2);
5145				|	SET_EX_OPLINE opline, r0
5146				|	jmp ->negative_shift
5147				|.code
5148			}
5149			|1:
5150			|	sar Ra(result_reg), cl
5151		}
5152	} else if (opcode == ZEND_MOD) {
5153		if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
5154			zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr));
5155
5156			if (op2_lval == 0) {
5157				zend_jit_invalidate_var_if_necessary(Dst, op1_type, op1_addr, op1);
5158				zend_jit_invalidate_var_if_necessary(Dst, op2_type, op2_addr, op2);
5159				|	SET_EX_OPLINE opline, r0
5160				|	jmp ->mod_by_zero
5161			} else if (zend_long_is_power_of_two(op2_lval) && op1_range && op1_range->min >= 0) {
5162				zval tmp;
5163				zend_jit_addr tmp_addr;
5164				zend_reg tmp_reg;
5165
5166				/* Optimisation for mod of power of 2 */
5167				ZVAL_LONG(&tmp, op2_lval - 1);
5168				tmp_addr = ZEND_ADDR_CONST_ZVAL(&tmp);
5169				if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_R0) {
5170					tmp_reg = ZREG_R1;
5171				} else if (result_reg != ZREG_R0) {
5172					tmp_reg = ZREG_R0;
5173				} else {
5174					tmp_reg = ZREG_R1;
5175				}
5176				|	GET_ZVAL_LVAL result_reg, op1_addr
5177				|	LONG_MATH ZEND_BW_AND, result_reg, tmp_addr, tmp_reg
5178				(void)tmp_reg;
5179			} else {
5180				if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RAX) {
5181					|	mov aword T1, r0 // save
5182				} else if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RCX) {
5183					|	mov aword T1, Ra(ZREG_RCX) // save
5184				}
5185				result_reg = ZREG_RDX;
5186				if (op2_lval == -1) {
5187					|	xor Ra(result_reg), Ra(result_reg)
5188				} else {
5189					|	GET_ZVAL_LVAL ZREG_RAX, op1_addr
5190					|	GET_ZVAL_LVAL ZREG_RCX, op2_addr
5191					|.if X64
5192					|	cqo
5193					|.else
5194					|	cdq
5195					|.endif
5196					|	idiv Ra(ZREG_RCX)
5197				}
5198				if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RAX) {
5199					|	mov r0, aword T1 // restore
5200				} else if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RCX) {
5201					|	mov Ra(ZREG_RCX), aword T1 // restore
5202				}
5203			}
5204		} else {
5205			if (!op2_range || (op2_range->min <= 0 && op2_range->max >= 0)) {
5206				if (Z_MODE(op2_addr) == IS_MEM_ZVAL) {
5207					|	cmp aword [Ra(Z_REG(op2_addr))+Z_OFFSET(op2_addr)], 0
5208				} else if (Z_MODE(op2_addr) == IS_REG) {
5209					|	test Ra(Z_REG(op2_addr)), Ra(Z_REG(op2_addr))
5210				}
5211				|	jz >1
5212				|.cold_code
5213				|1:
5214				zend_jit_invalidate_var_if_necessary(Dst, op1_type, op1_addr, op1);
5215				zend_jit_invalidate_var_if_necessary(Dst, op2_type, op2_addr, op2);
5216				|	SET_EX_OPLINE opline, r0
5217				|	jmp ->mod_by_zero
5218				|.code
5219			}
5220
5221			/* Prevent overflow error/crash if op1 == LONG_MIN and op2 == -1 */
5222			if (!op2_range || (op2_range->min <= -1 && op2_range->max >= -1)) {
5223				if (Z_MODE(op2_addr) == IS_MEM_ZVAL) {
5224					|	cmp aword [Ra(Z_REG(op2_addr))+Z_OFFSET(op2_addr)], -1
5225				} else if (Z_MODE(op2_addr) == IS_REG) {
5226					|	cmp Ra(Z_REG(op2_addr)), -1
5227				}
5228				|	jz >1
5229				|.cold_code
5230				|1:
5231				|	SET_ZVAL_LVAL res_addr, 0
5232				if (Z_MODE(res_addr) == IS_MEM_ZVAL) {
5233					if (Z_MODE(op1_addr) != IS_MEM_ZVAL || Z_REG(op1_addr) != Z_REG(res_addr) || Z_OFFSET(op1_addr) != Z_OFFSET(res_addr)) {
5234						if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_LONG) {
5235							|	SET_ZVAL_TYPE_INFO res_addr, IS_LONG
5236						}
5237					}
5238				}
5239				|	jmp >5
5240				|.code
5241			}
5242
5243			if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RAX) {
5244				|	mov aword T1, r0 // save
5245			}
5246			result_reg = ZREG_RDX;
5247			|	GET_ZVAL_LVAL ZREG_RAX, op1_addr
5248			|.if X64
5249			|	cqo
5250			|.else
5251			|	cdq
5252			|.endif
5253			if (Z_MODE(op2_addr) == IS_MEM_ZVAL) {
5254				|	idiv aword [Ra(Z_REG(op2_addr))+Z_OFFSET(op2_addr)]
5255			} else if (Z_MODE(op2_addr) == IS_REG) {
5256				|	idiv Ra(Z_REG(op2_addr))
5257			}
5258			if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RAX) {
5259				|	mov r0, aword T1 // restore
5260			}
5261		}
5262	} else if (same_ops) {
5263		|	GET_ZVAL_LVAL result_reg, op1_addr
5264		|	LONG_MATH_REG opcode, Ra(result_reg), Ra(result_reg)
5265	} else {
5266		zend_reg tmp_reg;
5267
5268		if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_R0) {
5269			tmp_reg = ZREG_R1;
5270		} else if (result_reg != ZREG_R0) {
5271			tmp_reg = ZREG_R0;
5272		} else {
5273			tmp_reg = ZREG_R1;
5274		}
5275		|	GET_ZVAL_LVAL result_reg, op1_addr
5276		|	LONG_MATH opcode, result_reg, op2_addr, tmp_reg
5277		(void)tmp_reg;
5278	}
5279
5280	if (Z_MODE(res_addr) != IS_REG || Z_REG(res_addr) != result_reg) {
5281		|	SET_ZVAL_LVAL res_addr, Ra(result_reg)
5282	}
5283	if (Z_MODE(res_addr) == IS_MEM_ZVAL) {
5284		if (Z_MODE(op1_addr) != IS_MEM_ZVAL || Z_REG(op1_addr) != Z_REG(res_addr) || Z_OFFSET(op1_addr) != Z_OFFSET(res_addr)) {
5285			if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_LONG) {
5286				|	SET_ZVAL_TYPE_INFO res_addr, IS_LONG
5287			}
5288		}
5289	}
5290
5291	if ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) ||
5292		(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))) {
5293		if ((op1_info & MAY_BE_LONG) &&
5294		    (op2_info & MAY_BE_LONG)) {
5295			|.cold_code
5296		}
5297		|6:
5298		if (Z_MODE(res_addr) == IS_REG) {
5299			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var);
5300			|	LOAD_ZVAL_ADDR FCARG1a, real_addr
5301		} else if (Z_REG(res_addr) != ZREG_FCARG1a || Z_OFFSET(res_addr) != 0) {
5302			|	LOAD_ZVAL_ADDR FCARG1a, res_addr
5303		}
5304		if (Z_MODE(op1_addr) == IS_REG) {
5305			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op1.var);
5306			if (!zend_jit_spill_store(Dst, op1_addr, real_addr, op1_info, 1)) {
5307				return 0;
5308			}
5309			op1_addr = real_addr;
5310		}
5311		|	LOAD_ZVAL_ADDR FCARG2a, op1_addr
5312		if (Z_MODE(op2_addr) == IS_REG) {
5313			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op2.var);
5314			if (!zend_jit_spill_store(Dst, op2_addr, real_addr, op2_info, 1)) {
5315				return 0;
5316			}
5317			op2_addr = real_addr;
5318		}
5319		|.if X64
5320			|	LOAD_ZVAL_ADDR CARG3, op2_addr
5321		|.else
5322			|	sub r4, 12
5323			|	PUSH_ZVAL_ADDR op2_addr, r0
5324		|.endif
5325		|	SET_EX_OPLINE opline, r0
5326		if (opcode == ZEND_BW_OR) {
5327			|	EXT_CALL bitwise_or_function, r0
5328		} else if (opcode == ZEND_BW_AND) {
5329			|	EXT_CALL bitwise_and_function, r0
5330		} else if (opcode == ZEND_BW_XOR) {
5331			|	EXT_CALL bitwise_xor_function, r0
5332		} else if (opcode == ZEND_SL) {
5333			|	EXT_CALL shift_left_function, r0
5334		} else if (opcode == ZEND_SR) {
5335			|	EXT_CALL shift_right_function, r0
5336		} else if (opcode == ZEND_MOD) {
5337			|	EXT_CALL mod_function, r0
5338		} else {
5339			ZEND_UNREACHABLE();
5340		}
5341		|.if not(X64)
5342		|	add r4, 12
5343		|.endif
5344		if (op1_addr == res_addr && (op2_info & MAY_BE_RCN)) {
5345			/* compound assignment may decrement "op2" refcount */
5346			op2_info |= MAY_BE_RC1;
5347		}
5348		|	FREE_OP op1_type, op1, op1_info, 0, opline
5349		|	FREE_OP op2_type, op2, op2_info, 0, opline
5350		if (may_throw) {
5351			if (opline->opcode == ZEND_ASSIGN_DIM_OP && (opline->op2_type & (IS_VAR|IS_TMP_VAR))) {
5352				|	MEM_OP2_1_ZTS cmp, aword, executor_globals, exception, 0, r0
5353				|	jne ->exception_handler_free_op2
5354			} else if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RX) {
5355				zend_jit_check_exception_undef_result(Dst, opline);
5356			} else {
5357				zend_jit_check_exception(Dst);
5358			}
5359		}
5360		if (Z_MODE(res_addr) == IS_REG) {
5361			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var);
5362			if (!zend_jit_load_reg(Dst, real_addr, res_addr, res_info)) {
5363				return 0;
5364			}
5365		}
5366		if ((op1_info & MAY_BE_LONG) &&
5367		    (op2_info & MAY_BE_LONG)) {
5368			|	jmp >5
5369			|.code
5370		}
5371	}
5372	|5:
5373
5374	return 1;
5375}
5376
5377static int zend_jit_long_math(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_ssa_range *op1_range, zend_jit_addr op1_addr, uint32_t op2_info, zend_ssa_range *op2_range, zend_jit_addr op2_addr, uint32_t res_use_info, uint32_t res_info, zend_jit_addr res_addr, int may_throw)
5378{
5379	ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF));
5380	ZEND_ASSERT((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG));
5381
5382	if (!zend_jit_long_math_helper(Dst, opline, opline->opcode,
5383			opline->op1_type, opline->op1, op1_addr, op1_info, op1_range,
5384			opline->op2_type, opline->op2, op2_addr, op2_info, op2_range,
5385			opline->result.var, res_addr, res_info, res_use_info, may_throw)) {
5386		return 0;
5387	}
5388	if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, res_info)) {
5389		return 0;
5390	}
5391	return 1;
5392}
5393
5394static int zend_jit_concat_helper(dasm_State    **Dst,
5395                                  const zend_op  *opline,
5396                                  zend_uchar      op1_type,
5397                                  znode_op        op1,
5398                                  zend_jit_addr   op1_addr,
5399                                  uint32_t        op1_info,
5400                                  zend_uchar      op2_type,
5401                                  znode_op        op2,
5402                                  zend_jit_addr   op2_addr,
5403                                  uint32_t        op2_info,
5404                                  zend_jit_addr   res_addr,
5405                                  int             may_throw)
5406{
5407#if 1
5408	if ((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING)) {
5409		if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING)) {
5410			|	IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, >6
5411		}
5412		if (op2_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING)) {
5413			|	IF_NOT_ZVAL_TYPE op2_addr, IS_STRING, >6
5414		}
5415		if (Z_MODE(op1_addr) == IS_MEM_ZVAL && Z_REG(op1_addr) == Z_REG(res_addr) && Z_OFFSET(op1_addr) == Z_OFFSET(res_addr)) {
5416			if (Z_REG(res_addr) != ZREG_FCARG1a || Z_OFFSET(res_addr) != 0) {
5417				|	LOAD_ZVAL_ADDR FCARG1a, res_addr
5418			}
5419			|	LOAD_ZVAL_ADDR FCARG2a, op2_addr
5420			|	EXT_CALL zend_jit_fast_assign_concat_helper, r0
5421			/* concatination with itself may reduce refcount */
5422			op2_info |= MAY_BE_RC1;
5423		} else {
5424			if (Z_REG(res_addr) != ZREG_FCARG1a || Z_OFFSET(res_addr) != 0) {
5425				|	LOAD_ZVAL_ADDR FCARG1a, res_addr
5426			}
5427			|	LOAD_ZVAL_ADDR FCARG2a, op1_addr
5428			|.if X64
5429				|	LOAD_ZVAL_ADDR CARG3, op2_addr
5430			|.else
5431				|	sub r4, 12
5432				|	PUSH_ZVAL_ADDR op2_addr, r0
5433			|.endif
5434			|	EXT_CALL zend_jit_fast_concat_helper, r0
5435			|.if not(X64)
5436			|	add r4, 12
5437			|.endif
5438		}
5439		/* concatination with empty string may increase refcount */
5440		op1_info |= MAY_BE_RCN;
5441		op2_info |= MAY_BE_RCN;
5442		|	FREE_OP op1_type, op1, op1_info, 0, opline
5443		|	FREE_OP op2_type, op2, op2_info, 0, opline
5444		|5:
5445	}
5446	if ((op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING)) ||
5447	    (op2_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING))) {
5448		if ((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING)) {
5449			|.cold_code
5450			|6:
5451		}
5452#endif
5453		if (Z_REG(res_addr) != ZREG_FCARG1a || Z_OFFSET(res_addr) != 0) {
5454			|	LOAD_ZVAL_ADDR FCARG1a, res_addr
5455		}
5456		|	LOAD_ZVAL_ADDR FCARG2a, op1_addr
5457		|.if X64
5458			|	LOAD_ZVAL_ADDR CARG3, op2_addr
5459		|.else
5460			|	sub r4, 12
5461			|	PUSH_ZVAL_ADDR op2_addr, r0
5462		|.endif
5463		|	SET_EX_OPLINE opline, r0
5464		|	EXT_CALL concat_function, r0
5465		|.if not(X64)
5466		|	add r4, 12
5467		|.endif
5468		/* concatination with empty string may increase refcount */
5469		op1_info |= MAY_BE_RCN;
5470		op2_info |= MAY_BE_RCN;
5471		|	FREE_OP op1_type, op1, op1_info, 0, opline
5472		|	FREE_OP op2_type, op2, op2_info, 0, opline
5473		if (may_throw) {
5474			if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RX) {
5475				zend_jit_check_exception_undef_result(Dst, opline);
5476			} else {
5477				zend_jit_check_exception(Dst);
5478			}
5479		}
5480#if 1
5481		if ((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING)) {
5482			|	jmp <5
5483			|.code
5484		}
5485	}
5486#endif
5487
5488	return 1;
5489}
5490
5491static int zend_jit_concat(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, uint32_t op2_info, zend_jit_addr res_addr, int may_throw)
5492{
5493	zend_jit_addr op1_addr, op2_addr;
5494
5495	ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF));
5496	ZEND_ASSERT((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING));
5497
5498	op1_addr = OP1_ADDR();
5499	op2_addr = OP2_ADDR();
5500
5501	return zend_jit_concat_helper(Dst, opline, opline->op1_type, opline->op1, op1_addr, op1_info, opline->op2_type, opline->op2, op2_addr, op2_info, res_addr, may_throw);
5502}
5503
5504static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_op *opline, uint32_t type, uint32_t op1_info, uint32_t op2_info, const void *found_exit_addr, const void *not_found_exit_addr, const void *exit_addr)
5505/* Labels: 1,2,3,4,5 */
5506{
5507	zend_jit_addr op2_addr = OP2_ADDR();
5508	zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
5509
5510	if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
5511	 && type == BP_VAR_R
5512	 && !exit_addr) {
5513		int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
5514		exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5515		if (!exit_addr) {
5516			return 0;
5517		}
5518	}
5519
5520	if (op2_info & MAY_BE_LONG) {
5521		zend_bool op2_loaded = 0;
5522		zend_bool packed_loaded = 0;
5523		zend_bool bad_packed_key = 0;
5524
5525		if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_LONG)) {
5526			|	// if (EXPECTED(Z_TYPE_P(dim) == IS_LONG))
5527			|	IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >3
5528		}
5529		if (op1_info & MAY_BE_PACKED_GUARD) {
5530			int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_PACKED_GUARD);
5531			const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5532
5533			if (!exit_addr) {
5534				return 0;
5535			}
5536			if (op1_info & MAY_BE_ARRAY_PACKED) {
5537				|	test dword [FCARG1a + offsetof(zend_array, u.flags)], HASH_FLAG_PACKED
5538				|	jz &exit_addr
5539			} else {
5540				|	test dword [FCARG1a + offsetof(zend_array, u.flags)], HASH_FLAG_PACKED
5541				|	jnz &exit_addr
5542			}
5543		}
5544		if (type == BP_VAR_W) {
5545			|	// hval = Z_LVAL_P(dim);
5546			|	GET_ZVAL_LVAL ZREG_FCARG2a, op2_addr
5547			op2_loaded = 1;
5548		}
5549		if (op1_info & MAY_BE_ARRAY_PACKED) {
5550			zend_long val = -1;
5551
5552			if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
5553				val = Z_LVAL_P(Z_ZV(op2_addr));
5554				if (val >= 0 && val < HT_MAX_SIZE) {
5555					packed_loaded = 1;
5556				} else {
5557					bad_packed_key = 1;
5558				}
5559			} else {
5560				if (!op2_loaded) {
5561					|	// hval = Z_LVAL_P(dim);
5562					|	GET_ZVAL_LVAL ZREG_FCARG2a, op2_addr
5563					op2_loaded = 1;
5564				}
5565				packed_loaded = 1;
5566			}
5567			if (packed_loaded) {
5568				|	// ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef);
5569				if (op1_info & MAY_BE_ARRAY_HASH) {
5570					|	test dword [FCARG1a + offsetof(zend_array, u.flags)], HASH_FLAG_PACKED
5571					|	jz >4 // HASH_FIND
5572				}
5573				|	// if (EXPECTED((zend_ulong)(_h) < (zend_ulong)(_ht)->nNumUsed))
5574				|.if X64
5575					|	mov eax, dword [FCARG1a + offsetof(zend_array, nNumUsed)]
5576					if (val == 0) {
5577						|	test r0, r0
5578					} else if (val > 0 && !op2_loaded) {
5579						|	cmp r0, val
5580					} else {
5581						|	cmp r0, FCARG2a
5582					}
5583				|.else
5584					if (val >= 0 && !op2_loaded) {
5585						|	cmp dword [FCARG1a + offsetof(zend_array, nNumUsed)], val
5586					} else {
5587						|	cmp dword [FCARG1a + offsetof(zend_array, nNumUsed)], FCARG2a
5588					}
5589				|.endif
5590				if (type == BP_JIT_IS) {
5591					if (not_found_exit_addr) {
5592						|	jbe &not_found_exit_addr
5593					} else {
5594						|	jbe >9 // NOT_FOUND
5595					}
5596				} else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
5597					|	jbe &exit_addr
5598				} else if (type == BP_VAR_IS && not_found_exit_addr) {
5599					|	jbe &not_found_exit_addr
5600				} else if (type == BP_VAR_IS && found_exit_addr) {
5601					|	jbe >7 // NOT_FOUND
5602				} else {
5603					|	jbe >2 // NOT_FOUND
5604				}
5605				|	// _ret = &_ht->arData[_h].val;
5606				if (val >= 0) {
5607					|	mov r0, aword [FCARG1a + offsetof(zend_array, arData)]
5608					if (val != 0) {
5609						|	add r0, val * sizeof(Bucket)
5610					}
5611				} else {
5612					|.if X64
5613						|	mov r0, FCARG2a
5614						|	shl r0, 5
5615					|.else
5616						|	imul r0, FCARG2a, sizeof(Bucket)
5617					|.endif
5618					|	add r0, aword [FCARG1a + offsetof(zend_array, arData)]
5619				}
5620			}
5621		}
5622		switch (type) {
5623			case BP_JIT_IS:
5624				if (op1_info & MAY_BE_ARRAY_HASH) {
5625					if (packed_loaded) {
5626						|	jmp >5
5627					}
5628					|4:
5629					if (!op2_loaded) {
5630						|	// hval = Z_LVAL_P(dim);
5631						|	GET_ZVAL_LVAL ZREG_FCARG2a, op2_addr
5632					}
5633					if (packed_loaded) {
5634						|	EXT_CALL _zend_hash_index_find, r0
5635					} else {
5636						|	EXT_CALL zend_hash_index_find, r0
5637					}
5638					|	test r0, r0
5639					if (not_found_exit_addr) {
5640						|	jz &not_found_exit_addr
5641					} else {
5642						|	jz >9 // NOT_FOUND
5643					}
5644					if (op2_info & MAY_BE_STRING) {
5645						|	jmp >5
5646					}
5647				} else if (packed_loaded) {
5648					if (op2_info & MAY_BE_STRING) {
5649						|	jmp >5
5650					}
5651				} else if (not_found_exit_addr) {
5652					|	jmp &not_found_exit_addr
5653				} else {
5654					|	jmp >9 // NOT_FOUND
5655				}
5656				break;
5657			case BP_VAR_R:
5658			case BP_VAR_IS:
5659			case BP_VAR_UNSET:
5660				if (packed_loaded) {
5661					if (op1_info & MAY_BE_ARRAY_HASH) {
5662						|	IF_NOT_Z_TYPE r0, IS_UNDEF, >8
5663					} else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
5664						/* perform IS_UNDEF check only after result type guard (during deoptimization) */
5665						if (!found_exit_addr || (op1_info & MAY_BE_ARRAY_HASH)) {
5666							|	IF_Z_TYPE r0, IS_UNDEF, &exit_addr
5667						}
5668					} else if (type == BP_VAR_IS && not_found_exit_addr) {
5669						|	IF_Z_TYPE r0, IS_UNDEF, &not_found_exit_addr
5670					} else if (type == BP_VAR_IS && found_exit_addr) {
5671						|	IF_Z_TYPE r0, IS_UNDEF, >7 // NOT_FOUND
5672					} else {
5673						|	IF_Z_TYPE r0, IS_UNDEF, >2 // NOT_FOUND
5674					}
5675				}
5676				if (!(op1_info & MAY_BE_ARRAY_KEY_LONG) || (packed_loaded && (op1_info & MAY_BE_ARRAY_HASH))) {
5677					if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
5678						|	jmp &exit_addr
5679					} else if (type == BP_VAR_IS && not_found_exit_addr) {
5680						|	jmp &not_found_exit_addr
5681					} else if (type == BP_VAR_IS && found_exit_addr) {
5682						|	jmp >7 // NOT_FOUND
5683					} else {
5684						|	jmp >2 // NOT_FOUND
5685					}
5686				}
5687				if (op1_info & MAY_BE_ARRAY_HASH) {
5688					|4:
5689					if (!op2_loaded) {
5690						|	// hval = Z_LVAL_P(dim);
5691						|	GET_ZVAL_LVAL ZREG_FCARG2a, op2_addr
5692					}
5693					if (packed_loaded) {
5694						|	EXT_CALL _zend_hash_index_find, r0
5695					} else {
5696						|	EXT_CALL zend_hash_index_find, r0
5697					}
5698					|	test r0, r0
5699					if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
5700						|	jz &exit_addr
5701					} else if (type == BP_VAR_IS && not_found_exit_addr) {
5702						|	jz &not_found_exit_addr
5703					} else if (type == BP_VAR_IS && found_exit_addr) {
5704						|	jz >7 // NOT_FOUND
5705					} else {
5706						|	jz >2 // NOT_FOUND
5707					}
5708				}
5709				|.cold_code
5710				|2:
5711				switch (type) {
5712					case BP_VAR_R:
5713						if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE) {
5714							|	// zend_error(E_WARNING,"Undefined array key " ZEND_LONG_FMT, hval);
5715							|	// retval = &EG(uninitialized_zval);
5716							|	UNDEFINED_OFFSET opline
5717							|	jmp >9
5718						}
5719						break;
5720					case BP_VAR_IS:
5721					case BP_VAR_UNSET:
5722						if (!not_found_exit_addr && !found_exit_addr) {
5723							|	// retval = &EG(uninitialized_zval);
5724							|	SET_ZVAL_TYPE_INFO res_addr, IS_NULL
5725							|	jmp >9
5726						}
5727						break;
5728					default:
5729						ZEND_UNREACHABLE();
5730				}
5731				|.code
5732				break;
5733			case BP_VAR_RW:
5734				if (packed_loaded) {
5735					|	IF_NOT_Z_TYPE r0, IS_UNDEF, >8
5736				}
5737				|2:
5738				|4:
5739				if (!op2_loaded) {
5740					|	// hval = Z_LVAL_P(dim);
5741					|	GET_ZVAL_LVAL ZREG_FCARG2a, op2_addr
5742				}
5743				|	SET_EX_OPLINE opline, r0
5744				if (packed_loaded) {
5745					|	EXT_CALL zend_jit_hash_index_lookup_rw_no_packed, r0
5746				} else {
5747					|	EXT_CALL zend_jit_hash_index_lookup_rw, r0
5748				}
5749				|	test r0, r0
5750				|	jz >9
5751				break;
5752			case BP_VAR_W:
5753				if (packed_loaded) {
5754					|	IF_NOT_Z_TYPE r0, IS_UNDEF, >8
5755				}
5756				if (!(op1_info & MAY_BE_ARRAY_KEY_LONG) || packed_loaded || bad_packed_key) {
5757					|2:
5758					|	//retval = zend_hash_index_add_new(ht, hval, &EG(uninitialized_zval));
5759					if (!op2_loaded) {
5760						|	// hval = Z_LVAL_P(dim);
5761						|	GET_ZVAL_LVAL ZREG_FCARG2a, op2_addr
5762					}
5763					|.if X64
5764						|	LOAD_ADDR_ZTS CARG3, executor_globals, uninitialized_zval
5765					|.else
5766						|	sub r4, 12
5767						|	PUSH_ADDR_ZTS executor_globals, uninitialized_zval, r0
5768					|.endif
5769					|	EXT_CALL zend_hash_index_add_new, r0
5770					|.if not(X64)
5771					|	add r4, 12
5772					|.endif
5773					if (op1_info & MAY_BE_ARRAY_HASH) {
5774						|	jmp >8
5775					}
5776				}
5777				if (op1_info & MAY_BE_ARRAY_HASH) {
5778					|4:
5779					if (!op2_loaded) {
5780						|	// hval = Z_LVAL_P(dim);
5781						|	GET_ZVAL_LVAL ZREG_FCARG2a, op2_addr
5782					}
5783					|	EXT_CALL zend_jit_hash_index_lookup_w, r0
5784				}
5785				break;
5786			default:
5787				ZEND_UNREACHABLE();
5788		}
5789
5790		if (type != BP_JIT_IS && (op2_info & MAY_BE_STRING)) {
5791			|	jmp >8
5792		}
5793	}
5794
5795	if (op2_info & MAY_BE_STRING) {
5796		|3:
5797		if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) {
5798			|	// if (EXPECTED(Z_TYPE_P(dim) == IS_STRING))
5799			|	IF_NOT_ZVAL_TYPE op2_addr, IS_STRING, >3
5800		}
5801		|	// offset_key = Z_STR_P(dim);
5802		|	GET_ZVAL_LVAL ZREG_FCARG2a, op2_addr
5803		|	// retval = zend_hash_find(ht, offset_key);
5804		switch (type) {
5805			case BP_JIT_IS:
5806				if (opline->op2_type != IS_CONST) {
5807					|	cmp byte [FCARG2a + offsetof(zend_string, val)], '9'
5808					|	jle >1
5809					|.cold_code
5810					|1:
5811					|	EXT_CALL zend_jit_symtable_find, r0
5812					|	jmp >1
5813					|.code
5814					|	EXT_CALL zend_hash_find, r0
5815					|1:
5816				} else {
5817					|	EXT_CALL _zend_hash_find_known_hash, r0
5818				}
5819				|	test r0, r0
5820				if (not_found_exit_addr) {
5821					|	jz &not_found_exit_addr
5822				} else {
5823					|	jz >9 // NOT_FOUND
5824				}
5825				|	// if (UNEXPECTED(Z_TYPE_P(retval) == IS_INDIRECT))
5826				|	IF_NOT_Z_TYPE r0, IS_INDIRECT, >1
5827				|	GET_Z_PTR r0, r0
5828				|1:
5829				break;
5830			case BP_VAR_R:
5831			case BP_VAR_IS:
5832			case BP_VAR_UNSET:
5833				if (opline->op2_type != IS_CONST) {
5834					|	cmp byte [FCARG2a + offsetof(zend_string, val)], '9'
5835					|	jle >1
5836					|.cold_code
5837					|1:
5838					|	EXT_CALL zend_jit_symtable_find, r0
5839					|	jmp >1
5840					|.code
5841					|	EXT_CALL zend_hash_find, r0
5842					|1:
5843				} else {
5844					|	EXT_CALL _zend_hash_find_known_hash, r0
5845				}
5846				|	test r0, r0
5847				if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
5848					|	jz &exit_addr
5849				} else if (type == BP_VAR_IS && not_found_exit_addr) {
5850					|	jz &not_found_exit_addr
5851				} else if (type == BP_VAR_IS && found_exit_addr) {
5852					|	jz >7 // NOT_FOUND
5853				} else {
5854					|	jz >2 // NOT_FOUND
5855				}
5856				|	// if (UNEXPECTED(Z_TYPE_P(retval) == IS_INDIRECT))
5857				|	IF_Z_TYPE r0, IS_INDIRECT, >1 // SLOW
5858				|.cold_code
5859				|1:
5860				|	// retval = Z_INDIRECT_P(retval);
5861				|	GET_Z_PTR r0, r0
5862				|	IF_NOT_Z_TYPE r0, IS_UNDEF, >8
5863				if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
5864					|	jmp &exit_addr
5865				} else if (type == BP_VAR_IS && not_found_exit_addr) {
5866					|	jmp &not_found_exit_addr
5867				}
5868				|2:
5869				switch (type) {
5870					case BP_VAR_R:
5871						if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE) {
5872							// zend_error(E_WARNING, "Undefined array key \"%s\"", ZSTR_VAL(offset_key));
5873							|	UNDEFINED_INDEX opline
5874							|	jmp >9
5875						}
5876						break;
5877					case BP_VAR_IS:
5878					case BP_VAR_UNSET:
5879						if (!not_found_exit_addr && !found_exit_addr) {
5880							|	// retval = &EG(uninitialized_zval);
5881							|	SET_ZVAL_TYPE_INFO res_addr, IS_NULL
5882							|	jmp >9
5883						}
5884						break;
5885					default:
5886						ZEND_UNREACHABLE();
5887				}
5888				|.code
5889				break;
5890			case BP_VAR_RW:
5891				|	SET_EX_OPLINE opline, r0
5892				if (opline->op2_type != IS_CONST) {
5893					|	EXT_CALL zend_jit_symtable_lookup_rw, r0
5894				} else {
5895					|	EXT_CALL zend_jit_hash_lookup_rw, r0
5896				}
5897				|	test r0, r0
5898				|	jz >9
5899				break;
5900			case BP_VAR_W:
5901				if (opline->op2_type != IS_CONST) {
5902					|	EXT_CALL zend_jit_symtable_lookup_w, r0
5903				} else {
5904					|	EXT_CALL zend_jit_hash_lookup_w, r0
5905				}
5906				break;
5907			default:
5908				ZEND_UNREACHABLE();
5909		}
5910	}
5911
5912	if (type == BP_JIT_IS && (op2_info & (MAY_BE_LONG|MAY_BE_STRING))) {
5913	    |5:
5914		if (op1_info & MAY_BE_ARRAY_OF_REF) {
5915			|	ZVAL_DEREF r0, MAY_BE_REF
5916		}
5917		|	cmp byte [r0 + 8], IS_NULL
5918		if (not_found_exit_addr) {
5919			|	jle &not_found_exit_addr
5920		} else if (found_exit_addr) {
5921			|	jg &found_exit_addr
5922		} else {
5923			|	jle >9 // NOT FOUND
5924		}
5925	}
5926
5927	if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) {
5928		if (op2_info & (MAY_BE_LONG|MAY_BE_STRING)) {
5929			|.cold_code
5930			|3:
5931		}
5932		|	SET_EX_OPLINE opline, r0
5933		|	LOAD_ZVAL_ADDR FCARG2a, op2_addr
5934		switch (type) {
5935			case BP_VAR_R:
5936				|.if X64
5937					|   LOAD_ZVAL_ADDR CARG3, res_addr
5938				|.else
5939					|	sub r4, 12
5940					|   PUSH_ZVAL_ADDR res_addr, r0
5941				|.endif
5942				|	EXT_CALL zend_jit_fetch_dim_r_helper, r0
5943				|.if not(X64)
5944				|	add r4, 12
5945				|.endif
5946				|	jmp >9
5947				break;
5948			case BP_JIT_IS:
5949				|	EXT_CALL zend_jit_fetch_dim_isset_helper, r0
5950				|	test r0, r0
5951				if (not_found_exit_addr) {
5952					|	je &not_found_exit_addr
5953					if (op2_info & (MAY_BE_LONG|MAY_BE_STRING)) {
5954						|	jmp >8
5955					}
5956				} else if (found_exit_addr) {
5957					|	jne &found_exit_addr
5958					if (op2_info & (MAY_BE_LONG|MAY_BE_STRING)) {
5959						|	jmp >9
5960					}
5961				} else {
5962					|	jne >8
5963					|	jmp >9
5964				}
5965				break;
5966			case BP_VAR_IS:
5967			case BP_VAR_UNSET:
5968				|.if X64
5969					|   LOAD_ZVAL_ADDR CARG3, res_addr
5970				|.else
5971					|	sub r4, 12
5972					|   PUSH_ZVAL_ADDR res_addr, r0
5973				|.endif
5974				|	EXT_CALL zend_jit_fetch_dim_is_helper, r0
5975				|.if not(X64)
5976				|	add r4, 12
5977				|.endif
5978				|	jmp >9
5979				break;
5980			case BP_VAR_RW:
5981				|	EXT_CALL zend_jit_fetch_dim_rw_helper, r0
5982				|	test r0, r0
5983				|	jne >8
5984				|	jmp >9
5985				break;
5986			case BP_VAR_W:
5987				|	EXT_CALL zend_jit_fetch_dim_w_helper, r0
5988				|	test r0, r0
5989				|	jne >8
5990				|	jmp >9
5991				break;
5992			default:
5993				ZEND_UNREACHABLE();
5994		}
5995		if (op2_info & (MAY_BE_LONG|MAY_BE_STRING)) {
5996			|.code
5997		}
5998	}
5999
6000	return 1;
6001}
6002
6003static int zend_jit_simple_assign(dasm_State    **Dst,
6004                                  const zend_op  *opline,
6005                                  zend_jit_addr   var_addr,
6006                                  uint32_t        var_info,
6007                                  uint32_t        var_def_info,
6008                                  zend_uchar      val_type,
6009                                  zend_jit_addr   val_addr,
6010                                  uint32_t        val_info,
6011                                  zend_jit_addr   res_addr,
6012                                  int             in_cold,
6013                                  int             save_r1)
6014/* Labels: 1,2,3 */
6015{
6016	zend_reg tmp_reg;
6017
6018	if (Z_MODE(var_addr) == IS_REG || Z_REG(var_addr) != ZREG_R0) {
6019		tmp_reg = ZREG_R0;
6020	} else {
6021		/* ASSIGN_DIM */
6022		tmp_reg = ZREG_FCARG1a;
6023	}
6024
6025	if (Z_MODE(val_addr) == IS_CONST_ZVAL) {
6026		zval *zv = Z_ZV(val_addr);
6027
6028		if (!res_addr) {
6029			|	ZVAL_COPY_CONST var_addr, var_info, var_def_info, zv, tmp_reg
6030		} else {
6031			|	ZVAL_COPY_CONST_2 var_addr, res_addr, var_info, var_def_info, zv, tmp_reg
6032		}
6033		if (Z_REFCOUNTED_P(zv)) {
6034			if (!res_addr) {
6035				|	ADDREF_CONST zv, Ra(tmp_reg)
6036			} else {
6037				|	ADDREF_CONST_2 zv, Ra(tmp_reg)
6038			}
6039		}
6040	} else {
6041		if (val_info & MAY_BE_UNDEF) {
6042			if (in_cold) {
6043				|	IF_NOT_ZVAL_TYPE val_addr, IS_UNDEF, >2
6044			} else {
6045				|	IF_ZVAL_TYPE val_addr, IS_UNDEF, >1
6046				|.cold_code
6047				|1:
6048			}
6049			|	// zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var))));
6050			if (save_r1) {
6051				|	mov aword T1, FCARG1a // save
6052			}
6053			|	SET_ZVAL_TYPE_INFO var_addr, IS_NULL
6054			if (res_addr) {
6055				|	SET_ZVAL_TYPE_INFO res_addr, IS_NULL
6056			}
6057			if (opline) {
6058				|	SET_EX_OPLINE opline, Ra(tmp_reg)
6059			}
6060			ZEND_ASSERT(Z_MODE(val_addr) == IS_MEM_ZVAL && Z_REG(val_addr) == ZREG_FP);
6061			|	mov FCARG1d, Z_OFFSET(val_addr)
6062			|	EXT_CALL zend_jit_undefined_op_helper, r0
6063			|	test r0, r0
6064			|	jz ->exception_handler_undef
6065			if (save_r1) {
6066				|	mov FCARG1a, aword T1 // restore
6067			}
6068			|	jmp >3
6069			if (in_cold) {
6070				|2:
6071			} else {
6072				|.code
6073			}
6074		}
6075		if (val_info & MAY_BE_REF) {
6076			if (val_type == IS_CV) {
6077				ZEND_ASSERT(Z_REG(var_addr) != ZREG_R2);
6078				if (Z_MODE(val_addr) != IS_MEM_ZVAL || Z_REG(val_addr) != ZREG_R2 || Z_OFFSET(val_addr) != 0) {
6079					|	LOAD_ZVAL_ADDR r2, val_addr
6080				}
6081				|	ZVAL_DEREF r2, val_info
6082				val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R2, 0);
6083			} else {
6084				zend_jit_addr ref_addr;
6085				zend_reg type_reg = tmp_reg;
6086
6087				if (in_cold) {
6088					|	IF_NOT_ZVAL_TYPE val_addr, IS_REFERENCE, >1
6089				} else {
6090					|	IF_ZVAL_TYPE val_addr, IS_REFERENCE, >1
6091					|.cold_code
6092					|1:
6093				}
6094				|	// zend_refcounted *ref = Z_COUNTED_P(retval_ptr);
6095				|	GET_ZVAL_PTR r2, val_addr
6096				|	GC_DELREF r2
6097				|	// ZVAL_COPY_VALUE(return_value, &ref->value);
6098				ref_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R2, 8);
6099				if (!res_addr) {
6100					|	ZVAL_COPY_VALUE var_addr, var_info, ref_addr, val_info, type_reg, tmp_reg
6101				} else {
6102					|	ZVAL_COPY_VALUE_2 var_addr, var_info, res_addr, ref_addr, val_info, type_reg, tmp_reg
6103				}
6104				|	je >2
6105				if (tmp_reg == ZREG_R0) {
6106					|	IF_NOT_REFCOUNTED ah, >3
6107				} else {
6108					|	IF_NOT_FLAGS Rd(tmp_reg), (IS_TYPE_REFCOUNTED << Z_TYPE_FLAGS_SHIFT), >3
6109				}
6110				|	GET_ZVAL_PTR Ra(tmp_reg), var_addr
6111
6112				if (!res_addr) {
6113					|	GC_ADDREF Ra(tmp_reg)
6114				} else {
6115					|	add dword [Ra(tmp_reg)], 2
6116				}
6117				|	jmp >3
6118				|2:
6119				if (res_addr) {
6120					if (tmp_reg == ZREG_R0) {
6121						|	IF_NOT_REFCOUNTED ah, >2
6122					} else {
6123						|	IF_NOT_FLAGS Rd(tmp_reg), (IS_TYPE_REFCOUNTED << Z_TYPE_FLAGS_SHIFT), >2
6124					}
6125					|	GET_ZVAL_PTR Ra(tmp_reg), var_addr
6126					|	GC_ADDREF Ra(tmp_reg)
6127					|2:
6128				}
6129				if (save_r1) {
6130					|	mov aword T1, FCARG1a // save
6131				}
6132				|	EFREE_REFERENCE r2
6133				if (save_r1) {
6134					|	mov FCARG1a, aword T1 // restore
6135				}
6136				|	jmp >3
6137				if (in_cold) {
6138					|1:
6139				} else {
6140					|.code
6141				}
6142			}
6143		}
6144
6145		if (!res_addr) {
6146			|	ZVAL_COPY_VALUE var_addr, var_info, val_addr, val_info, ZREG_R2, tmp_reg
6147		} else {
6148			|	ZVAL_COPY_VALUE_2 var_addr, var_info, res_addr, val_addr, val_info, ZREG_R2, tmp_reg
6149		}
6150
6151		if (val_type == IS_CV) {
6152			if (!res_addr) {
6153				|	TRY_ADDREF val_info, dh, Ra(tmp_reg)
6154			} else {
6155				|	TRY_ADDREF_2 val_info, dh, Ra(tmp_reg)
6156			}
6157		} else {
6158			if (res_addr) {
6159				|	TRY_ADDREF val_info, dh, Ra(tmp_reg)
6160			}
6161		}
6162		|3:
6163	}
6164	return 1;
6165}
6166
6167static int zend_jit_assign_to_typed_ref(dasm_State         **Dst,
6168                                       const zend_op        *opline,
6169                                       zend_uchar            val_type,
6170                                       zend_jit_addr         val_addr,
6171                                       zend_jit_addr         res_addr,
6172                                       zend_bool             check_exception)
6173{
6174	|	// if (UNEXPECTED(ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(variable_ptr)))) {
6175	|	cmp aword [FCARG1a + offsetof(zend_reference, sources.ptr)], 0
6176	|	jnz >2
6177	|.cold_code
6178	|2:
6179	if (Z_MODE(val_addr) != IS_MEM_ZVAL || Z_REG(val_addr) != ZREG_FCARG2a || Z_OFFSET(val_addr) != 0) {
6180		|	LOAD_ZVAL_ADDR FCARG2a, val_addr
6181	}
6182	if (opline) {
6183		|	SET_EX_OPLINE opline, r0
6184	}
6185	if (val_type == IS_CONST) {
6186		|	EXT_CALL zend_jit_assign_const_to_typed_ref, r0
6187	} else if (val_type == IS_TMP_VAR) {
6188		|	EXT_CALL zend_jit_assign_tmp_to_typed_ref, r0
6189	} else if (val_type == IS_VAR) {
6190		|	EXT_CALL zend_jit_assign_var_to_typed_ref, r0
6191	} else if (val_type == IS_CV) {
6192		|	EXT_CALL zend_jit_assign_cv_to_typed_ref, r0
6193	} else {
6194		ZEND_UNREACHABLE();
6195	}
6196	if (res_addr) {
6197		zend_jit_addr ret_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0);
6198
6199		|	ZVAL_COPY_VALUE res_addr, -1, ret_addr, -1, ZREG_R1, ZREG_R2
6200		|	TRY_ADDREF -1, ch, r2
6201	}
6202	if (check_exception) {
6203		|	// if (UNEXPECTED(EG(exception) != NULL)) {
6204		|	MEM_OP2_1_ZTS cmp, aword, executor_globals, exception, 0, r0
6205		|	je >8  // END OF zend_jit_assign_to_variable()
6206		|	jmp ->exception_handler
6207	} else {
6208		|	jmp >8
6209	}
6210	|.code
6211
6212	return 1;
6213}
6214
6215static int zend_jit_assign_to_variable_call(dasm_State    **Dst,
6216                                            const zend_op  *opline,
6217                                            zend_jit_addr   __var_use_addr,
6218                                            zend_jit_addr   var_addr,
6219                                            uint32_t        __var_info,
6220                                            uint32_t        __var_def_info,
6221                                            zend_uchar      val_type,
6222                                            zend_jit_addr   val_addr,
6223                                            uint32_t        val_info,
6224                                            zend_jit_addr   __res_addr,
6225                                            zend_bool       __check_exception)
6226{
6227	if (val_info & MAY_BE_UNDEF) {
6228		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
6229			int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
6230			const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
6231
6232			if (!exit_addr) {
6233				return 0;
6234			}
6235
6236			|	IF_ZVAL_TYPE val_addr, IS_UNDEF, &exit_addr
6237		} else {
6238			|	IF_ZVAL_TYPE val_addr, IS_UNDEF, >1
6239			|.cold_code
6240			|1:
6241			ZEND_ASSERT(Z_REG(val_addr) == ZREG_FP);
6242			if (Z_REG(var_addr) != ZREG_FP) {
6243				|	mov aword T1, Ra(Z_REG(var_addr)) // save
6244			}
6245			|	SET_EX_OPLINE opline, r0
6246			|	mov FCARG1d, Z_OFFSET(val_addr)
6247			|	EXT_CALL zend_jit_undefined_op_helper, r0
6248			if (Z_REG(var_addr) != ZREG_FP) {
6249				|	mov Ra(Z_REG(var_addr)), aword T1 // restore
6250			}
6251			if (Z_MODE(var_addr) != IS_MEM_ZVAL || Z_REG(var_addr) != ZREG_FCARG1a || Z_OFFSET(var_addr) != 0) {
6252				|	LOAD_ZVAL_ADDR FCARG1a, var_addr
6253			}
6254			|	LOAD_ADDR_ZTS FCARG2a, executor_globals, uninitialized_zval
6255			|	call ->assign_const
6256			|	jmp >9
6257			|.code
6258		}
6259	}
6260	if (Z_MODE(var_addr) != IS_MEM_ZVAL || Z_REG(var_addr) != ZREG_FCARG1a || Z_OFFSET(var_addr) != 0) {
6261		|	LOAD_ZVAL_ADDR FCARG1a, var_addr
6262	}
6263	if (Z_MODE(val_addr) != IS_MEM_ZVAL || Z_REG(val_addr) != ZREG_FCARG2a || Z_OFFSET(val_addr) != 0) {
6264		|	LOAD_ZVAL_ADDR FCARG2a, val_addr
6265	}
6266	if (opline) {
6267		|	SET_EX_OPLINE opline, r0
6268	}
6269	if (!(val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) {
6270		|	call ->assign_tmp
6271	} else if (val_type == IS_CONST) {
6272		|	call ->assign_const
6273	} else if (val_type == IS_TMP_VAR) {
6274		|	call ->assign_tmp
6275	} else if (val_type == IS_VAR) {
6276		if (!(val_info & MAY_BE_REF)) {
6277			|	call ->assign_tmp
6278		} else {
6279			|	call ->assign_var
6280		}
6281	} else if (val_type == IS_CV) {
6282		if (!(val_info & MAY_BE_REF)) {
6283			|	call ->assign_cv_noref
6284		} else {
6285			|	call ->assign_cv
6286		}
6287		if ((val_info & MAY_BE_UNDEF) && JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE) {
6288			|9:
6289		}
6290	} else {
6291		ZEND_UNREACHABLE();
6292	}
6293
6294	return 1;
6295}
6296
6297static int zend_jit_assign_to_variable(dasm_State    **Dst,
6298                                       const zend_op  *opline,
6299                                       zend_jit_addr   var_use_addr,
6300                                       zend_jit_addr   var_addr,
6301                                       uint32_t        var_info,
6302                                       uint32_t        var_def_info,
6303                                       zend_uchar      val_type,
6304                                       zend_jit_addr   val_addr,
6305                                       uint32_t        val_info,
6306                                       zend_jit_addr   res_addr,
6307                                       zend_bool       check_exception)
6308/* Labels: 1,2,3,4,5,8 */
6309{
6310	int done = 0;
6311	zend_reg ref_reg, tmp_reg;
6312
6313	if (Z_MODE(var_addr) == IS_REG || Z_REG(var_use_addr) != ZREG_R0) {
6314		ref_reg = ZREG_FCARG1a;
6315		tmp_reg = ZREG_R0;
6316	} else {
6317		/* ASSIGN_DIM */
6318		ref_reg = ZREG_R0;
6319		tmp_reg = ZREG_FCARG1a;
6320	}
6321
6322	if (var_info & MAY_BE_REF) {
6323		if (Z_MODE(var_use_addr) != IS_MEM_ZVAL || Z_REG(var_use_addr) != ref_reg || Z_OFFSET(var_use_addr) != 0) {
6324			|	LOAD_ZVAL_ADDR Ra(ref_reg), var_use_addr
6325			var_addr = var_use_addr = ZEND_ADDR_MEM_ZVAL(ref_reg, 0);
6326		}
6327		|	// if (Z_ISREF_P(variable_ptr)) {
6328		|	IF_NOT_Z_TYPE, Ra(ref_reg), IS_REFERENCE, >3
6329		|	// if (UNEXPECTED(ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(variable_ptr)))) {
6330		|	GET_Z_PTR FCARG1a, Ra(ref_reg)
6331		if (!zend_jit_assign_to_typed_ref(Dst, opline, val_type, val_addr, res_addr, check_exception)) {
6332			return 0;
6333		}
6334		|	lea Ra(ref_reg), [FCARG1a + offsetof(zend_reference, val)]
6335		|3:
6336	}
6337	if (var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
6338		if (RC_MAY_BE_1(var_info)) {
6339			int in_cold = 0;
6340
6341			if (var_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
6342				|	IF_ZVAL_REFCOUNTED var_use_addr, >1
6343				|.cold_code
6344				|1:
6345				in_cold = 1;
6346			}
6347			if (Z_REG(var_use_addr) == ZREG_FCARG1a || Z_REG(var_use_addr) == ZREG_R0) {
6348				zend_bool keep_gc = 0;
6349
6350				|	GET_ZVAL_PTR Ra(tmp_reg), var_use_addr
6351				if (tmp_reg == ZREG_FCARG1a) {
6352					if (Z_MODE(val_addr) == IS_REG) {
6353						keep_gc = 1;
6354					} else if ((val_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_GUARD)-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) == 0) {
6355						keep_gc = 1;
6356					} else if (Z_MODE(val_addr) == IS_CONST_ZVAL) {
6357						if (sizeof(void*) == 4) {
6358							keep_gc = 1;
6359						} else {
6360							zval *zv = Z_ZV(val_addr);
6361
6362							if (Z_TYPE_P(zv) == IS_DOUBLE) {
6363								if (Z_DVAL_P(zv) == 0 || IS_SIGNED_32BIT(zv)) {
6364									keep_gc = 1;
6365								}
6366							} else if (IS_SIGNED_32BIT(Z_LVAL_P(zv))) {
6367								keep_gc = 1;
6368							}
6369						}
6370					} else if (Z_MODE(val_addr) == IS_MEM_ZVAL) {
6371						if ((val_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_GUARD)) == MAY_BE_DOUBLE) {
6372							keep_gc = 1;
6373						}
6374					}
6375				}
6376				if (!keep_gc) {
6377					|	mov aword T1, Ra(tmp_reg) // save
6378				}
6379				if (!zend_jit_simple_assign(Dst, opline, var_addr, var_info, var_def_info, val_type, val_addr, val_info, res_addr, in_cold, 0)) {
6380					return 0;
6381				}
6382				if (!keep_gc) {
6383					|	mov FCARG1a, aword T1 // restore
6384				}
6385			} else {
6386				|	GET_ZVAL_PTR FCARG1a, var_use_addr
6387				if (!zend_jit_simple_assign(Dst, opline, var_addr, var_info, var_def_info, val_type, val_addr, val_info, res_addr, in_cold, 1)) {
6388					return 0;
6389				}
6390			}
6391			|	GC_DELREF FCARG1a
6392			if (RC_MAY_BE_N(var_info) && (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT)) != 0) {
6393				|	jnz >4
6394			} else {
6395				|	jnz >8
6396			}
6397			|	ZVAL_DTOR_FUNC var_info, opline
6398			if (in_cold || (RC_MAY_BE_N(var_info) && (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT)) != 0)) {
6399				if (check_exception) {
6400					|	MEM_OP2_1_ZTS cmp, aword, executor_globals, exception, 0, r0
6401					|	je >8
6402					|	jmp ->exception_handler
6403				} else {
6404					|	jmp >8
6405				}
6406			}
6407			if (RC_MAY_BE_N(var_info) && (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT)) != 0) {
6408				|4:
6409				|	IF_GC_MAY_NOT_LEAK FCARG1a, >8
6410				|	EXT_CALL gc_possible_root, r0
6411				if (in_cold) {
6412					|	jmp >8
6413				}
6414			}
6415			if (in_cold) {
6416				|.code
6417			} else {
6418				done = 1;
6419			}
6420		} else /* if (RC_MAY_BE_N(var_info)) */ {
6421			if (var_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
6422				|	IF_NOT_ZVAL_REFCOUNTED var_use_addr, >5
6423			}
6424			if (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT)) {
6425				if (Z_REG(var_use_addr) == ZREG_FP) {
6426					|	mov T1, Ra(Z_REG(var_use_addr)) // save
6427				}
6428				|	GET_ZVAL_PTR FCARG1a, var_use_addr
6429				|	GC_DELREF FCARG1a
6430				|	IF_GC_MAY_NOT_LEAK FCARG1a, >5
6431				|	EXT_CALL gc_possible_root, r0
6432				if (Z_REG(var_use_addr) != ZREG_FP) {
6433					|	mov Ra(Z_REG(var_use_addr)), T1 // restore
6434				}
6435			} else {
6436				|	GET_ZVAL_PTR Ra(tmp_reg), var_use_addr
6437				|	GC_DELREF Ra(tmp_reg)
6438			}
6439			|5:
6440	    }
6441	}
6442
6443	if (!done && !zend_jit_simple_assign(Dst, opline, var_addr, var_info, var_def_info, val_type, val_addr, val_info, res_addr, 0, 0)) {
6444		return 0;
6445	}
6446
6447	|8:
6448
6449	return 1;
6450}
6451
6452static int zend_jit_assign_dim(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint32_t op2_info, uint32_t val_info, int may_throw)
6453{
6454	zend_jit_addr op2_addr, op3_addr, res_addr;
6455
6456	op2_addr = (opline->op2_type != IS_UNUSED) ? OP2_ADDR() : 0;
6457	op3_addr = OP1_DATA_ADDR();
6458	if (opline->result_type == IS_UNUSED) {
6459		res_addr = 0;
6460	} else {
6461		res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
6462	}
6463
6464	if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && (val_info & MAY_BE_UNDEF)) {
6465		int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
6466		const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
6467
6468		if (!exit_addr) {
6469			return 0;
6470		}
6471
6472		|	IF_ZVAL_TYPE op3_addr, IS_UNDEF, &exit_addr
6473
6474		val_info &= ~MAY_BE_UNDEF;
6475	}
6476
6477	if (op1_info & MAY_BE_REF) {
6478		|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
6479		|	IF_NOT_Z_TYPE FCARG1a, IS_REFERENCE, >1
6480		|	GET_Z_PTR FCARG2a, FCARG1a
6481		|	IF_NOT_TYPE byte [FCARG2a + offsetof(zend_reference, val) + offsetof(zval, u1.v.type)], IS_ARRAY, >2
6482		|	lea FCARG1a, [FCARG2a + offsetof(zend_reference, val)]
6483		|	jmp >3
6484		|.cold_code
6485		|2:
6486		|	SET_EX_OPLINE opline, r0
6487		|	EXT_CALL zend_jit_prepare_assign_dim_ref, r0
6488		|	test r0, r0
6489		|	mov FCARG1a, r0
6490		|	jne >1
6491		|	jmp ->exception_handler_undef
6492		|.code
6493		|1:
6494		op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
6495	}
6496
6497	if (op1_info & MAY_BE_ARRAY) {
6498		if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
6499			|	IF_NOT_ZVAL_TYPE op1_addr, IS_ARRAY, >7
6500		}
6501		|3:
6502		|	SEPARATE_ARRAY op1_addr, op1_info, 1
6503	} else if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {
6504		if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY))) {
6505			|	CMP_ZVAL_TYPE op1_addr, IS_FALSE
6506			|	jg >7
6507		}
6508		|	// ZVAL_ARR(container, zend_new_array(8));
6509		if (Z_REG(op1_addr) != ZREG_FP) {
6510			|	mov T1, Ra(Z_REG(op1_addr)) // save
6511		}
6512		|	EXT_CALL _zend_new_array_0, r0
6513		if (Z_REG(op1_addr) != ZREG_FP) {
6514			|	mov Ra(Z_REG(op1_addr)), T1 // restore
6515		}
6516		|	SET_ZVAL_LVAL op1_addr, r0
6517		|	SET_ZVAL_TYPE_INFO op1_addr, IS_ARRAY_EX
6518		|	mov FCARG1a, r0
6519	}
6520
6521	if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY)) {
6522		|6:
6523		if (opline->op2_type == IS_UNUSED) {
6524			uint32_t var_info = MAY_BE_NULL;
6525			zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0);
6526
6527			|	// var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
6528			|	LOAD_ADDR_ZTS FCARG2a, executor_globals, uninitialized_zval
6529			|	EXT_CALL zend_hash_next_index_insert, r0
6530			|	// if (UNEXPECTED(!var_ptr)) {
6531			|	test r0, r0
6532			|	jz >1
6533			|.cold_code
6534			|1:
6535			|	// zend_throw_error(NULL, "Cannot add element to the array as the next element is already occupied");
6536			|	CANNOT_ADD_ELEMENT opline
6537			|	//ZEND_VM_C_GOTO(assign_dim_op_ret_null);
6538			|	jmp >9
6539			|.code
6540
6541			if (!zend_jit_simple_assign(Dst, opline, var_addr, var_info, -1, (opline+1)->op1_type, op3_addr, val_info, res_addr, 0, 0)) {
6542				return 0;
6543			}
6544		} else {
6545			uint32_t var_info = zend_array_element_type(op1_info, opline->op1_type, 0, 0);
6546			zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0);
6547
6548			if (!zend_jit_fetch_dimension_address_inner(Dst, opline, BP_VAR_W, op1_info, op2_info, NULL, NULL, NULL)) {
6549				return 0;
6550			}
6551
6552			if (op1_info & (MAY_BE_ARRAY_OF_REF|MAY_BE_OBJECT)) {
6553				var_info |= MAY_BE_REF;
6554			}
6555			if (var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
6556				var_info |= MAY_BE_RC1;
6557			}
6558
6559			|8:
6560			|	// value = zend_assign_to_variable(variable_ptr, value, OP_DATA_TYPE);
6561			if (opline->op1_type == IS_VAR) {
6562				ZEND_ASSERT(opline->result_type == IS_UNUSED);
6563				if (!zend_jit_assign_to_variable_call(Dst, opline, var_addr, var_addr, var_info, -1, (opline+1)->op1_type, op3_addr, val_info, res_addr, 0)) {
6564					return 0;
6565				}
6566			} else {
6567				if (!zend_jit_assign_to_variable(Dst, opline, var_addr, var_addr, var_info, -1, (opline+1)->op1_type, op3_addr, val_info, res_addr, 0)) {
6568					return 0;
6569				}
6570			}
6571		}
6572	}
6573
6574	if (((op1_info & MAY_BE_ARRAY) &&
6575	     (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE))) ||
6576	    (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY)))) {
6577		if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY)) {
6578			|.cold_code
6579			|7:
6580		}
6581
6582		if ((op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) &&
6583		    (op1_info & MAY_BE_ARRAY)) {
6584			if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY))) {
6585				|	CMP_ZVAL_TYPE op1_addr, IS_FALSE
6586				|	jg >2
6587			}
6588			|	// ZVAL_ARR(container, zend_new_array(8));
6589			if (Z_REG(op1_addr) != ZREG_FP) {
6590				|	mov T1, Ra(Z_REG(op1_addr)) // save
6591			}
6592			|	EXT_CALL _zend_new_array_0, r0
6593			if (Z_REG(op1_addr) != ZREG_FP) {
6594				|	mov Ra(Z_REG(op1_addr)), T1 // restore
6595			}
6596			|	SET_ZVAL_LVAL op1_addr, r0
6597			|	SET_ZVAL_TYPE_INFO op1_addr, IS_ARRAY_EX
6598			|	mov FCARG1a, r0
6599			|	// ZEND_VM_C_GOTO(assign_dim_op_new_array);
6600			|	jmp <6
6601			|2:
6602		}
6603
6604		if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY))) {
6605			|	SET_EX_OPLINE opline, r0
6606		    if (Z_REG(op1_addr) != ZREG_FCARG1a || Z_OFFSET(op1_addr) != 0) {
6607				|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
6608			}
6609		    if (opline->op2_type == IS_UNUSED) {
6610				|	xor FCARG2a, FCARG2a
6611			} else if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
6612				ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
6613				|	LOAD_ADDR FCARG2a, (Z_ZV(op2_addr) + 1)
6614			} else {
6615				|	LOAD_ZVAL_ADDR FCARG2a, op2_addr
6616			}
6617			|.if not(X64)
6618			|	sub r4, 8
6619			|.endif
6620			if (opline->result_type == IS_UNUSED) {
6621				|.if X64
6622					|	xor CARG4, CARG4
6623				|.else
6624					|	push 0
6625				|.endif
6626			} else {
6627				|.if X64
6628					|	LOAD_ZVAL_ADDR CARG4, res_addr
6629				|.else
6630					|	PUSH_ZVAL_ADDR res_addr, r0
6631				|.endif
6632			}
6633			|.if X64
6634				|	LOAD_ZVAL_ADDR CARG3, op3_addr
6635			|.else
6636				|	PUSH_ZVAL_ADDR op3_addr, r0
6637			|.endif
6638			|	EXT_CALL zend_jit_assign_dim_helper, r0
6639			|.if not(X64)
6640			|	add r4, 8
6641			|.endif
6642
6643#ifdef ZEND_JIT_USE_RC_INFERENCE
6644			if (((opline+1)->op1_type & (IS_TMP_VAR|IS_VAR)) && (val_info & MAY_BE_RC1)) {
6645				/* ASSIGN_DIM may increase refcount of the value */
6646				val_info |= MAY_BE_RCN;
6647			}
6648#endif
6649
6650			|	FREE_OP (opline+1)->op1_type, (opline+1)->op1, val_info, 0, opline
6651		}
6652
6653		if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY)) {
6654			if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY))) {
6655				|	jmp >9 // END
6656			}
6657			|.code
6658		}
6659	}
6660
6661#ifdef ZEND_JIT_USE_RC_INFERENCE
6662	if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY|MAY_BE_OBJECT))) {
6663		/* ASSIGN_DIM may increase refcount of the key */
6664		op2_info |= MAY_BE_RCN;
6665	}
6666#endif
6667
6668	|9:
6669	|	FREE_OP opline->op2_type, opline->op2, op2_info, 0, opline
6670
6671	if (may_throw) {
6672		zend_jit_check_exception(Dst);
6673	}
6674
6675	return 1;
6676}
6677
6678static int zend_jit_assign_dim_op(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, uint32_t op1_def_info, zend_jit_addr op1_addr, uint32_t op2_info, uint32_t op1_data_info, zend_ssa_range *op1_data_range, int may_throw)
6679{
6680	zend_jit_addr op2_addr, op3_addr, var_addr;
6681
6682	ZEND_ASSERT(opline->result_type == IS_UNUSED);
6683
6684	op2_addr = (opline->op2_type != IS_UNUSED) ? OP2_ADDR() : 0;
6685	op3_addr = OP1_DATA_ADDR();
6686
6687	if (op1_info & MAY_BE_REF) {
6688		|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
6689		|	IF_NOT_Z_TYPE FCARG1a, IS_REFERENCE, >1
6690		|	GET_Z_PTR FCARG2a, FCARG1a
6691		|	IF_NOT_TYPE byte [FCARG2a + offsetof(zend_reference, val) + offsetof(zval, u1.v.type)], IS_ARRAY, >2
6692		|	lea FCARG1a, [FCARG2a + offsetof(zend_reference, val)]
6693		|	jmp >3
6694		|.cold_code
6695		|2:
6696		|	SET_EX_OPLINE opline, r0
6697		|	EXT_CALL zend_jit_prepare_assign_dim_ref, r0
6698		|	test r0, r0
6699		|	mov FCARG1a, r0
6700		|	jne >1
6701		|	jmp ->exception_handler_undef
6702		|.code
6703		|1:
6704		op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
6705	}
6706
6707	if (op1_info & MAY_BE_ARRAY) {
6708		if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
6709			|	IF_NOT_ZVAL_TYPE op1_addr, IS_ARRAY, >7
6710		}
6711		|3:
6712		|	SEPARATE_ARRAY op1_addr, op1_info, 1
6713	}
6714	if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {
6715		if (op1_info & MAY_BE_ARRAY) {
6716			|.cold_code
6717			|7:
6718		}
6719		if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY))) {
6720			|	CMP_ZVAL_TYPE op1_addr, IS_FALSE
6721			|	jg >7
6722		}
6723		if (Z_REG(op1_addr) != ZREG_FP) {
6724			|	mov T1, Ra(Z_REG(op1_addr)) // save
6725		}
6726		if (op1_info & MAY_BE_UNDEF) {
6727			if (op1_info & (MAY_BE_NULL|MAY_BE_FALSE)) {
6728				|	IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >1
6729			}
6730			|	SET_EX_OPLINE opline, r0
6731			|	mov FCARG1a, opline->op1.var
6732			|	EXT_CALL zend_jit_undefined_op_helper, r0
6733			|1:
6734		}
6735		|	// ZVAL_ARR(container, zend_new_array(8));
6736		|	EXT_CALL _zend_new_array_0, r0
6737		if (Z_REG(op1_addr) != ZREG_FP) {
6738			|	mov Ra(Z_REG(op1_addr)), T1 // restore
6739		}
6740		|	SET_ZVAL_LVAL op1_addr, r0
6741		|	SET_ZVAL_TYPE_INFO op1_addr, IS_ARRAY_EX
6742		|	mov FCARG1a, r0
6743		if (op1_info & MAY_BE_ARRAY) {
6744			|	jmp >1
6745			|.code
6746			|1:
6747		}
6748	}
6749
6750	if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY)) {
6751		uint32_t var_info;
6752		uint32_t var_def_info = zend_array_element_type(op1_def_info, opline->op1_type, 1, 0);
6753
6754		|6:
6755		if (opline->op2_type == IS_UNUSED) {
6756			var_info = MAY_BE_NULL;
6757
6758			|	// var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
6759			|	LOAD_ADDR_ZTS FCARG2a, executor_globals, uninitialized_zval
6760			|	EXT_CALL zend_hash_next_index_insert, r0
6761			|	// if (UNEXPECTED(!var_ptr)) {
6762			|	test r0, r0
6763			|	jz >1
6764			|.cold_code
6765			|1:
6766			|	// zend_throw_error(NULL, "Cannot add element to the array as the next element is already occupied");
6767			|	CANNOT_ADD_ELEMENT opline
6768			|	//ZEND_VM_C_GOTO(assign_dim_op_ret_null);
6769			|	jmp >9
6770			|.code
6771		} else {
6772			var_info = zend_array_element_type(op1_info, opline->op1_type, 0, 0);
6773			if (op1_info & (MAY_BE_ARRAY_OF_REF|MAY_BE_OBJECT)) {
6774				var_info |= MAY_BE_REF;
6775			}
6776			if (var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
6777				var_info |= MAY_BE_RC1;
6778			}
6779
6780			if (!zend_jit_fetch_dimension_address_inner(Dst, opline, BP_VAR_RW, op1_info, op2_info, NULL, NULL, NULL)) {
6781				return 0;
6782			}
6783
6784			|8:
6785			if (op1_info & (MAY_BE_ARRAY_OF_REF)) {
6786				binary_op_type binary_op = get_binary_op(opline->extended_value);
6787				|	IF_NOT_Z_TYPE, r0, IS_REFERENCE, >1
6788				|	GET_Z_PTR FCARG1a, r0
6789				|	cmp aword [FCARG1a + offsetof(zend_reference, sources.ptr)], 0
6790				|	jnz >2
6791				|	lea r0, aword [FCARG1a + offsetof(zend_reference, val)]
6792				|.cold_code
6793				|2:
6794				|	LOAD_ZVAL_ADDR FCARG2a, op3_addr
6795				|.if X64
6796					|	LOAD_ADDR CARG3, binary_op
6797				|.else
6798					|	sub r4, 12
6799					|	PUSH_ADDR binary_op, r0
6800				|.endif
6801				|	SET_EX_OPLINE opline, r0
6802				if (((opline+1)->op1_type & (IS_TMP_VAR|IS_VAR))
6803				 && (op1_data_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
6804					|	EXT_CALL zend_jit_assign_op_to_typed_ref_tmp, r0
6805				} else {
6806					|	EXT_CALL zend_jit_assign_op_to_typed_ref, r0
6807				}
6808				|.if not(X64)
6809				|	add r4, 12
6810				|.endif
6811				zend_jit_check_exception(Dst);
6812				|	jmp >9
6813				|.code
6814				|1:
6815			}
6816		}
6817
6818		var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0);
6819		switch (opline->extended_value) {
6820			case ZEND_ADD:
6821			case ZEND_SUB:
6822			case ZEND_MUL:
6823			case ZEND_DIV:
6824				if (!zend_jit_math_helper(Dst, opline, opline->extended_value, IS_CV, opline->op1, var_addr, var_info, (opline+1)->op1_type, (opline+1)->op1, op3_addr, op1_data_info, 0, var_addr, var_def_info, var_info,
6825						1 /* may overflow */, may_throw)) {
6826					return 0;
6827				}
6828				break;
6829			case ZEND_BW_OR:
6830			case ZEND_BW_AND:
6831			case ZEND_BW_XOR:
6832			case ZEND_SL:
6833			case ZEND_SR:
6834			case ZEND_MOD:
6835				if (!zend_jit_long_math_helper(Dst, opline, opline->extended_value,
6836						IS_CV, opline->op1, var_addr, var_info, NULL,
6837						(opline+1)->op1_type, (opline+1)->op1, op3_addr, op1_data_info,
6838						op1_data_range,
6839						0, var_addr, var_def_info, var_info, may_throw)) {
6840					return 0;
6841				}
6842				break;
6843			case ZEND_CONCAT:
6844				if (!zend_jit_concat_helper(Dst, opline, IS_CV, opline->op1, var_addr, var_info, (opline+1)->op1_type, (opline+1)->op1, op3_addr, op1_data_info, var_addr,
6845						may_throw)) {
6846					return 0;
6847				}
6848				break;
6849			default:
6850				ZEND_UNREACHABLE();
6851		}
6852	}
6853
6854	if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY))) {
6855		binary_op_type binary_op;
6856
6857		if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY)) {
6858			|.cold_code
6859			|7:
6860		}
6861
6862		|	SET_EX_OPLINE opline, r0
6863		if (Z_REG(op1_addr) != ZREG_FCARG1a || Z_OFFSET(op1_addr) != 0) {
6864			|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
6865		}
6866	    if (opline->op2_type == IS_UNUSED) {
6867			|	xor FCARG2a, FCARG2a
6868		} else if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
6869			ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
6870			|	LOAD_ADDR FCARG2a, (Z_ZV(op2_addr) + 1)
6871		} else {
6872			|	LOAD_ZVAL_ADDR FCARG2a, op2_addr
6873		}
6874		binary_op = get_binary_op(opline->extended_value);
6875		|.if X64
6876			|	LOAD_ZVAL_ADDR CARG3, op3_addr
6877			|	LOAD_ADDR CARG4, binary_op
6878		|.else
6879			|	sub r4, 8
6880			|	PUSH_ADDR binary_op, r0
6881			|	PUSH_ZVAL_ADDR op3_addr, r0
6882		|.endif
6883		|	EXT_CALL zend_jit_assign_dim_op_helper, r0
6884		|.if not(X64)
6885		|	add r4, 8
6886		|.endif
6887		if (!zend_jit_check_exception(Dst)) {
6888			return 0;
6889		}
6890
6891		if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY)) {
6892			|	jmp >9 // END
6893			|.code
6894		}
6895	}
6896
6897	|9:
6898	|	FREE_OP opline->op2_type, opline->op2, op2_info, 0, opline
6899
6900	return 1;
6901}
6902
6903static int zend_jit_assign_op(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, uint32_t op1_def_info, zend_ssa_range *op1_range, uint32_t op2_info, zend_ssa_range *op2_range, int may_overflow, int may_throw)
6904{
6905	zend_jit_addr op1_addr, op2_addr;
6906
6907	ZEND_ASSERT(opline->op1_type == IS_CV && opline->result_type == IS_UNUSED);
6908	ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF));
6909
6910	op1_addr = OP1_ADDR();
6911	op2_addr = OP2_ADDR();
6912
6913	if (op1_info & MAY_BE_REF) {
6914		binary_op_type binary_op = get_binary_op(opline->extended_value);
6915		|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
6916		|	IF_NOT_Z_TYPE, FCARG1a, IS_REFERENCE, >1
6917		|	GET_Z_PTR FCARG1a, FCARG1a
6918		|	cmp aword [FCARG1a + offsetof(zend_reference, sources.ptr)], 0
6919		|	jnz >2
6920		|	add FCARG1a, offsetof(zend_reference, val)
6921		|.cold_code
6922		|2:
6923		|	LOAD_ZVAL_ADDR FCARG2a, op2_addr
6924		|.if X64
6925			|	LOAD_ADDR CARG3, binary_op
6926		|.else
6927			|	sub r4, 12
6928			|	PUSH_ADDR binary_op, r0
6929		|.endif
6930		|	SET_EX_OPLINE opline, r0
6931		if ((opline->op2_type & (IS_TMP_VAR|IS_VAR))
6932		 && (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
6933			|	EXT_CALL zend_jit_assign_op_to_typed_ref_tmp, r0
6934		} else {
6935			|	EXT_CALL zend_jit_assign_op_to_typed_ref, r0
6936		}
6937		|.if not(X64)
6938		|	add r4, 12
6939		|.endif
6940		zend_jit_check_exception(Dst);
6941		|	jmp >9
6942		|.code
6943		|1:
6944		op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
6945	}
6946
6947	int result;
6948	switch (opline->extended_value) {
6949		case ZEND_ADD:
6950		case ZEND_SUB:
6951		case ZEND_MUL:
6952		case ZEND_DIV:
6953			result = zend_jit_math_helper(Dst, opline, opline->extended_value, opline->op1_type, opline->op1, op1_addr, op1_info, opline->op2_type, opline->op2, op2_addr, op2_info, opline->op1.var, op1_addr, op1_def_info, op1_info, may_overflow, may_throw);
6954			break;
6955		case ZEND_BW_OR:
6956		case ZEND_BW_AND:
6957		case ZEND_BW_XOR:
6958		case ZEND_SL:
6959		case ZEND_SR:
6960		case ZEND_MOD:
6961			result = zend_jit_long_math_helper(Dst, opline, opline->extended_value,
6962				opline->op1_type, opline->op1, op1_addr, op1_info, op1_range,
6963				opline->op2_type, opline->op2, op2_addr, op2_info, op2_range,
6964				opline->op1.var, op1_addr, op1_def_info, op1_info, may_throw);
6965			break;
6966		case ZEND_CONCAT:
6967			result = zend_jit_concat_helper(Dst, opline, opline->op1_type, opline->op1, op1_addr, op1_info, opline->op2_type, opline->op2, op2_addr, op2_info, op1_addr, may_throw);
6968			break;
6969		default:
6970			ZEND_UNREACHABLE();
6971	}
6972	|9:
6973	return result;
6974}
6975
6976static int zend_jit_is_constant_cmp_long_long(const zend_op  *opline,
6977                                              zend_ssa_range *op1_range,
6978                                              zend_jit_addr   op1_addr,
6979                                              zend_ssa_range *op2_range,
6980                                              zend_jit_addr   op2_addr,
6981                                              zend_bool      *result)
6982{
6983	zend_long op1_min;
6984	zend_long op1_max;
6985	zend_long op2_min;
6986	zend_long op2_max;
6987
6988	if (op1_range) {
6989		op1_min = op1_range->min;
6990		op1_max = op1_range->max;
6991	} else if (Z_MODE(op1_addr) == IS_CONST_ZVAL) {
6992		ZEND_ASSERT(Z_TYPE_P(Z_ZV(op1_addr)) == IS_LONG);
6993		op1_min = op1_max = Z_LVAL_P(Z_ZV(op1_addr));
6994	} else {
6995		return 0;
6996	}
6997
6998	if (op2_range) {
6999		op2_min = op2_range->min;
7000		op2_max = op2_range->max;
7001	} else if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
7002		ZEND_ASSERT(Z_TYPE_P(Z_ZV(op2_addr)) == IS_LONG);
7003		op2_min = op2_max = Z_LVAL_P(Z_ZV(op2_addr));
7004	} else {
7005		return 0;
7006	}
7007
7008	switch (opline->opcode) {
7009		case ZEND_IS_EQUAL:
7010		case ZEND_IS_IDENTICAL:
7011		case ZEND_CASE:
7012		case ZEND_CASE_STRICT:
7013			if (op1_min == op1_max && op2_min == op2_max && op1_min == op2_min) {
7014				*result = 1;
7015				return 1;
7016			} else if (op1_max < op2_min || op1_min > op2_max) {
7017				*result = 0;
7018				return 1;
7019			}
7020			return 0;
7021		case ZEND_IS_NOT_EQUAL:
7022		case ZEND_IS_NOT_IDENTICAL:
7023			if (op1_min == op1_max && op2_min == op2_max && op1_min == op2_min) {
7024				*result = 0;
7025				return 1;
7026			} else if (op1_max < op2_min || op1_min > op2_max) {
7027				*result = 1;
7028				return 1;
7029			}
7030			return 0;
7031		case ZEND_IS_SMALLER:
7032			if (op1_max < op2_min) {
7033				*result = 1;
7034				return 1;
7035			} else if (op1_min >= op2_max) {
7036				*result = 0;
7037				return 1;
7038			}
7039			return 0;
7040		case ZEND_IS_SMALLER_OR_EQUAL:
7041			if (op1_max <= op2_min) {
7042				*result = 1;
7043				return 1;
7044			} else if (op1_min > op2_max) {
7045				*result = 0;
7046				return 1;
7047			}
7048			return 0;
7049		default:
7050			ZEND_UNREACHABLE();
7051	}
7052	return 0;
7053}
7054
7055static int zend_jit_cmp_long_long(dasm_State    **Dst,
7056                                  const zend_op  *opline,
7057                                  zend_ssa_range *op1_range,
7058                                  zend_jit_addr   op1_addr,
7059                                  zend_ssa_range *op2_range,
7060                                  zend_jit_addr   op2_addr,
7061                                  zend_jit_addr   res_addr,
7062                                  zend_uchar      smart_branch_opcode,
7063                                  uint32_t        target_label,
7064                                  uint32_t        target_label2,
7065                                  const void     *exit_addr,
7066                                  zend_bool       skip_comparison)
7067{
7068	zend_bool swap = 0;
7069	zend_bool result;
7070
7071	if (zend_jit_is_constant_cmp_long_long(opline, op1_range, op1_addr, op2_range, op2_addr, &result)) {
7072		if (!smart_branch_opcode ||
7073		    smart_branch_opcode == ZEND_JMPZ_EX ||
7074		    smart_branch_opcode == ZEND_JMPNZ_EX) {
7075			|	SET_ZVAL_TYPE_INFO res_addr, (result ? IS_TRUE : IS_FALSE)
7076		}
7077		if (smart_branch_opcode && !exit_addr) {
7078			if (smart_branch_opcode == ZEND_JMPZ ||
7079			    smart_branch_opcode == ZEND_JMPZ_EX) {
7080				if (!result) {
7081					| jmp => target_label
7082				}
7083			} else if (smart_branch_opcode == ZEND_JMPNZ ||
7084			           smart_branch_opcode == ZEND_JMPNZ_EX) {
7085				if (result) {
7086					| jmp => target_label
7087				}
7088			} else if (smart_branch_opcode == ZEND_JMPZNZ) {
7089				if (!result) {
7090					| jmp => target_label
7091				} else {
7092					| jmp => target_label2
7093				}
7094			} else {
7095				ZEND_UNREACHABLE();
7096			}
7097		}
7098		return 1;
7099	}
7100
7101	if (skip_comparison) {
7102		if (Z_MODE(op1_addr) != IS_REG &&
7103		    (Z_MODE(op2_addr) == IS_REG ||
7104		     (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_MODE(op2_addr) != IS_CONST_ZVAL))) {
7105			swap = 1;
7106		}
7107	} else if (Z_MODE(op1_addr) == IS_REG) {
7108		if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 0) {
7109			|	test Ra(Z_REG(op1_addr)), Ra(Z_REG(op1_addr))
7110		} else {
7111			|	LONG_OP cmp, Z_REG(op1_addr), op2_addr, r0
7112		}
7113	} else if (Z_MODE(op2_addr) == IS_REG) {
7114		if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op1_addr)) == 0) {
7115			|	test Ra(Z_REG(op2_addr)), Ra(Z_REG(op2_addr))
7116		} else {
7117			|	LONG_OP cmp, Z_REG(op2_addr), op1_addr, r0
7118		}
7119		swap = 1;
7120	} else if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_MODE(op2_addr) != IS_CONST_ZVAL) {
7121		|	LONG_OP_WITH_CONST cmp, op2_addr, Z_LVAL_P(Z_ZV(op1_addr))
7122		swap = 1;
7123	} else if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_MODE(op1_addr) != IS_CONST_ZVAL) {
7124		|	LONG_OP_WITH_CONST cmp, op1_addr, Z_LVAL_P(Z_ZV(op2_addr))
7125	} else {
7126		|	GET_ZVAL_LVAL ZREG_R0, op1_addr
7127		if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 0) {
7128			|	test r0, r0
7129		} else {
7130			|	LONG_OP cmp, ZREG_R0, op2_addr, r0
7131		}
7132	}
7133
7134	if (smart_branch_opcode) {
7135		if (smart_branch_opcode == ZEND_JMPZ_EX ||
7136		    smart_branch_opcode == ZEND_JMPNZ_EX) {
7137
7138			switch (opline->opcode) {
7139				case ZEND_IS_EQUAL:
7140				case ZEND_IS_IDENTICAL:
7141				case ZEND_CASE:
7142				case ZEND_CASE_STRICT:
7143					|	sete al
7144					break;
7145				case ZEND_IS_NOT_EQUAL:
7146				case ZEND_IS_NOT_IDENTICAL:
7147					|	setne al
7148					break;
7149				case ZEND_IS_SMALLER:
7150					if (swap) {
7151						|	setg al
7152					} else {
7153						|	setl al
7154					}
7155					break;
7156				case ZEND_IS_SMALLER_OR_EQUAL:
7157					if (swap) {
7158						|	setge al
7159					} else {
7160						|	setle al
7161					}
7162					break;
7163				default:
7164					ZEND_UNREACHABLE();
7165			}
7166			|	movzx eax, al
7167			|	lea eax, [eax + 2]
7168			|	SET_ZVAL_TYPE_INFO res_addr, eax
7169		}
7170		if (smart_branch_opcode == ZEND_JMPZ ||
7171		    smart_branch_opcode == ZEND_JMPZ_EX) {
7172			switch (opline->opcode) {
7173				case ZEND_IS_EQUAL:
7174				case ZEND_IS_IDENTICAL:
7175				case ZEND_CASE:
7176				case ZEND_CASE_STRICT:
7177					if (exit_addr) {
7178						| jne &exit_addr
7179					} else {
7180						| jne => target_label
7181					}
7182					break;
7183				case ZEND_IS_NOT_EQUAL:
7184					if (exit_addr) {
7185						| je &exit_addr
7186					} else {
7187						| je => target_label
7188					}
7189					break;
7190				case ZEND_IS_NOT_IDENTICAL:
7191					if (exit_addr) {
7192						| jne &exit_addr
7193					} else {
7194						| je => target_label
7195					}
7196					break;
7197				case ZEND_IS_SMALLER:
7198					if (swap) {
7199						if (exit_addr) {
7200							| jle &exit_addr
7201						} else {
7202							| jle => target_label
7203						}
7204					} else {
7205						if (exit_addr) {
7206							| jge &exit_addr
7207						} else {
7208							| jge => target_label
7209						}
7210					}
7211					break;
7212				case ZEND_IS_SMALLER_OR_EQUAL:
7213					if (swap) {
7214						if (exit_addr) {
7215							| jl &exit_addr
7216						} else {
7217							| jl => target_label
7218						}
7219					} else {
7220						if (exit_addr) {
7221							| jg &exit_addr
7222						} else {
7223							| jg => target_label
7224						}
7225					}
7226					break;
7227				default:
7228					ZEND_UNREACHABLE();
7229			}
7230		} else if (smart_branch_opcode == ZEND_JMPNZ ||
7231		           smart_branch_opcode == ZEND_JMPNZ_EX) {
7232			switch (opline->opcode) {
7233				case ZEND_IS_EQUAL:
7234				case ZEND_IS_IDENTICAL:
7235				case ZEND_CASE:
7236				case ZEND_CASE_STRICT:
7237					if (exit_addr) {
7238						| je &exit_addr
7239					} else {
7240						| je => target_label
7241					}
7242					break;
7243				case ZEND_IS_NOT_EQUAL:
7244					if (exit_addr) {
7245						| jne &exit_addr
7246					} else {
7247						| jne => target_label
7248					}
7249					break;
7250				case ZEND_IS_NOT_IDENTICAL:
7251					if (exit_addr) {
7252						| je &exit_addr
7253					} else {
7254						| jne => target_label
7255					}
7256					break;
7257				case ZEND_IS_SMALLER:
7258					if (swap) {
7259						if (exit_addr) {
7260							| jg &exit_addr
7261						} else {
7262							| jg => target_label
7263						}
7264					} else {
7265						if (exit_addr) {
7266							| jl &exit_addr
7267						} else {
7268							| jl => target_label
7269						}
7270					}
7271					break;
7272				case ZEND_IS_SMALLER_OR_EQUAL:
7273					if (swap) {
7274						if (exit_addr) {
7275							| jge &exit_addr
7276						} else {
7277							| jge => target_label
7278						}
7279					} else {
7280						if (exit_addr) {
7281							| jle &exit_addr
7282						} else {
7283							| jle => target_label
7284						}
7285					}
7286					break;
7287				default:
7288					ZEND_UNREACHABLE();
7289			}
7290		} else if (smart_branch_opcode == ZEND_JMPZNZ) {
7291			switch (opline->opcode) {
7292				case ZEND_IS_EQUAL:
7293				case ZEND_IS_IDENTICAL:
7294				case ZEND_CASE:
7295				case ZEND_CASE_STRICT:
7296					| jne => target_label
7297					break;
7298				case ZEND_IS_NOT_EQUAL:
7299				case ZEND_IS_NOT_IDENTICAL:
7300					| je => target_label
7301					break;
7302				case ZEND_IS_SMALLER:
7303				    if (swap) {
7304						| jle => target_label
7305				    } else {
7306						| jge => target_label
7307					}
7308					break;
7309				case ZEND_IS_SMALLER_OR_EQUAL:
7310					if (swap) {
7311						| jl => target_label
7312					} else {
7313						| jg => target_label
7314					}
7315					break;
7316				default:
7317					ZEND_UNREACHABLE();
7318			}
7319			| jmp => target_label2
7320		} else {
7321			ZEND_UNREACHABLE();
7322		}
7323	} else {
7324		switch (opline->opcode) {
7325			case ZEND_IS_EQUAL:
7326			case ZEND_IS_IDENTICAL:
7327			case ZEND_CASE:
7328			case ZEND_CASE_STRICT:
7329				|	sete al
7330				break;
7331			case ZEND_IS_NOT_EQUAL:
7332			case ZEND_IS_NOT_IDENTICAL:
7333				|	setne al
7334				break;
7335			case ZEND_IS_SMALLER:
7336				if (swap) {
7337					|	setg al
7338				} else {
7339					|	setl al
7340				}
7341				break;
7342			case ZEND_IS_SMALLER_OR_EQUAL:
7343				if (swap) {
7344					|	setge al
7345				} else {
7346					|	setle al
7347				}
7348				break;
7349			default:
7350				ZEND_UNREACHABLE();
7351		}
7352		|	movzx eax, al
7353		|	add eax, 2
7354		|	SET_ZVAL_TYPE_INFO res_addr, eax
7355	}
7356
7357	return 1;
7358}
7359
7360static int zend_jit_cmp_double_common(dasm_State **Dst, const zend_op *opline, zend_jit_addr res_addr, zend_bool swap, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
7361{
7362	if (smart_branch_opcode) {
7363		if (smart_branch_opcode == ZEND_JMPZ) {
7364			switch (opline->opcode) {
7365				case ZEND_IS_EQUAL:
7366				case ZEND_IS_IDENTICAL:
7367				case ZEND_CASE:
7368				case ZEND_CASE_STRICT:
7369					if (exit_addr) {
7370						| jne &exit_addr
7371						| jp &exit_addr
7372					} else {
7373						| jne => target_label
7374						| jp => target_label
7375					}
7376					break;
7377				case ZEND_IS_NOT_EQUAL:
7378					| jp >1
7379					if (exit_addr) {
7380						| je &exit_addr
7381					} else {
7382						| je => target_label
7383					}
7384					|1:
7385					break;
7386				case ZEND_IS_NOT_IDENTICAL:
7387					if (exit_addr) {
7388						| jne &exit_addr
7389						| jp &exit_addr
7390					} else {
7391						| jp >1
7392						| je => target_label
7393						|1:
7394					}
7395					break;
7396				case ZEND_IS_SMALLER:
7397					if (swap) {
7398						if (exit_addr) {
7399							| jbe &exit_addr
7400						} else {
7401							| jbe => target_label
7402						}
7403					} else {
7404						if (exit_addr) {
7405							| jae &exit_addr
7406							| jp &exit_addr
7407						} else {
7408							| jae => target_label
7409							| jp => target_label
7410						}
7411					}
7412					break;
7413				case ZEND_IS_SMALLER_OR_EQUAL:
7414					if (swap) {
7415						if (exit_addr) {
7416							| jb &exit_addr
7417						} else {
7418							| jb => target_label
7419						}
7420					} else {
7421						if (exit_addr) {
7422							| ja &exit_addr
7423							| jp &exit_addr
7424						} else {
7425							| ja => target_label
7426							| jp => target_label
7427						}
7428					}
7429					break;
7430				default:
7431					ZEND_UNREACHABLE();
7432			}
7433		} else if (smart_branch_opcode == ZEND_JMPNZ) {
7434			switch (opline->opcode) {
7435				case ZEND_IS_EQUAL:
7436				case ZEND_IS_IDENTICAL:
7437				case ZEND_CASE:
7438				case ZEND_CASE_STRICT:
7439					| jp >1
7440					if (exit_addr) {
7441						| je &exit_addr
7442					} else {
7443						| je => target_label
7444					}
7445					|1:
7446					break;
7447				case ZEND_IS_NOT_EQUAL:
7448					if (exit_addr) {
7449						| jne &exit_addr
7450						| jp &exit_addr
7451					} else {
7452						| jne => target_label
7453						| jp => target_label
7454					}
7455					break;
7456				case ZEND_IS_NOT_IDENTICAL:
7457					if (exit_addr) {
7458						| jp >1
7459						| je &exit_addr
7460						|1:
7461					} else {
7462						| jne => target_label
7463						| jp => target_label
7464					}
7465					break;
7466				case ZEND_IS_SMALLER:
7467					if (swap) {
7468						if (exit_addr) {
7469							| ja &exit_addr
7470						} else {
7471							| ja => target_label
7472						}
7473					} else {
7474						| jp >1
7475						if (exit_addr) {
7476							| jb &exit_addr
7477						} else {
7478							| jb => target_label
7479						}
7480						|1:
7481					}
7482					break;
7483				case ZEND_IS_SMALLER_OR_EQUAL:
7484					if (swap) {
7485						if (exit_addr) {
7486							| jae &exit_addr
7487						} else {
7488							| jae => target_label
7489						}
7490					} else {
7491						| jp >1
7492						if (exit_addr) {
7493							| jbe &exit_addr
7494						} else {
7495							| jbe => target_label
7496						}
7497						|1:
7498					}
7499					break;
7500				default:
7501					ZEND_UNREACHABLE();
7502			}
7503		} else if (smart_branch_opcode == ZEND_JMPZNZ) {
7504			switch (opline->opcode) {
7505				case ZEND_IS_EQUAL:
7506				case ZEND_IS_IDENTICAL:
7507				case ZEND_CASE:
7508				case ZEND_CASE_STRICT:
7509					| jne => target_label
7510					| jp => target_label
7511					break;
7512				case ZEND_IS_NOT_EQUAL:
7513				case ZEND_IS_NOT_IDENTICAL:
7514					| jp => target_label2
7515					| je => target_label
7516					break;
7517				case ZEND_IS_SMALLER:
7518					if (swap) {
7519						| jbe => target_label
7520					} else {
7521						| jae => target_label
7522						| jp => target_label
7523					}
7524					break;
7525				case ZEND_IS_SMALLER_OR_EQUAL:
7526					if (swap) {
7527						| jb => target_label
7528					} else {
7529						| ja => target_label
7530						| jp => target_label
7531					}
7532					break;
7533				default:
7534					ZEND_UNREACHABLE();
7535			}
7536			| jmp => target_label2
7537		} else if (smart_branch_opcode == ZEND_JMPZ_EX) {
7538			switch (opline->opcode) {
7539				case ZEND_IS_EQUAL:
7540				case ZEND_IS_IDENTICAL:
7541				case ZEND_CASE:
7542				case ZEND_CASE_STRICT:
7543					|	SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
7544					|	jne => target_label
7545					|	jp => target_label
7546					|	SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
7547					break;
7548				case ZEND_IS_NOT_EQUAL:
7549				case ZEND_IS_NOT_IDENTICAL:
7550					|	jp >1
7551					|	SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
7552					|	je => target_label
7553					|1:
7554					|	SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
7555					break;
7556				case ZEND_IS_SMALLER:
7557					if (swap) {
7558						|	SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
7559						|	jbe => target_label
7560						|	SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
7561					} else {
7562						|	SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
7563						|	jae => target_label
7564						|	jp => target_label
7565						|	SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
7566					}
7567					break;
7568				case ZEND_IS_SMALLER_OR_EQUAL:
7569					if (swap) {
7570						|	SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
7571						|	jb => target_label
7572						|	SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
7573					} else {
7574						|	SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
7575						|	ja => target_label
7576						|	jp => target_label
7577						|	SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
7578					}
7579					break;
7580				default:
7581					ZEND_UNREACHABLE();
7582			}
7583		} else if (smart_branch_opcode == ZEND_JMPNZ_EX) {
7584			switch (opline->opcode) {
7585				case ZEND_IS_EQUAL:
7586				case ZEND_IS_IDENTICAL:
7587				case ZEND_CASE:
7588				case ZEND_CASE_STRICT:
7589					|	jp >1
7590					|	SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
7591					|	je => target_label
7592					|1:
7593					|	SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
7594					break;
7595				case ZEND_IS_NOT_EQUAL:
7596				case ZEND_IS_NOT_IDENTICAL:
7597					|	SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
7598					|	jne => target_label
7599					|	jp => target_label
7600					|	SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
7601					break;
7602				case ZEND_IS_SMALLER:
7603					if (swap) {
7604						|	seta al
7605						|	movzx eax, al
7606						|	lea eax, [eax + 2]
7607						|	SET_ZVAL_TYPE_INFO res_addr, eax
7608						|	ja => target_label
7609					} else {
7610						|	jp >1
7611						|	SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
7612						|	jb => target_label
7613						|1:
7614						|	SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
7615					}
7616					break;
7617				case ZEND_IS_SMALLER_OR_EQUAL:
7618					if (swap) {
7619						|	setae al
7620						|	movzx eax, al
7621						|	lea eax, [eax + 2]
7622						|	SET_ZVAL_TYPE_INFO res_addr, eax
7623						|	jae => target_label
7624					} else {
7625						|	jp >1
7626						|	SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
7627						|	jbe => target_label
7628						|1:
7629						|	SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
7630					}
7631					break;
7632				default:
7633					ZEND_UNREACHABLE();
7634			}
7635		} else {
7636			ZEND_UNREACHABLE();
7637		}
7638	} else {
7639		switch (opline->opcode) {
7640			case ZEND_IS_EQUAL:
7641			case ZEND_IS_IDENTICAL:
7642			case ZEND_CASE:
7643			case ZEND_CASE_STRICT:
7644				|	jp >1
7645				|	mov eax, IS_TRUE
7646				|	je >2
7647				|1:
7648				|	mov eax, IS_FALSE
7649				|2:
7650				break;
7651			case ZEND_IS_NOT_EQUAL:
7652			case ZEND_IS_NOT_IDENTICAL:
7653				|	jp >1
7654				|	mov eax, IS_FALSE
7655				|	je >2
7656				|1:
7657				|	mov eax, IS_TRUE
7658				|2:
7659				break;
7660			case ZEND_IS_SMALLER:
7661				if (swap) {
7662					|	seta al
7663					|	movzx eax, al
7664					|	add eax, 2
7665				} else {
7666					|	jp >1
7667					|	mov eax, IS_TRUE
7668					|	jb >2
7669					|1:
7670					|	mov eax, IS_FALSE
7671					|2:
7672				}
7673				break;
7674			case ZEND_IS_SMALLER_OR_EQUAL:
7675				if (swap) {
7676					|	setae al
7677					|	movzx eax, al
7678					|	add eax, 2
7679				} else {
7680					|	jp >1
7681					|	mov eax, IS_TRUE
7682					|	jbe >2
7683					|1:
7684					|	mov eax, IS_FALSE
7685					|2:
7686				}
7687				break;
7688			default:
7689				ZEND_UNREACHABLE();
7690		}
7691		|	SET_ZVAL_TYPE_INFO res_addr, eax
7692	}
7693
7694	return 1;
7695}
7696
7697static int zend_jit_cmp_long_double(dasm_State **Dst, const zend_op *opline, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
7698{
7699	zend_reg tmp_reg = ZREG_XMM0;
7700
7701	|	SSE_GET_ZVAL_LVAL tmp_reg, op1_addr, ZREG_R0
7702	|	SSE_AVX_OP ucomisd, vucomisd, tmp_reg, op2_addr
7703
7704	return zend_jit_cmp_double_common(Dst, opline, res_addr, 0, smart_branch_opcode, target_label, target_label2, exit_addr);
7705}
7706
7707static int zend_jit_cmp_double_long(dasm_State **Dst, const zend_op *opline, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
7708{
7709	zend_reg tmp_reg = ZREG_XMM0;
7710
7711	|	SSE_GET_ZVAL_LVAL tmp_reg, op2_addr, ZREG_R0
7712	|	SSE_AVX_OP ucomisd, vucomisd, tmp_reg, op1_addr
7713
7714	return zend_jit_cmp_double_common(Dst, opline, res_addr, /* swap */ 1, smart_branch_opcode, target_label, target_label2, exit_addr);
7715}
7716
7717static int zend_jit_cmp_double_double(dasm_State **Dst, const zend_op *opline, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
7718{
7719	zend_bool swap = 0;
7720
7721	if (Z_MODE(op1_addr) == IS_REG) {
7722		|	SSE_AVX_OP ucomisd, vucomisd, Z_REG(op1_addr), op2_addr
7723	} else if (Z_MODE(op2_addr) == IS_REG) {
7724		|	SSE_AVX_OP ucomisd, vucomisd, Z_REG(op2_addr), op1_addr
7725		swap = 1;
7726	} else {
7727		zend_reg tmp_reg = ZREG_XMM0;
7728
7729		|	SSE_GET_ZVAL_DVAL tmp_reg, op1_addr
7730		|	SSE_AVX_OP ucomisd, vucomisd, tmp_reg, op2_addr
7731	}
7732
7733	return zend_jit_cmp_double_common(Dst, opline, res_addr, swap, smart_branch_opcode, target_label, target_label2, exit_addr);
7734}
7735
7736static int zend_jit_cmp_slow(dasm_State **Dst, const zend_op *opline, zend_jit_addr res_addr, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
7737{
7738	|	LONG_OP_WITH_CONST cmp, res_addr, Z_L(0)
7739	if (smart_branch_opcode) {
7740		if (smart_branch_opcode == ZEND_JMPZ_EX ||
7741		    smart_branch_opcode == ZEND_JMPNZ_EX) {
7742			switch (opline->opcode) {
7743				case ZEND_IS_EQUAL:
7744				case ZEND_CASE:
7745					|	sete al
7746					break;
7747				case ZEND_IS_NOT_EQUAL:
7748					|	setne al
7749					break;
7750				case ZEND_IS_SMALLER:
7751					|	setl al
7752					break;
7753				case ZEND_IS_SMALLER_OR_EQUAL:
7754					|	setle al
7755					break;
7756				default:
7757					ZEND_UNREACHABLE();
7758			}
7759			|	movzx eax, al
7760			|	lea eax, [eax + 2]
7761			|	SET_ZVAL_TYPE_INFO res_addr, eax
7762		}
7763		if (smart_branch_opcode == ZEND_JMPZ ||
7764		    smart_branch_opcode == ZEND_JMPZ_EX) {
7765			switch (opline->opcode) {
7766				case ZEND_IS_EQUAL:
7767				case ZEND_CASE:
7768					if (exit_addr) {
7769						| jne &exit_addr
7770					} else {
7771						| jne => target_label
7772					}
7773					break;
7774				case ZEND_IS_NOT_EQUAL:
7775					if (exit_addr) {
7776						| je &exit_addr
7777					} else {
7778						| je => target_label
7779					}
7780					break;
7781				case ZEND_IS_SMALLER:
7782					if (exit_addr) {
7783						| jge &exit_addr
7784					} else {
7785						| jge => target_label
7786					}
7787					break;
7788				case ZEND_IS_SMALLER_OR_EQUAL:
7789					if (exit_addr) {
7790						| jg &exit_addr
7791					} else {
7792						| jg => target_label
7793					}
7794					break;
7795				default:
7796					ZEND_UNREACHABLE();
7797			}
7798		} else if (smart_branch_opcode == ZEND_JMPNZ ||
7799		           smart_branch_opcode == ZEND_JMPNZ_EX) {
7800			switch (opline->opcode) {
7801				case ZEND_IS_EQUAL:
7802				case ZEND_CASE:
7803					if (exit_addr) {
7804						| je &exit_addr
7805					} else {
7806						| je => target_label
7807					}
7808					break;
7809				case ZEND_IS_NOT_EQUAL:
7810					if (exit_addr) {
7811						| jne &exit_addr
7812					} else {
7813						| jne => target_label
7814					}
7815					break;
7816				case ZEND_IS_SMALLER:
7817					if (exit_addr) {
7818						| jl &exit_addr
7819					} else {
7820						| jl => target_label
7821					}
7822					break;
7823				case ZEND_IS_SMALLER_OR_EQUAL:
7824					if (exit_addr) {
7825						| jle &exit_addr
7826					} else {
7827						| jle => target_label
7828					}
7829					break;
7830				default:
7831					ZEND_UNREACHABLE();
7832			}
7833		} else if (smart_branch_opcode == ZEND_JMPZNZ) {
7834			switch (opline->opcode) {
7835				case ZEND_IS_EQUAL:
7836				case ZEND_CASE:
7837					| jne => target_label
7838					break;
7839				case ZEND_IS_NOT_EQUAL:
7840					| je => target_label
7841					break;
7842				case ZEND_IS_SMALLER:
7843					| jge => target_label
7844					break;
7845				case ZEND_IS_SMALLER_OR_EQUAL:
7846					| jg => target_label
7847					break;
7848				default:
7849					ZEND_UNREACHABLE();
7850			}
7851			| jmp => target_label2
7852		} else {
7853			ZEND_UNREACHABLE();
7854		}
7855	} else {
7856		switch (opline->opcode) {
7857			case ZEND_IS_EQUAL:
7858			case ZEND_CASE:
7859				|	sete al
7860				break;
7861			case ZEND_IS_NOT_EQUAL:
7862				|	setne al
7863				break;
7864			case ZEND_IS_SMALLER:
7865				|	setl al
7866				break;
7867			case ZEND_IS_SMALLER_OR_EQUAL:
7868				|	setle al
7869				break;
7870			default:
7871				ZEND_UNREACHABLE();
7872		}
7873		|	movzx eax, al
7874		|	add eax, 2
7875		|	SET_ZVAL_TYPE_INFO res_addr, eax
7876	}
7877
7878	return 1;
7879}
7880
7881static int zend_jit_cmp(dasm_State    **Dst,
7882                        const zend_op  *opline,
7883                        uint32_t        op1_info,
7884                        zend_ssa_range *op1_range,
7885                        zend_jit_addr   op1_addr,
7886                        uint32_t        op2_info,
7887                        zend_ssa_range *op2_range,
7888                        zend_jit_addr   op2_addr,
7889                        zend_jit_addr   res_addr,
7890                        int             may_throw,
7891                        zend_uchar      smart_branch_opcode,
7892                        uint32_t        target_label,
7893                        uint32_t        target_label2,
7894                        const void     *exit_addr,
7895                        zend_bool       skip_comparison)
7896{
7897	zend_bool same_ops = (opline->op1_type == opline->op2_type) && (opline->op1.var == opline->op2.var);
7898	zend_bool has_slow;
7899
7900	has_slow =
7901		(op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
7902		(op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
7903		((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) ||
7904		 (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))));
7905
7906	if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG)) {
7907		if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
7908			if (op1_info & MAY_BE_DOUBLE) {
7909				|	IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >4
7910			} else {
7911				|	IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >9
7912			}
7913		}
7914		if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))) {
7915			if (op2_info & MAY_BE_DOUBLE) {
7916				|	IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >3
7917				|.cold_code
7918				|3:
7919				if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
7920					|	IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >9
7921				}
7922				if (!zend_jit_cmp_long_double(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) {
7923					return 0;
7924				}
7925				|	jmp >6
7926				|.code
7927			} else {
7928				|	IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >9
7929			}
7930		}
7931		if (!zend_jit_cmp_long_long(Dst, opline, op1_range, op1_addr, op2_range, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr, skip_comparison)) {
7932			return 0;
7933		}
7934		if (op1_info & MAY_BE_DOUBLE) {
7935			|.cold_code
7936			|4:
7937			if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
7938				|	IF_NOT_ZVAL_TYPE op1_addr, IS_DOUBLE, >9
7939			}
7940			if (op2_info & MAY_BE_DOUBLE) {
7941				if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE))) {
7942					if (!same_ops) {
7943						|	IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >5
7944					} else {
7945						|	IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >9
7946					}
7947				}
7948				if (!zend_jit_cmp_double_double(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) {
7949					return 0;
7950				}
7951				|	jmp >6
7952			}
7953			if (!same_ops) {
7954				|5:
7955				if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
7956					|	IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >9
7957				}
7958				if (!zend_jit_cmp_double_long(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) {
7959					return 0;
7960				}
7961				|	jmp >6
7962			}
7963			|.code
7964		}
7965	} else if ((op1_info & MAY_BE_DOUBLE) &&
7966	           !(op1_info & MAY_BE_LONG) &&
7967	           (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
7968		if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE)) {
7969			|	IF_NOT_ZVAL_TYPE op1_addr, IS_DOUBLE, >9
7970		}
7971		if (op2_info & MAY_BE_DOUBLE) {
7972			if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE))) {
7973				if (!same_ops && (op2_info & MAY_BE_LONG)) {
7974					|	IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >3
7975				} else {
7976					|	IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >9
7977				}
7978			}
7979			if (!zend_jit_cmp_double_double(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) {
7980				return 0;
7981			}
7982		}
7983		if (!same_ops && (op2_info & MAY_BE_LONG)) {
7984			if (op2_info & MAY_BE_DOUBLE) {
7985				|.cold_code
7986			}
7987		    |3:
7988			if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
7989				|	IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >9
7990			}
7991			if (!zend_jit_cmp_double_long(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) {
7992				return 0;
7993			}
7994			if (op2_info & MAY_BE_DOUBLE) {
7995				|	jmp >6
7996				|.code
7997			}
7998		}
7999	} else if ((op2_info & MAY_BE_DOUBLE) &&
8000	           !(op2_info & MAY_BE_LONG) &&
8001	           (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
8002		if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE)) {
8003			|	IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >9
8004		}
8005		if (op1_info & MAY_BE_DOUBLE) {
8006			if (!same_ops && (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE))) {
8007				if (!same_ops && (op1_info & MAY_BE_LONG)) {
8008					|	IF_NOT_ZVAL_TYPE op1_addr, IS_DOUBLE, >3
8009				} else {
8010					|	IF_NOT_ZVAL_TYPE op1_addr, IS_DOUBLE, >9
8011				}
8012			}
8013			if (!zend_jit_cmp_double_double(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) {
8014				return 0;
8015			}
8016		}
8017		if (!same_ops && (op1_info & MAY_BE_LONG)) {
8018			if (op1_info & MAY_BE_DOUBLE) {
8019				|.cold_code
8020			}
8021			|3:
8022			if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
8023				|	IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >9
8024			}
8025			if (!zend_jit_cmp_long_double(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) {
8026				return 0;
8027			}
8028			if (op1_info & MAY_BE_DOUBLE) {
8029				|	jmp >6
8030				|.code
8031			}
8032		}
8033	}
8034
8035	if (has_slow ||
8036	    (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) ||
8037	    (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)))) {
8038		if (has_slow) {
8039			|.cold_code
8040			|9:
8041		}
8042		|	SET_EX_OPLINE opline, r0
8043		if (Z_MODE(op1_addr) == IS_REG) {
8044			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
8045			if (!zend_jit_spill_store(Dst, op1_addr, real_addr, op1_info, 1)) {
8046				return 0;
8047			}
8048			op1_addr = real_addr;
8049		}
8050		if (Z_MODE(op2_addr) == IS_REG) {
8051			zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
8052			if (!zend_jit_spill_store(Dst, op2_addr, real_addr, op2_info, 1)) {
8053				return 0;
8054			}
8055			op2_addr = real_addr;
8056		}
8057		|	LOAD_ZVAL_ADDR FCARG2a, op1_addr
8058		if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
8059			|	IF_NOT_Z_TYPE FCARG2a, IS_UNDEF, >1
8060			|	mov FCARG1a, opline->op1.var
8061			|	EXT_CALL zend_jit_undefined_op_helper, r0
8062			|	LOAD_ADDR_ZTS FCARG2a, executor_globals, uninitialized_zval
8063			|1:
8064		}
8065		if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) {
8066			|	IF_NOT_ZVAL_TYPE op2_addr, IS_UNDEF, >1
8067			|	mov T1, FCARG2a // save
8068			|	mov FCARG1a, opline->op2.var
8069			|	EXT_CALL zend_jit_undefined_op_helper, r0
8070			|	mov FCARG2a, T1 // restore
8071			|.if X64
8072				|	LOAD_ADDR_ZTS CARG3, executor_globals, uninitialized_zval
8073			|.else
8074				|	sub r4, 12
8075				|	PUSH_ADDR_ZTS executor_globals, uninitialized_zval, r0
8076			|.endif
8077			|	jmp >2
8078			|1:
8079			|.if X64
8080				|	LOAD_ZVAL_ADDR CARG3, op2_addr
8081			|.else
8082				|	sub r4, 12
8083				|	PUSH_ZVAL_ADDR op2_addr, r0
8084			|.endif
8085			|2:
8086		} else {
8087			|.if X64
8088				|	LOAD_ZVAL_ADDR CARG3, op2_addr
8089			|.else
8090				|	sub r4, 12
8091				|	PUSH_ZVAL_ADDR op2_addr, r0
8092			|.endif
8093		}
8094		|	LOAD_ZVAL_ADDR FCARG1a, res_addr
8095		|	EXT_CALL compare_function, r0
8096		|.if not(X64)
8097		|	add r4, 12
8098		|.endif
8099		if (opline->opcode != ZEND_CASE) {
8100			|	FREE_OP opline->op1_type, opline->op1, op1_info, 0, opline
8101		}
8102		|	FREE_OP opline->op2_type, opline->op2, op2_info, 0, opline
8103		if (may_throw) {
8104			zend_jit_check_exception_undef_result(Dst, opline);
8105		}
8106		if (!zend_jit_cmp_slow(Dst, opline, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) {
8107			return 0;
8108		}
8109		if (has_slow) {
8110			|	jmp >6
8111			|.code
8112		}
8113	}
8114
8115	|6:
8116
8117	return 1;
8118}
8119
8120static int zend_jit_identical(dasm_State    **Dst,
8121                              const zend_op  *opline,
8122                              uint32_t        op1_info,
8123                              zend_ssa_range *op1_range,
8124                              zend_jit_addr   op1_addr,
8125                              uint32_t        op2_info,
8126                              zend_ssa_range *op2_range,
8127                              zend_jit_addr   op2_addr,
8128                              zend_jit_addr   res_addr,
8129                              int             may_throw,
8130                              zend_uchar      smart_branch_opcode,
8131                              uint32_t        target_label,
8132                              uint32_t        target_label2,
8133                              const void     *exit_addr,
8134                              zend_bool       skip_comparison)
8135{
8136	uint32_t identical_label = (uint32_t)-1;
8137	uint32_t not_identical_label = (uint32_t)-1;
8138
8139	if (smart_branch_opcode && !exit_addr) {
8140		if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
8141			if (smart_branch_opcode == ZEND_JMPZ) {
8142				not_identical_label = target_label;
8143			} else if (smart_branch_opcode == ZEND_JMPNZ) {
8144				identical_label = target_label;
8145			} else if (smart_branch_opcode == ZEND_JMPZNZ) {
8146				not_identical_label = target_label;
8147				identical_label = target_label2;
8148			} else {
8149				ZEND_UNREACHABLE();
8150			}
8151		} else {
8152			if (smart_branch_opcode == ZEND_JMPZ) {
8153				identical_label = target_label;
8154			} else if (smart_branch_opcode == ZEND_JMPNZ) {
8155				not_identical_label = target_label;
8156			} else if (smart_branch_opcode == ZEND_JMPZNZ) {
8157				identical_label = target_label;
8158				not_identical_label = target_label2;
8159			} else {
8160				ZEND_UNREACHABLE();
8161			}
8162		}
8163	}
8164
8165	if ((op1_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG &&
8166	    (op2_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) {
8167		if (!zend_jit_cmp_long_long(Dst, opline, op1_range, op1_addr, op2_range, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr, skip_comparison)) {
8168			return 0;
8169		}
8170		return 1;
8171	} else if ((op1_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_DOUBLE &&
8172	           (op2_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_DOUBLE) {
8173		if (!zend_jit_cmp_double_double(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) {
8174			return 0;
8175		}
8176		return 1;
8177	}
8178
8179	if ((op1_info & MAY_BE_UNDEF) && (op2_info & MAY_BE_UNDEF)) {
8180		op1_info |= MAY_BE_NULL;
8181		op2_info |= MAY_BE_NULL;
8182		|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
8183		|	IF_Z_TYPE FCARG1a, IS_UNDEF, >1
8184		|.cold_code
8185		|1:
8186		|	// zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var))));
8187		|	SET_EX_OPLINE opline, r0
8188		|	mov FCARG1d, opline->op1.var
8189		|	EXT_CALL zend_jit_undefined_op_helper, r0
8190		if (may_throw) {
8191			zend_jit_check_exception_undef_result(Dst, opline);
8192		}
8193		|	LOAD_ADDR_ZTS FCARG1a, executor_globals, uninitialized_zval
8194		|	jmp >1
8195		|.code
8196		|1:
8197		|	LOAD_ZVAL_ADDR FCARG2a, op2_addr
8198		|	IF_Z_TYPE FCARG2a, IS_UNDEF, >1
8199		|.cold_code
8200		|1:
8201		|	// zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var))));
8202		|	SET_EX_OPLINE opline, r0
8203		|	mov aword T1, FCARG1a // save
8204		|	mov FCARG1d, opline->op2.var
8205		|	EXT_CALL zend_jit_undefined_op_helper, r0
8206		if (may_throw) {
8207			zend_jit_check_exception_undef_result(Dst, opline);
8208		}
8209		|	mov FCARG1a, aword T1 // restore
8210		|	LOAD_ADDR_ZTS FCARG2a, executor_globals, uninitialized_zval
8211		|	jmp >1
8212		|.code
8213		|1:
8214	} else if (op1_info & MAY_BE_UNDEF) {
8215		op1_info |= MAY_BE_NULL;
8216		|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
8217		|	IF_Z_TYPE FCARG1a, IS_UNDEF, >1
8218		|.cold_code
8219		|1:
8220		|	// zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var))));
8221		|	SET_EX_OPLINE opline, r0
8222		|	mov FCARG1d, opline->op1.var
8223		|	EXT_CALL zend_jit_undefined_op_helper, r0
8224		if (may_throw) {
8225			zend_jit_check_exception_undef_result(Dst, opline);
8226		}
8227		|	LOAD_ADDR_ZTS FCARG1a, executor_globals, uninitialized_zval
8228		|	jmp >1
8229		|.code
8230		|1:
8231		if (opline->op2_type != IS_CONST) {
8232			|	LOAD_ZVAL_ADDR FCARG2a, op2_addr
8233		}
8234	} else if (op2_info & MAY_BE_UNDEF) {
8235		op2_info |= MAY_BE_NULL;
8236		|	LOAD_ZVAL_ADDR FCARG2a, op2_addr
8237		|	IF_Z_TYPE FCARG2a, IS_UNDEF, >1
8238		|.cold_code
8239		|1:
8240		|	// zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var))));
8241		|	SET_EX_OPLINE opline, r0
8242		|	mov FCARG1d, opline->op2.var
8243		|	EXT_CALL zend_jit_undefined_op_helper, r0
8244		if (may_throw) {
8245			zend_jit_check_exception_undef_result(Dst, opline);
8246		}
8247		|	LOAD_ADDR_ZTS FCARG2a, executor_globals, uninitialized_zval
8248		|	jmp >1
8249		|.code
8250		|1:
8251		if (opline->op1_type != IS_CONST) {
8252			|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
8253		}
8254	} else {
8255		if (opline->op1_type != IS_CONST) {
8256			if (Z_MODE(op1_addr) == IS_REG) {
8257				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
8258				if (!zend_jit_spill_store(Dst, op1_addr, real_addr, op1_info, 1)) {
8259					return 0;
8260				}
8261				op1_addr = real_addr;
8262			}
8263			|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
8264		}
8265		if (opline->op2_type != IS_CONST) {
8266			if (Z_MODE(op2_addr) == IS_REG) {
8267				zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
8268				if (!zend_jit_spill_store(Dst, op2_addr, real_addr, op2_info, 1)) {
8269					return 0;
8270				}
8271				op2_addr = real_addr;
8272			}
8273			|	LOAD_ZVAL_ADDR FCARG2a, op2_addr
8274		}
8275	}
8276	if (opline->op1_type & (IS_CV|IS_VAR)) {
8277		|	ZVAL_DEREF FCARG1a, op1_info
8278	}
8279	if (opline->op2_type & (IS_CV|IS_VAR)) {
8280		|	ZVAL_DEREF FCARG2a, op2_info
8281	}
8282
8283	if ((op1_info & op2_info & MAY_BE_ANY) == 0) {
8284		if ((opline->opcode != ZEND_CASE_STRICT &&
8285		     (opline->op1_type & (IS_VAR|IS_TMP_VAR)) &&
8286		     (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) ||
8287		    ((opline->op2_type & (IS_VAR|IS_TMP_VAR)) &&
8288		     (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)))) {
8289			|	SET_EX_OPLINE opline, r0
8290			if (opline->opcode != ZEND_CASE_STRICT) {
8291				|	FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline
8292			}
8293			|	FREE_OP opline->op2_type, opline->op2, op2_info, 1, opline
8294		}
8295		if (smart_branch_opcode) {
8296			zend_jit_check_exception_undef_result(Dst, opline);
8297			if (exit_addr) {
8298				if (smart_branch_opcode == ZEND_JMPZ) {
8299					|	jmp &exit_addr
8300				}
8301			} else if (not_identical_label != (uint32_t)-1) {
8302				|	jmp =>not_identical_label
8303			}
8304		} else {
8305			|	SET_ZVAL_TYPE_INFO res_addr, (opline->opcode != ZEND_IS_NOT_IDENTICAL ? IS_FALSE : IS_TRUE)
8306			zend_jit_check_exception(Dst);
8307		}
8308	} else if (has_concrete_type(op1_info) &&
8309	           has_concrete_type(op2_info) &&
8310	           concrete_type(op1_info) == concrete_type(op2_info) &&
8311	           concrete_type(op1_info) <= IS_TRUE) {
8312		if (smart_branch_opcode) {
8313			if (exit_addr) {
8314				if (smart_branch_opcode == ZEND_JMPNZ) {
8315					|	jmp &exit_addr
8316				}
8317			} else if (identical_label != (uint32_t)-1) {
8318				|	jmp =>identical_label
8319			}
8320		} else {
8321			|	SET_ZVAL_TYPE_INFO res_addr, (opline->opcode != ZEND_IS_NOT_IDENTICAL ? IS_TRUE : IS_FALSE)
8322		}
8323	} else if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_MODE(op2_addr) == IS_CONST_ZVAL) {
8324		if (zend_is_identical(Z_ZV(op1_addr), Z_ZV(op2_addr))) {
8325			if (smart_branch_opcode) {
8326				if (exit_addr) {
8327					if (smart_branch_opcode == ZEND_JMPNZ) {
8328						|	jmp &exit_addr
8329					}
8330				} else if (identical_label != (uint32_t)-1) {
8331					|	jmp =>identical_label
8332				}
8333			} else {
8334				|	SET_ZVAL_TYPE_INFO res_addr, (opline->opcode != ZEND_IS_NOT_IDENTICAL ? IS_TRUE : IS_FALSE)
8335			}
8336		} else {
8337			if (smart_branch_opcode) {
8338				if (exit_addr) {
8339					if (smart_branch_opcode == ZEND_JMPZ) {
8340						|	jmp &exit_addr
8341					}
8342				} else if (not_identical_label != (uint32_t)-1) {
8343					|	jmp =>not_identical_label
8344				}
8345			} else {
8346				|	SET_ZVAL_TYPE_INFO res_addr, (opline->opcode != ZEND_IS_NOT_IDENTICAL ? IS_FALSE : IS_TRUE)
8347			}
8348		}
8349	} else if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_TYPE_P(Z_ZV(op1_addr)) <= IS_TRUE) {
8350		zval *val = Z_ZV(op1_addr);
8351
8352		|	cmp byte [FCARG2a + offsetof(zval, u1.v.type)], Z_TYPE_P(val)
8353		if (smart_branch_opcode) {
8354			if (opline->op2_type == IS_VAR && (op2_info & MAY_BE_REF)) {
8355				|	jne >8
8356				|	SET_EX_OPLINE opline, r0
8357				|	FREE_OP opline->op2_type, opline->op2, op2_info, 1, opline
8358				zend_jit_check_exception_undef_result(Dst, opline);
8359				if (exit_addr && smart_branch_opcode == ZEND_JMPNZ) {
8360					|	jmp &exit_addr
8361				} else if (identical_label != (uint32_t)-1) {
8362					|	jmp =>identical_label
8363				} else {
8364					|	jmp >9
8365				}
8366				|8:
8367			} else if (exit_addr && smart_branch_opcode == ZEND_JMPNZ) {
8368				|	je &exit_addr
8369			} else if (identical_label != (uint32_t)-1) {
8370				|	je =>identical_label
8371			} else {
8372				|	je >9
8373			}
8374		} else {
8375			if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
8376				|	sete al
8377			} else {
8378				|	setne al
8379			}
8380			|	movzx eax, al
8381			|	lea eax, [eax + 2]
8382			|	SET_ZVAL_TYPE_INFO res_addr, eax
8383		}
8384		if ((opline->op2_type & (IS_VAR|IS_TMP_VAR)) &&
8385		    (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) {
8386			|	SET_EX_OPLINE opline, r0
8387			|	FREE_OP opline->op2_type, opline->op2, op2_info, 1, opline
8388			zend_jit_check_exception_undef_result(Dst, opline);
8389		}
8390		if (exit_addr) {
8391			if (smart_branch_opcode == ZEND_JMPZ) {
8392				|	jmp &exit_addr
8393			}
8394		} else if (smart_branch_opcode && not_identical_label != (uint32_t)-1) {
8395			|	jmp =>not_identical_label
8396		}
8397	} else if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_TYPE_P(Z_ZV(op2_addr)) <= IS_TRUE) {
8398		zval *val = Z_ZV(op2_addr);
8399
8400		|	cmp byte [FCARG1a + offsetof(zval, u1.v.type)], Z_TYPE_P(val)
8401		if (smart_branch_opcode) {
8402			if (opline->opcode != ZEND_CASE_STRICT
8403			 && opline->op1_type == IS_VAR && (op1_info & MAY_BE_REF)) {
8404				|	jne >8
8405				|	SET_EX_OPLINE opline, r0
8406				|	FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline
8407				zend_jit_check_exception_undef_result(Dst, opline);
8408				if (exit_addr && smart_branch_opcode == ZEND_JMPNZ) {
8409					|	jmp &exit_addr
8410				} else if (identical_label != (uint32_t)-1) {
8411					|	jmp =>identical_label
8412				} else {
8413					|	jmp >9
8414				}
8415				|8:
8416			} else if (exit_addr && smart_branch_opcode == ZEND_JMPNZ) {
8417				|	je &exit_addr
8418			} else if (identical_label != (uint32_t)-1) {
8419				|	je =>identical_label
8420			} else {
8421				|	je >9
8422			}
8423		} else {
8424			if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
8425				|	sete al
8426			} else {
8427				|	setne al
8428			}
8429			|	movzx eax, al
8430			|	lea eax, [eax + 2]
8431			|	SET_ZVAL_TYPE_INFO res_addr, eax
8432		}
8433		if (opline->opcode != ZEND_CASE_STRICT
8434		 && (opline->op1_type & (IS_VAR|IS_TMP_VAR)) &&
8435		    (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) {
8436			|	SET_EX_OPLINE opline, r0
8437			|	FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline
8438			zend_jit_check_exception_undef_result(Dst, opline);
8439		}
8440		if (smart_branch_opcode) {
8441			if (exit_addr) {
8442				if (smart_branch_opcode == ZEND_JMPZ) {
8443					|	jmp &exit_addr
8444				}
8445			} else if (not_identical_label != (uint32_t)-1) {
8446				|	jmp =>not_identical_label
8447			}
8448		}
8449	} else {
8450		if (opline->op1_type == IS_CONST) {
8451			|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
8452		}
8453		if (opline->op2_type == IS_CONST) {
8454			|	LOAD_ZVAL_ADDR FCARG2a, op2_addr
8455		}
8456		|	EXT_CALL zend_is_identical, r0
8457			if ((opline->opcode != ZEND_CASE_STRICT &&
8458			     (opline->op1_type & (IS_VAR|IS_TMP_VAR)) &&
8459			     (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) ||
8460			    ((opline->op2_type & (IS_VAR|IS_TMP_VAR)) &&
8461			     (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)))) {
8462				|	mov aword T1, r0 // save
8463				|	SET_EX_OPLINE opline, r0
8464				if (opline->opcode != ZEND_CASE_STRICT) {
8465					|	FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline
8466				}
8467				|	FREE_OP opline->op2_type, opline->op2, op2_info, 1, opline
8468				zend_jit_check_exception_undef_result(Dst, opline);
8469				|	mov r0, aword T1 // restore
8470			}
8471		if (smart_branch_opcode) {
8472			|	test al, al
8473			if (exit_addr) {
8474				if (smart_branch_opcode == ZEND_JMPNZ) {
8475					|	jnz &exit_addr
8476				} else {
8477					|	jz &exit_addr
8478				}
8479			} else if (not_identical_label != (uint32_t)-1) {
8480				|	jz =>not_identical_label
8481				if (identical_label != (uint32_t)-1) {
8482					|	jmp =>identical_label
8483				}
8484			} else if (identical_label != (uint32_t)-1) {
8485				|	jnz =>identical_label
8486			}
8487		} else {
8488			|	movzx eax, al
8489			if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
8490				|	lea eax, [eax + 2]
8491			} else {
8492				|	neg eax
8493				|	lea eax, [eax + 3]
8494			}
8495			|	SET_ZVAL_TYPE_INFO res_addr, eax
8496		}
8497	}
8498
8499	|9:
8500	if (may_throw) {
8501		zend_jit_check_exception(Dst);
8502	}
8503	return 1;
8504}
8505
8506static int zend_jit_bool_jmpznz(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr res_addr, uint32_t target_label, uint32_t target_label2, int may_throw, zend_uchar branch_opcode, const void *exit_addr)
8507{
8508	uint32_t true_label = -1;
8509	uint32_t false_label = -1;
8510	zend_bool set_bool = 0;
8511	zend_bool set_bool_not = 0;
8512	zend_bool set_delayed = 0;
8513	zend_bool jmp_done = 0;
8514
8515	if (branch_opcode == ZEND_BOOL) {
8516		set_bool = 1;
8517	} else if (branch_opcode == ZEND_BOOL_NOT) {
8518		set_bool = 1;
8519		set_bool_not = 1;
8520	} else if (branch_opcode == ZEND_JMPZ) {
8521		false_label = target_label;
8522	} else if (branch_opcode == ZEND_JMPNZ) {
8523		true_label = target_label;
8524	} else if (branch_opcode == ZEND_JMPZNZ) {
8525		true_label = target_label2;
8526		false_label = target_label;
8527	} else if (branch_opcode == ZEND_JMPZ_EX) {
8528		set_bool = 1;
8529		false_label = target_label;
8530	} else if (branch_opcode == ZEND_JMPNZ_EX) {
8531		set_bool = 1;
8532		true_label = target_label;
8533	} else {
8534		ZEND_UNREACHABLE();
8535	}
8536
8537	if (Z_MODE(op1_addr) == IS_CONST_ZVAL) {
8538		if (zend_is_true(Z_ZV(op1_addr))) {
8539			/* Always TRUE */
8540			if (set_bool) {
8541				if (set_bool_not) {
8542					|	SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
8543				} else {
8544					|	SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
8545				}
8546			}
8547			if (true_label != (uint32_t)-1) {
8548				|	jmp =>true_label;
8549			}
8550		} else {
8551			/* Always FALSE */
8552			if (set_bool) {
8553				if (set_bool_not) {
8554					|	SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
8555				} else {
8556					|	SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
8557				}
8558			}
8559			if (false_label != (uint32_t)-1) {
8560				|	jmp =>false_label;
8561			}
8562		}
8563		return 1;
8564	}
8565
8566	if (opline->op1_type == IS_CV && (op1_info & MAY_BE_REF)) {
8567		|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
8568		|	ZVAL_DEREF FCARG1a, op1_info
8569		op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
8570	}
8571
8572	if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE)) {
8573		if (!(op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)-MAY_BE_TRUE))) {
8574			/* Always TRUE */
8575			if (set_bool) {
8576				if (set_bool_not) {
8577					|	SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
8578				} else {
8579					|	SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
8580				}
8581			}
8582			if (true_label != (uint32_t)-1) {
8583				|	jmp =>true_label;
8584			}
8585		} else {
8586			if (!(op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE)))) {
8587				/* Always FALSE */
8588				if (set_bool) {
8589					if (set_bool_not) {
8590						|	SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
8591					} else {
8592						|	SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
8593					}
8594				}
8595			} else {
8596				|	CMP_ZVAL_TYPE op1_addr, IS_TRUE
8597				if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) {
8598				    if ((op1_info & MAY_BE_LONG) &&
8599				        !(op1_info & MAY_BE_UNDEF) &&
8600				        !set_bool) {
8601						if (exit_addr) {
8602							if (branch_opcode == ZEND_JMPNZ) {
8603								|	jl >9
8604							} else {
8605								|	jl &exit_addr
8606							}
8607						} else if (false_label != (uint32_t)-1) {
8608							|	jl =>false_label
8609						} else {
8610							|	jl >9
8611						}
8612						jmp_done = 1;
8613					} else {
8614						|	jg >2
8615					}
8616				}
8617				if (!(op1_info & MAY_BE_TRUE)) {
8618					/* It's FALSE */
8619					if (set_bool) {
8620						if (set_bool_not) {
8621							|	SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
8622						} else {
8623							|	SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
8624						}
8625					}
8626				} else {
8627					if (exit_addr) {
8628						if (set_bool) {
8629							|	jne >1
8630							|	SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
8631							if (branch_opcode == ZEND_JMPNZ || branch_opcode == ZEND_JMPNZ_EX) {
8632								|	jmp &exit_addr
8633							} else {
8634								|	jmp >9
8635							}
8636							|1:
8637							|	SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
8638							if (branch_opcode == ZEND_JMPZ || branch_opcode == ZEND_JMPZ_EX) {
8639								if (!(op1_info & (MAY_BE_UNDEF|MAY_BE_LONG))) {
8640									|	jne &exit_addr
8641								}
8642							}
8643						} else {
8644							if (branch_opcode == ZEND_JMPNZ || branch_opcode == ZEND_JMPNZ_EX) {
8645								|	je &exit_addr
8646							} else if (!(op1_info & (MAY_BE_UNDEF|MAY_BE_LONG))) {
8647								|	jne &exit_addr
8648							} else {
8649								|	je >9
8650							}
8651						}
8652					} else if (true_label != (uint32_t)-1 || false_label != (uint32_t)-1) {
8653						if (set_bool) {
8654							|	jne >1
8655							|	SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
8656							if (true_label != (uint32_t)-1) {
8657								|	jmp =>true_label
8658							} else {
8659								|	jmp >9
8660							}
8661							|1:
8662							|	SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
8663						} else {
8664							if (true_label != (uint32_t)-1) {
8665								|	je =>true_label
8666							} else if (!(op1_info & (MAY_BE_UNDEF|MAY_BE_LONG))) {
8667								|	jne =>false_label
8668								jmp_done = 1;
8669							} else {
8670								|	je >9
8671							}
8672						}
8673					} else if (set_bool) {
8674						|	sete al
8675						|	movzx eax, al
8676						if (set_bool_not) {
8677							|	neg eax
8678							|	add eax, 3
8679						} else {
8680							|	add eax, 2
8681						}
8682						if ((op1_info & MAY_BE_UNDEF) && (op1_info & MAY_BE_ANY)) {
8683							set_delayed = 1;
8684						} else {
8685							|	SET_ZVAL_TYPE_INFO res_addr, eax
8686						}
8687					}
8688				}
8689			}
8690
8691			/* It's FALSE, but may be UNDEF */
8692			if (op1_info & MAY_BE_UNDEF) {
8693				if (op1_info & MAY_BE_ANY) {
8694					if (set_delayed) {
8695						|	CMP_ZVAL_TYPE op1_addr, IS_UNDEF
8696						|	SET_ZVAL_TYPE_INFO res_addr, eax
8697						|	jz >1
8698					} else {
8699						|	IF_ZVAL_TYPE op1_addr, IS_UNDEF, >1
8700					}
8701					|.cold_code
8702					|1:
8703				}
8704				|	mov FCARG1d, opline->op1.var
8705				|	SET_EX_OPLINE opline, r0
8706				|	EXT_CALL zend_jit_undefined_op_helper, r0
8707
8708				if (may_throw) {
8709					if (!zend_jit_check_exception_undef_result(Dst, opline)) {
8710						return 0;
8711					}
8712				}
8713
8714				if (exit_addr) {
8715					if (branch_opcode == ZEND_JMPZ || branch_opcode == ZEND_JMPZ_EX) {
8716						|	jmp &exit_addr
8717					}
8718				} else if (false_label != (uint32_t)-1) {
8719					|	jmp =>false_label
8720				}
8721				if (op1_info & MAY_BE_ANY) {
8722					if (exit_addr) {
8723						if (branch_opcode == ZEND_JMPNZ || branch_opcode == ZEND_JMPNZ_EX) {
8724							|	jmp >9
8725						}
8726					} else if (false_label == (uint32_t)-1) {
8727						|	jmp >9
8728					}
8729					|.code
8730				}
8731			}
8732
8733			if (!jmp_done) {
8734				if (exit_addr) {
8735					if (branch_opcode == ZEND_JMPNZ || branch_opcode == ZEND_JMPNZ_EX) {
8736						if (op1_info & MAY_BE_LONG) {
8737							|	jmp >9
8738						}
8739					} else if (op1_info & MAY_BE_LONG) {
8740						|	jmp &exit_addr
8741					}
8742				} else if (false_label != (uint32_t)-1) {
8743					|	jmp =>false_label
8744				} else if ((op1_info & MAY_BE_LONG) || (op1_info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
8745					|	jmp >9
8746				}
8747			}
8748		}
8749	}
8750
8751	if (op1_info & MAY_BE_LONG) {
8752		|2:
8753		if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG))) {
8754			|	IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >2
8755		}
8756		if (Z_MODE(op1_addr) == IS_REG) {
8757			|	test Ra(Z_REG(op1_addr)), Ra(Z_REG(op1_addr))
8758		} else {
8759			|	LONG_OP_WITH_CONST, cmp, op1_addr, Z_L(0)
8760		}
8761		if (set_bool) {
8762			|	setne al
8763			|	movzx eax, al
8764			if (set_bool_not) {
8765				|	neg eax
8766				|	add eax, 3
8767			} else {
8768				|	lea eax, [eax + 2]
8769			}
8770			|	SET_ZVAL_TYPE_INFO res_addr, eax
8771		}
8772		if (exit_addr) {
8773			if (branch_opcode == ZEND_JMPNZ || branch_opcode == ZEND_JMPNZ_EX) {
8774				|	jne &exit_addr
8775			} else {
8776				|	je &exit_addr
8777			}
8778		} else if (true_label != (uint32_t)-1 || false_label != (uint32_t)-1) {
8779			if (true_label != (uint32_t)-1) {
8780				|	jne =>true_label
8781				if (false_label != (uint32_t)-1) {
8782					|	jmp =>false_label
8783				}
8784			} else {
8785				|	je =>false_label
8786			}
8787		}
8788	}
8789
8790	if ((op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG))) == MAY_BE_DOUBLE) {
8791		if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) {
8792			|.cold_code
8793		}
8794		|2:
8795		if (CAN_USE_AVX()) {
8796			|	vxorps xmm0, xmm0, xmm0
8797		} else {
8798			|	xorps xmm0, xmm0
8799		}
8800		|	SSE_AVX_OP ucomisd, vucomisd, ZREG_XMM0, op1_addr
8801
8802		if (set_bool) {
8803			if (exit_addr) {
8804				if (branch_opcode == ZEND_JMPNZ || branch_opcode == ZEND_JMPNZ_EX) {
8805					|	SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
8806					|	jp &exit_addr
8807					|	jne &exit_addr
8808					|	SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
8809				} else {
8810					|	jp >1
8811					|	SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
8812					|	je &exit_addr
8813					|1:
8814					|	SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
8815				}
8816			} else if (false_label != (uint32_t)-1) { // JMPZ_EX (p=>true, z=>false, false=>jmp)
8817				|	jp  >1
8818				|	SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
8819				|	je  => false_label
8820				|1:
8821				|	SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
8822			} else if (true_label != (uint32_t)-1) { // JMPNZ_EX (p=>true, z=>false, true=>jmp)
8823				|	SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
8824				|	jp  => true_label
8825				|	jne  => true_label
8826				|	SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
8827			} else if (set_bool_not) { // BOOL_NOT (p=>false, z=>true)
8828				|	mov eax, IS_FALSE
8829				|	jp >1
8830				|	jne >1
8831				|	mov eax, IS_TRUE
8832				|1:
8833				|	SET_ZVAL_TYPE_INFO res_addr, eax
8834			} else { // BOOL (p=>true, z=>false)
8835				|	mov eax, IS_TRUE
8836				|	jp >1
8837				|	jne >1
8838				|	mov eax, IS_FALSE
8839				|1:
8840				|	SET_ZVAL_TYPE_INFO res_addr, eax
8841			}
8842			if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) {
8843				|	jmp >9
8844				|.code
8845			}
8846		} else {
8847			if (exit_addr) {
8848				if (branch_opcode == ZEND_JMPNZ || branch_opcode == ZEND_JMPNZ_EX) {
8849					|	jp &exit_addr
8850					|	jne &exit_addr
8851					|1:
8852				} else {
8853					|	jp >1
8854					|	je &exit_addr
8855					|1:
8856				}
8857				if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) {
8858					|	jmp >9
8859				}
8860			} else {
8861				ZEND_ASSERT(true_label != (uint32_t)-1 || false_label != (uint32_t)-1);
8862				if (false_label != (uint32_t)-1 ) {
8863					|	jp  >1
8864					|	je  => false_label
8865					|1:
8866					if (true_label != (uint32_t)-1) {
8867						|	jmp =>true_label
8868					} else if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) {
8869						|	jmp >9
8870					}
8871				} else {
8872					|	jp  => true_label
8873					|	jne  => true_label
8874					if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) {
8875						|	jmp >9
8876					}
8877				}
8878			}
8879			if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) {
8880				|.code
8881			}
8882		}
8883	} else if (op1_info & (MAY_BE_ANY - (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG))) {
8884		if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) {
8885			|.cold_code
8886			|2:
8887		}
8888		if (Z_REG(op1_addr) != ZREG_FCARG1a || Z_OFFSET(op1_addr) != 0) {
8889			|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
8890		}
8891		|	SET_EX_OPLINE opline, r0
8892		|	EXT_CALL zend_is_true, r0
8893
8894		if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) &&
8895			(op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
8896			op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
8897
8898			if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
8899				|	IF_NOT_ZVAL_REFCOUNTED op1_addr, >3
8900			}
8901			|	GET_ZVAL_PTR FCARG1a, op1_addr
8902			|	GC_DELREF FCARG1a
8903			|	jnz >3
8904			|	mov aword T1, r0 // save
8905			|	ZVAL_DTOR_FUNC op1_info, opline
8906			|	mov r0, aword T1 // restore
8907			|3:
8908		}
8909		if (may_throw) {
8910			|	MEM_OP2_1_ZTS cmp, aword, executor_globals, exception, 0, r1
8911			|	jne ->exception_handler_undef
8912		}
8913
8914		if (set_bool) {
8915			if (set_bool_not) {
8916				|	neg eax
8917				|	add eax, 3
8918			} else {
8919				|	add eax, 2
8920			}
8921			|	SET_ZVAL_TYPE_INFO res_addr, eax
8922			if (exit_addr) {
8923				|	CMP_ZVAL_TYPE res_addr, IS_FALSE
8924				if (branch_opcode == ZEND_JMPNZ || branch_opcode == ZEND_JMPNZ_EX) {
8925					|	jne &exit_addr
8926				} else {
8927					|	je &exit_addr
8928				}
8929			} else if (true_label != (uint32_t)-1 || false_label != (uint32_t)-1) {
8930				|	CMP_ZVAL_TYPE res_addr, IS_FALSE
8931				if (true_label != (uint32_t)-1) {
8932					|	jne =>true_label
8933					if (false_label != (uint32_t)-1) {
8934						|	jmp =>false_label
8935					} else if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) {
8936						|	jmp >9
8937					}
8938				} else {
8939					|	je =>false_label
8940				}
8941			}
8942			if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) {
8943				|	jmp >9
8944				|.code
8945			}
8946		} else {
8947			|	test r0, r0
8948			if (exit_addr) {
8949				if (branch_opcode == ZEND_JMPNZ || branch_opcode == ZEND_JMPNZ_EX) {
8950					|	jne &exit_addr
8951					if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) {
8952						|	jmp >9
8953					}
8954				} else {
8955					|	je &exit_addr
8956					if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) {
8957						|	jmp >9
8958					}
8959				}
8960			} else if (true_label != (uint32_t)-1) {
8961				|	jne =>true_label
8962				if (false_label != (uint32_t)-1) {
8963					|	jmp =>false_label
8964				} else if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) {
8965					|	jmp >9
8966				}
8967			} else {
8968				|	je =>false_label
8969				if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) {
8970					|	jmp >9
8971				}
8972			}
8973
8974			if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) {
8975				|.code
8976			}
8977		}
8978	}
8979
8980	|9:
8981
8982	return 1;
8983}
8984
8985static int zend_jit_qm_assign(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr op1_def_addr, uint32_t res_use_info, uint32_t res_info, zend_jit_addr res_addr)
8986{
8987	if (op1_addr != op1_def_addr) {
8988		if (!zend_jit_update_regs(Dst, opline->op1.var, op1_addr, op1_def_addr, op1_info)) {
8989			return 0;
8990		}
8991		if (Z_MODE(op1_def_addr) == IS_REG && Z_MODE(op1_addr) != IS_REG) {
8992			op1_addr = op1_def_addr;
8993		}
8994	}
8995
8996	if (!zend_jit_simple_assign(Dst, opline, res_addr, res_use_info, res_info, opline->op1_type, op1_addr, op1_info, 0, 0, 0)) {
8997		return 0;
8998	}
8999	if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, res_info)) {
9000		return 0;
9001	}
9002	if (op1_info & MAY_BE_UNDEF) {
9003		zend_jit_check_exception(Dst);
9004	}
9005	return 1;
9006}
9007
9008static int zend_jit_assign(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_use_addr, uint32_t op1_def_info, zend_jit_addr op1_addr, uint32_t op2_info, zend_jit_addr op2_addr, zend_jit_addr op2_def_addr, uint32_t res_info, zend_jit_addr res_addr, int may_throw)
9009{
9010	ZEND_ASSERT(opline->op1_type == IS_CV);
9011
9012	if (op2_addr != op2_def_addr) {
9013		if (!zend_jit_update_regs(Dst, opline->op2.var, op2_addr, op2_def_addr, op2_info)) {
9014			return 0;
9015		}
9016		if (Z_MODE(op2_def_addr) == IS_REG && Z_MODE(op2_addr) != IS_REG) {
9017			op2_addr = op2_def_addr;
9018		}
9019	}
9020
9021	if (Z_MODE(op1_addr) != IS_REG
9022	 && Z_MODE(op1_use_addr) == IS_REG
9023	 && !Z_LOAD(op1_use_addr)
9024	 && !Z_STORE(op1_use_addr)) {
9025		/* Force type update */
9026		op1_info |= MAY_BE_UNDEF;
9027	}
9028	if (!zend_jit_assign_to_variable(Dst, opline, op1_use_addr, op1_addr, op1_info, op1_def_info, opline->op2_type, op2_addr, op2_info, res_addr,
9029			may_throw)) {
9030		return 0;
9031	}
9032	if (!zend_jit_store_var_if_necessary_ex(Dst, opline->op1.var, op1_addr, op1_def_info, op1_use_addr, op1_info)) {
9033		return 0;
9034	}
9035	if (opline->result_type != IS_UNUSED) {
9036		if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, res_info)) {
9037			return 0;
9038		}
9039	}
9040
9041	return 1;
9042}
9043
9044/* copy of hidden zend_closure */
9045typedef struct _zend_closure {
9046	zend_object       std;
9047	zend_function     func;
9048	zval              this_ptr;
9049	zend_class_entry *called_scope;
9050	zif_handler       orig_internal_handler;
9051} zend_closure;
9052
9053static int zend_jit_stack_check(dasm_State **Dst, const zend_op *opline, uint32_t used_stack)
9054{
9055	int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9056	const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9057
9058	if (!exit_addr) {
9059		return 0;
9060	}
9061
9062	|	// Check Stack Overflow
9063	|	MEM_OP2_2_ZTS mov, r1, aword, executor_globals, vm_stack_end, r0
9064	|	MEM_OP2_2_ZTS sub, r1, aword, executor_globals, vm_stack_top, r0
9065	|	cmp r1, used_stack
9066	|	jb &exit_addr
9067
9068	return 1;
9069}
9070
9071static int zend_jit_push_call_frame(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, zend_function *func, zend_bool is_closure, zend_bool use_this, zend_bool stack_check)
9072{
9073	uint32_t used_stack;
9074
9075	if (func) {
9076		used_stack = zend_vm_calc_used_stack(opline->extended_value, func);
9077	} else {
9078		used_stack = (ZEND_CALL_FRAME_SLOT + opline->extended_value) * sizeof(zval);
9079
9080		|	// if (EXPECTED(ZEND_USER_CODE(func->type))) {
9081		if (!is_closure) {
9082			|	test byte [r0 + offsetof(zend_function, type)], 1
9083			|	mov FCARG1a, used_stack
9084			|	jnz >1
9085		} else {
9086			|	mov FCARG1a, used_stack
9087		}
9088		|	// used_stack += (func->op_array.last_var + func->op_array.T - MIN(func->op_array.num_args, num_args)) * sizeof(zval);
9089		|	mov edx, opline->extended_value
9090		if (!is_closure) {
9091			|	cmp edx, dword [r0 + offsetof(zend_function, op_array.num_args)]
9092			|	cmova edx, dword [r0 + offsetof(zend_function, op_array.num_args)]
9093			|	sub edx, dword [r0 + offsetof(zend_function, op_array.last_var)]
9094			|	sub edx, dword [r0 + offsetof(zend_function, op_array.T)]
9095		} else {
9096			|	cmp edx, dword [r0 + offsetof(zend_closure, func.op_array.num_args)]
9097			|	cmova edx, dword [r0 + offsetof(zend_closure, func.op_array.num_args)]
9098			|	sub edx, dword [r0 + offsetof(zend_closure, func.op_array.last_var)]
9099			|	sub edx, dword [r0 + offsetof(zend_closure, func.op_array.T)]
9100		}
9101		|	shl edx, 4
9102		|.if X64
9103			|	movsxd r2, edx
9104		|.endif
9105		|	sub FCARG1a, r2
9106		|1:
9107	}
9108
9109	zend_jit_start_reuse_ip();
9110
9111	|	// if (UNEXPECTED(used_stack > (size_t)(((char*)EG(vm_stack_end)) - (char*)call))) {
9112	|	MEM_OP2_2_ZTS mov, RX, aword, executor_globals, vm_stack_top, RX
9113
9114	if (stack_check) {
9115		|	// Check Stack Overflow
9116		|	MEM_OP2_2_ZTS mov, r2, aword, executor_globals, vm_stack_end, r2
9117		|	sub r2, RX
9118		if (func) {
9119			|	cmp r2, used_stack
9120		} else {
9121			|	cmp r2, FCARG1a
9122		}
9123
9124		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
9125			int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9126			const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9127
9128			if (!exit_addr) {
9129				return 0;
9130			}
9131
9132			|	jb &exit_addr
9133		} else {
9134			|	jb >1
9135			|	// EG(vm_stack_top) = (zval*)((char*)call + used_stack);
9136			|.cold_code
9137			|1:
9138			if (func) {
9139				|	mov FCARG1d, used_stack
9140			}
9141#ifdef _WIN32
9142			if (0) {
9143#else
9144			if (opline->opcode == ZEND_INIT_FCALL && func && func->type == ZEND_INTERNAL_FUNCTION) {
9145#endif
9146				|	SET_EX_OPLINE opline, r0
9147				|	EXT_CALL zend_jit_int_extend_stack_helper, r0
9148			} else {
9149				if (!is_closure) {
9150					if (func
9151					 && op_array == &func->op_array
9152					 && (func->op_array.fn_flags & ZEND_ACC_IMMUTABLE)
9153					 && (sizeof(void*) != 8 || IS_SIGNED_32BIT(func))) {
9154						|	LOAD_ADDR FCARG2a, func
9155					} else {
9156						|	mov FCARG2a, r0
9157					}
9158				} else {
9159					|	lea FCARG2a, aword [r0 + offsetof(zend_closure, func)]
9160				}
9161				|	SET_EX_OPLINE opline, r0
9162				|	EXT_CALL zend_jit_extend_stack_helper, r0
9163			}
9164			|	mov RX, r0
9165			|	jmp >1
9166			|.code
9167		}
9168	}
9169
9170	if (func) {
9171		|	MEM_OP2_1_ZTS add, aword, executor_globals, vm_stack_top, used_stack, r2
9172	} else {
9173		|	MEM_OP2_1_ZTS add, aword, executor_globals, vm_stack_top, FCARG1a, r2
9174	}
9175	|	// zend_vm_init_call_frame(call, call_info, func, num_args, called_scope, object);
9176	if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE || opline->opcode != ZEND_INIT_METHOD_CALL) {
9177		|	// ZEND_SET_CALL_INFO(call, 0, call_info);
9178		|	mov dword EX:RX->This.u1.type_info, (IS_UNDEF | ZEND_CALL_NESTED_FUNCTION)
9179	}
9180#ifdef _WIN32
9181	if (0) {
9182#else
9183	if (opline->opcode == ZEND_INIT_FCALL && func && func->type == ZEND_INTERNAL_FUNCTION) {
9184#endif
9185		|	// call->func = func;
9186		|1:
9187		|	ADDR_OP2_2 mov, aword EX:RX->func, func, r1
9188	} else {
9189		if (!is_closure) {
9190			|	// call->func = func;
9191			if (func
9192			 && op_array == &func->op_array
9193			 && (func->op_array.fn_flags & ZEND_ACC_IMMUTABLE)
9194			 && (sizeof(void*) != 8 || IS_SIGNED_32BIT(func))) {
9195				|	ADDR_OP2_2 mov, aword EX:RX->func, func, r1
9196			} else {
9197				|	mov aword EX:RX->func, r0
9198			}
9199		} else {
9200			|	// call->func = &closure->func;
9201			|	lea r1, aword [r0 + offsetof(zend_closure, func)]
9202			|	mov aword EX:RX->func, r1
9203		}
9204		|1:
9205	}
9206	if (opline->opcode == ZEND_INIT_METHOD_CALL) {
9207		|	// Z_PTR(call->This) = obj;
9208		|	mov r1, aword T1
9209		|	mov aword EX:RX->This.value.ptr, r1
9210	    if (opline->op1_type == IS_UNUSED || use_this) {
9211			|	// call->call_info |= ZEND_CALL_HAS_THIS;
9212			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
9213				|	mov dword EX:RX->This.u1.type_info, ZEND_CALL_HAS_THIS
9214			} else {
9215				|	or dword EX:RX->This.u1.type_info, ZEND_CALL_HAS_THIS
9216			}
9217	    } else {
9218			if (opline->op1_type == IS_CV) {
9219				|	// GC_ADDREF(obj);
9220				|	add dword [r1], 1
9221			}
9222			|	// call->call_info |= ZEND_CALL_HAS_THIS | ZEND_CALL_RELEASE_THIS;
9223			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
9224				|	mov dword EX:RX->This.u1.type_info, (ZEND_CALL_HAS_THIS | ZEND_CALL_RELEASE_THIS)
9225			} else {
9226				|	or dword EX:RX->This.u1.type_info, (ZEND_CALL_HAS_THIS | ZEND_CALL_RELEASE_THIS)
9227			}
9228	    }
9229	} else if (!is_closure) {
9230		|	// Z_CE(call->This) = called_scope;
9231		|	mov aword EX:RX->This.value.ptr, 0
9232	} else {
9233		if (opline->op2_type == IS_CV) {
9234			|	// GC_ADDREF(closure);
9235			|	add dword [r0], 1
9236		}
9237		|	//	object_or_called_scope = closure->called_scope;
9238		|	mov r1, aword [r0 + offsetof(zend_closure, called_scope)]
9239		|	mov aword EX:RX->This.value.ptr, r1
9240		|	// call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC | ZEND_CALL_CLOSURE |
9241		|	//	(closure->func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE);
9242		|	mov edx, dword [r0 + offsetof(zend_closure, func.common.fn_flags)]
9243		|	and edx, ZEND_ACC_FAKE_CLOSURE
9244		|	or edx, (ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC | ZEND_CALL_CLOSURE)
9245		|	//	if (Z_TYPE(closure->this_ptr) != IS_UNDEF) {
9246		|	cmp byte [r0 + offsetof(zend_closure, this_ptr.u1.v.type)], IS_UNDEF
9247		|	jz >1
9248		|	//	call_info |= ZEND_CALL_HAS_THIS;
9249		|	or edx, ZEND_CALL_HAS_THIS
9250		|	//	object_or_called_scope = Z_OBJ(closure->this_ptr);
9251		|	mov r1, aword [r0 + offsetof(zend_closure, this_ptr.value.ptr)]
9252	    |1:
9253		|	// ZEND_SET_CALL_INFO(call, 0, call_info);
9254		|	or dword EX:RX->This.u1.type_info, edx
9255		|	// Z_PTR(call->This) = object_or_called_scope;
9256		|	mov aword EX:RX->This.value.ptr, r1
9257		|	cmp aword [r0 + offsetof(zend_closure, func.op_array.run_time_cache__ptr)], 0
9258		|	jnz >1
9259		|	lea FCARG1a, aword [r0 + offsetof(zend_closure, func)]
9260		|	EXT_CALL zend_jit_init_func_run_time_cache_helper, r0
9261		|1:
9262	}
9263	|	// ZEND_CALL_NUM_ARGS(call) = num_args;
9264	|	mov dword EX:RX->This.u2.num_args, opline->extended_value
9265	return 1;
9266}
9267
9268static int zend_jit_needs_call_chain(zend_call_info *call_info, uint32_t b, const zend_op_array *op_array, zend_ssa *ssa, const zend_ssa_op *ssa_op, const zend_op *opline, int call_level, zend_jit_trace_rec *trace)
9269{
9270	int skip;
9271
9272	if (trace) {
9273		zend_jit_trace_rec *p = trace;
9274
9275		ssa_op++;
9276		while (1) {
9277			if (p->op == ZEND_JIT_TRACE_VM) {
9278				switch (p->opline->opcode) {
9279					case ZEND_SEND_ARRAY:
9280					case ZEND_SEND_USER:
9281					case ZEND_SEND_UNPACK:
9282					case ZEND_INIT_FCALL:
9283					case ZEND_INIT_METHOD_CALL:
9284					case ZEND_INIT_STATIC_METHOD_CALL:
9285					case ZEND_INIT_FCALL_BY_NAME:
9286					case ZEND_INIT_NS_FCALL_BY_NAME:
9287					case ZEND_INIT_DYNAMIC_CALL:
9288					case ZEND_NEW:
9289					case ZEND_INIT_USER_CALL:
9290					case ZEND_FAST_CALL:
9291					case ZEND_JMP:
9292					case ZEND_JMPZNZ:
9293					case ZEND_JMPZ:
9294					case ZEND_JMPNZ:
9295					case ZEND_JMPZ_EX:
9296					case ZEND_JMPNZ_EX:
9297					case ZEND_FE_RESET_R:
9298					case ZEND_FE_RESET_RW:
9299					case ZEND_JMP_SET:
9300					case ZEND_COALESCE:
9301					case ZEND_JMP_NULL:
9302					case ZEND_ASSERT_CHECK:
9303					case ZEND_CATCH:
9304					case ZEND_DECLARE_ANON_CLASS:
9305					case ZEND_FE_FETCH_R:
9306					case ZEND_FE_FETCH_RW:
9307						return 1;
9308					case ZEND_DO_ICALL:
9309					case ZEND_DO_UCALL:
9310					case ZEND_DO_FCALL_BY_NAME:
9311					case ZEND_DO_FCALL:
9312						return 0;
9313					case ZEND_SEND_VAL:
9314					case ZEND_SEND_VAR:
9315					case ZEND_SEND_VAL_EX:
9316					case ZEND_SEND_VAR_EX:
9317					case ZEND_SEND_FUNC_ARG:
9318					case ZEND_SEND_REF:
9319					case ZEND_SEND_VAR_NO_REF:
9320					case ZEND_SEND_VAR_NO_REF_EX:
9321						/* skip */
9322						break;
9323					default:
9324						if (zend_may_throw(opline, ssa_op, op_array, ssa)) {
9325							return 1;
9326						}
9327				}
9328				ssa_op += zend_jit_trace_op_len(opline);
9329			} else if (p->op == ZEND_JIT_TRACE_ENTER ||
9330			           p->op == ZEND_JIT_TRACE_BACK ||
9331			           p->op == ZEND_JIT_TRACE_END) {
9332				return 1;
9333			}
9334			p++;
9335		}
9336	}
9337
9338	if (!call_info) {
9339		const zend_op *end = op_array->opcodes + op_array->last;
9340
9341		opline++;
9342		ssa_op++;
9343		skip = (call_level == 1);
9344		while (opline != end) {
9345			if (!skip) {
9346				if (zend_may_throw(opline, ssa_op, op_array, ssa)) {
9347					return 1;
9348				}
9349			}
9350			switch (opline->opcode) {
9351				case ZEND_SEND_VAL:
9352				case ZEND_SEND_VAR:
9353				case ZEND_SEND_VAL_EX:
9354				case ZEND_SEND_VAR_EX:
9355				case ZEND_SEND_FUNC_ARG:
9356				case ZEND_SEND_REF:
9357				case ZEND_SEND_VAR_NO_REF:
9358				case ZEND_SEND_VAR_NO_REF_EX:
9359					skip = 0;
9360					break;
9361				case ZEND_SEND_ARRAY:
9362				case ZEND_SEND_USER:
9363				case ZEND_SEND_UNPACK:
9364				case ZEND_INIT_FCALL:
9365				case ZEND_INIT_METHOD_CALL:
9366				case ZEND_INIT_STATIC_METHOD_CALL:
9367				case ZEND_INIT_FCALL_BY_NAME:
9368				case ZEND_INIT_NS_FCALL_BY_NAME:
9369				case ZEND_INIT_DYNAMIC_CALL:
9370				case ZEND_NEW:
9371				case ZEND_INIT_USER_CALL:
9372				case ZEND_FAST_CALL:
9373				case ZEND_JMP:
9374				case ZEND_JMPZNZ:
9375				case ZEND_JMPZ:
9376				case ZEND_JMPNZ:
9377				case ZEND_JMPZ_EX:
9378				case ZEND_JMPNZ_EX:
9379				case ZEND_FE_RESET_R:
9380				case ZEND_FE_RESET_RW:
9381				case ZEND_JMP_SET:
9382				case ZEND_COALESCE:
9383				case ZEND_JMP_NULL:
9384				case ZEND_ASSERT_CHECK:
9385				case ZEND_CATCH:
9386				case ZEND_DECLARE_ANON_CLASS:
9387				case ZEND_FE_FETCH_R:
9388				case ZEND_FE_FETCH_RW:
9389					return 1;
9390				case ZEND_DO_ICALL:
9391				case ZEND_DO_UCALL:
9392				case ZEND_DO_FCALL_BY_NAME:
9393				case ZEND_DO_FCALL:
9394					end = opline;
9395					if (end - op_array->opcodes >= ssa->cfg.blocks[b].start + ssa->cfg.blocks[b].len) {
9396						/* INIT_FCALL and DO_FCALL in different BasicBlocks */
9397						return 1;
9398					}
9399					return 0;
9400			}
9401			opline++;
9402			ssa_op++;
9403		}
9404
9405		return 1;
9406	} else {
9407		const zend_op *end = call_info->caller_call_opline;
9408
9409		if (end - op_array->opcodes >= ssa->cfg.blocks[b].start + ssa->cfg.blocks[b].len) {
9410			/* INIT_FCALL and DO_FCALL in different BasicBlocks */
9411			return 1;
9412		}
9413
9414		opline++;
9415		ssa_op++;
9416		skip = (call_level == 1);
9417		while (opline != end) {
9418			if (skip) {
9419				switch (opline->opcode) {
9420					case ZEND_SEND_VAL:
9421					case ZEND_SEND_VAR:
9422					case ZEND_SEND_VAL_EX:
9423					case ZEND_SEND_VAR_EX:
9424					case ZEND_SEND_FUNC_ARG:
9425					case ZEND_SEND_REF:
9426					case ZEND_SEND_VAR_NO_REF:
9427					case ZEND_SEND_VAR_NO_REF_EX:
9428						skip = 0;
9429						break;
9430					case ZEND_SEND_ARRAY:
9431					case ZEND_SEND_USER:
9432					case ZEND_SEND_UNPACK:
9433						return 1;
9434				}
9435			} else {
9436				if (zend_may_throw(opline, ssa_op, op_array, ssa)) {
9437					return 1;
9438				}
9439			}
9440			opline++;
9441			ssa_op++;
9442		}
9443
9444		return 0;
9445	}
9446}
9447
9448static int zend_jit_init_fcall_guard(dasm_State **Dst, uint32_t level, const zend_function *func, const zend_op *to_opline)
9449{
9450	int32_t exit_point;
9451	const void *exit_addr;
9452
9453	if (func->type == ZEND_INTERNAL_FUNCTION) {
9454#ifdef ZEND_WIN32
9455		// TODO: ASLR may cause different addresses in different workers ???
9456		return 0;
9457#endif
9458	} else if (func->type == ZEND_USER_FUNCTION) {
9459		if (!zend_accel_in_shm(func->op_array.opcodes)) {
9460			/* op_array and op_array->opcodes are not persistent. We can't link. */
9461			return 0;
9462		}
9463	} else {
9464		ZEND_UNREACHABLE();
9465		return 0;
9466	}
9467
9468	exit_point = zend_jit_trace_get_exit_point(to_opline, ZEND_JIT_EXIT_POLYMORPHISM);
9469	exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9470	if (!exit_addr) {
9471		return 0;
9472	}
9473
9474	|	// call = EX(call);
9475	|	mov r1, EX->call
9476	while (level > 0) {
9477		|	mov r1, EX:r1->prev_execute_data
9478		level--;
9479	}
9480
9481	if (func->type == ZEND_USER_FUNCTION &&
9482	    (!(func->common.fn_flags & ZEND_ACC_IMMUTABLE) ||
9483	     (func->common.fn_flags & ZEND_ACC_CLOSURE) ||
9484	     !func->common.function_name)) {
9485		const zend_op *opcodes = func->op_array.opcodes;
9486
9487		|	mov r1, aword EX:r1->func
9488		|   .if X64
9489		||		if (!IS_SIGNED_32BIT(opcodes)) {
9490		|			mov64 r2, ((ptrdiff_t)opcodes)
9491		|			cmp aword [r1 + offsetof(zend_op_array, opcodes)], r2
9492		||		} else {
9493		|			cmp aword [r1 + offsetof(zend_op_array, opcodes)], opcodes
9494		||		}
9495		|	.else
9496		|		cmp aword [r1 + offsetof(zend_op_array, opcodes)], opcodes
9497		|	.endif
9498		|	jne &exit_addr
9499	} else {
9500		|   .if X64
9501		||		if (!IS_SIGNED_32BIT(func)) {
9502		|			mov64 r2, ((ptrdiff_t)func)
9503		|			cmp aword EX:r1->func, r2
9504		||		} else {
9505		|			cmp aword EX:r1->func, func
9506		||		}
9507		|	.else
9508		|		cmp aword EX:r1->func, func
9509		|	.endif
9510		|	jne &exit_addr
9511	}
9512
9513	return 1;
9514}
9515
9516static int zend_jit_init_fcall(dasm_State **Dst, const zend_op *opline, uint32_t b, const zend_op_array *op_array, zend_ssa *ssa, const zend_ssa_op *ssa_op, int call_level, zend_jit_trace_rec *trace, zend_bool stack_check)
9517{
9518	zend_func_info *info = ZEND_FUNC_INFO(op_array);
9519	zend_call_info *call_info = NULL;
9520	zend_function *func = NULL;
9521
9522	if (delayed_call_chain) {
9523		if (!zend_jit_save_call_chain(Dst, delayed_call_level)) {
9524			return 0;
9525		}
9526	}
9527
9528	if (info) {
9529		call_info = info->callee_info;
9530		while (call_info && call_info->caller_init_opline != opline) {
9531			call_info = call_info->next_callee;
9532		}
9533		if (call_info && call_info->callee_func) {
9534			func = call_info->callee_func;
9535		}
9536	}
9537
9538	if (!func
9539	 && trace
9540	 && trace->op == ZEND_JIT_TRACE_INIT_CALL) {
9541#ifdef _WIN32
9542		/* ASLR */
9543		if (trace->func->type != ZEND_INTERNAL_FUNCTION) {
9544			func = (zend_function*)trace->func;
9545		}
9546#else
9547		func = (zend_function*)trace->func;
9548#endif
9549	}
9550
9551#ifdef _WIN32
9552	if (0) {
9553#else
9554	if (opline->opcode == ZEND_INIT_FCALL
9555	 && func
9556	 && func->type == ZEND_INTERNAL_FUNCTION) {
9557#endif
9558		/* load constant address later */
9559	} else if (func && op_array == &func->op_array) {
9560		/* recursive call */
9561		if (!(func->op_array.fn_flags & ZEND_ACC_IMMUTABLE) ||
9562		    (sizeof(void*) == 8 && !IS_SIGNED_32BIT(func))) {
9563			|	mov r0, EX->func
9564		}
9565	} else {
9566		|	// if (CACHED_PTR(opline->result.num))
9567		|	mov r0, EX->run_time_cache
9568		|	mov r0, aword [r0 + opline->result.num]
9569		|	test r0, r0
9570		|	jz >1
9571		|.cold_code
9572		|1:
9573		if (opline->opcode == ZEND_INIT_FCALL
9574		 && func
9575		 && func->type == ZEND_USER_FUNCTION
9576		 && (func->op_array.fn_flags & ZEND_ACC_IMMUTABLE)) {
9577			|	LOAD_ADDR FCARG1a, func
9578			|	EXT_CALL zend_jit_init_func_run_time_cache_helper, r0
9579			|	mov r1, EX->run_time_cache
9580			|	mov aword [r1 + opline->result.num], r0
9581			|	jmp >3
9582		} else {
9583			zval *zv = RT_CONSTANT(opline, opline->op2);
9584
9585			if (opline->opcode == ZEND_INIT_FCALL) {
9586				|	LOAD_ADDR FCARG1a, Z_STR_P(zv);
9587				|	EXT_CALL zend_jit_find_func_helper, r0
9588			} else if (opline->opcode == ZEND_INIT_FCALL_BY_NAME) {
9589				|	LOAD_ADDR FCARG1a, Z_STR_P(zv + 1);
9590				|	EXT_CALL zend_jit_find_func_helper, r0
9591			} else if (opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME) {
9592				|	LOAD_ADDR FCARG1a, zv;
9593				|	EXT_CALL zend_jit_find_ns_func_helper, r0
9594			} else {
9595				ZEND_UNREACHABLE();
9596			}
9597			|	// CACHE_PTR(opline->result.num, fbc);
9598			|	mov r1, EX->run_time_cache
9599			|	mov aword [r1 + opline->result.num], r0
9600			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
9601				int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
9602				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9603
9604				if (!exit_addr) {
9605					return 0;
9606				}
9607
9608				if (!func || opline->opcode == ZEND_INIT_FCALL) {
9609					|	test r0, r0
9610					|	jnz >3
9611				} else if (func->type == ZEND_USER_FUNCTION
9612					 && !(func->common.fn_flags & ZEND_ACC_IMMUTABLE)) {
9613					const zend_op *opcodes = func->op_array.opcodes;
9614
9615					|   .if X64
9616					||		if (!IS_SIGNED_32BIT(opcodes)) {
9617					|			mov64 r1, ((ptrdiff_t)opcodes)
9618					|			cmp aword [r0 + offsetof(zend_op_array, opcodes)], r1
9619					||		} else {
9620					|			cmp aword [r0 + offsetof(zend_op_array, opcodes)], opcodes
9621					||		}
9622					|	.else
9623					|		cmp aword [r0 + offsetof(zend_op_array, opcodes)], opcodes
9624					|	.endif
9625					|	jz >3
9626				} else {
9627					|   .if X64
9628					||		if (!IS_SIGNED_32BIT(func)) {
9629					|			mov64 r1, ((ptrdiff_t)func)
9630					|			cmp r0, r1
9631					||		} else {
9632					|			cmp r0, func
9633					||		}
9634					|	.else
9635					|		cmp r0, func
9636					|	.endif
9637					|	jz >3
9638				}
9639				|	jmp &exit_addr
9640			} else {
9641				|	test r0, r0
9642				|	jnz >3
9643				|	// SAVE_OPLINE();
9644				|	SET_EX_OPLINE opline, r0
9645				|	jmp ->undefined_function
9646			}
9647		}
9648		|.code
9649		|3:
9650	}
9651
9652	if (!zend_jit_push_call_frame(Dst, opline, op_array, func, 0, 0, stack_check)) {
9653		return 0;
9654	}
9655
9656	if (zend_jit_needs_call_chain(call_info, b, op_array, ssa, ssa_op, opline, call_level, trace)) {
9657		if (!zend_jit_save_call_chain(Dst, call_level)) {
9658			return 0;
9659		}
9660	} else {
9661		delayed_call_chain = 1;
9662		delayed_call_level = call_level;
9663	}
9664
9665	return 1;
9666}
9667
9668static int zend_jit_init_method_call(dasm_State          **Dst,
9669                                     const zend_op        *opline,
9670                                     uint32_t              b,
9671                                     const zend_op_array  *op_array,
9672                                     zend_ssa             *ssa,
9673                                     const zend_ssa_op    *ssa_op,
9674                                     int                   call_level,
9675                                     uint32_t              op1_info,
9676                                     zend_jit_addr         op1_addr,
9677                                     zend_class_entry     *ce,
9678                                     zend_bool             ce_is_instanceof,
9679                                     zend_bool             use_this,
9680                                     zend_class_entry     *trace_ce,
9681                                     zend_jit_trace_rec   *trace,
9682                                     zend_bool             stack_check,
9683                                     zend_bool             polymorphic_side_trace)
9684{
9685	zend_func_info *info = ZEND_FUNC_INFO(op_array);
9686	zend_call_info *call_info = NULL;
9687	zend_function *func = NULL;
9688	zval *function_name;
9689
9690	ZEND_ASSERT(opline->op2_type == IS_CONST);
9691	ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
9692
9693	function_name = RT_CONSTANT(opline, opline->op2);
9694
9695	if (info) {
9696		call_info = info->callee_info;
9697		while (call_info && call_info->caller_init_opline != opline) {
9698			call_info = call_info->next_callee;
9699		}
9700		if (call_info && call_info->callee_func) {
9701			func = call_info->callee_func;
9702		}
9703	}
9704
9705	if (polymorphic_side_trace) {
9706		/* function is passed in r0 from parent_trace */
9707	} else {
9708		if (opline->op1_type == IS_UNUSED || use_this) {
9709			zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
9710
9711			|	GET_ZVAL_PTR FCARG1a, this_addr
9712		} else {
9713		    if (op1_info & MAY_BE_REF) {
9714				if (opline->op1_type == IS_CV) {
9715					if (Z_REG(op1_addr) != ZREG_FCARG1a || Z_OFFSET(op1_addr) != 0) {
9716						|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
9717					}
9718					|	ZVAL_DEREF FCARG1a, op1_info
9719					op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
9720				} else {
9721					/* Hack: Convert reference to regular value to simplify JIT code */
9722					ZEND_ASSERT(Z_REG(op1_addr) == ZREG_FP);
9723					|	IF_NOT_ZVAL_TYPE op1_addr, IS_REFERENCE, >1
9724					|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
9725					|	EXT_CALL zend_jit_unref_helper, r0
9726					|1:
9727				}
9728			}
9729			if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
9730				if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
9731					int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9732					const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9733
9734					if (!exit_addr) {
9735						return 0;
9736					}
9737					|	IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, &exit_addr
9738				} else {
9739					|	IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, >1
9740					|.cold_code
9741					|1:
9742					if (Z_REG(op1_addr) != ZREG_FCARG1a || Z_OFFSET(op1_addr) != 0) {
9743						|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
9744					}
9745					|	SET_EX_OPLINE opline, r0
9746					if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !use_this) {
9747						|	EXT_CALL zend_jit_invalid_method_call_tmp, r0
9748					} else {
9749						|	EXT_CALL zend_jit_invalid_method_call, r0
9750					}
9751					|	jmp ->exception_handler
9752					|.code
9753				}
9754			}
9755			|	GET_ZVAL_PTR FCARG1a, op1_addr
9756		}
9757
9758		if (delayed_call_chain) {
9759			if (!zend_jit_save_call_chain(Dst, delayed_call_level)) {
9760				return 0;
9761			}
9762		}
9763
9764		|	mov aword T1, FCARG1a // save
9765
9766		if (func) {
9767			|	// fbc = CACHED_PTR(opline->result.num + sizeof(void*));
9768			|	mov r0, EX->run_time_cache
9769			|	mov r0, aword [r0 + opline->result.num + sizeof(void*)]
9770			|	test r0, r0
9771			|	jz >1
9772		} else {
9773			|	// if (CACHED_PTR(opline->result.num) == obj->ce)) {
9774			|	mov r0, EX->run_time_cache
9775			|	mov r2, aword [r0 + opline->result.num]
9776			|	cmp r2, [FCARG1a + offsetof(zend_object, ce)]
9777			|	jnz >1
9778			|	// fbc = CACHED_PTR(opline->result.num + sizeof(void*));
9779			|	mov r0, aword [r0 + opline->result.num + sizeof(void*)]
9780		}
9781
9782		|.cold_code
9783		|1:
9784		|	LOAD_ADDR FCARG2a, function_name
9785		|.if X64
9786		|	lea CARG3, aword T1
9787		|.else
9788		|	lea r0, aword T1
9789		|	sub r4, 12
9790		|	push r0
9791		|.endif
9792		|	SET_EX_OPLINE opline, r0
9793		if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !use_this) {
9794			|	EXT_CALL zend_jit_find_method_tmp_helper, r0
9795		} else {
9796			|	EXT_CALL zend_jit_find_method_helper, r0
9797		}
9798		|.if not(X64)
9799		|	add r4, 12
9800		|.endif
9801		|	test r0, r0
9802		|	jnz >2
9803		|	jmp ->exception_handler
9804		|.code
9805		|2:
9806	}
9807
9808	if (!func
9809	 && trace
9810	 && trace->op == ZEND_JIT_TRACE_INIT_CALL
9811	 && trace->func
9812#ifdef _WIN32
9813	 && trace->func->type != ZEND_INTERNAL_FUNCTION
9814#endif
9815	) {
9816		int32_t exit_point;
9817		const void *exit_addr;
9818
9819		exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_METHOD_CALL);
9820		exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9821		if (!exit_addr) {
9822			return 0;
9823		}
9824
9825		func = (zend_function*)trace->func;
9826
9827		if (func->type == ZEND_USER_FUNCTION &&
9828		    (!(func->common.fn_flags & ZEND_ACC_IMMUTABLE) ||
9829		     (func->common.fn_flags & ZEND_ACC_CLOSURE) ||
9830		     !func->common.function_name)) {
9831			const zend_op *opcodes = func->op_array.opcodes;
9832
9833			|   .if X64
9834			||		if (!IS_SIGNED_32BIT(opcodes)) {
9835			|			mov64 r1, ((ptrdiff_t)opcodes)
9836			|			cmp aword [r0 + offsetof(zend_op_array, opcodes)], r1
9837			||		} else {
9838			|			cmp aword [r0 + offsetof(zend_op_array, opcodes)], opcodes
9839			||		}
9840			|	.else
9841			|		cmp aword [r0 + offsetof(zend_op_array, opcodes)], opcodes
9842			|	.endif
9843			|	jne &exit_addr
9844		} else {
9845			|   .if X64
9846			||		if (!IS_SIGNED_32BIT(func)) {
9847			|			mov64 r1, ((ptrdiff_t)func)
9848			|			cmp r0, r1
9849			||		} else {
9850			|			cmp r0, func
9851			||		}
9852			|	.else
9853			|		cmp r0, func
9854			|	.endif
9855			|	jne &exit_addr
9856		}
9857	}
9858
9859	if (!func) {
9860		|	// if (fbc->common.fn_flags & ZEND_ACC_STATIC) {
9861		|	test dword [r0 + offsetof(zend_function, common.fn_flags)], ZEND_ACC_STATIC
9862		|	jnz >1
9863		|.cold_code
9864		|1:
9865	}
9866
9867	if (!func || (func->common.fn_flags & ZEND_ACC_STATIC) != 0) {
9868		|	mov FCARG1a, aword T1 // restore
9869		|	mov FCARG2a, r0
9870		|.if X64
9871		|	mov CARG3d, opline->extended_value
9872		|.else
9873		|	sub r4, 12
9874		|	push opline->extended_value
9875		|.endif
9876		if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !use_this) {
9877			|	EXT_CALL zend_jit_push_static_metod_call_frame_tmp, r0
9878		} else {
9879			|	EXT_CALL zend_jit_push_static_metod_call_frame, r0
9880		}
9881		|.if not(X64)
9882		|	add r4, 12
9883		|.endif
9884		if ((opline->op1_type & (IS_VAR|IS_TMP_VAR) && !use_this)) {
9885			|	test r0, r0
9886			|	jz ->exception_handler
9887		}
9888		|	mov RX, r0
9889	}
9890
9891	if (!func) {
9892		|	jmp >9
9893		|.code
9894	}
9895
9896	if (!func || (func->common.fn_flags & ZEND_ACC_STATIC) == 0) {
9897		if (!zend_jit_push_call_frame(Dst, opline, NULL, func, 0, use_this, stack_check)) {
9898			return 0;
9899		}
9900	}
9901
9902	if (!func) {
9903		|9:
9904	}
9905	zend_jit_start_reuse_ip();
9906
9907	if (zend_jit_needs_call_chain(call_info, b, op_array, ssa, ssa_op, opline, call_level, trace)) {
9908		if (!zend_jit_save_call_chain(Dst, call_level)) {
9909			return 0;
9910		}
9911	} else {
9912		delayed_call_chain = 1;
9913		delayed_call_level = call_level;
9914	}
9915
9916	return 1;
9917}
9918
9919static int zend_jit_init_closure_call(dasm_State          **Dst,
9920                                      const zend_op        *opline,
9921                                      uint32_t              b,
9922                                      const zend_op_array  *op_array,
9923                                      zend_ssa             *ssa,
9924                                      const zend_ssa_op    *ssa_op,
9925                                      int                   call_level,
9926                                      zend_jit_trace_rec   *trace,
9927                                      zend_bool             stack_check)
9928{
9929	zend_function *func = NULL;
9930	zend_jit_addr op2_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
9931
9932	|	GET_ZVAL_PTR r0, op2_addr
9933
9934	if (ssa->var_info[ssa_op->op2_use].ce != zend_ce_closure
9935	 && !(ssa->var_info[ssa_op->op2_use].type & MAY_BE_CLASS_GUARD)) {
9936		int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9937		const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9938
9939		if (!exit_addr) {
9940			return 0;
9941		}
9942
9943		|.if X64
9944		||	if (!IS_SIGNED_32BIT(zend_ce_closure)) {
9945		|		mov64 FCARG1a, ((ptrdiff_t)zend_ce_closure)
9946		|		cmp aword [r0 + offsetof(zend_object, ce)], FCARG1a
9947		||	} else {
9948		|		cmp aword [r0 + offsetof(zend_object, ce)], zend_ce_closure
9949		||	}
9950		|.else
9951		|	cmp aword [r0 + offsetof(zend_object, ce)], zend_ce_closure
9952		|.endif
9953		|	jne &exit_addr
9954		if (ssa->var_info && ssa_op->op2_use >= 0) {
9955			ssa->var_info[ssa_op->op2_use].type |= MAY_BE_CLASS_GUARD;
9956			ssa->var_info[ssa_op->op2_use].ce = zend_ce_closure;
9957			ssa->var_info[ssa_op->op2_use].is_instanceof = 0;
9958		}
9959	}
9960
9961	if (trace
9962	 && trace->op == ZEND_JIT_TRACE_INIT_CALL
9963	 && trace->func
9964	 && trace->func->type == ZEND_USER_FUNCTION) {
9965		const zend_op *opcodes;
9966		int32_t exit_point;
9967		const void *exit_addr;
9968
9969		func = (zend_function*)trace->func;
9970		opcodes = func->op_array.opcodes;
9971		exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_CLOSURE_CALL);
9972		exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9973		if (!exit_addr) {
9974			return 0;
9975		}
9976
9977		|   .if X64
9978		||		if (!IS_SIGNED_32BIT(opcodes)) {
9979		|			mov64 FCARG1a, ((ptrdiff_t)opcodes)
9980		|			cmp aword [r0 + offsetof(zend_closure, func.op_array.opcodes)], FCARG1a
9981		||		} else {
9982		|			cmp aword [r0 + offsetof(zend_closure, func.op_array.opcodes)], opcodes
9983		||		}
9984		|	.else
9985		|		cmp aword [r0 + offsetof(zend_closure, func.op_array.opcodes)], opcodes
9986		|	.endif
9987		|	jne &exit_addr
9988	}
9989
9990	if (delayed_call_chain) {
9991		if (!zend_jit_save_call_chain(Dst, delayed_call_level)) {
9992			return 0;
9993		}
9994	}
9995
9996	if (!zend_jit_push_call_frame(Dst, opline, NULL, func, 1, 0, stack_check)) {
9997		return 0;
9998	}
9999
10000	if (zend_jit_needs_call_chain(NULL, b, op_array, ssa, ssa_op, opline, call_level, trace)) {
10001		if (!zend_jit_save_call_chain(Dst, call_level)) {
10002			return 0;
10003		}
10004	} else {
10005		delayed_call_chain = 1;
10006		delayed_call_level = call_level;
10007	}
10008
10009	if (trace
10010	 && trace->op == ZEND_JIT_TRACE_END
10011	 && trace->stop == ZEND_JIT_TRACE_STOP_INTERPRETER) {
10012		if (!zend_jit_set_valid_ip(Dst, opline + 1)) {
10013			return 0;
10014		}
10015	}
10016
10017	return 1;
10018}
10019
10020static uint32_t skip_valid_arguments(const zend_op_array *op_array, zend_ssa *ssa, const zend_call_info *call_info)
10021{
10022	uint32_t num_args = 0;
10023	zend_function *func = call_info->callee_func;
10024
10025	while (num_args < call_info->num_args) {
10026		zend_arg_info *arg_info = func->op_array.arg_info + num_args;
10027
10028		if (ZEND_TYPE_IS_SET(arg_info->type)) {
10029			if (ZEND_TYPE_IS_ONLY_MASK(arg_info->type)) {
10030				zend_op *opline = call_info->arg_info[num_args].opline;
10031				zend_ssa_op *ssa_op = &ssa->ops[opline - op_array->opcodes];
10032				uint32_t type_mask = ZEND_TYPE_PURE_MASK(arg_info->type);
10033				if ((OP1_INFO() & (MAY_BE_ANY|MAY_BE_UNDEF)) & ~type_mask) {
10034					break;
10035				}
10036			} else {
10037				break;
10038			}
10039		}
10040		num_args++;
10041	}
10042	return num_args;
10043}
10044
10045static int zend_jit_do_fcall(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa, int call_level, unsigned int next_block, zend_jit_trace_rec *trace)
10046{
10047	zend_func_info *info = ZEND_FUNC_INFO(op_array);
10048	zend_call_info *call_info = NULL;
10049	const zend_function *func = NULL;
10050	uint32_t i;
10051	zend_jit_addr res_addr;
10052	uint32_t call_num_args = 0;
10053	zend_bool unknown_num_args = 0;
10054	const void *exit_addr = NULL;
10055	const zend_op *prev_opline;
10056
10057	if (RETURN_VALUE_USED(opline)) {
10058		res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
10059	} else {
10060		/* CPU stack allocated temporary zval */
10061		res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R4, TMP_ZVAL_OFFSET);
10062	}
10063
10064	prev_opline = opline - 1;
10065	while (prev_opline->opcode == ZEND_EXT_FCALL_BEGIN || prev_opline->opcode == ZEND_TICKS) {
10066		prev_opline--;
10067	}
10068	if (prev_opline->opcode == ZEND_SEND_UNPACK || prev_opline->opcode == ZEND_SEND_ARRAY ||
10069			prev_opline->opcode == ZEND_CHECK_UNDEF_ARGS) {
10070		unknown_num_args = 1;
10071	}
10072
10073	if (info) {
10074		call_info = info->callee_info;
10075		while (call_info && call_info->caller_call_opline != opline) {
10076			call_info = call_info->next_callee;
10077		}
10078		if (call_info && call_info->callee_func) {
10079			func = call_info->callee_func;
10080		}
10081		if ((op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)
10082		 && JIT_G(current_frame)
10083		 && JIT_G(current_frame)->call
10084		 && !JIT_G(current_frame)->call->func) {
10085			call_info = NULL; func = NULL; /* megamorphic call from trait */
10086		}
10087	}
10088	if (!func) {
10089		/* resolve function at run time */
10090	} else if (func->type == ZEND_USER_FUNCTION) {
10091		ZEND_ASSERT(opline->opcode != ZEND_DO_ICALL);
10092		call_num_args = call_info->num_args;
10093	} else if (func->type == ZEND_INTERNAL_FUNCTION) {
10094		ZEND_ASSERT(opline->opcode != ZEND_DO_UCALL);
10095		call_num_args = call_info->num_args;
10096	} else {
10097		ZEND_UNREACHABLE();
10098	}
10099
10100	if (trace && !func) {
10101		if (trace->op == ZEND_JIT_TRACE_DO_ICALL) {
10102			ZEND_ASSERT(trace->func->type == ZEND_INTERNAL_FUNCTION);
10103#ifndef ZEND_WIN32
10104			// TODO: ASLR may cause different addresses in different workers ???
10105			func = trace->func;
10106			if (JIT_G(current_frame) &&
10107			    JIT_G(current_frame)->call &&
10108			    TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call) >= 0) {
10109				call_num_args = TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call);
10110			} else {
10111				unknown_num_args = 1;
10112			}
10113#endif
10114		} else if (trace->op == ZEND_JIT_TRACE_ENTER) {
10115			ZEND_ASSERT(trace->func->type == ZEND_USER_FUNCTION);
10116			if (zend_accel_in_shm(trace->func->op_array.opcodes)) {
10117				func = trace->func;
10118				if (JIT_G(current_frame) &&
10119				    JIT_G(current_frame)->call &&
10120				    TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call) >= 0) {
10121					call_num_args = TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call);
10122				} else {
10123					unknown_num_args = 1;
10124				}
10125			}
10126		}
10127	}
10128
10129	bool may_have_extra_named_params =
10130		opline->extended_value == ZEND_FCALL_MAY_HAVE_EXTRA_NAMED_PARAMS &&
10131		(!func || func->common.fn_flags & ZEND_ACC_VARIADIC);
10132
10133	if (!reuse_ip) {
10134		zend_jit_start_reuse_ip();
10135		|	// call = EX(call);
10136		|	mov RX, EX->call
10137	}
10138	zend_jit_stop_reuse_ip();
10139
10140	|	// fbc = call->func;
10141	|	// mov r2, EX:RX->func ???
10142	|	// SAVE_OPLINE();
10143	|	SET_EX_OPLINE opline, r0
10144
10145	if (opline->opcode == ZEND_DO_FCALL) {
10146		if (!func) {
10147			if (trace) {
10148				uint32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
10149
10150				exit_addr = zend_jit_trace_get_exit_addr(exit_point);
10151				if (!exit_addr) {
10152					return 0;
10153				}
10154				|	mov r0, EX:RX->func
10155				|	test dword [r0 + offsetof(zend_op_array, fn_flags)], ZEND_ACC_DEPRECATED
10156				|	jnz &exit_addr
10157			}
10158		}
10159	}
10160
10161	if (!delayed_call_chain) {
10162		if (call_level == 1) {
10163			|	mov aword EX->call, 0
10164		} else {
10165			|	//EX(call) = call->prev_execute_data;
10166			|	mov r0, EX:RX->prev_execute_data
10167			|	mov EX->call, r0
10168		}
10169	}
10170	delayed_call_chain = 0;
10171
10172	|	//call->prev_execute_data = execute_data;
10173	|	mov EX:RX->prev_execute_data, EX
10174
10175	if (!func) {
10176		|	mov r0, EX:RX->func
10177	}
10178
10179	if (opline->opcode == ZEND_DO_FCALL) {
10180		if (!func) {
10181			if (!trace) {
10182				|	test dword [r0 + offsetof(zend_op_array, fn_flags)], ZEND_ACC_DEPRECATED
10183				|	jnz >1
10184				|.cold_code
10185				|1:
10186				if (!GCC_GLOBAL_REGS) {
10187					|	mov FCARG1a, RX
10188				}
10189				|	EXT_CALL zend_jit_deprecated_helper, r0
10190				|	test al, al
10191				|	mov r0, EX:RX->func // reload
10192				|	jne >1
10193				|	jmp ->exception_handler
10194				|.code
10195				|1:
10196			}
10197		} else if (func->common.fn_flags & ZEND_ACC_DEPRECATED) {
10198			if (!GCC_GLOBAL_REGS) {
10199				|	mov FCARG1a, RX
10200			}
10201			|	EXT_CALL zend_jit_deprecated_helper, r0
10202			|	test al, al
10203			|	je ->exception_handler
10204		}
10205	}
10206
10207	if (!func
10208	 && opline->opcode != ZEND_DO_UCALL
10209	 && opline->opcode != ZEND_DO_ICALL) {
10210		|	cmp byte [r0 + offsetof(zend_function, type)], ZEND_USER_FUNCTION
10211		|	jne >8
10212	}
10213
10214	if ((!func || func->type == ZEND_USER_FUNCTION)
10215	 && opline->opcode != ZEND_DO_ICALL) {
10216		|	// EX(call) = NULL;
10217		|	mov aword EX:RX->call, 0
10218
10219		if (RETURN_VALUE_USED(opline)) {
10220			|	// EX(return_value) = EX_VAR(opline->result.var);
10221			|	LOAD_ZVAL_ADDR r2, res_addr
10222			|	mov aword EX:RX->return_value, r2
10223		} else {
10224			|	// EX(return_value) = 0;
10225			|	mov aword EX:RX->return_value, 0
10226		}
10227
10228		//EX_LOAD_RUN_TIME_CACHE(op_array);
10229		if (!func || func->op_array.cache_size) {
10230			if (func && op_array == &func->op_array) {
10231				/* recursive call */
10232				if (trace || func->op_array.cache_size > sizeof(void*)) {
10233					|	mov r2, EX->run_time_cache
10234					|	mov EX:RX->run_time_cache, r2
10235				}
10236			} else {
10237				if (func) {
10238					|	mov r0, EX:RX->func
10239				}
10240				|	mov r2, aword [r0 + offsetof(zend_op_array, run_time_cache__ptr)]
10241#if ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR
10242				|	mov r2, aword [r2]
10243#elif ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR_OR_OFFSET
10244				if (func && !(func->op_array.fn_flags & ZEND_ACC_CLOSURE)) {
10245					if (ZEND_MAP_PTR_IS_OFFSET(func->op_array.run_time_cache)) {
10246						|	MEM_OP2_2_ZTS add, r2, aword, compiler_globals, map_ptr_base, r1
10247					} else if (!zend_accel_in_shm(func->op_array.opcodes)) {
10248						/* the called op_array may be not persisted yet */
10249						|	test r2, 1
10250						|	jz >1
10251						|	MEM_OP2_2_ZTS add, r2, aword, compiler_globals, map_ptr_base, r1
10252						|1:
10253					}
10254					|	mov r2, aword [r2]
10255				} else {
10256					|	test r2, 1
10257					|	jz >1
10258					|	MEM_OP2_2_ZTS add, r2, aword, compiler_globals, map_ptr_base, r1
10259					|1:
10260					|	mov r2, aword [r2]
10261				}
10262#else
10263# error "Unknown ZEND_MAP_PTR_KIND"
10264#endif
10265				|	mov EX:RX->run_time_cache, r2
10266			}
10267		}
10268
10269		|	// EG(current_execute_data) = execute_data;
10270		|	MEM_OP2_1_ZTS mov, aword, executor_globals, current_execute_data, RX, r1
10271		|	mov FP, RX
10272
10273		|	// opline = op_array->opcodes;
10274		if (func && !unknown_num_args) {
10275
10276			for (i = call_num_args; i < func->op_array.last_var; i++) {
10277				uint32_t n = EX_NUM_TO_VAR(i);
10278				|	SET_Z_TYPE_INFO RX + n, IS_UNDEF
10279			}
10280
10281			if (call_num_args <= func->op_array.num_args) {
10282				if (!trace || (trace->op == ZEND_JIT_TRACE_END
10283				 && trace->stop == ZEND_JIT_TRACE_STOP_INTERPRETER)) {
10284					uint32_t num_args;
10285
10286					if ((func->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0) {
10287						if (trace) {
10288							num_args = 0;
10289						} else if (call_info) {
10290							num_args = skip_valid_arguments(op_array, ssa, call_info);
10291						} else {
10292							num_args = call_num_args;
10293						}
10294					} else {
10295						num_args = call_num_args;
10296					}
10297					if (zend_accel_in_shm(func->op_array.opcodes)) {
10298						|	LOAD_IP_ADDR (func->op_array.opcodes + num_args)
10299					} else {
10300						|	mov r0, EX->func
10301						if (GCC_GLOBAL_REGS) {
10302							|	mov IP, aword [r0 + offsetof(zend_op_array, opcodes)]
10303							if (num_args) {
10304								|	add IP, (num_args * sizeof(zend_op))
10305							}
10306						} else {
10307							|	mov FCARG1a, aword [r0 + offsetof(zend_op_array, opcodes)]
10308							if (num_args) {
10309								|	add FCARG1a, (num_args * sizeof(zend_op))
10310							}
10311							|	mov aword EX->opline, FCARG1a
10312						}
10313					}
10314
10315					if (GCC_GLOBAL_REGS && !trace && op_array == &func->op_array
10316							&& num_args >= op_array->required_num_args) {
10317						/* recursive call */
10318						if (ZEND_OBSERVER_ENABLED) {
10319							|	SAVE_IP
10320							|	mov FCARG1a, FP
10321							|	EXT_CALL zend_observer_fcall_begin, r0
10322						}
10323#ifdef CONTEXT_THREADED_JIT
10324						|	call >1
10325						|.cold_code
10326						|1:
10327						|	pop r0
10328						|	jmp =>num_args
10329						|.code
10330#else
10331						|	jmp =>num_args
10332#endif
10333						return 1;
10334					}
10335				}
10336			} else {
10337				if (!trace || (trace->op == ZEND_JIT_TRACE_END
10338				 && trace->stop == ZEND_JIT_TRACE_STOP_INTERPRETER)) {
10339					if (func && zend_accel_in_shm(func->op_array.opcodes)) {
10340						|	LOAD_IP_ADDR (func->op_array.opcodes)
10341					} else if (GCC_GLOBAL_REGS) {
10342						|	mov IP, aword [r0 + offsetof(zend_op_array, opcodes)]
10343					} else {
10344						|	mov FCARG1a, aword [r0 + offsetof(zend_op_array, opcodes)]
10345						|	mov aword EX->opline, FCARG1a
10346					}
10347				}
10348				if (!GCC_GLOBAL_REGS) {
10349					|	mov FCARG1a, FP
10350				}
10351				|	EXT_CALL zend_jit_copy_extra_args_helper, r0
10352			}
10353		} else {
10354			|	// opline = op_array->opcodes
10355			if (func && zend_accel_in_shm(func->op_array.opcodes)) {
10356				|	LOAD_IP_ADDR (func->op_array.opcodes)
10357			} else if (GCC_GLOBAL_REGS) {
10358				|	mov IP, aword [r0 + offsetof(zend_op_array, opcodes)]
10359			} else {
10360				|	mov FCARG1a, aword [r0 + offsetof(zend_op_array, opcodes)]
10361				|	mov aword EX->opline, FCARG1a
10362			}
10363			if (func) {
10364				|	// num_args = EX_NUM_ARGS();
10365				|	mov ecx, dword [FP + offsetof(zend_execute_data, This.u2.num_args)]
10366				|	// if (UNEXPECTED(num_args > first_extra_arg))
10367				|	cmp ecx, (func->op_array.num_args)
10368			} else {
10369				|	// first_extra_arg = op_array->num_args;
10370				|	mov edx, dword [r0 + offsetof(zend_op_array, num_args)]
10371				|	// num_args = EX_NUM_ARGS();
10372				|	mov ecx, dword [FP + offsetof(zend_execute_data, This.u2.num_args)]
10373				|	// if (UNEXPECTED(num_args > first_extra_arg))
10374				|	cmp ecx, edx
10375			}
10376			|	jg >1
10377			|.cold_code
10378			|1:
10379			if (!GCC_GLOBAL_REGS) {
10380				|	mov FCARG1a, FP
10381			}
10382			|	EXT_CALL zend_jit_copy_extra_args_helper, r0
10383			if (!func) {
10384				|	mov r0, EX->func // reload
10385			}
10386			|	mov ecx, dword [FP + offsetof(zend_execute_data, This.u2.num_args)] // reload
10387			|	jmp >1
10388			|.code
10389			if (!func || (func->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0) {
10390				if (!func) {
10391					|	// if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0))
10392					|	test dword [r0 + offsetof(zend_op_array, fn_flags)], ZEND_ACC_HAS_TYPE_HINTS
10393					|	jnz >1
10394				}
10395				|	// opline += num_args;
10396				|.if X64
10397					||	ZEND_ASSERT(sizeof(zend_op) == 32);
10398					|	mov edx, ecx
10399					|	shl r2, 5
10400				|.else
10401					|	imul r2, ecx, sizeof(zend_op)
10402				|.endif
10403				|	ADD_IP r2
10404			}
10405			|1:
10406			|	// if (EXPECTED((int)num_args < op_array->last_var)) {
10407			if (func) {
10408				|	mov edx, (func->op_array.last_var)
10409			} else {
10410				|	mov edx, dword [r0 + offsetof(zend_op_array, last_var)]
10411			}
10412			|	sub edx, ecx
10413			|	jle >3 //???
10414			|	// zval *var = EX_VAR_NUM(num_args);
10415//			|.if X64
10416//				|	movsxd r1, ecx
10417//			|.endif
10418			|	shl r1, 4
10419			|	lea r1, [FP + r1 + (ZEND_CALL_FRAME_SLOT * sizeof(zval))]
10420			|2:
10421			|	SET_Z_TYPE_INFO r1, IS_UNDEF
10422			|	sub edx, 1
10423			|	lea r1, [r1 + 16]
10424			|	jne <2
10425			|3:
10426		}
10427
10428		if (ZEND_OBSERVER_ENABLED) {
10429			|	SAVE_IP
10430			|	mov FCARG1a, FP
10431			|	EXT_CALL zend_observer_fcall_begin, r0
10432		}
10433
10434		if (trace) {
10435			if (!func && (opline->opcode != ZEND_DO_UCALL)) {
10436				|	jmp >9
10437			}
10438		} else {
10439#ifdef CONTEXT_THREADED_JIT
10440			|	call ->context_threaded_call
10441			if (!func && (opline->opcode != ZEND_DO_UCALL)) {
10442				|	jmp >9
10443			}
10444			|	call ->context_threaded_call
10445			if (!func) {
10446				|	jmp >9
10447			}
10448#else
10449			if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
10450				|	ADD_HYBRID_SPAD
10451				|	JMP_IP
10452			} else if (GCC_GLOBAL_REGS) {
10453				|	add r4, SPAD // stack alignment
10454				|	JMP_IP
10455			} else {
10456				|	mov FP, aword T2 // restore FP
10457				|	mov RX, aword T3 // restore IP
10458				|	add r4, NR_SPAD // stack alignment
10459				|	mov r0, 1 // ZEND_VM_ENTER
10460				|	ret
10461			}
10462		}
10463#endif
10464	}
10465
10466	if ((!func || func->type == ZEND_INTERNAL_FUNCTION)
10467	 && (opline->opcode != ZEND_DO_UCALL)) {
10468		if (!func && (opline->opcode != ZEND_DO_ICALL)) {
10469			|8:
10470		}
10471		if (opline->opcode == ZEND_DO_FCALL_BY_NAME) {
10472			if (!func) {
10473				if (trace) {
10474					uint32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
10475
10476					exit_addr = zend_jit_trace_get_exit_addr(exit_point);
10477					if (!exit_addr) {
10478						return 0;
10479					}
10480					|	test dword [r0 + offsetof(zend_op_array, fn_flags)], ZEND_ACC_DEPRECATED
10481					|	jnz &exit_addr
10482				} else {
10483					|	test dword [r0 + offsetof(zend_op_array, fn_flags)], ZEND_ACC_DEPRECATED
10484					|	jnz >1
10485						|.cold_code
10486					|1:
10487					if (!GCC_GLOBAL_REGS) {
10488						|	mov FCARG1a, RX
10489					}
10490					|	EXT_CALL zend_jit_deprecated_helper, r0
10491					|	test al, al
10492					|	mov r0, EX:RX->func // reload
10493					|	jne >1
10494					|	jmp ->exception_handler
10495					|.code
10496					|1:
10497				}
10498			} else if (func->common.fn_flags & ZEND_ACC_DEPRECATED) {
10499				if (!GCC_GLOBAL_REGS) {
10500					|	mov FCARG1a, RX
10501				}
10502				|	EXT_CALL zend_jit_deprecated_helper, r0
10503				|	test al, al
10504				|	je ->exception_handler
10505				|	mov r0, EX:RX->func // reload
10506			}
10507		}
10508
10509		|	// ZVAL_NULL(EX_VAR(opline->result.var));
10510		|	LOAD_ZVAL_ADDR FCARG2a, res_addr
10511		|	SET_Z_TYPE_INFO FCARG2a, IS_NULL
10512
10513		|	// EG(current_execute_data) = execute_data;
10514		|	MEM_OP2_1_ZTS mov, aword, executor_globals, current_execute_data, RX, r1
10515
10516		zend_jit_reset_last_valid_opline();
10517
10518		|	// fbc->internal_function.handler(call, ret);
10519		|	mov FCARG1a, RX
10520		if (func) {
10521			|	EXT_CALL func->internal_function.handler, r0
10522		} else {
10523			|	call aword [r0 + offsetof(zend_internal_function, handler)]
10524		}
10525
10526		|	// EG(current_execute_data) = execute_data;
10527		|	MEM_OP2_1_ZTS mov, aword, executor_globals, current_execute_data, FP, r0
10528
10529		|	// zend_vm_stack_free_args(call);
10530		if (func && !unknown_num_args) {
10531			for (i = 0; i < call_num_args; i++ ) {
10532				uint32_t offset = EX_NUM_TO_VAR(i);
10533				|	ZVAL_PTR_DTOR ZEND_ADDR_MEM_ZVAL(ZREG_RX, offset), MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN, 0, 1, opline
10534			}
10535		} else {
10536			|	mov FCARG1a, RX
10537			|	EXT_CALL zend_jit_vm_stack_free_args_helper, r0
10538		}
10539		if (may_have_extra_named_params) {
10540			|	test byte [RX + offsetof(zend_execute_data, This.u1.type_info) + 3], (ZEND_CALL_HAS_EXTRA_NAMED_PARAMS >> 24)
10541			|	jnz >1
10542			|.cold_code
10543			|1:
10544			|	mov FCARG1a, aword [RX + offsetof(zend_execute_data, extra_named_params)]
10545			|	EXT_CALL zend_free_extra_named_params, r0
10546			|	jmp >2
10547			|.code
10548			|2:
10549		}
10550
10551		|8:
10552		if (opline->opcode == ZEND_DO_FCALL) {
10553			// TODO: optimize ???
10554			|	// if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS))
10555			|	test byte [RX + offsetof(zend_execute_data, This.u1.type_info) + 2], (ZEND_CALL_RELEASE_THIS >> 16)
10556			|	jnz >1
10557			|.cold_code
10558			|1:
10559			|	GET_Z_PTR FCARG1a, RX + offsetof(zend_execute_data, This)
10560			|	// OBJ_RELEASE(object);
10561			|	OBJ_RELEASE ZREG_FCARG1a, >2
10562			|	jmp >2
10563			|.code
10564			|2:
10565		}
10566
10567		if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
10568		    !JIT_G(current_frame) ||
10569		    !JIT_G(current_frame)->call ||
10570		    !TRACE_FRAME_IS_NESTED(JIT_G(current_frame)->call) ||
10571		    prev_opline->opcode == ZEND_SEND_UNPACK ||
10572		    prev_opline->opcode == ZEND_SEND_ARRAY ||
10573			prev_opline->opcode == ZEND_CHECK_UNDEF_ARGS) {
10574
10575			|	// zend_vm_stack_free_call_frame(call);
10576			|	test byte [RX + offsetof(zend_execute_data, This.u1.type_info) + 2], (ZEND_CALL_ALLOCATED >> 16)
10577			|	jnz >1
10578			|.cold_code
10579			|1:
10580			|	mov FCARG1a, RX
10581			|	EXT_CALL zend_jit_free_call_frame, r0
10582			|	jmp >1
10583			|.code
10584		}
10585		|	MEM_OP2_1_ZTS mov, aword, executor_globals, vm_stack_top, RX, r0
10586		|1:
10587
10588		if (!RETURN_VALUE_USED(opline)) {
10589			zend_class_entry *ce;
10590			zend_bool ce_is_instanceof;
10591			uint32_t func_info = call_info ?
10592				zend_get_func_info(call_info, ssa, &ce, &ce_is_instanceof) :
10593				(MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN);
10594
10595			/* If an exception is thrown, the return_value may stay at the
10596			 * original value of null. */
10597			func_info |= MAY_BE_NULL;
10598
10599			if (func_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
10600				|	ZVAL_PTR_DTOR res_addr, func_info, 1, 1, opline
10601			}
10602		}
10603
10604		|	// if (UNEXPECTED(EG(exception) != NULL)) {
10605		|	MEM_OP2_1_ZTS cmp, aword, executor_globals, exception, 0, r0
10606		|	jne ->icall_throw_handler
10607
10608		// TODO: Can we avoid checking for interrupts after each call ???
10609		if (trace && last_valid_opline != opline) {
10610			int32_t exit_point = zend_jit_trace_get_exit_point(opline + 1, ZEND_JIT_EXIT_TO_VM);
10611
10612			exit_addr = zend_jit_trace_get_exit_addr(exit_point);
10613			if (!exit_addr) {
10614				return 0;
10615			}
10616		} else {
10617			exit_addr = NULL;
10618		}
10619		if (!zend_jit_check_timeout(Dst, opline + 1, exit_addr)) {
10620			return 0;
10621		}
10622
10623		if ((!trace || !func) && opline->opcode != ZEND_DO_ICALL) {
10624			|	LOAD_IP_ADDR (opline + 1)
10625		} else if (trace
10626		 && trace->op == ZEND_JIT_TRACE_END
10627		 && trace->stop == ZEND_JIT_TRACE_STOP_INTERPRETER) {
10628			|	LOAD_IP_ADDR (opline + 1)
10629		}
10630	}
10631
10632	if (!func) {
10633		|9:
10634	}
10635
10636	return 1;
10637}
10638
10639static int zend_jit_send_val(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr)
10640{
10641	uint32_t arg_num = opline->op2.num;
10642	zend_jit_addr arg_addr;
10643
10644	ZEND_ASSERT(opline->opcode == ZEND_SEND_VAL || arg_num <= MAX_ARG_FLAG_NUM);
10645
10646	if (!zend_jit_reuse_ip(Dst)) {
10647		return 0;
10648	}
10649
10650	if (opline->opcode == ZEND_SEND_VAL_EX) {
10651		uint32_t mask = ZEND_SEND_BY_REF << ((arg_num + 3) * 2);
10652
10653		ZEND_ASSERT(arg_num <= MAX_ARG_FLAG_NUM);
10654
10655		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
10656		 && JIT_G(current_frame)
10657		 && JIT_G(current_frame)->call
10658		 && JIT_G(current_frame)->call->func) {
10659			if (ARG_MUST_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
10660				/* Don't generate code that always throws exception */
10661				return 0;
10662			}
10663		} else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
10664			int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
10665			const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
10666			if (!exit_addr) {
10667				return 0;
10668			}
10669			|	mov r0, EX:RX->func
10670			|	test dword [r0 + offsetof(zend_function, quick_arg_flags)], mask
10671			|	jnz &exit_addr
10672		} else {
10673			|	mov r0, EX:RX->func
10674			|	test dword [r0 + offsetof(zend_function, quick_arg_flags)], mask
10675			|	jnz >1
10676			|.cold_code
10677			|1:
10678			|	SET_EX_OPLINE opline, r0
10679			|	jmp ->throw_cannot_pass_by_ref
10680			|.code
10681
10682		}
10683	}
10684
10685	arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, opline->result.var);
10686
10687	if (opline->op1_type == IS_CONST) {
10688		zval *zv = RT_CONSTANT(opline, opline->op1);
10689
10690		|	ZVAL_COPY_CONST arg_addr, MAY_BE_ANY, MAY_BE_ANY, zv, ZREG_R0
10691		if (Z_REFCOUNTED_P(zv)) {
10692			|	ADDREF_CONST zv, r0
10693		}
10694	} else {
10695		|	ZVAL_COPY_VALUE arg_addr, MAY_BE_ANY, op1_addr, op1_info, ZREG_R0, ZREG_R2
10696	}
10697
10698	return 1;
10699}
10700
10701static int zend_jit_check_undef_args(dasm_State **Dst, const zend_op *opline)
10702{
10703	|	mov FCARG1a, EX->call
10704	|	test byte [FCARG1a + offsetof(zend_execute_data, This.u1.type_info) + 3], (ZEND_CALL_MAY_HAVE_UNDEF >> 24)
10705	|	jnz >1
10706	|.cold_code
10707	|1:
10708	|	SET_EX_OPLINE opline, r0
10709	|	EXT_CALL zend_handle_undef_args, r0
10710	|	test r0, r0
10711	|	jnz ->exception_handler
10712	|	jmp >2
10713	|.code
10714	|2:
10715
10716	return 1;
10717}
10718
10719static int zend_jit_send_ref(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, int cold)
10720{
10721	zend_jit_addr op1_addr, arg_addr, ref_addr;
10722
10723	op1_addr = OP1_ADDR();
10724	arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, opline->result.var);
10725
10726	if (!zend_jit_reuse_ip(Dst)) {
10727		return 0;
10728	}
10729
10730	if (opline->op1_type == IS_VAR) {
10731		if (op1_info & MAY_BE_INDIRECT) {
10732			|	LOAD_ZVAL_ADDR r0, op1_addr
10733			|	// if (EXPECTED(Z_TYPE_P(ret) == IS_INDIRECT)) {
10734			|	IF_NOT_Z_TYPE r0, IS_INDIRECT, >1
10735			|	// ret = Z_INDIRECT_P(ret);
10736			|	GET_Z_PTR r0, r0
10737			|1:
10738			op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0);
10739		}
10740	} else if (opline->op1_type == IS_CV) {
10741		if (op1_info & MAY_BE_UNDEF) {
10742			if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
10743				|	IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >1
10744				|	SET_ZVAL_TYPE_INFO op1_addr, IS_NULL
10745				|	jmp >2
10746				|1:
10747			}
10748			op1_info &= ~MAY_BE_UNDEF;
10749			op1_info |= MAY_BE_NULL;
10750		}
10751	} else {
10752		ZEND_UNREACHABLE();
10753	}
10754
10755	if (op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) {
10756		if (op1_info & MAY_BE_REF) {
10757			|	IF_NOT_ZVAL_TYPE op1_addr, IS_REFERENCE, >2
10758			|	GET_ZVAL_PTR r1, op1_addr
10759			|	GC_ADDREF r1
10760			|	SET_ZVAL_PTR arg_addr, r1
10761			|	SET_ZVAL_TYPE_INFO arg_addr, IS_REFERENCE_EX
10762			|	jmp >6
10763		}
10764		|2:
10765		|	// ZVAL_NEW_REF(arg, varptr);
10766		if (opline->op1_type == IS_VAR) {
10767			if (Z_REG(op1_addr) != ZREG_R0 || Z_OFFSET(op1_addr) != 0) {
10768				|	LOAD_ZVAL_ADDR r0, op1_addr
10769			}
10770			|	mov aword T1, r0 // save
10771		}
10772		|	EMALLOC sizeof(zend_reference), op_array, opline
10773		|	mov dword [r0], 2
10774		|	mov dword [r0 + offsetof(zend_reference, gc.u.type_info)], GC_REFERENCE
10775		|	mov aword [r0 + offsetof(zend_reference, sources.ptr)], 0
10776		ref_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R0, offsetof(zend_reference, val));
10777		if (opline->op1_type == IS_VAR) {
10778			zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R1, 0);
10779
10780			|	mov r1, aword T1 // restore
10781			|	ZVAL_COPY_VALUE ref_addr, MAY_BE_ANY, val_addr, op1_info, ZREG_R2, ZREG_R2
10782			|	SET_ZVAL_PTR val_addr, r0
10783			|	SET_ZVAL_TYPE_INFO val_addr, IS_REFERENCE_EX
10784		} else {
10785			|	ZVAL_COPY_VALUE ref_addr, MAY_BE_ANY, op1_addr, op1_info, ZREG_R1, ZREG_R2
10786			|	SET_ZVAL_PTR op1_addr, r0
10787			|	SET_ZVAL_TYPE_INFO op1_addr, IS_REFERENCE_EX
10788		}
10789		|	SET_ZVAL_PTR arg_addr, r0
10790		|	SET_ZVAL_TYPE_INFO arg_addr, IS_REFERENCE_EX
10791	}
10792
10793	|6:
10794	|	FREE_OP opline->op1_type, opline->op1, op1_info, !cold, opline
10795	|7:
10796
10797	return 1;
10798}
10799
10800static int zend_jit_send_var(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr op1_def_addr)
10801{
10802	uint32_t arg_num = opline->op2.num;
10803	zend_jit_addr arg_addr;
10804
10805	ZEND_ASSERT((opline->opcode != ZEND_SEND_VAR_EX &&
10806	     opline->opcode != ZEND_SEND_VAR_NO_REF_EX) ||
10807	    arg_num <= MAX_ARG_FLAG_NUM);
10808
10809	arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, opline->result.var);
10810
10811	if (!zend_jit_reuse_ip(Dst)) {
10812		return 0;
10813	}
10814
10815	if (opline->opcode == ZEND_SEND_VAR_EX) {
10816		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
10817		 && JIT_G(current_frame)
10818		 && JIT_G(current_frame)->call
10819		 && JIT_G(current_frame)->call->func) {
10820			if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
10821				if (!zend_jit_send_ref(Dst, opline, op_array, op1_info, 0)) {
10822					return 0;
10823				}
10824				return 1;
10825			}
10826		} else {
10827			uint32_t mask = (ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) << ((arg_num + 3) * 2);
10828
10829			|	mov r0, EX:RX->func
10830			|	test dword [r0 + offsetof(zend_function, quick_arg_flags)], mask
10831			|	jnz >1
10832			|.cold_code
10833			|1:
10834			if (!zend_jit_send_ref(Dst, opline, op_array, op1_info, 1)) {
10835				return 0;
10836			}
10837			|	jmp >7
10838			|.code
10839		}
10840	} else if (opline->opcode == ZEND_SEND_VAR_NO_REF_EX) {
10841		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
10842		 && JIT_G(current_frame)
10843		 && JIT_G(current_frame)->call
10844		 && JIT_G(current_frame)->call->func) {
10845			if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
10846
10847				|	ZVAL_COPY_VALUE arg_addr, MAY_BE_ANY, op1_addr, op1_info, ZREG_R1, ZREG_R2
10848
10849				if (!ARG_MAY_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
10850					if (!(op1_info & MAY_BE_REF)) {
10851						/* Don't generate code that always throws exception */
10852						return 0;
10853					} else {
10854						int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
10855						const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
10856						if (!exit_addr) {
10857							return 0;
10858						}
10859						|	cmp cl, IS_REFERENCE
10860						|	jne &exit_addr
10861					}
10862				}
10863				return 1;
10864			}
10865		} else {
10866			uint32_t mask = (ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) << ((arg_num + 3) * 2);
10867
10868			|	mov r0, EX:RX->func
10869			|	test dword [r0 + offsetof(zend_function, quick_arg_flags)], mask
10870			|	jnz >1
10871			|.cold_code
10872			|1:
10873
10874			mask = ZEND_SEND_PREFER_REF << ((arg_num + 3) * 2);
10875
10876			|	ZVAL_COPY_VALUE arg_addr, MAY_BE_ANY, op1_addr, op1_info, ZREG_R1, ZREG_R2
10877			if (op1_info & MAY_BE_REF) {
10878				|	cmp cl, IS_REFERENCE
10879				|	je >7
10880			}
10881			|	test dword [r0 + offsetof(zend_function, quick_arg_flags)], mask
10882			|	jnz >7
10883			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
10884				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
10885				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
10886				if (!exit_addr) {
10887					return 0;
10888				}
10889				|	jmp &exit_addr
10890			} else {
10891				|	SET_EX_OPLINE opline, r0
10892				|	LOAD_ZVAL_ADDR FCARG1a, arg_addr
10893				|	EXT_CALL zend_jit_only_vars_by_reference, r0
10894				if (!zend_jit_check_exception(Dst)) {
10895					return 0;
10896				}
10897				|	jmp >7
10898			}
10899
10900			|.code
10901		}
10902	} else if (opline->opcode == ZEND_SEND_FUNC_ARG) {
10903		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
10904		 && JIT_G(current_frame)
10905		 && JIT_G(current_frame)->call
10906		 && JIT_G(current_frame)->call->func) {
10907			if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
10908				if (!zend_jit_send_ref(Dst, opline, op_array, op1_info, 0)) {
10909					return 0;
10910				}
10911				return 1;
10912			}
10913		} else {
10914			|	test dword [RX + offsetof(zend_execute_data, This.u1.type_info)], ZEND_CALL_SEND_ARG_BY_REF
10915			|	jnz >1
10916			|.cold_code
10917			|1:
10918			if (!zend_jit_send_ref(Dst, opline, op_array, op1_info, 1)) {
10919				return 0;
10920			}
10921			|	jmp >7
10922			|.code
10923		}
10924	}
10925
10926	if (op1_info & MAY_BE_UNDEF) {
10927		if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
10928			|	IF_ZVAL_TYPE op1_addr, IS_UNDEF, >1
10929			|.cold_code
10930			|1:
10931		}
10932
10933		|	SET_EX_OPLINE opline, r0
10934		|	mov FCARG1d, opline->op1.var
10935		|	EXT_CALL zend_jit_undefined_op_helper, r0
10936		|	SET_ZVAL_TYPE_INFO arg_addr, IS_NULL
10937		|	test r0, r0
10938		|	jz ->exception_handler
10939
10940		if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
10941			|	jmp >7
10942			|.code
10943		} else {
10944			|7:
10945			return 1;
10946		}
10947	}
10948
10949	if (opline->opcode == ZEND_SEND_VAR_NO_REF) {
10950		|	ZVAL_COPY_VALUE arg_addr, MAY_BE_ANY, op1_addr, op1_info, ZREG_R1, ZREG_R2
10951		if (op1_info & MAY_BE_REF) {
10952			|	cmp cl, IS_REFERENCE
10953			|	je >7
10954		}
10955		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
10956			int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
10957			const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
10958			if (!exit_addr) {
10959				return 0;
10960			}
10961			|	jmp &exit_addr
10962		} else {
10963			|	SET_EX_OPLINE opline, r0
10964			|	LOAD_ZVAL_ADDR FCARG1a, arg_addr
10965			|	EXT_CALL zend_jit_only_vars_by_reference, r0
10966			if (!zend_jit_check_exception(Dst)) {
10967				return 0;
10968			}
10969		}
10970	} else {
10971		if (op1_info & MAY_BE_REF) {
10972			if (opline->op1_type == IS_CV) {
10973				zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
10974
10975				|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
10976				|	ZVAL_DEREF FCARG1a, op1_info
10977				|	ZVAL_COPY_VALUE arg_addr, MAY_BE_ANY, val_addr, op1_info, ZREG_R0, ZREG_R2
10978				|	TRY_ADDREF op1_info, ah, r2
10979			} else {
10980				zend_jit_addr ref_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 8);
10981
10982				|	IF_ZVAL_TYPE op1_addr, IS_REFERENCE, >1
10983				|.cold_code
10984				|1:
10985				|	// zend_refcounted *ref = Z_COUNTED_P(retval_ptr);
10986				|	GET_ZVAL_PTR FCARG1a, op1_addr
10987				|	// ZVAL_COPY_VALUE(return_value, &ref->value);
10988				|	ZVAL_COPY_VALUE arg_addr, MAY_BE_ANY, ref_addr, op1_info, ZREG_R0, ZREG_R2
10989				|	GC_DELREF FCARG1a
10990				|	je >1
10991				|	IF_NOT_REFCOUNTED ah, >2
10992				|	GC_ADDREF r2
10993				|	jmp >2
10994				|1:
10995				|	EFREE_REG_REFERENCE
10996				|	jmp >2
10997				|.code
10998				|	ZVAL_COPY_VALUE arg_addr, MAY_BE_ANY, op1_addr, op1_info, ZREG_R0, ZREG_R2
10999				|2:
11000			}
11001		} else {
11002			if (op1_addr != op1_def_addr) {
11003				if (!zend_jit_update_regs(Dst, opline->op1.var, op1_addr, op1_def_addr, op1_info)) {
11004					return 0;
11005				}
11006				if (Z_MODE(op1_def_addr) == IS_REG && Z_MODE(op1_addr) != IS_REG) {
11007					op1_addr= op1_def_addr;
11008				}
11009			}
11010			|	ZVAL_COPY_VALUE arg_addr, MAY_BE_ANY, op1_addr, op1_info, ZREG_R0, ZREG_R2
11011			if (opline->op1_type == IS_CV) {
11012				|	TRY_ADDREF op1_info, ah, r2
11013			}
11014		}
11015	}
11016	|7:
11017
11018	return 1;
11019}
11020
11021static int zend_jit_check_func_arg(dasm_State **Dst, const zend_op *opline)
11022{
11023	uint32_t arg_num = opline->op2.num;
11024
11025	if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
11026	 && JIT_G(current_frame)
11027	 && JIT_G(current_frame)->call
11028	 && JIT_G(current_frame)->call->func) {
11029		if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
11030			if (!TRACE_FRAME_IS_LAST_SEND_BY_REF(JIT_G(current_frame)->call)) {
11031				TRACE_FRAME_SET_LAST_SEND_BY_REF(JIT_G(current_frame)->call);
11032				|	// ZEND_ADD_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
11033				||	if (reuse_ip) {
11034				|		or dword [RX + offsetof(zend_execute_data, This.u1.type_info)], ZEND_CALL_SEND_ARG_BY_REF
11035				||	} else {
11036				|		mov r0, EX->call
11037				|		or dword [r0 + offsetof(zend_execute_data, This.u1.type_info)], ZEND_CALL_SEND_ARG_BY_REF
11038				||	}
11039			}
11040		} else {
11041			if (!TRACE_FRAME_IS_LAST_SEND_BY_VAL(JIT_G(current_frame)->call)) {
11042				TRACE_FRAME_SET_LAST_SEND_BY_VAL(JIT_G(current_frame)->call);
11043				|	// ZEND_DEL_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
11044				||	if (reuse_ip) {
11045				|		and dword [RX + offsetof(zend_execute_data, This.u1.type_info)], ~ZEND_CALL_SEND_ARG_BY_REF
11046				||	} else {
11047				|		mov r0, EX->call
11048				|		and dword [r0 + offsetof(zend_execute_data, This.u1.type_info)], ~ZEND_CALL_SEND_ARG_BY_REF
11049				||	}
11050			}
11051		}
11052	} else {
11053		// if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
11054		uint32_t mask = (ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) << ((arg_num + 3) * 2);
11055
11056		if (!zend_jit_reuse_ip(Dst)) {
11057			return 0;
11058		}
11059
11060		|	mov r0, EX:RX->func
11061		|	test dword [r0 + offsetof(zend_function, quick_arg_flags)], mask
11062		|	jnz >1
11063		|.cold_code
11064		|1:
11065		|	// ZEND_ADD_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
11066		|	or dword [RX + offsetof(zend_execute_data, This.u1.type_info)], ZEND_CALL_SEND_ARG_BY_REF
11067		|	jmp >1
11068		|.code
11069		|	// ZEND_DEL_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
11070		|	and dword [RX + offsetof(zend_execute_data, This.u1.type_info)], ~ZEND_CALL_SEND_ARG_BY_REF
11071		|1:
11072	}
11073
11074	return 1;
11075}
11076
11077static int zend_jit_smart_true(dasm_State **Dst, const zend_op *opline, int jmp, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2)
11078{
11079	if (smart_branch_opcode) {
11080		if (smart_branch_opcode == ZEND_JMPZ) {
11081			if (jmp) {
11082				|	jmp >7
11083			}
11084		} else if (smart_branch_opcode == ZEND_JMPNZ) {
11085			|	jmp =>target_label
11086		} else if (smart_branch_opcode == ZEND_JMPZNZ) {
11087			|	jmp =>target_label2
11088		} else {
11089			ZEND_UNREACHABLE();
11090		}
11091	} else {
11092		zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
11093
11094		|	SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
11095		if (jmp) {
11096			|	jmp >7
11097		}
11098	}
11099
11100	return 1;
11101}
11102
11103static int zend_jit_smart_false(dasm_State **Dst, const zend_op *opline, int jmp, zend_uchar smart_branch_opcode, uint32_t target_label)
11104{
11105	if (smart_branch_opcode) {
11106		if (smart_branch_opcode == ZEND_JMPZ) {
11107			|	jmp =>target_label
11108		} else if (smart_branch_opcode == ZEND_JMPNZ) {
11109			if (jmp) {
11110				|	jmp >7
11111			}
11112		} else if (smart_branch_opcode == ZEND_JMPZNZ) {
11113			|	jmp =>target_label
11114		} else {
11115			ZEND_UNREACHABLE();
11116		}
11117	} else {
11118		zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
11119
11120		|	SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
11121		if (jmp) {
11122			|	jmp >7
11123		}
11124	}
11125
11126	return 1;
11127}
11128
11129static int zend_jit_defined(dasm_State **Dst, const zend_op *opline, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
11130{
11131	uint32_t defined_label = (uint32_t)-1;
11132	uint32_t undefined_label = (uint32_t)-1;
11133	zval *zv = RT_CONSTANT(opline, opline->op1);
11134	zend_jit_addr res_addr = 0;
11135
11136	if (smart_branch_opcode && !exit_addr) {
11137		if (smart_branch_opcode == ZEND_JMPZ) {
11138			undefined_label = target_label;
11139		} else if (smart_branch_opcode == ZEND_JMPNZ) {
11140			defined_label = target_label;
11141		} else if (smart_branch_opcode == ZEND_JMPZNZ) {
11142			undefined_label = target_label;
11143			defined_label = target_label2;
11144		} else {
11145			ZEND_UNREACHABLE();
11146		}
11147	}
11148
11149	|	// if (CACHED_PTR(opline->extended_value)) {
11150	|	mov r0, EX->run_time_cache
11151	|	mov r0, aword [r0 + opline->extended_value]
11152	|	test r0, r0
11153	|	jz >1
11154	|	test r0, 0x1
11155	|	jnz >4
11156	|.cold_code
11157	|4:
11158	|	MEM_OP2_2_ZTS mov, FCARG1a, aword, executor_globals, zend_constants, FCARG1a
11159	|	shr r0, 1
11160	|	cmp dword [FCARG1a + offsetof(HashTable, nNumOfElements)], eax
11161
11162	if (smart_branch_opcode) {
11163		if (exit_addr) {
11164			if (smart_branch_opcode == ZEND_JMPZ) {
11165				|	jz &exit_addr
11166			} else {
11167				|	jz >3
11168			}
11169		} else if (undefined_label != (uint32_t)-1) {
11170			|	jz =>undefined_label
11171		} else {
11172			|	jz >3
11173		}
11174	} else {
11175		|	jz >2
11176	}
11177	|1:
11178	|	SET_EX_OPLINE opline, r0
11179	|	LOAD_ADDR FCARG1a, zv
11180	|	EXT_CALL zend_jit_check_constant, r0
11181	|	test r0, r0
11182	if (exit_addr) {
11183		if (smart_branch_opcode == ZEND_JMPNZ) {
11184			|	jz >3
11185		} else {
11186			|	jnz >3
11187		}
11188		|	jmp &exit_addr
11189	} else if (smart_branch_opcode) {
11190		if (undefined_label != (uint32_t)-1) {
11191			|	jz =>undefined_label
11192		} else {
11193			|	jz >3
11194		}
11195		if (defined_label != (uint32_t)-1) {
11196			|	jmp =>defined_label
11197		} else {
11198			|	jmp >3
11199		}
11200	} else {
11201		res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
11202		|	jnz >1
11203		|2:
11204		|	SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
11205		|	jmp >3
11206	}
11207	|.code
11208	if (smart_branch_opcode) {
11209		if (exit_addr) {
11210			if (smart_branch_opcode == ZEND_JMPNZ) {
11211				|	jmp &exit_addr
11212			}
11213		} else if (defined_label != (uint32_t)-1) {
11214			|	jmp =>defined_label
11215		}
11216	} else {
11217		|1:
11218		|	SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
11219	}
11220	|3:
11221
11222	return 1;
11223}
11224
11225static int zend_jit_type_check(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
11226{
11227	uint32_t  mask;
11228	zend_uchar type;
11229	zend_jit_addr op1_addr = OP1_ADDR();
11230
11231	// TODO: support for is_resource() ???
11232	ZEND_ASSERT(opline->extended_value != MAY_BE_RESOURCE);
11233
11234	if (op1_info & MAY_BE_UNDEF) {
11235		if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
11236			|	IF_ZVAL_TYPE op1_addr, IS_UNDEF, >1
11237			|.cold_code
11238			|1:
11239		}
11240		|	SET_EX_OPLINE opline, r0
11241		|	mov FCARG1d, opline->op1.var
11242		|	EXT_CALL zend_jit_undefined_op_helper, r0
11243		zend_jit_check_exception_undef_result(Dst, opline);
11244		if (opline->extended_value & MAY_BE_NULL) {
11245			if (exit_addr) {
11246				if (smart_branch_opcode == ZEND_JMPNZ) {
11247					|	jmp &exit_addr
11248				} else if ((op1_info & (MAY_BE_ANY|MAY_BE_REF)) != 0) {
11249					|	jmp >7
11250				}
11251			} else if (!zend_jit_smart_true(Dst, opline, (op1_info & (MAY_BE_ANY|MAY_BE_REF)) != 0, smart_branch_opcode, target_label, target_label2)) {
11252				return 0;
11253			}
11254		} else {
11255			if (exit_addr) {
11256				if (smart_branch_opcode == ZEND_JMPZ) {
11257					|	jmp &exit_addr
11258				} else if ((op1_info & (MAY_BE_ANY|MAY_BE_REF)) != 0) {
11259					|	jmp >7
11260				}
11261			} else if (!zend_jit_smart_false(Dst, opline, (op1_info & (MAY_BE_ANY|MAY_BE_REF)) != 0, smart_branch_opcode, target_label)) {
11262				return 0;
11263			}
11264		}
11265		if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
11266			|.code
11267		}
11268	}
11269
11270	if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
11271		mask = opline->extended_value;
11272		switch (mask) {
11273			case MAY_BE_NULL:   type = IS_NULL;   break;
11274			case MAY_BE_FALSE:  type = IS_FALSE;  break;
11275			case MAY_BE_TRUE:   type = IS_TRUE;   break;
11276			case MAY_BE_LONG:   type = IS_LONG;   break;
11277			case MAY_BE_DOUBLE: type = IS_DOUBLE; break;
11278			case MAY_BE_STRING: type = IS_STRING; break;
11279			case MAY_BE_ARRAY:  type = IS_ARRAY;  break;
11280			case MAY_BE_OBJECT: type = IS_OBJECT; break;
11281			default:
11282				type = 0;
11283		}
11284
11285		if (!(op1_info & MAY_BE_GUARD) && !(op1_info & (MAY_BE_ANY - mask))) {
11286			|	FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline
11287			if (exit_addr) {
11288				if (smart_branch_opcode == ZEND_JMPNZ) {
11289					|	jmp &exit_addr
11290				}
11291			} else if (!zend_jit_smart_true(Dst, opline, 0, smart_branch_opcode, target_label, target_label2)) {
11292				return 0;
11293			}
11294	    } else if (!(op1_info & MAY_BE_GUARD) && !(op1_info & mask)) {
11295			|	FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline
11296			if (exit_addr) {
11297				if (smart_branch_opcode == ZEND_JMPZ) {
11298					|	jmp &exit_addr
11299				}
11300			} else if (!zend_jit_smart_false(Dst, opline, 0, smart_branch_opcode, target_label)) {
11301				return 0;
11302			}
11303		} else {
11304			if (op1_info & MAY_BE_REF) {
11305				|	LOAD_ZVAL_ADDR r0, op1_addr
11306				|	ZVAL_DEREF r0, op1_info
11307			}
11308			if (type == 0) {
11309				if (smart_branch_opcode &&
11310				    (opline->op1_type & (IS_VAR|IS_TMP_VAR)) &&
11311				    (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11312					if ((op1_info) & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11313						|	// if (Z_REFCOUNTED_P(cv)) {
11314						|	IF_ZVAL_REFCOUNTED op1_addr, >1
11315						|.cold_code
11316						|1:
11317					}
11318					|	// if (!Z_DELREF_P(cv)) {
11319					|	GET_ZVAL_PTR FCARG1a, op1_addr
11320					|	GC_DELREF FCARG1a
11321					if (RC_MAY_BE_1(op1_info)) {
11322						if (RC_MAY_BE_N(op1_info)) {
11323							|	jnz >3
11324						}
11325						if (op1_info & MAY_BE_REF) {
11326							|	mov al, byte [r0 + 8]
11327						} else {
11328							|	mov al, byte [FP + opline->op1.var + 8]
11329						}
11330						|	mov byte T1, al // save
11331						|	// zval_dtor_func(r);
11332						|	ZVAL_DTOR_FUNC op1_info, opline
11333						|	mov cl, byte T1 // restore
11334						|jmp >2
11335					}
11336					if ((op1_info) & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11337						if (!RC_MAY_BE_1(op1_info)) {
11338							|	jmp >3
11339						}
11340						|.code
11341					}
11342					|3:
11343					if (op1_info & MAY_BE_REF) {
11344						|	mov cl, byte [r0 + 8]
11345					} else {
11346						|	mov cl, byte [FP + opline->op1.var + 8]
11347					}
11348					|2:
11349				} else {
11350					if (op1_info & MAY_BE_REF) {
11351						|	mov cl, byte [r0 + 8]
11352					} else {
11353						|	mov cl, byte [FP + opline->op1.var + 8]
11354					}
11355				}
11356				|	mov eax, 1
11357				|	shl eax, cl
11358				|	test eax, mask
11359				if (exit_addr) {
11360					if (smart_branch_opcode == ZEND_JMPNZ) {
11361						|	jne &exit_addr
11362					} else {
11363						|	je &exit_addr
11364					}
11365				} else if (smart_branch_opcode) {
11366					if (smart_branch_opcode == ZEND_JMPZ) {
11367						|	je =>target_label
11368					} else if (smart_branch_opcode == ZEND_JMPNZ) {
11369						|	jne =>target_label
11370					} else if (smart_branch_opcode == ZEND_JMPZNZ) {
11371						|	je =>target_label
11372						|	jmp =>target_label2
11373					} else {
11374						ZEND_UNREACHABLE();
11375					}
11376				} else {
11377					zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
11378
11379					|	setne al
11380					|	movzx eax, al
11381					|	add eax, 2
11382					|	SET_ZVAL_TYPE_INFO res_addr, eax
11383					|	FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline
11384				}
11385			} else {
11386				if (smart_branch_opcode &&
11387				    (opline->op1_type & (IS_VAR|IS_TMP_VAR)) &&
11388				    (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11389					if ((op1_info) & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11390						|	// if (Z_REFCOUNTED_P(cv)) {
11391						|	IF_ZVAL_REFCOUNTED op1_addr, >1
11392						|.cold_code
11393						|1:
11394					}
11395					|	// if (!Z_DELREF_P(cv)) {
11396					|	GET_ZVAL_PTR FCARG1a, op1_addr
11397					|	GC_DELREF FCARG1a
11398					if (RC_MAY_BE_1(op1_info)) {
11399						if (RC_MAY_BE_N(op1_info)) {
11400							|	jnz >3
11401						}
11402						if (op1_info & MAY_BE_REF) {
11403							|	mov al, byte [r0 + 8]
11404						} else {
11405							|	mov al, byte [FP + opline->op1.var + 8]
11406						}
11407						|	mov byte T1, al // save
11408						|	// zval_dtor_func(r);
11409						|	ZVAL_DTOR_FUNC op1_info, opline
11410						|	mov cl, byte T1 // restore
11411						|jmp >2
11412					}
11413					if ((op1_info) & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11414						if (!RC_MAY_BE_1(op1_info)) {
11415							|	jmp >3
11416						}
11417						|.code
11418					}
11419					|3:
11420					if (op1_info & MAY_BE_REF) {
11421						|	mov cl, byte [r0 + 8]
11422					} else {
11423						|	mov cl, byte [FP + opline->op1.var + 8]
11424					}
11425					|2:
11426					|	cmp cl, type
11427				} else {
11428					if (op1_info & MAY_BE_REF) {
11429						|	cmp byte [r0 + 8], type
11430					} else {
11431						|	cmp byte [FP + opline->op1.var + 8], type
11432					}
11433				}
11434				if (exit_addr) {
11435					if (smart_branch_opcode == ZEND_JMPNZ) {
11436						|	je &exit_addr
11437					} else {
11438						|	jne &exit_addr
11439					}
11440				} else if (smart_branch_opcode) {
11441					if (smart_branch_opcode == ZEND_JMPZ) {
11442						|	jne =>target_label
11443					} else if (smart_branch_opcode == ZEND_JMPNZ) {
11444						|	je =>target_label
11445					} else if (smart_branch_opcode == ZEND_JMPZNZ) {
11446						|	jne =>target_label
11447						|	jmp =>target_label2
11448					} else {
11449						ZEND_UNREACHABLE();
11450					}
11451				} else {
11452					zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
11453
11454					|	sete al
11455					|	movzx eax, al
11456					|	add eax, 2
11457					|	SET_ZVAL_TYPE_INFO res_addr, eax
11458					|	FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline
11459				}
11460			}
11461	    }
11462	}
11463
11464	|7:
11465
11466	return 1;
11467}
11468
11469static uint32_t zend_ssa_cv_info(const zend_op_array *op_array, zend_ssa *ssa, uint32_t var)
11470{
11471	uint32_t j, info;
11472
11473	if (ssa->vars && ssa->var_info) {
11474		info = ssa->var_info[var].type;
11475		for (j = op_array->last_var; j < ssa->vars_count; j++) {
11476			if (ssa->vars[j].var == var) {
11477				info |= ssa->var_info[j].type;
11478			}
11479		}
11480	} else {
11481		info = MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_UNDEF |
11482			MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
11483	}
11484
11485#ifdef ZEND_JIT_USE_RC_INFERENCE
11486	/* Refcount may be increased by RETURN opcode */
11487	if ((info & MAY_BE_RC1) && !(info & MAY_BE_RCN)) {
11488		for (j = 0; j < ssa->cfg.blocks_count; j++) {
11489			if ((ssa->cfg.blocks[j].flags & ZEND_BB_REACHABLE) &&
11490			    ssa->cfg.blocks[j].len > 0) {
11491				const zend_op *opline = op_array->opcodes + ssa->cfg.blocks[j].start + ssa->cfg.blocks[j].len - 1;
11492
11493				if (opline->opcode == ZEND_RETURN) {
11494					if (opline->op1_type == IS_CV && opline->op1.var == EX_NUM_TO_VAR(var)) {
11495						info |= MAY_BE_RCN;
11496						break;
11497					}
11498				}
11499			}
11500		}
11501	}
11502#endif
11503
11504	return info;
11505}
11506
11507static int zend_jit_leave_frame(dasm_State **Dst)
11508{
11509	|	// EG(current_execute_data) = EX(prev_execute_data);
11510	|	mov r0, EX->prev_execute_data
11511	|	MEM_OP2_1_ZTS mov, aword, executor_globals, current_execute_data, r0, r2
11512	return 1;
11513}
11514
11515static int zend_jit_free_cv(dasm_State **Dst, uint32_t info, uint32_t var)
11516{
11517	if (info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
11518		uint32_t offset = EX_NUM_TO_VAR(var);
11519		| ZVAL_PTR_DTOR ZEND_ADDR_MEM_ZVAL(ZREG_FP, offset), info, 1, 1, NULL
11520	}
11521	return 1;
11522}
11523
11524static int zend_jit_free_op(dasm_State **Dst, const zend_op *opline, uint32_t info, uint32_t var_offset)
11525{
11526	if (info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
11527		| ZVAL_PTR_DTOR ZEND_ADDR_MEM_ZVAL(ZREG_FP, var_offset), info, 0, 1, opline
11528	}
11529	return 1;
11530}
11531
11532static int zend_jit_leave_func(dasm_State          **Dst,
11533                               const zend_op_array  *op_array,
11534                               const zend_op        *opline,
11535                               uint32_t              op1_info,
11536                               zend_bool             left_frame,
11537                               zend_jit_trace_rec   *trace,
11538                               zend_jit_trace_info  *trace_info,
11539                               int                   indirect_var_access,
11540                               int                   may_throw)
11541{
11542	zend_bool may_be_top_frame =
11543		JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
11544		!JIT_G(current_frame) ||
11545		!TRACE_FRAME_IS_NESTED(JIT_G(current_frame));
11546	zend_bool may_need_call_helper =
11547		indirect_var_access || /* may have symbol table */
11548		!op_array->function_name || /* may have symbol table */
11549		may_be_top_frame ||
11550		(op_array->fn_flags & ZEND_ACC_VARIADIC) || /* may have extra named args */
11551		JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
11552		!JIT_G(current_frame) ||
11553		TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) == -1 || /* unknown number of args */
11554		(uint32_t)TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) > op_array->num_args; /* extra args */
11555	zend_bool may_need_release_this =
11556		!(op_array->fn_flags & ZEND_ACC_CLOSURE) &&
11557		op_array->scope &&
11558		!(op_array->fn_flags & ZEND_ACC_STATIC) &&
11559		(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
11560		 !JIT_G(current_frame) ||
11561		 !TRACE_FRAME_NO_NEED_RELEASE_THIS(JIT_G(current_frame)));
11562
11563	if (may_need_call_helper || may_need_release_this) {
11564		|	mov FCARG1d, dword [FP + offsetof(zend_execute_data, This.u1.type_info)]
11565	}
11566	if (may_need_call_helper) {
11567		if (!left_frame) {
11568			left_frame = 1;
11569		    if (!zend_jit_leave_frame(Dst)) {
11570				return 0;
11571		    }
11572		}
11573		/* ZEND_CALL_FAKE_CLOSURE handled on slow path to eliminate check for ZEND_CALL_CLOSURE on fast path */
11574		|	test FCARG1d, (ZEND_CALL_TOP|ZEND_CALL_HAS_SYMBOL_TABLE|ZEND_CALL_FREE_EXTRA_ARGS|ZEND_CALL_ALLOCATED|ZEND_CALL_HAS_EXTRA_NAMED_PARAMS|ZEND_CALL_FAKE_CLOSURE)
11575		if (trace && trace->op != ZEND_JIT_TRACE_END) {
11576			|	jnz >1
11577			|.cold_code
11578			|1:
11579			if (!GCC_GLOBAL_REGS) {
11580				|	mov FCARG2a, FP
11581			}
11582			|	EXT_CALL zend_jit_leave_func_helper, r0
11583
11584			if (may_be_top_frame) {
11585				// TODO: try to avoid this check ???
11586				if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
11587#if 0
11588					/* this check should be handled by the following OPLINE guard */
11589					|	cmp IP, zend_jit_halt_op
11590					|	je ->trace_halt
11591#endif
11592				} else if (GCC_GLOBAL_REGS) {
11593					|	test IP, IP
11594					|	je ->trace_halt
11595				} else {
11596					|	test eax, eax
11597					|	jl ->trace_halt
11598				}
11599			}
11600
11601			if (!GCC_GLOBAL_REGS) {
11602				|	// execute_data = EG(current_execute_data)
11603				|	MEM_OP2_2_ZTS mov, FP, aword, executor_globals, current_execute_data, r0
11604			}
11605			|	jmp >8
11606			|.code
11607		} else {
11608			|	jnz ->leave_function_handler
11609		}
11610	}
11611
11612	if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
11613		if (!left_frame) {
11614			left_frame = 1;
11615		    if (!zend_jit_leave_frame(Dst)) {
11616				return 0;
11617		    }
11618		}
11619		|	// OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func)));
11620		|	mov FCARG1a, EX->func
11621		|	sub FCARG1a, sizeof(zend_object)
11622		|	OBJ_RELEASE ZREG_FCARG1a, >4
11623		|4:
11624	} else if (may_need_release_this) {
11625		if (!left_frame) {
11626			left_frame = 1;
11627		    if (!zend_jit_leave_frame(Dst)) {
11628				return 0;
11629		    }
11630		}
11631		|	// if (call_info & ZEND_CALL_RELEASE_THIS)
11632		|	test FCARG1d, ZEND_CALL_RELEASE_THIS
11633		|	je >4
11634		|	// zend_object *object = Z_OBJ(execute_data->This);
11635		|	mov FCARG1a, EX->This.value.obj
11636		|	// OBJ_RELEASE(object);
11637		|	OBJ_RELEASE ZREG_FCARG1a, >4
11638		|4:
11639		// TODO: avoid EG(excption) check for $this->foo() calls
11640		may_throw = 1;
11641	}
11642
11643	|	// EG(vm_stack_top) = (zval*)execute_data;
11644	|	MEM_OP2_1_ZTS mov, aword, executor_globals, vm_stack_top, FP, r0
11645	|	// execute_data = EX(prev_execute_data);
11646	|	mov FP, EX->prev_execute_data
11647
11648	if (!left_frame) {
11649		|	// EG(current_execute_data) = execute_data;
11650		|	MEM_OP2_1_ZTS mov, aword, executor_globals, current_execute_data, FP, r0
11651	}
11652
11653	|9:
11654	if (trace) {
11655		if (trace->op != ZEND_JIT_TRACE_END
11656		 && (JIT_G(current_frame) && !TRACE_FRAME_IS_UNKNOWN_RETURN(JIT_G(current_frame)))) {
11657			zend_jit_reset_last_valid_opline();
11658		} else {
11659			|	LOAD_IP
11660			|	ADD_IP sizeof(zend_op)
11661		}
11662
11663		|8:
11664
11665		if (trace->op == ZEND_JIT_TRACE_BACK
11666		 && (!JIT_G(current_frame) || TRACE_FRAME_IS_UNKNOWN_RETURN(JIT_G(current_frame)))) {
11667			const zend_op *next_opline = trace->opline;
11668
11669			if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
11670			 && (op1_info & MAY_BE_RC1)
11671			 && (op1_info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))) {
11672				/* exception might be thrown during destruction of unused return value */
11673				|	// if (EG(exception))
11674				|	MEM_OP2_1_ZTS cmp, aword, executor_globals, exception, 0, r0
11675				|	jne ->leave_throw_handler
11676			}
11677			do {
11678				trace++;
11679			} while (trace->op == ZEND_JIT_TRACE_INIT_CALL);
11680			ZEND_ASSERT(trace->op == ZEND_JIT_TRACE_VM || trace->op == ZEND_JIT_TRACE_END);
11681			next_opline = trace->opline;
11682			ZEND_ASSERT(next_opline != NULL);
11683
11684			if (trace->op == ZEND_JIT_TRACE_END
11685			 && trace->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
11686				trace_info->flags |= ZEND_JIT_TRACE_LOOP;
11687				|	CMP_IP next_opline
11688				|	je =>0 // LOOP
11689#ifdef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE
11690				|	JMP_IP
11691#else
11692				|	jmp ->trace_escape
11693#endif
11694			} else {
11695				|	CMP_IP next_opline
11696				|	jne ->trace_escape
11697			}
11698
11699			zend_jit_set_last_valid_opline(trace->opline);
11700
11701			return 1;
11702		} else if (may_throw ||
11703				(((opline->op1_type & (IS_VAR|IS_TMP_VAR))
11704				  && (op1_info & MAY_BE_RC1)
11705				  && (op1_info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY)))
11706				 && (!JIT_G(current_frame) || TRACE_FRAME_IS_RETURN_VALUE_UNUSED(JIT_G(current_frame))))) {
11707			|	// if (EG(exception))
11708			|	MEM_OP2_1_ZTS cmp, aword, executor_globals, exception, 0, r0
11709			|	jne ->leave_throw_handler
11710		}
11711
11712		return 1;
11713	} else {
11714		|	// if (EG(exception))
11715		|	MEM_OP2_1_ZTS cmp, aword, executor_globals, exception, 0, r0
11716		|	LOAD_IP
11717		|	jne ->leave_throw_handler
11718		|	// opline = EX(opline) + 1
11719		|	ADD_IP sizeof(zend_op)
11720	}
11721
11722	if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
11723		|	ADD_HYBRID_SPAD
11724#ifdef CONTEXT_THREADED_JIT
11725		|	push aword [IP]
11726		|	ret
11727#else
11728		|	JMP_IP
11729#endif
11730	} else if (GCC_GLOBAL_REGS) {
11731		|	add r4, SPAD // stack alignment
11732#ifdef CONTEXT_THREADED_JIT
11733		|	push aword [IP]
11734		|	ret
11735#else
11736		|	JMP_IP
11737#endif
11738	} else {
11739#ifdef CONTEXT_THREADED_JIT
11740		ZEND_UNREACHABLE();
11741		// TODO: context threading can't work without GLOBAL REGS because we have to change
11742		//       the value of execute_data in execute_ex()
11743		|	mov FCARG1a, FP
11744		|	mov r0, aword [FP]
11745		|	mov FP, aword T2 // restore FP
11746		|	mov RX, aword T3 // restore IP
11747		|	add r4, NR_SPAD // stack alignment
11748		|	push aword [r0]
11749		|	ret
11750#else
11751		|	mov FP, aword T2 // restore FP
11752		|	mov RX, aword T3 // restore IP
11753		|	add r4, NR_SPAD // stack alignment
11754		|	mov r0, 2 // ZEND_VM_LEAVE
11755		|	ret
11756#endif
11757	}
11758
11759	return 1;
11760}
11761
11762static int zend_jit_return(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, zend_jit_addr op1_addr)
11763{
11764	zend_jit_addr ret_addr;
11765	int8_t return_value_used;
11766
11767	ZEND_ASSERT(op_array->type != ZEND_EVAL_CODE && op_array->function_name);
11768	ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF));
11769
11770	if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && JIT_G(current_frame)) {
11771		if (TRACE_FRAME_IS_RETURN_VALUE_USED(JIT_G(current_frame))) {
11772			return_value_used = 1;
11773		} else if (TRACE_FRAME_IS_RETURN_VALUE_UNUSED(JIT_G(current_frame))) {
11774			return_value_used = 0;
11775		} else {
11776			return_value_used = -1;
11777		}
11778	} else {
11779		return_value_used = -1;
11780	}
11781
11782	if (ZEND_OBSERVER_ENABLED) {
11783		if (Z_MODE(op1_addr) == IS_REG) {
11784			zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
11785
11786			if (!zend_jit_spill_store(Dst, op1_addr, dst, op1_info, 1)) {
11787				return 0;
11788			}
11789			op1_addr = dst;
11790		}
11791		|	LOAD_ZVAL_ADDR FCARG2a, op1_addr
11792		|	mov FCARG1a, FP
11793		|	SET_EX_OPLINE opline, r0
11794		|	EXT_CALL zend_observer_fcall_end, r0
11795	}
11796
11797	// if (!EX(return_value))
11798	if (Z_MODE(op1_addr) == IS_REG && Z_REG(op1_addr) == ZREG_R1) {
11799		if (return_value_used != 0) {
11800			|	mov r2, EX->return_value
11801		}
11802		if (return_value_used == -1) {
11803			|	test r2, r2
11804		}
11805		ret_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R2, 0);
11806	} else {
11807		if (return_value_used != 0) {
11808			|	mov r1, EX->return_value
11809		}
11810		if (return_value_used == -1) {
11811			|	test r1, r1
11812		}
11813		ret_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R1, 0);
11814	}
11815	if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) &&
11816	    (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11817		if (return_value_used == -1) {
11818			|	jz >1
11819			|.cold_code
11820			|1:
11821		}
11822		if (return_value_used != 1) {
11823			if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11824				if (jit_return_label >= 0) {
11825					|	IF_NOT_ZVAL_REFCOUNTED op1_addr, =>jit_return_label
11826				} else {
11827					|	IF_NOT_ZVAL_REFCOUNTED op1_addr, >9
11828				}
11829			}
11830			|	GET_ZVAL_PTR FCARG1a, op1_addr
11831			|	GC_DELREF FCARG1a
11832			if (RC_MAY_BE_1(op1_info)) {
11833				if (RC_MAY_BE_N(op1_info)) {
11834					if (jit_return_label >= 0) {
11835						|	jnz =>jit_return_label
11836					} else {
11837						|	jnz >9
11838					}
11839				}
11840				|	//SAVE_OPLINE()
11841				|	ZVAL_DTOR_FUNC op1_info, opline
11842				|	//????mov r1, EX->return_value // reload ???
11843			}
11844			if (return_value_used == -1) {
11845				if (jit_return_label >= 0) {
11846					|	jmp =>jit_return_label
11847				} else {
11848					|	jmp >9
11849				}
11850				|.code
11851			}
11852		}
11853	} else if (return_value_used == -1) {
11854		if (jit_return_label >= 0) {
11855			|	jz =>jit_return_label
11856		} else {
11857			|	jz >9
11858		}
11859	}
11860
11861	if (return_value_used == 0) {
11862		|9:
11863		return 1;
11864	}
11865
11866	if (opline->op1_type == IS_CONST) {
11867		zval *zv = RT_CONSTANT(opline, opline->op1);
11868		|	ZVAL_COPY_CONST ret_addr, MAY_BE_ANY, MAY_BE_ANY, zv, ZREG_R0
11869		if (Z_REFCOUNTED_P(zv)) {
11870			|	ADDREF_CONST zv, r0
11871		}
11872	} else if (opline->op1_type == IS_TMP_VAR) {
11873		|	ZVAL_COPY_VALUE ret_addr, MAY_BE_ANY, op1_addr, op1_info, ZREG_R0, ZREG_R2
11874	} else if (opline->op1_type == IS_CV) {
11875		if (op1_info & MAY_BE_REF) {
11876			|	LOAD_ZVAL_ADDR r0, op1_addr
11877			|	ZVAL_DEREF r0, op1_info
11878			op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0);
11879		}
11880		|	ZVAL_COPY_VALUE ret_addr, MAY_BE_ANY, op1_addr, op1_info, ZREG_R0, ZREG_R2
11881		if (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
11882			if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
11883			    (op1_info & (MAY_BE_REF|MAY_BE_OBJECT)) ||
11884			    !op_array->function_name) {
11885				|	TRY_ADDREF op1_info, ah, r2
11886			} else if (return_value_used != 1) {
11887				|	// if (EXPECTED(!(EX_CALL_INFO() & ZEND_CALL_CODE))) ZVAL_NULL(retval_ptr);
11888				|	SET_ZVAL_TYPE_INFO op1_addr, IS_NULL
11889			}
11890		}
11891	} else {
11892		if (op1_info & MAY_BE_REF) {
11893			zend_jit_addr ref_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R0, offsetof(zend_reference, val));
11894
11895			|	IF_ZVAL_TYPE op1_addr, IS_REFERENCE, >1
11896			|.cold_code
11897			|1:
11898			|	// zend_refcounted *ref = Z_COUNTED_P(retval_ptr);
11899			|	GET_ZVAL_PTR r0, op1_addr
11900			|	// ZVAL_COPY_VALUE(return_value, &ref->value);
11901			|	ZVAL_COPY_VALUE ret_addr, MAY_BE_ANY, ref_addr, op1_info, ZREG_R2, ZREG_R2
11902			|	GC_DELREF r0
11903			|	je >2
11904			|	// if (IS_REFCOUNTED())
11905			if (jit_return_label >= 0) {
11906				|	IF_NOT_REFCOUNTED dh, =>jit_return_label
11907			} else {
11908				|	IF_NOT_REFCOUNTED dh, >9
11909			}
11910			|	// ADDREF
11911			|	GET_ZVAL_PTR r2, ret_addr // reload
11912			|	GC_ADDREF r2
11913			if (jit_return_label >= 0) {
11914				|	jmp =>jit_return_label
11915			} else {
11916				|	jmp >9
11917			}
11918			|2:
11919			|	EFREE_REFERENCE r0
11920			if (jit_return_label >= 0) {
11921				|	jmp =>jit_return_label
11922			} else {
11923				|	jmp >9
11924			}
11925			|.code
11926		}
11927		|	ZVAL_COPY_VALUE ret_addr, MAY_BE_ANY, op1_addr, op1_info, ZREG_R0, ZREG_R2
11928	}
11929
11930	|9:
11931	return 1;
11932}
11933
11934static int zend_jit_zval_copy_deref(dasm_State **Dst, zend_jit_addr res_addr, zend_jit_addr val_addr, zend_reg type_reg)
11935{
11936	ZEND_ASSERT(type_reg == ZREG_R2);
11937
11938	|.if not(X64)
11939	||	if (Z_REG(val_addr) == ZREG_R1) {
11940	|	GET_ZVAL_W2 r0, val_addr
11941	||	}
11942	|.endif
11943	|	GET_ZVAL_PTR r1, val_addr
11944	|.if not(X64)
11945	||	if (Z_REG(val_addr) != ZREG_R1) {
11946	|	GET_ZVAL_W2 r0, val_addr
11947	||	}
11948	|.endif
11949	|	IF_NOT_REFCOUNTED dh, >2
11950	|	IF_NOT_TYPE dl, IS_REFERENCE, >1
11951	|	GET_Z_TYPE_INFO edx, r1+offsetof(zend_reference, val)
11952	|.if not(X64)
11953	|	GET_Z_W2 r0, r1+offsetof(zend_reference, val)
11954	|.endif
11955	|	GET_Z_PTR r1, r1+offsetof(zend_reference, val)
11956	|	IF_NOT_REFCOUNTED dh, >2
11957	|1:
11958	|	GC_ADDREF r1
11959	|2:
11960	|	SET_ZVAL_PTR res_addr, r1
11961	|.if not(X64)
11962	|	SET_ZVAL_W2 res_addr, r0
11963	|.endif
11964	|	SET_ZVAL_TYPE_INFO res_addr, edx
11965
11966	return 1;
11967}
11968
11969static zend_bool zend_jit_may_avoid_refcounting(const zend_op *opline, uint32_t op1_info)
11970{
11971	switch (opline->opcode) {
11972		case ZEND_FETCH_OBJ_FUNC_ARG:
11973			if (!JIT_G(current_frame) ||
11974			    !JIT_G(current_frame)->call->func ||
11975			    !TRACE_FRAME_IS_LAST_SEND_BY_VAL(JIT_G(current_frame)->call)) {
11976				return 0;
11977			}
11978			/* break missing intentionally */
11979		case ZEND_FETCH_OBJ_R:
11980		case ZEND_FETCH_OBJ_IS:
11981			if ((op1_info & MAY_BE_OBJECT)
11982			 && opline->op2_type == IS_CONST
11983			 && Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_STRING
11984			 && Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] != '\0') {
11985				return 1;
11986			}
11987			break;
11988		case ZEND_FETCH_DIM_FUNC_ARG:
11989			if (!JIT_G(current_frame) ||
11990			    !JIT_G(current_frame)->call->func ||
11991			    !TRACE_FRAME_IS_LAST_SEND_BY_VAL(JIT_G(current_frame)->call)) {
11992				return 0;
11993			}
11994			/* break missing intentionally */
11995		case ZEND_FETCH_DIM_R:
11996		case ZEND_FETCH_DIM_IS:
11997			return 1;
11998		case ZEND_ISSET_ISEMPTY_DIM_OBJ:
11999			if (!(opline->extended_value & ZEND_ISEMPTY)) {
12000				return 1;
12001			}
12002			break;
12003	}
12004	return 0;
12005}
12006
12007static int zend_jit_fetch_dim_read(dasm_State        **Dst,
12008                                   const zend_op      *opline,
12009                                   zend_ssa           *ssa,
12010                                   const zend_ssa_op  *ssa_op,
12011                                   uint32_t            op1_info,
12012                                   zend_jit_addr       op1_addr,
12013                                   zend_bool           op1_avoid_refcounting,
12014                                   uint32_t            op2_info,
12015                                   uint32_t            res_info,
12016                                   zend_jit_addr       res_addr,
12017                                   int                 may_throw)
12018{
12019	zend_jit_addr orig_op1_addr, op2_addr;
12020	const void *exit_addr = NULL;
12021	const void *not_found_exit_addr = NULL;
12022	const void *res_exit_addr = NULL;
12023	zend_bool result_avoid_refcounting = 0;
12024	uint32_t may_be_string = (opline->opcode != ZEND_FETCH_LIST_R) ? MAY_BE_STRING : 0;
12025
12026	orig_op1_addr = OP1_ADDR();
12027	op2_addr = OP2_ADDR();
12028
12029	if (opline->opcode != ZEND_FETCH_DIM_IS
12030	 && JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
12031		int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
12032		exit_addr = zend_jit_trace_get_exit_addr(exit_point);
12033		if (!exit_addr) {
12034			return 0;
12035		}
12036	}
12037
12038	if ((res_info & MAY_BE_GUARD)
12039	 && JIT_G(current_frame)
12040	 && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) {
12041		uint32_t flags = 0;
12042		uint32_t old_op1_info = 0;
12043		uint32_t old_info;
12044		zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
12045		int32_t exit_point;
12046
12047		if (opline->opcode != ZEND_FETCH_LIST_R
12048		 && (opline->op1_type & (IS_VAR|IS_TMP_VAR))
12049		 && !op1_avoid_refcounting) {
12050			flags |= ZEND_JIT_EXIT_FREE_OP1;
12051		}
12052		if ((opline->op2_type & (IS_VAR|IS_TMP_VAR))
12053		 && (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
12054			flags |= ZEND_JIT_EXIT_FREE_OP2;
12055		}
12056		if ((opline->result_type & (IS_VAR|IS_TMP_VAR))
12057		 && !(flags & ZEND_JIT_EXIT_FREE_OP1)
12058		 && (res_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))
12059		 && (ssa_op+1)->op1_use == ssa_op->result_def
12060		 && !(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF) - (MAY_BE_STRING|MAY_BE_LONG)))
12061		 && zend_jit_may_avoid_refcounting(opline+1, res_info)) {
12062			result_avoid_refcounting = 1;
12063			ssa->var_info[ssa_op->result_def].avoid_refcounting = 1;
12064		}
12065
12066		if (op1_avoid_refcounting) {
12067			old_op1_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
12068			SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
12069		}
12070
12071		if (!(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF) - (MAY_BE_STRING|MAY_BE_LONG)))) {
12072			old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
12073			SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN, 1);
12074			SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_ZVAL_COPY_R0);
12075			exit_point = zend_jit_trace_get_exit_point(opline+1, flags);
12076			SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_info);
12077			res_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
12078			if (!res_exit_addr) {
12079				return 0;
12080			}
12081			res_info &= ~MAY_BE_GUARD;
12082			ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
12083		}
12084
12085		if (opline->opcode == ZEND_FETCH_DIM_IS
12086		 && !(res_info & MAY_BE_NULL)) {
12087			old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
12088			SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_NULL, 0);
12089			SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_NULL);
12090			exit_point = zend_jit_trace_get_exit_point(opline+1, flags);
12091			SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_info);
12092			not_found_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
12093			if (!not_found_exit_addr) {
12094				return 0;
12095			}
12096		}
12097
12098		if (op1_avoid_refcounting) {
12099			SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_op1_info);
12100		}
12101	}
12102
12103	if (op1_info & MAY_BE_REF) {
12104		|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
12105		|	ZVAL_DEREF FCARG1a, op1_info
12106		op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
12107	}
12108
12109	if (op1_info & MAY_BE_ARRAY) {
12110		if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
12111			if (exit_addr && !(op1_info & (MAY_BE_OBJECT|may_be_string))) {
12112				|	IF_NOT_ZVAL_TYPE op1_addr, IS_ARRAY, &exit_addr
12113			} else {
12114				|	IF_NOT_ZVAL_TYPE op1_addr, IS_ARRAY, >7
12115			}
12116		}
12117		|	GET_ZVAL_LVAL ZREG_FCARG1a, op1_addr
12118		if (!zend_jit_fetch_dimension_address_inner(Dst, opline, (opline->opcode != ZEND_FETCH_DIM_IS) ? BP_VAR_R : BP_VAR_IS, op1_info, op2_info, res_exit_addr, not_found_exit_addr, exit_addr)) {
12119			return 0;
12120		}
12121	}
12122
12123	if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_ARRAY)) {
12124		if (op1_info & MAY_BE_ARRAY) {
12125			|.cold_code
12126			|7:
12127		}
12128
12129		if (opline->opcode != ZEND_FETCH_LIST_R && (op1_info & MAY_BE_STRING)) {
12130			if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_STRING))) {
12131				if (exit_addr && !(op1_info & MAY_BE_OBJECT)) {
12132					|	IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, &exit_addr
12133				} else {
12134					|	IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, >6
12135				}
12136			}
12137			|	SET_EX_OPLINE opline, r0
12138			|	GET_ZVAL_LVAL ZREG_FCARG1a, op1_addr
12139			if (opline->opcode != ZEND_FETCH_DIM_IS) {
12140				if ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) == MAY_BE_LONG) {
12141					|	GET_ZVAL_LVAL ZREG_FCARG2a, op2_addr
12142					|	EXT_CALL zend_jit_fetch_dim_str_offset_r_helper, r0
12143				} else {
12144					|	LOAD_ZVAL_ADDR FCARG2a, op2_addr
12145					|	EXT_CALL zend_jit_fetch_dim_str_r_helper, r0
12146				}
12147				|	SET_ZVAL_PTR res_addr, r0
12148				|	SET_ZVAL_TYPE_INFO res_addr, IS_STRING
12149			} else {
12150				|	LOAD_ZVAL_ADDR FCARG2a, op2_addr
12151				|.if X64
12152					|   LOAD_ZVAL_ADDR CARG3, res_addr
12153				|.else
12154					|	sub r4, 12
12155					|   PUSH_ZVAL_ADDR res_addr, r0
12156				|.endif
12157				|	EXT_CALL zend_jit_fetch_dim_str_is_helper, r0
12158				|.if not(X64)
12159				|	add r4, 12
12160				|.endif
12161			}
12162			if ((op1_info & MAY_BE_ARRAY) ||
12163				(op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_STRING)))) {
12164				|	jmp >9 // END
12165			}
12166			|6:
12167		}
12168
12169		if (op1_info & MAY_BE_OBJECT) {
12170			if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_OBJECT|may_be_string))) {
12171				if (exit_addr) {
12172					|	IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, &exit_addr
12173				} else {
12174					|	IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, >6
12175				}
12176			}
12177			|	SET_EX_OPLINE opline, r0
12178		    if (Z_REG(op1_addr) != ZREG_FCARG1a || Z_OFFSET(op1_addr) != 0) {
12179				|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
12180		    }
12181			if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
12182				ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
12183				|	LOAD_ADDR FCARG2a, (Z_ZV(op2_addr) + 1)
12184			} else {
12185				|	LOAD_ZVAL_ADDR FCARG2a, op2_addr
12186			}
12187			|.if X64
12188				|   LOAD_ZVAL_ADDR CARG3, res_addr
12189			|.else
12190				|	sub r4, 12
12191				|   PUSH_ZVAL_ADDR res_addr, r0
12192			|.endif
12193			if (opline->opcode != ZEND_FETCH_DIM_IS) {
12194				|	EXT_CALL zend_jit_fetch_dim_obj_r_helper, r0
12195			} else {
12196				|	EXT_CALL zend_jit_fetch_dim_obj_is_helper, r0
12197			}
12198			|.if not(X64)
12199			|	add r4, 12
12200			|.endif
12201			if ((op1_info & MAY_BE_ARRAY) ||
12202				(op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_OBJECT|may_be_string)))) {
12203				|	jmp >9 // END
12204			}
12205			|6:
12206		}
12207
12208		if ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_OBJECT|may_be_string)))
12209		 && (!exit_addr || !(op1_info & (MAY_BE_ARRAY|MAY_BE_OBJECT|may_be_string)))) {
12210			if ((opline->opcode != ZEND_FETCH_DIM_IS && (op1_info & MAY_BE_UNDEF)) || (op2_info & MAY_BE_UNDEF)) {
12211				|	SET_EX_OPLINE opline, r0
12212				if (opline->opcode != ZEND_FETCH_DIM_IS && (op1_info & MAY_BE_UNDEF)) {
12213					|	IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >1
12214					|	// zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var))));
12215					|	mov FCARG1d, opline->op1.var
12216					|	EXT_CALL zend_jit_undefined_op_helper, r0
12217					|1:
12218				}
12219
12220				if (op2_info & MAY_BE_UNDEF) {
12221					|	IF_NOT_ZVAL_TYPE op2_addr, IS_UNDEF, >1
12222					|	mov FCARG1d, opline->op2.var
12223					|	EXT_CALL zend_jit_undefined_op_helper, r0
12224					|1:
12225				}
12226			}
12227
12228			if (opline->opcode != ZEND_FETCH_DIM_IS && opline->opcode != ZEND_FETCH_LIST_R) {
12229				if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
12230					|	LOAD_ZVAL_ADDR FCARG1a, orig_op1_addr
12231				} else {
12232					|	SET_EX_OPLINE opline, r0
12233					if (Z_MODE(op1_addr) != IS_MEM_ZVAL ||
12234					    Z_REG(op1_addr) != ZREG_FCARG1a ||
12235					    Z_OFFSET(op1_addr) != 0) {
12236						|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
12237					}
12238				}
12239				|	EXT_CALL zend_jit_invalid_array_access, r0
12240			}
12241			|	SET_ZVAL_TYPE_INFO res_addr, IS_NULL
12242			if (op1_info & MAY_BE_ARRAY) {
12243				|	jmp >9 // END
12244			}
12245		}
12246
12247		if (op1_info & MAY_BE_ARRAY) {
12248			|.code
12249		}
12250	}
12251
12252	if (op1_info & MAY_BE_ARRAY) {
12253		zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0);
12254
12255		|8:
12256		if (res_exit_addr) {
12257			zend_uchar type = concrete_type(res_info);
12258
12259			if (op1_info & MAY_BE_ARRAY_OF_REF) {
12260				|	ZVAL_DEREF r0, MAY_BE_REF
12261			}
12262			if (type < IS_STRING) {
12263				|	IF_NOT_ZVAL_TYPE val_addr, type, &res_exit_addr
12264			} else {
12265				|	GET_ZVAL_TYPE_INFO edx, val_addr
12266				|	IF_NOT_TYPE dl, type, &res_exit_addr
12267			}
12268			|	// ZVAL_COPY
12269			|7:
12270			|	ZVAL_COPY_VALUE_V res_addr, -1, val_addr, res_info, ZREG_R0, ZREG_R1
12271			if (Z_MODE(res_addr) == IS_MEM_ZVAL) {
12272				if (type < IS_STRING) {
12273					if (Z_REG(res_addr) != ZREG_FP ||
12274					    JIT_G(current_frame) == NULL ||
12275					    STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(res_addr))) != type) {
12276						|	SET_ZVAL_TYPE_INFO res_addr, type
12277					}
12278				} else {
12279					|	SET_ZVAL_TYPE_INFO res_addr, edx
12280					if (!result_avoid_refcounting) {
12281						|	TRY_ADDREF res_info, dh, r1
12282					}
12283				}
12284			} else if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, res_info)) {
12285				return 0;
12286			}
12287		} else if (op1_info & MAY_BE_ARRAY_OF_REF) {
12288			|	// ZVAL_COPY_DEREF
12289			|	GET_ZVAL_TYPE_INFO Rd(ZREG_R2), val_addr
12290			if (!zend_jit_zval_copy_deref(Dst, res_addr, val_addr, ZREG_R2)) {
12291				return 0;
12292			}
12293		} else  {
12294			|	// ZVAL_COPY
12295			|	ZVAL_COPY_VALUE res_addr, -1, val_addr, res_info, ZREG_R1, ZREG_R2
12296			|	TRY_ADDREF res_info, ch, r2
12297		}
12298	}
12299	|9: // END
12300
12301#ifdef ZEND_JIT_USE_RC_INFERENCE
12302	if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && (op1_info & MAY_BE_OBJECT)) {
12303		/* Magic offsetGet() may increase refcount of the key */
12304		op2_info |= MAY_BE_RCN;
12305	}
12306#endif
12307
12308	|	FREE_OP opline->op2_type, opline->op2, op2_info, 0, opline
12309	if (opline->opcode != ZEND_FETCH_LIST_R && !op1_avoid_refcounting) {
12310		|	FREE_OP opline->op1_type, opline->op1, op1_info, 0, opline
12311	}
12312
12313	if (may_throw) {
12314		if (!zend_jit_check_exception(Dst)) {
12315			return 0;
12316		}
12317	}
12318
12319	return 1;
12320}
12321
12322static int zend_jit_fetch_dim(dasm_State    **Dst,
12323                              const zend_op  *opline,
12324                              uint32_t        op1_info,
12325                              zend_jit_addr   op1_addr,
12326                              uint32_t        op2_info,
12327                              zend_jit_addr   res_addr,
12328                              int             may_throw)
12329{
12330	zend_jit_addr op2_addr;
12331
12332	op2_addr = (opline->op2_type != IS_UNUSED) ? OP2_ADDR() : 0;
12333
12334	if (op1_info & MAY_BE_REF) {
12335		|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
12336		|	IF_NOT_Z_TYPE FCARG1a, IS_REFERENCE, >1
12337		|	GET_Z_PTR FCARG2a, FCARG1a
12338		|	IF_NOT_TYPE byte [FCARG2a + offsetof(zend_reference, val) + offsetof(zval, u1.v.type)], IS_ARRAY, >2
12339		|	lea FCARG1a, [FCARG2a + offsetof(zend_reference, val)]
12340		|	jmp >3
12341		|.cold_code
12342		|2:
12343		|	SET_EX_OPLINE opline, r0
12344		|	EXT_CALL zend_jit_prepare_assign_dim_ref, r0
12345		|	test r0, r0
12346		|	mov FCARG1a, r0
12347		|	jne >1
12348		|	jmp ->exception_handler_undef
12349		|.code
12350		|1:
12351		op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
12352	}
12353
12354	if (op1_info & MAY_BE_ARRAY) {
12355		if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
12356			|	IF_NOT_ZVAL_TYPE op1_addr, IS_ARRAY, >7
12357		}
12358		|3:
12359		|	SEPARATE_ARRAY op1_addr, op1_info, 1
12360	}
12361	if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {
12362		if (op1_info & MAY_BE_ARRAY) {
12363			|.cold_code
12364			|7:
12365		}
12366		if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY))) {
12367			|	CMP_ZVAL_TYPE op1_addr, IS_FALSE
12368			|	jg >7
12369		}
12370		if (Z_REG(op1_addr) != ZREG_FP) {
12371			|	mov T1, Ra(Z_REG(op1_addr)) // save
12372		}
12373		if ((op1_info & MAY_BE_UNDEF)
12374		 && opline->opcode == ZEND_FETCH_DIM_RW) {
12375			if (op1_info & (MAY_BE_NULL|MAY_BE_FALSE)) {
12376				|	IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >1
12377			}
12378			|	SET_EX_OPLINE opline, r0
12379			|	mov FCARG1a, opline->op1.var
12380			|	EXT_CALL zend_jit_undefined_op_helper, r0
12381			|1:
12382		}
12383		|	// ZVAL_ARR(container, zend_new_array(8));
12384		|	EXT_CALL _zend_new_array_0, r0
12385		if (Z_REG(op1_addr) != ZREG_FP) {
12386			|	mov Ra(Z_REG(op1_addr)), T1 // restore
12387		}
12388		|	SET_ZVAL_LVAL op1_addr, r0
12389		|	SET_ZVAL_TYPE_INFO op1_addr, IS_ARRAY_EX
12390		|	mov FCARG1a, r0
12391		if (op1_info & MAY_BE_ARRAY) {
12392			|	jmp >1
12393			|.code
12394			|1:
12395		}
12396	}
12397
12398	if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY)) {
12399		|6:
12400		if (opline->op2_type == IS_UNUSED) {
12401			|	// var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
12402			|	LOAD_ADDR_ZTS FCARG2a, executor_globals, uninitialized_zval
12403			|	EXT_CALL zend_hash_next_index_insert, r0
12404			|	// if (UNEXPECTED(!var_ptr)) {
12405			|	test r0, r0
12406			|	jz >1
12407			|.cold_code
12408			|1:
12409			|	// zend_throw_error(NULL, "Cannot add element to the array as the next element is already occupied");
12410			|	CANNOT_ADD_ELEMENT opline
12411			|	SET_ZVAL_TYPE_INFO res_addr, IS_UNDEF
12412			|	//ZEND_VM_C_GOTO(assign_dim_op_ret_null);
12413			|	jmp >8
12414			|.code
12415			|	SET_ZVAL_PTR res_addr, r0
12416			|	SET_ZVAL_TYPE_INFO res_addr, IS_INDIRECT
12417		} else {
12418			uint32_t type;
12419
12420			switch (opline->opcode) {
12421				case ZEND_FETCH_DIM_W:
12422				case ZEND_FETCH_LIST_W:
12423					type = BP_VAR_W;
12424					break;
12425				case ZEND_FETCH_DIM_RW:
12426					type = BP_VAR_RW;
12427					break;
12428				case ZEND_FETCH_DIM_UNSET:
12429					type = BP_VAR_UNSET;
12430					break;
12431				default:
12432					ZEND_UNREACHABLE();
12433			}
12434
12435			if (!zend_jit_fetch_dimension_address_inner(Dst, opline, type, op1_info, op2_info, NULL, NULL, NULL)) {
12436				return 0;
12437			}
12438
12439			|8:
12440			|	SET_ZVAL_PTR res_addr, r0
12441			|	SET_ZVAL_TYPE_INFO res_addr, IS_INDIRECT
12442
12443			if (type == BP_VAR_RW || (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING)))) {
12444				|.cold_code
12445				|9:
12446				|	SET_ZVAL_TYPE_INFO res_addr, IS_NULL
12447				|	jmp >8
12448				|.code
12449			}
12450		}
12451	}
12452
12453	if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY))) {
12454		if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY)) {
12455			|.cold_code
12456			|7:
12457		}
12458
12459		|	SET_EX_OPLINE opline, r0
12460		if (Z_REG(op1_addr) != ZREG_FCARG1a || Z_OFFSET(op1_addr) != 0) {
12461			|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
12462		}
12463	    if (opline->op2_type == IS_UNUSED) {
12464			|	xor FCARG2a, FCARG2a
12465		} else if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
12466			ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
12467			|	LOAD_ADDR FCARG2a, (Z_ZV(op2_addr) + 1)
12468		} else {
12469			|	LOAD_ZVAL_ADDR FCARG2a, op2_addr
12470		}
12471		|.if X64
12472			|	LOAD_ZVAL_ADDR CARG3, res_addr
12473		|.else
12474			|	sub r4, 12
12475			|	PUSH_ZVAL_ADDR res_addr, r0
12476		|.endif
12477		switch (opline->opcode) {
12478			case ZEND_FETCH_DIM_W:
12479			case ZEND_FETCH_LIST_W:
12480				|	EXT_CALL zend_jit_fetch_dim_obj_w_helper, r0
12481				break;
12482			case ZEND_FETCH_DIM_RW:
12483				|	EXT_CALL zend_jit_fetch_dim_obj_rw_helper, r0
12484				break;
12485//			case ZEND_FETCH_DIM_UNSET:
12486//				|	EXT_CALL zend_jit_fetch_dim_obj_unset_helper, r0
12487//				break;
12488			default:
12489				ZEND_UNREACHABLE();
12490			}
12491		|.if not(X64)
12492		|	add r4, 12
12493		|.endif
12494
12495		if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY)) {
12496			|	jmp >8 // END
12497			|.code
12498		}
12499	}
12500
12501#ifdef ZEND_JIT_USE_RC_INFERENCE
12502	if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY|MAY_BE_OBJECT))) {
12503		/* ASSIGN_DIM may increase refcount of the key */
12504		op2_info |= MAY_BE_RCN;
12505	}
12506#endif
12507
12508	|8:
12509	|	FREE_OP opline->op2_type, opline->op2, op2_info, 0, opline
12510
12511	if (may_throw) {
12512		if (!zend_jit_check_exception(Dst)) {
12513			return 0;
12514		}
12515	}
12516
12517	return 1;
12518}
12519
12520static int zend_jit_isset_isempty_dim(dasm_State    **Dst,
12521                                      const zend_op  *opline,
12522                                      uint32_t        op1_info,
12523                                      zend_jit_addr   op1_addr,
12524                                      zend_bool       op1_avoid_refcounting,
12525                                      uint32_t        op2_info,
12526                                      int             may_throw,
12527                                      zend_uchar      smart_branch_opcode,
12528                                      uint32_t        target_label,
12529                                      uint32_t        target_label2,
12530                                      const void     *exit_addr)
12531{
12532	zend_jit_addr op2_addr, res_addr;
12533
12534	// TODO: support for empty() ???
12535	ZEND_ASSERT(!(opline->extended_value & ZEND_ISEMPTY));
12536
12537	op2_addr = OP2_ADDR();
12538	res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
12539
12540	if (op1_info & MAY_BE_REF) {
12541		|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
12542		|	ZVAL_DEREF FCARG1a, op1_info
12543		op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
12544	}
12545
12546	if (op1_info & MAY_BE_ARRAY) {
12547		const void *found_exit_addr = NULL;
12548		const void *not_found_exit_addr = NULL;
12549
12550		if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
12551			|	IF_NOT_ZVAL_TYPE op1_addr, IS_ARRAY, >7
12552		}
12553		|	GET_ZVAL_LVAL ZREG_FCARG1a, op1_addr
12554		if (exit_addr
12555		 && !(op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_ARRAY))
12556		 && !may_throw
12557		 && (!(opline->op1_type & (IS_TMP_VAR|IS_VAR)) || op1_avoid_refcounting)
12558		 && (!(opline->op2_type & (IS_TMP_VAR|IS_VAR)) || !(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)))) {
12559			if (smart_branch_opcode == ZEND_JMPNZ) {
12560				found_exit_addr = exit_addr;
12561			} else {
12562				not_found_exit_addr = exit_addr;
12563			}
12564		}
12565		if (!zend_jit_fetch_dimension_address_inner(Dst, opline, BP_JIT_IS, op1_info, op2_info, found_exit_addr, not_found_exit_addr, NULL)) {
12566			return 0;
12567		}
12568
12569		if (found_exit_addr) {
12570			|9:
12571			return 1;
12572		} else if (not_found_exit_addr) {
12573			|8:
12574			return 1;
12575		}
12576	}
12577
12578	if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_ARRAY)) {
12579		if (op1_info & MAY_BE_ARRAY) {
12580			|.cold_code
12581			|7:
12582		}
12583
12584		if (op1_info & (MAY_BE_STRING|MAY_BE_OBJECT)) {
12585			|	SET_EX_OPLINE opline, r0
12586		    if (Z_REG(op1_addr) != ZREG_FCARG1a || Z_OFFSET(op1_addr) != 0) {
12587				|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
12588			}
12589			if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
12590				ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
12591				|	LOAD_ADDR FCARG2a, (Z_ZV(op2_addr) + 1)
12592			} else {
12593				|	LOAD_ZVAL_ADDR FCARG2a, op2_addr
12594			}
12595			|	EXT_CALL zend_jit_isset_dim_helper, r0
12596			|	test r0, r0
12597			|	jz >9
12598			if (op1_info & MAY_BE_ARRAY) {
12599				|	jmp >8
12600				|.code
12601			}
12602		} else {
12603			if (op2_info & MAY_BE_UNDEF) {
12604				if (op2_info & MAY_BE_ANY) {
12605					|	IF_NOT_ZVAL_TYPE op2_addr, IS_UNDEF, >1
12606				}
12607				|	SET_EX_OPLINE opline, r0
12608				|	mov FCARG1d, opline->op2.var
12609				|	EXT_CALL zend_jit_undefined_op_helper, r0
12610				|1:
12611			}
12612			if (op1_info & MAY_BE_ARRAY) {
12613				|	jmp >9
12614				|.code
12615			}
12616		}
12617	}
12618
12619#ifdef ZEND_JIT_USE_RC_INFERENCE
12620	if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && (op1_info & MAY_BE_OBJECT)) {
12621		/* Magic offsetExists() may increase refcount of the key */
12622		op2_info |= MAY_BE_RCN;
12623	}
12624#endif
12625
12626	if (op1_info & (MAY_BE_ARRAY|MAY_BE_STRING|MAY_BE_OBJECT)) {
12627		|8:
12628		|	FREE_OP opline->op2_type, opline->op2, op2_info, 0, opline
12629		if (!op1_avoid_refcounting) {
12630			|	FREE_OP opline->op1_type, opline->op1, op1_info, 0, opline
12631		}
12632		if (may_throw) {
12633			if (!zend_jit_check_exception_undef_result(Dst, opline)) {
12634				return 0;
12635			}
12636		}
12637		if (!(opline->extended_value & ZEND_ISEMPTY)) {
12638			if (exit_addr) {
12639				if (smart_branch_opcode == ZEND_JMPNZ) {
12640					|	jmp &exit_addr
12641				} else {
12642					|	jmp >8
12643				}
12644			} else if (smart_branch_opcode) {
12645				if (smart_branch_opcode == ZEND_JMPZ) {
12646					|	jmp =>target_label2
12647				} else if (smart_branch_opcode == ZEND_JMPNZ) {
12648					|	jmp =>target_label
12649				} else if (smart_branch_opcode == ZEND_JMPZNZ) {
12650					|	jmp =>target_label2
12651				} else {
12652					ZEND_UNREACHABLE();
12653				}
12654			} else {
12655				|	SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
12656				|	jmp >8
12657			}
12658		} else {
12659			|	//????
12660			|	int3
12661		}
12662	}
12663
12664	|9: // not found
12665	|	FREE_OP opline->op2_type, opline->op2, op2_info, 0, opline
12666	if (!op1_avoid_refcounting) {
12667		|	FREE_OP opline->op1_type, opline->op1, op1_info, 0, opline
12668	}
12669	if (may_throw) {
12670		if (!zend_jit_check_exception_undef_result(Dst, opline)) {
12671			return 0;
12672		}
12673	}
12674	if (!(opline->extended_value & ZEND_ISEMPTY)) {
12675		if (exit_addr) {
12676			if (smart_branch_opcode == ZEND_JMPZ) {
12677				|	jmp &exit_addr
12678			}
12679		} else if (smart_branch_opcode) {
12680			if (smart_branch_opcode == ZEND_JMPZ) {
12681				|	jmp =>target_label
12682			} else if (smart_branch_opcode == ZEND_JMPNZ) {
12683			} else if (smart_branch_opcode == ZEND_JMPZNZ) {
12684				|	jmp =>target_label
12685			} else {
12686				ZEND_UNREACHABLE();
12687			}
12688		} else {
12689			|	SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
12690		}
12691	} else {
12692		|	//????
12693		|	int3
12694	}
12695
12696	|8:
12697
12698	return 1;
12699}
12700
12701static int zend_jit_bind_global(dasm_State **Dst, const zend_op *opline, uint32_t op1_info)
12702{
12703	zend_jit_addr op1_addr = OP1_ADDR();
12704	zend_string *varname = Z_STR_P(RT_CONSTANT(opline, opline->op2));
12705
12706	|	// idx = (uint32_t)(uintptr_t)CACHED_PTR(opline->extended_value) - 1;
12707	|	mov r0, EX->run_time_cache
12708	|	mov r0, aword [r0 + opline->extended_value]
12709	|	sub r0, 1
12710	|	// if (EXPECTED(idx < EG(symbol_table).nNumUsed * sizeof(Bucket)))
12711	|	MEM_OP2_2_ZTS mov, ecx, dword, executor_globals, symbol_table.nNumUsed, r1
12712	|.if X64
12713		|	shl r1, 5
12714	|.else
12715		|	imul r1, sizeof(Bucket)
12716	|.endif
12717	|	cmp r0, r1
12718	|	jae >9
12719	|	// Bucket *p = (Bucket*)((char*)EG(symbol_table).arData + idx);
12720	|	MEM_OP2_2_ZTS add, r0, aword, executor_globals, symbol_table.arData, r1
12721	|	IF_NOT_Z_TYPE r0, IS_REFERENCE, >9
12722	|	// (EXPECTED(p->key == varname))
12723	|	ADDR_OP2_2 cmp, aword [r0 + offsetof(Bucket, key)], varname, r1
12724	|	jne >9
12725	|	GET_Z_PTR r0, r0
12726	|	GC_ADDREF r0
12727	|1:
12728	if (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
12729		if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
12730			|	// if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr)))
12731			|	IF_ZVAL_REFCOUNTED op1_addr, >2
12732			|.cold_code
12733			|2:
12734		}
12735		|	// zend_refcounted *garbage = Z_COUNTED_P(variable_ptr);
12736		|	GET_ZVAL_PTR FCARG1a, op1_addr
12737		|	// ZVAL_REF(variable_ptr, ref)
12738		|	SET_ZVAL_PTR op1_addr, r0
12739		|	SET_ZVAL_TYPE_INFO op1_addr, IS_REFERENCE_EX
12740		|	// if (GC_DELREF(garbage) == 0)
12741		|	GC_DELREF FCARG1a
12742		if (op1_info & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT)) {
12743			|	jnz >3
12744		} else {
12745			|	jnz >5
12746		}
12747		|	ZVAL_DTOR_FUNC op1_info, opline
12748		|	jmp >5
12749		if (op1_info & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT)) {
12750			|3:
12751			|	// GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr)
12752			|	IF_GC_MAY_NOT_LEAK FCARG1a, >5
12753			|	EXT_CALL gc_possible_root, r1
12754			|	jmp >5
12755		}
12756		if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
12757			|.code
12758		}
12759	}
12760
12761	if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
12762		|	// ZVAL_REF(variable_ptr, ref)
12763		|	SET_ZVAL_PTR op1_addr, r0
12764		|	SET_ZVAL_TYPE_INFO op1_addr, IS_REFERENCE_EX
12765	}
12766	|5:
12767	//END of handler
12768
12769	|.cold_code
12770	|9:
12771	|	LOAD_ADDR FCARG1a, (ptrdiff_t)varname
12772	|	mov FCARG2a, EX->run_time_cache
12773	if (opline->extended_value) {
12774		|	add FCARG2a, opline->extended_value
12775	}
12776	|	EXT_CALL zend_jit_fetch_global_helper, r0
12777	|	jmp <1
12778	|.code
12779
12780	return 1;
12781}
12782
12783static int zend_jit_verify_arg_type(dasm_State **Dst, const zend_op *opline, zend_arg_info *arg_info, zend_bool check_exception)
12784{
12785	zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
12786	zend_bool in_cold = 0;
12787	uint32_t type_mask = ZEND_TYPE_PURE_MASK(arg_info->type) & MAY_BE_ANY;
12788	zend_reg tmp_reg = (type_mask == 0 || is_power_of_two(type_mask)) ? ZREG_FCARG1a : ZREG_R0;
12789
12790	if (ZEND_ARG_SEND_MODE(arg_info)) {
12791		if (opline->opcode == ZEND_RECV_INIT) {
12792			|	LOAD_ZVAL_ADDR Ra(tmp_reg), res_addr
12793			|	ZVAL_DEREF Ra(tmp_reg), MAY_BE_REF
12794			res_addr = ZEND_ADDR_MEM_ZVAL(tmp_reg, 0);
12795		} else {
12796			|	GET_ZVAL_PTR Ra(tmp_reg), res_addr
12797			res_addr = ZEND_ADDR_MEM_ZVAL(tmp_reg, offsetof(zend_reference, val));
12798		}
12799	}
12800
12801	if (type_mask != 0) {
12802		if (is_power_of_two(type_mask)) {
12803			uint32_t type_code = concrete_type(type_mask);
12804			|	IF_NOT_ZVAL_TYPE res_addr, type_code, >1
12805		} else {
12806			|	mov edx, 1
12807			|	mov cl, byte [Ra(Z_REG(res_addr))+Z_OFFSET(res_addr)+offsetof(zval, u1.v.type)]
12808			|	shl edx, cl
12809			|	test edx, type_mask
12810			|	je >1
12811		}
12812
12813		|.cold_code
12814		|1:
12815
12816		in_cold = 1;
12817	}
12818
12819	if (Z_REG(res_addr) != ZREG_FCARG1a || Z_OFFSET(res_addr) != 0) {
12820		|	LOAD_ZVAL_ADDR FCARG1a, res_addr
12821	}
12822	if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
12823		|	SET_EX_OPLINE opline, r0
12824	} else {
12825		|	ADDR_OP2_2 mov, aword EX->opline, opline, r0
12826	}
12827	|	LOAD_ADDR FCARG2a, (ptrdiff_t)arg_info
12828	|	EXT_CALL zend_jit_verify_arg_slow, r0
12829
12830	if (check_exception) {
12831		|	test al, al
12832		if (in_cold) {
12833			|	jnz >1
12834			|	jmp ->exception_handler
12835			|.code
12836			|1:
12837		} else {
12838			|	jz ->exception_handler
12839		}
12840	} else if (in_cold) {
12841		|	jmp >1
12842		|.code
12843		|1:
12844	}
12845
12846	return 1;
12847}
12848
12849static int zend_jit_recv(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array)
12850{
12851	uint32_t arg_num = opline->op1.num;
12852	zend_arg_info *arg_info = NULL;
12853
12854	if (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
12855		if (EXPECTED(arg_num <= op_array->num_args)) {
12856			arg_info = &op_array->arg_info[arg_num-1];
12857		} else if (UNEXPECTED(op_array->fn_flags & ZEND_ACC_VARIADIC)) {
12858			arg_info = &op_array->arg_info[op_array->num_args];
12859		}
12860		if (arg_info && !ZEND_TYPE_IS_SET(arg_info->type)) {
12861			arg_info = NULL;
12862		}
12863	}
12864
12865	if (arg_info || (opline+1)->opcode != ZEND_RECV) {
12866		|	cmp dword EX->This.u2.num_args, arg_num
12867		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
12868			int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
12869			const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
12870
12871			if (!exit_addr) {
12872				return 0;
12873			}
12874			|	jb &exit_addr
12875		} else {
12876			|	jb >1
12877			|.cold_code
12878			|1:
12879			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
12880				|	SET_EX_OPLINE opline, r0
12881			} else {
12882				|	ADDR_OP2_2 mov, aword EX->opline, opline, r0
12883			}
12884			|	mov FCARG1a, FP
12885			|	EXT_CALL zend_missing_arg_error, r0
12886			|	jmp ->exception_handler
12887			|.code
12888		}
12889	}
12890
12891	if (arg_info) {
12892		if (!zend_jit_verify_arg_type(Dst, opline, arg_info, 1)) {
12893			return 0;
12894		}
12895	}
12896
12897	if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE) {
12898		if ((opline+1)->opcode != ZEND_RECV && (opline+1)->opcode != ZEND_RECV_INIT) {
12899			|	LOAD_IP_ADDR (opline + 1)
12900			zend_jit_set_last_valid_opline(opline + 1);
12901		}
12902	}
12903
12904	return 1;
12905}
12906
12907static int zend_jit_recv_init(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, zend_bool is_last, int may_throw)
12908{
12909	uint32_t arg_num = opline->op1.num;
12910	zval *zv = RT_CONSTANT(opline, opline->op2);
12911	zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
12912
12913	if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
12914	    (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
12915		|	cmp dword EX->This.u2.num_args, arg_num
12916		|	jae >5
12917	}
12918	|	ZVAL_COPY_CONST res_addr, -1, -1, zv, ZREG_R0
12919	if (Z_REFCOUNTED_P(zv)) {
12920		|	ADDREF_CONST zv, r0
12921	}
12922
12923	if (Z_CONSTANT_P(zv)) {
12924		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
12925			|	SET_EX_OPLINE opline, r0
12926		} else {
12927			|	ADDR_OP2_2 mov, aword EX->opline, opline, r0
12928		}
12929		|	LOAD_ZVAL_ADDR FCARG1a, res_addr
12930		|	mov r0, EX->func
12931		|	mov FCARG2a, [r0 + offsetof(zend_op_array, scope)]
12932		|	.if X64
12933		|		EXT_CALL zval_update_constant_ex, r0
12934		|	.else
12935		||#if (PHP_VERSION_ID < 80100) && (SIZEOF_SIZE_T == 4)
12936		|		EXT_CALL zval_jit_update_constant_ex, r0
12937		||#else
12938		|		EXT_CALL zval_update_constant_ex, r0
12939		||#endif
12940		|	.endif
12941		|	test al, al
12942		|	jnz >1
12943		|.cold_code
12944		|1:
12945		|	ZVAL_PTR_DTOR res_addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN, 1, 0, opline
12946		|	SET_ZVAL_TYPE_INFO res_addr, IS_UNDEF
12947		|	jmp ->exception_handler
12948		|.code
12949	}
12950
12951	|5:
12952
12953	if (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
12954		do {
12955			zend_arg_info *arg_info;
12956
12957			if (arg_num <= op_array->num_args) {
12958				arg_info = &op_array->arg_info[arg_num-1];
12959			} else if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
12960				arg_info = &op_array->arg_info[op_array->num_args];
12961			} else {
12962				break;
12963			}
12964			if (!ZEND_TYPE_IS_SET(arg_info->type)) {
12965				break;
12966			}
12967			if (!zend_jit_verify_arg_type(Dst, opline, arg_info, may_throw)) {
12968				return 0;
12969			}
12970		} while (0);
12971	}
12972
12973	if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE) {
12974		if (is_last) {
12975			|	LOAD_IP_ADDR (opline + 1)
12976			zend_jit_set_last_valid_opline(opline + 1);
12977		}
12978	}
12979
12980	return 1;
12981}
12982
12983static zend_property_info* zend_get_known_property_info(zend_class_entry *ce, zend_string *member, zend_bool on_this, zend_string *filename)
12984{
12985	zend_property_info *info = NULL;
12986
12987	if (!ce ||
12988	    !(ce->ce_flags & ZEND_ACC_LINKED) ||
12989	    (ce->ce_flags & ZEND_ACC_TRAIT) ||
12990	    ce->create_object) {
12991		return NULL;
12992	}
12993
12994	if (!(ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
12995		if (ce->info.user.filename != filename) {
12996			/* class declaration might be changed independently */
12997			return NULL;
12998		}
12999
13000		if (ce->parent) {
13001			zend_class_entry *parent = ce->parent;
13002
13003			do {
13004				if (parent->type == ZEND_INTERNAL_CLASS) {
13005					break;
13006				} else if (parent->info.user.filename != filename) {
13007					/* some of parents class declarations might be changed independently */
13008					/* TODO: this check may be not enough, because even
13009					 * in the same it's possible to conditionally define
13010					 * few classes with the same name, and "parent" may
13011					 * change from request to request.
13012					 */
13013					return NULL;
13014				}
13015				parent = parent->parent;
13016			} while (parent);
13017		}
13018	}
13019
13020	info = (zend_property_info*)zend_hash_find_ptr(&ce->properties_info, member);
13021	if (info == NULL ||
13022	    !IS_VALID_PROPERTY_OFFSET(info->offset) ||
13023	    (info->flags & ZEND_ACC_STATIC)) {
13024		return NULL;
13025	}
13026
13027	if (!(info->flags & ZEND_ACC_PUBLIC) &&
13028	    (!on_this || info->ce != ce)) {
13029		return NULL;
13030	}
13031
13032	return info;
13033}
13034
13035static zend_bool zend_may_be_dynamic_property(zend_class_entry *ce, zend_string *member, zend_bool on_this, zend_string *filename)
13036{
13037	zend_property_info *info;
13038
13039	if (!ce || (ce->ce_flags & ZEND_ACC_TRAIT)) {
13040		return 1;
13041	}
13042
13043	if (!(ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
13044		if (ce->info.user.filename != filename) {
13045			/* class declaration might be changed independently */
13046			return 1;
13047		}
13048	}
13049
13050	info = (zend_property_info*)zend_hash_find_ptr(&ce->properties_info, member);
13051	if (info == NULL ||
13052	    !IS_VALID_PROPERTY_OFFSET(info->offset) ||
13053	    (info->flags & ZEND_ACC_STATIC)) {
13054		return 1;
13055	}
13056
13057	if (!(info->flags & ZEND_ACC_PUBLIC) &&
13058	    (!on_this || info->ce != ce)) {
13059		return 1;
13060	}
13061
13062	return 0;
13063}
13064
13065static int zend_jit_class_guard(dasm_State **Dst, const zend_op *opline, zend_class_entry *ce)
13066{
13067	int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
13068	const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
13069
13070	if (!exit_addr) {
13071		return 0;
13072	}
13073
13074	|.if X64
13075	||	if (!IS_SIGNED_32BIT(ce)) {
13076	|		mov64 r0, ((ptrdiff_t)ce)
13077	|		cmp aword [FCARG1a + offsetof(zend_object, ce)], r0
13078	||	} else {
13079	|		cmp aword [FCARG1a + offsetof(zend_object, ce)], ce
13080	||	}
13081	|.else
13082	|	cmp aword [FCARG1a + offsetof(zend_object, ce)], ce
13083	|.endif
13084	|	jne &exit_addr
13085
13086	return 1;
13087}
13088
13089static int zend_jit_fetch_obj(dasm_State          **Dst,
13090                              const zend_op        *opline,
13091                              const zend_op_array  *op_array,
13092                              zend_ssa             *ssa,
13093                              const zend_ssa_op    *ssa_op,
13094                              uint32_t              op1_info,
13095                              zend_jit_addr         op1_addr,
13096                              zend_bool             op1_indirect,
13097                              zend_class_entry     *ce,
13098                              zend_bool             ce_is_instanceof,
13099                              zend_bool             use_this,
13100                              zend_bool             op1_avoid_refcounting,
13101                              zend_class_entry     *trace_ce,
13102                              int                   may_throw)
13103{
13104	zval *member;
13105	zend_property_info *prop_info;
13106	zend_bool may_be_dynamic = 1;
13107	zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
13108	zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
13109	zend_jit_addr prop_addr;
13110	uint32_t res_info = RES_INFO();
13111
13112	ZEND_ASSERT(opline->op2_type == IS_CONST);
13113	ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
13114
13115	member = RT_CONSTANT(opline, opline->op2);
13116	ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
13117	prop_info = zend_get_known_property_info(ce, Z_STR_P(member), opline->op1_type == IS_UNUSED, op_array->filename);
13118
13119	if (opline->op1_type == IS_UNUSED || use_this) {
13120		|	GET_ZVAL_PTR FCARG1a, this_addr
13121	} else {
13122		if (opline->op1_type == IS_VAR
13123		 && opline->opcode == ZEND_FETCH_OBJ_W
13124		 && (op1_info & MAY_BE_INDIRECT)
13125		 && Z_REG(op1_addr) == ZREG_FP) {
13126			|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
13127			|	IF_NOT_Z_TYPE FCARG1a, IS_INDIRECT, >1
13128			|	GET_Z_PTR FCARG1a, FCARG1a
13129			|1:
13130			op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
13131		}
13132		if (op1_info & MAY_BE_REF) {
13133			if (Z_REG(op1_addr) != ZREG_FCARG1a || Z_OFFSET(op1_addr) != 0) {
13134				|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
13135			}
13136			|	ZVAL_DEREF FCARG1a, op1_info
13137			op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
13138		}
13139		if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
13140			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
13141				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
13142				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
13143
13144				if (!exit_addr) {
13145					return 0;
13146				}
13147				|	IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, &exit_addr
13148			} else {
13149				|	IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, >7
13150			}
13151		}
13152		|	GET_ZVAL_PTR FCARG1a, op1_addr
13153	}
13154
13155	if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
13156		prop_info = zend_get_known_property_info(trace_ce, Z_STR_P(member), opline->op1_type == IS_UNUSED, op_array->filename);
13157		if (prop_info) {
13158			ce = trace_ce;
13159			ce_is_instanceof = 0;
13160			if (!(op1_info & MAY_BE_CLASS_GUARD)) {
13161				if (!zend_jit_class_guard(Dst, opline, trace_ce)) {
13162					return 0;
13163				}
13164				if (ssa->var_info && ssa_op->op1_use >= 0) {
13165					ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
13166					ssa->var_info[ssa_op->op1_use].ce = ce;
13167					ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
13168				}
13169			}
13170		}
13171	}
13172
13173	if (!prop_info) {
13174		|	mov r0, EX->run_time_cache
13175		|	mov r2, aword [r0 + (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS)]
13176		|	cmp r2, aword [FCARG1a + offsetof(zend_object, ce)]
13177		|	jne >5
13178		|	mov r0, aword [r0 + (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*)]
13179		may_be_dynamic = zend_may_be_dynamic_property(ce, Z_STR_P(member), opline->op1_type == IS_UNUSED, op_array->filename);
13180		if (may_be_dynamic) {
13181			|	test r0, r0
13182			if (opline->opcode == ZEND_FETCH_OBJ_W) {
13183				|	jl >5
13184			} else {
13185				|	jl >8 // dynamic property
13186			}
13187		}
13188		|	mov edx, dword [FCARG1a + r0 + 8]
13189		|	IF_UNDEF dl, >5
13190		|	add FCARG1a, r0
13191		prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
13192		if (opline->opcode == ZEND_FETCH_OBJ_W
13193		 && (opline->extended_value & ZEND_FETCH_OBJ_FLAGS)
13194		 && (!ce ||	ce_is_instanceof || (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS))) {
13195			uint32_t flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS;
13196
13197			|	mov r0, EX->run_time_cache
13198			|	mov FCARG2a, aword [r0 + (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2]
13199			|	test FCARG2a, FCARG2a
13200			|	jnz >1
13201			|.cold_code
13202			|1:
13203			if (flags == ZEND_FETCH_DIM_WRITE) {
13204				|	SET_EX_OPLINE opline, r0
13205				|	EXT_CALL zend_jit_check_array_promotion, r0
13206				|	jmp >9
13207			} else if (flags == ZEND_FETCH_REF) {
13208				|.if X64
13209					|	LOAD_ZVAL_ADDR CARG3, res_addr
13210				|.else
13211					|	sub r4, 12
13212					|	PUSH_ZVAL_ADDR res_addr, r0
13213				|.endif
13214				|	EXT_CALL zend_jit_create_typed_ref, r0
13215				|.if not(X64)
13216				|	add r4, 12
13217				|.endif
13218				|	jmp >9
13219			} else {
13220				ZEND_UNREACHABLE();
13221			}
13222			|.code
13223		}
13224	} else {
13225		prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, prop_info->offset);
13226		|	mov edx, dword [FCARG1a + prop_info->offset + 8]
13227		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
13228			if (opline->opcode == ZEND_FETCH_OBJ_W || !(res_info & MAY_BE_GUARD) || !JIT_G(current_frame)) {
13229				/* perform IS_UNDEF check only after result type guard (during deoptimization) */
13230				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
13231				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
13232
13233				if (!exit_addr) {
13234					return 0;
13235				}
13236				|	IF_UNDEF dl, &exit_addr
13237			}
13238		} else {
13239			|	IF_UNDEF dl, >5
13240		}
13241		if (opline->opcode == ZEND_FETCH_OBJ_W
13242		 && (opline->extended_value & ZEND_FETCH_OBJ_FLAGS)
13243		 && ZEND_TYPE_IS_SET(prop_info->type)) {
13244			uint32_t flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS;
13245
13246			if (flags == ZEND_FETCH_DIM_WRITE) {
13247				if ((ZEND_TYPE_FULL_MASK(prop_info->type) & (MAY_BE_ITERABLE|MAY_BE_ARRAY)) == 0) {
13248					|	cmp dl, IS_FALSE
13249					|	jle >1
13250					|.cold_code
13251					|1:
13252					if (Z_REG(prop_addr) != ZREG_FCARG1a || Z_OFFSET(prop_addr) != 0) {
13253						|	LOAD_ZVAL_ADDR FCARG1a, prop_addr
13254					}
13255					|	LOAD_ADDR FCARG2a, prop_info
13256					|	SET_EX_OPLINE opline, r0
13257					|	EXT_CALL zend_jit_check_array_promotion, r0
13258					|	jmp >9
13259					|.code
13260				}
13261			} else if (flags == ZEND_FETCH_REF) {
13262				|	IF_TYPE dl, IS_REFERENCE, >1
13263				if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
13264					|	LOAD_ADDR FCARG2a, prop_info
13265				} else {
13266					int prop_info_offset =
13267						(((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
13268
13269					|	mov r0, aword [FCARG1a + offsetof(zend_object, ce)]
13270					|	mov	r0, aword [r0 + offsetof(zend_class_entry, properties_info_table)]
13271					|	mov FCARG2a, aword[r0 + prop_info_offset]
13272				}
13273				if (Z_REG(prop_addr) != ZREG_FCARG1a || Z_OFFSET(prop_addr) != 0) {
13274					|	LOAD_ZVAL_ADDR FCARG1a, prop_addr
13275				}
13276				|.if X64
13277					|	LOAD_ZVAL_ADDR CARG3, res_addr
13278				|.else
13279					|	sub r4, 12
13280					|	PUSH_ZVAL_ADDR res_addr, r0
13281				|.endif
13282				|	EXT_CALL zend_jit_create_typed_ref, r0
13283				|.if not(X64)
13284				|	add r4, 12
13285				|.endif
13286				|	jmp >9
13287				|1:
13288			} else {
13289				ZEND_UNREACHABLE();
13290			}
13291		}
13292	}
13293	if (op1_avoid_refcounting) {
13294		SET_STACK_REG(JIT_G(current_frame)->stack,
13295			EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
13296	}
13297	if (opline->opcode == ZEND_FETCH_OBJ_W) {
13298		if (Z_REG(prop_addr) != ZREG_FCARG1a || Z_OFFSET(prop_addr) != 0) {
13299			|	LOAD_ZVAL_ADDR FCARG1a, prop_addr
13300		}
13301		|	SET_ZVAL_PTR res_addr, FCARG1a
13302		|	SET_ZVAL_TYPE_INFO res_addr, IS_INDIRECT
13303		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && prop_info) {
13304			ssa->var_info[ssa_op->result_def].indirect_reference = 1;
13305		}
13306	} else {
13307		zend_bool result_avoid_refcounting = 0;
13308
13309		if ((res_info & MAY_BE_GUARD) && JIT_G(current_frame) && prop_info) {
13310			uint32_t flags = 0;
13311			uint32_t old_info;
13312			zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
13313			int32_t exit_point;
13314			const void *exit_addr;
13315			zend_uchar type;
13316			zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0);
13317
13318			if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
13319			 && !use_this
13320			 && !op1_avoid_refcounting) {
13321				flags = ZEND_JIT_EXIT_FREE_OP1;
13322			}
13323
13324			|	LOAD_ZVAL_ADDR r0, prop_addr
13325
13326			if ((opline->result_type & (IS_VAR|IS_TMP_VAR))
13327			 && !(flags & ZEND_JIT_EXIT_FREE_OP1)
13328			 && (res_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))
13329			 && (ssa_op+1)->op1_use == ssa_op->result_def
13330			 && zend_jit_may_avoid_refcounting(opline+1, res_info)) {
13331				result_avoid_refcounting = 1;
13332				ssa->var_info[ssa_op->result_def].avoid_refcounting = 1;
13333			}
13334
13335			old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
13336			SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN, 1);
13337			SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_ZVAL_COPY_R0);
13338			exit_point = zend_jit_trace_get_exit_point(opline+1, flags);
13339			SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_info);
13340			exit_addr = zend_jit_trace_get_exit_addr(exit_point);
13341			if (!exit_addr) {
13342				return 0;
13343			}
13344
13345			res_info &= ~MAY_BE_GUARD;
13346			ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
13347			type = concrete_type(res_info);
13348
13349			|	// ZVAL_DEREF()
13350			|	IF_NOT_TYPE dl, IS_REFERENCE, >1
13351			|	GET_Z_PTR r0, r0
13352			|	add r0, offsetof(zend_reference, val)
13353			if (type < IS_STRING) {
13354				|1:
13355				|	IF_NOT_ZVAL_TYPE val_addr, type, &exit_addr
13356			} else {
13357				|	GET_ZVAL_TYPE_INFO edx, val_addr
13358				|1:
13359				|	IF_NOT_TYPE dl, type, &exit_addr
13360			}
13361			|	// ZVAL_COPY
13362			|	ZVAL_COPY_VALUE_V res_addr, -1, val_addr, res_info, ZREG_R0, ZREG_R1
13363			if (type < IS_STRING) {
13364				if (Z_REG(res_addr) != ZREG_FP ||
13365				    JIT_G(current_frame) == NULL ||
13366				    STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(res_addr))) != type) {
13367					|	SET_ZVAL_TYPE_INFO res_addr, type
13368				}
13369			} else {
13370				|	SET_ZVAL_TYPE_INFO res_addr, edx
13371				if (!result_avoid_refcounting) {
13372					|	TRY_ADDREF res_info, dh, r1
13373				}
13374			}
13375		} else {
13376			if (!zend_jit_zval_copy_deref(Dst, res_addr, prop_addr, ZREG_R2)) {
13377				return 0;
13378			}
13379		}
13380	}
13381
13382	|.cold_code
13383
13384	if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE || !prop_info) {
13385		|5:
13386		|	SET_EX_OPLINE opline, r0
13387		if (opline->opcode == ZEND_FETCH_OBJ_W) {
13388			|	EXT_CALL zend_jit_fetch_obj_w_slow, r0
13389		} else if (opline->opcode != ZEND_FETCH_OBJ_IS) {
13390			|	EXT_CALL zend_jit_fetch_obj_r_slow, r0
13391		} else {
13392			|	EXT_CALL zend_jit_fetch_obj_is_slow, r0
13393		}
13394		|	jmp >9
13395	}
13396
13397	if ((op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)- MAY_BE_OBJECT)) && JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE) {
13398		|7:
13399		if (opline->opcode != ZEND_FETCH_OBJ_IS) {
13400			|	SET_EX_OPLINE opline, r0
13401			if (opline->opcode != ZEND_FETCH_OBJ_W
13402			 && (op1_info & MAY_BE_UNDEF)) {
13403				zend_jit_addr orig_op1_addr = OP1_ADDR();
13404
13405				if (op1_info & MAY_BE_ANY) {
13406					|	IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >1
13407				}
13408				|	mov FCARG1d, opline->op1.var
13409				|	EXT_CALL zend_jit_undefined_op_helper, r0
13410				|1:
13411				|	LOAD_ZVAL_ADDR FCARG1a, orig_op1_addr
13412			} else if (Z_REG(op1_addr) != ZREG_FCARG1a || Z_OFFSET(op1_addr) != 0) {
13413				|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
13414			}
13415			|	LOAD_ADDR FCARG2a, Z_STRVAL_P(member)
13416			if (opline->opcode == ZEND_FETCH_OBJ_W) {
13417				|	EXT_CALL zend_jit_invalid_property_write, r0
13418				|	SET_ZVAL_TYPE_INFO res_addr, _IS_ERROR
13419			} else {
13420				|	EXT_CALL zend_jit_invalid_property_read, r0
13421				|	SET_ZVAL_TYPE_INFO res_addr, IS_NULL
13422			}
13423			|	jmp >9
13424		} else {
13425			|	SET_ZVAL_TYPE_INFO res_addr, IS_NULL
13426			|	jmp >9
13427		}
13428	}
13429
13430	if (!prop_info
13431	 && may_be_dynamic
13432	 && opline->opcode != ZEND_FETCH_OBJ_W) {
13433		|8:
13434		|	mov FCARG2a, r0
13435		|	SET_EX_OPLINE opline, r0
13436		if (opline->opcode != ZEND_FETCH_OBJ_IS) {
13437			|	EXT_CALL zend_jit_fetch_obj_r_dynamic, r0
13438		} else {
13439			|	EXT_CALL zend_jit_fetch_obj_is_dynamic, r0
13440		}
13441		|	jmp >9
13442	}
13443
13444	|.code;
13445	|9: // END
13446	if (opline->op1_type != IS_UNUSED && !use_this && !op1_indirect) {
13447		if (opline->op1_type == IS_VAR
13448		 && opline->opcode == ZEND_FETCH_OBJ_W
13449		 && (op1_info & MAY_BE_RC1)) {
13450			zend_jit_addr orig_op1_addr = OP1_ADDR();
13451
13452			|	IF_NOT_ZVAL_REFCOUNTED orig_op1_addr, >1
13453			|	GET_ZVAL_PTR FCARG1a, orig_op1_addr
13454			|	GC_DELREF FCARG1a
13455			|	jnz >1
13456			|	SET_EX_OPLINE opline, r0
13457			|	EXT_CALL zend_jit_extract_helper, r0
13458			|1:
13459		} else if (!op1_avoid_refcounting) {
13460			|	FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline
13461		}
13462	}
13463
13464	if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
13465	 && prop_info
13466	 && (opline->opcode != ZEND_FETCH_OBJ_W ||
13467	     !(opline->extended_value & ZEND_FETCH_OBJ_FLAGS) ||
13468	     !ZEND_TYPE_IS_SET(prop_info->type))
13469	 && opline->op1_type != IS_VAR
13470	 && opline->op1_type != IS_TMP_VAR) {
13471		may_throw = 0;
13472	}
13473
13474	if (may_throw) {
13475		if (!zend_jit_check_exception(Dst)) {
13476			return 0;
13477		}
13478	}
13479
13480	return 1;
13481}
13482
13483static int zend_jit_incdec_obj(dasm_State          **Dst,
13484                               const zend_op        *opline,
13485                               const zend_op_array  *op_array,
13486                               zend_ssa             *ssa,
13487                               const zend_ssa_op    *ssa_op,
13488                               uint32_t              op1_info,
13489                               zend_jit_addr         op1_addr,
13490                               zend_bool             op1_indirect,
13491                               zend_class_entry     *ce,
13492                               zend_bool             ce_is_instanceof,
13493                               zend_bool             use_this,
13494                               zend_class_entry     *trace_ce,
13495                               int                   may_throw)
13496{
13497	zval *member;
13498	zend_string *name;
13499	zend_property_info *prop_info;
13500	zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
13501	zend_jit_addr res_addr = 0;
13502	zend_jit_addr prop_addr;
13503	zend_bool needs_slow_path = 0;
13504
13505	ZEND_ASSERT(opline->op2_type == IS_CONST);
13506	ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
13507
13508	if (opline->result_type != IS_UNUSED) {
13509		res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
13510	}
13511
13512	member = RT_CONSTANT(opline, opline->op2);
13513	ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
13514	name = Z_STR_P(member);
13515	prop_info = zend_get_known_property_info(ce, name, opline->op1_type == IS_UNUSED, op_array->filename);
13516
13517	if (opline->op1_type == IS_UNUSED || use_this) {
13518		|	GET_ZVAL_PTR FCARG1a, this_addr
13519	} else {
13520		if (opline->op1_type == IS_VAR
13521		 && (op1_info & MAY_BE_INDIRECT)
13522		 && Z_REG(op1_addr) == ZREG_FP) {
13523			|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
13524			|	IF_NOT_Z_TYPE FCARG1a, IS_INDIRECT, >1
13525			|	GET_Z_PTR FCARG1a, FCARG1a
13526			|1:
13527			op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
13528		}
13529		if (op1_info & MAY_BE_REF) {
13530			if (Z_REG(op1_addr) != ZREG_FCARG1a || Z_OFFSET(op1_addr) != 0) {
13531				|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
13532			}
13533			|	ZVAL_DEREF FCARG1a, op1_info
13534			op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
13535		}
13536		if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
13537			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
13538				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
13539				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
13540
13541				if (!exit_addr) {
13542					return 0;
13543				}
13544				|	IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, &exit_addr
13545			} else {
13546				|	IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, >1
13547				|.cold_code
13548				|1:
13549				|	SET_EX_OPLINE opline, r0
13550				if (Z_REG(op1_addr) != ZREG_FCARG1a || Z_OFFSET(op1_addr) != 0) {
13551					|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
13552				}
13553				|	LOAD_ADDR FCARG2a, ZSTR_VAL(name)
13554				|	EXT_CALL zend_jit_invalid_property_incdec, r0
13555				|	jmp ->exception_handler
13556				|.code
13557			}
13558		}
13559		|	GET_ZVAL_PTR FCARG1a, op1_addr
13560	}
13561
13562	if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
13563		prop_info = zend_get_known_property_info(trace_ce, name, opline->op1_type == IS_UNUSED, op_array->filename);
13564		if (prop_info) {
13565			ce = trace_ce;
13566			ce_is_instanceof = 0;
13567			if (!(op1_info & MAY_BE_CLASS_GUARD)) {
13568				if (!zend_jit_class_guard(Dst, opline, trace_ce)) {
13569					return 0;
13570				}
13571				if (ssa->var_info && ssa_op->op1_use >= 0) {
13572					ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
13573					ssa->var_info[ssa_op->op1_use].ce = ce;
13574					ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
13575				}
13576				if (ssa->var_info && ssa_op->op1_def >= 0) {
13577					ssa->var_info[ssa_op->op1_def].type |= MAY_BE_CLASS_GUARD;
13578					ssa->var_info[ssa_op->op1_def].ce = ce;
13579					ssa->var_info[ssa_op->op1_def].is_instanceof = ce_is_instanceof;
13580				}
13581			}
13582		}
13583	}
13584
13585	if (!prop_info) {
13586		needs_slow_path = 1;
13587
13588		|	mov r0, EX->run_time_cache
13589		|	mov r2, aword [r0 + opline->extended_value]
13590		|	cmp r2, aword [FCARG1a + offsetof(zend_object, ce)]
13591		|	jne >7
13592		if (!ce || ce_is_instanceof || (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
13593			|	cmp aword [r0 + opline->extended_value + sizeof(void*) * 2], 0
13594			|	jnz >7
13595		}
13596		|	mov r0, aword [r0 + opline->extended_value + sizeof(void*)]
13597		|	test r0, r0
13598		|	jl >7
13599		|	IF_TYPE byte [FCARG1a + r0 + 8], IS_UNDEF, >7
13600		|	add FCARG1a, r0
13601		prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
13602	} else {
13603		prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, prop_info->offset);
13604		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
13605			int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
13606			const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
13607
13608			if (!exit_addr) {
13609				return 0;
13610			}
13611			|	IF_TYPE byte [FCARG1a + prop_info->offset + 8], IS_UNDEF, &exit_addr
13612		} else {
13613			|	IF_TYPE byte [FCARG1a + prop_info->offset + 8], IS_UNDEF, >7
13614			needs_slow_path = 1;
13615		}
13616		if (ZEND_TYPE_IS_SET(prop_info->type)) {
13617			|	SET_EX_OPLINE opline, r0
13618			if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
13619				|	LOAD_ADDR FCARG2a, prop_info
13620			} else {
13621				int prop_info_offset =
13622					(((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
13623
13624				|	mov r0, aword [FCARG1a + offsetof(zend_object, ce)]
13625				|	mov	r0, aword [r0 + offsetof(zend_class_entry, properties_info_table)]
13626				|	mov FCARG2a, aword[r0 + prop_info_offset]
13627			}
13628			|	LOAD_ZVAL_ADDR FCARG1a, prop_addr
13629			if (opline->result_type == IS_UNUSED) {
13630				switch (opline->opcode) {
13631					case ZEND_PRE_INC_OBJ:
13632					case ZEND_POST_INC_OBJ:
13633						|	EXT_CALL zend_jit_inc_typed_prop, r0
13634						break;
13635					case ZEND_PRE_DEC_OBJ:
13636					case ZEND_POST_DEC_OBJ:
13637						|	EXT_CALL zend_jit_dec_typed_prop, r0
13638						break;
13639					default:
13640						ZEND_UNREACHABLE();
13641				}
13642			} else {
13643				|.if X64
13644					|	LOAD_ZVAL_ADDR CARG3, res_addr
13645				|.else
13646					|	sub r4, 12
13647					|	PUSH_ZVAL_ADDR res_addr, r0
13648				|.endif
13649				switch (opline->opcode) {
13650					case ZEND_PRE_INC_OBJ:
13651						|	EXT_CALL zend_jit_pre_inc_typed_prop, r0
13652						break;
13653					case ZEND_PRE_DEC_OBJ:
13654						|	EXT_CALL zend_jit_pre_dec_typed_prop, r0
13655						break;
13656					case ZEND_POST_INC_OBJ:
13657						|	EXT_CALL zend_jit_post_inc_typed_prop, r0
13658						break;
13659					case ZEND_POST_DEC_OBJ:
13660						|	EXT_CALL zend_jit_post_dec_typed_prop, r0
13661						break;
13662					default:
13663						ZEND_UNREACHABLE();
13664				}
13665				|.if not(X64)
13666					|	add r4, 12
13667				|.endif
13668			}
13669		}
13670	}
13671
13672	if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) {
13673		zend_jit_addr var_addr = prop_addr;
13674
13675		var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
13676		if (Z_REG(prop_addr) != ZREG_FCARG1a || Z_OFFSET(prop_addr) != 0) {
13677			|	LOAD_ZVAL_ADDR FCARG1a, prop_addr
13678		}
13679
13680		|	IF_NOT_ZVAL_TYPE var_addr, IS_REFERENCE, >2
13681		|	GET_ZVAL_PTR FCARG1a, var_addr
13682		|	cmp aword [FCARG1a + offsetof(zend_reference, sources.ptr)], 0
13683		|	jnz >1
13684		|	lea FCARG1a, aword [FCARG1a + offsetof(zend_reference, val)]
13685		|.cold_code
13686		|1:
13687		if (opline) {
13688			|	SET_EX_OPLINE opline, r0
13689		}
13690		if (opline->result_type == IS_UNUSED) {
13691			|	xor FCARG2a, FCARG2a
13692		} else {
13693			|	LOAD_ZVAL_ADDR FCARG2a, res_addr
13694		}
13695		switch (opline->opcode) {
13696			case ZEND_PRE_INC_OBJ:
13697				|	EXT_CALL zend_jit_pre_inc_typed_ref, r0
13698				break;
13699			case ZEND_PRE_DEC_OBJ:
13700				|	EXT_CALL zend_jit_pre_dec_typed_ref, r0
13701				break;
13702			case ZEND_POST_INC_OBJ:
13703				|	EXT_CALL zend_jit_post_inc_typed_ref, r0
13704				break;
13705			case ZEND_POST_DEC_OBJ:
13706				|	EXT_CALL zend_jit_post_dec_typed_ref, r0
13707				break;
13708			default:
13709				ZEND_UNREACHABLE();
13710		}
13711		|	jmp >9
13712		|.code
13713
13714		|2:
13715		|	IF_NOT_ZVAL_TYPE var_addr, IS_LONG, >2
13716		if (opline->opcode == ZEND_POST_INC_OBJ || opline->opcode == ZEND_POST_DEC_OBJ) {
13717			if (opline->result_type != IS_UNUSED) {
13718				|	ZVAL_COPY_VALUE res_addr, -1, var_addr, MAY_BE_LONG, ZREG_R1, ZREG_R2
13719			}
13720		}
13721		if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_POST_INC_OBJ) {
13722			|	LONG_OP_WITH_32BIT_CONST add, var_addr, Z_L(1)
13723		} else {
13724			|	LONG_OP_WITH_32BIT_CONST sub, var_addr, Z_L(1)
13725		}
13726		|	jo	>3
13727		if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_PRE_DEC_OBJ) {
13728			if (opline->result_type != IS_UNUSED) {
13729				|	ZVAL_COPY_VALUE res_addr, -1, var_addr, MAY_BE_LONG, ZREG_R0, ZREG_R2
13730			}
13731		}
13732		|.cold_code
13733		|2:
13734		if (opline->opcode == ZEND_POST_INC_OBJ || opline->opcode == ZEND_POST_DEC_OBJ) {
13735			|	ZVAL_COPY_VALUE res_addr, -1, var_addr, MAY_BE_ANY, ZREG_R0, ZREG_R2
13736			|	TRY_ADDREF MAY_BE_ANY, ah, r2
13737		}
13738		if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_POST_INC_OBJ) {
13739			if (opline->opcode == ZEND_PRE_INC_OBJ && opline->result_type != IS_UNUSED) {
13740				|	LOAD_ZVAL_ADDR FCARG2a, res_addr
13741				|	EXT_CALL zend_jit_pre_inc, r0
13742			} else {
13743				|	EXT_CALL increment_function, r0
13744			}
13745		} else {
13746			if (opline->opcode == ZEND_PRE_DEC_OBJ && opline->result_type != IS_UNUSED) {
13747				|	LOAD_ZVAL_ADDR FCARG2a, res_addr
13748				|	EXT_CALL zend_jit_pre_dec, r0
13749			} else {
13750				|	EXT_CALL decrement_function, r0
13751			}
13752		}
13753		|	jmp >4
13754
13755		|3:
13756		if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_POST_INC_OBJ) {
13757			|.if X64
13758				|	mov64 rax, 0x43e0000000000000
13759				|	SET_ZVAL_LVAL var_addr, rax
13760				|	SET_ZVAL_TYPE_INFO var_addr, IS_DOUBLE
13761				if (opline->opcode == ZEND_PRE_INC_OBJ && opline->result_type != IS_UNUSED) {
13762					|	SET_ZVAL_LVAL res_addr, rax
13763					|	SET_ZVAL_TYPE_INFO res_addr, IS_DOUBLE
13764				}
13765			|.else
13766				|	SET_ZVAL_LVAL var_addr, 0
13767				|	SET_ZVAL_W2 var_addr, 0x41e00000
13768				|	SET_ZVAL_TYPE_INFO var_addr, IS_DOUBLE
13769				if (opline->opcode == ZEND_PRE_INC_OBJ && opline->result_type != IS_UNUSED) {
13770					|	SET_ZVAL_LVAL res_addr, 0
13771					|	SET_ZVAL_W2 res_addr, 0x41e00000
13772					|	SET_ZVAL_TYPE_INFO res_addr, IS_DOUBLE
13773				}
13774			|.endif
13775		} else {
13776			|.if X64
13777				|	mov64 rax, 0xc3e0000000000000
13778				|	SET_ZVAL_LVAL var_addr, rax
13779				|	SET_ZVAL_TYPE_INFO var_addr, IS_DOUBLE
13780				if (opline->opcode == ZEND_PRE_DEC_OBJ && opline->result_type != IS_UNUSED) {
13781					|	SET_ZVAL_LVAL res_addr, rax
13782					|	SET_ZVAL_TYPE_INFO res_addr, IS_DOUBLE
13783				}
13784			|.else
13785				|	SET_ZVAL_LVAL var_addr, 0x00200000
13786				|	SET_ZVAL_W2 var_addr, 0xc1e00000
13787				|	SET_ZVAL_TYPE_INFO var_addr, IS_DOUBLE
13788				if (opline->opcode == ZEND_PRE_DEC_OBJ && opline->result_type != IS_UNUSED) {
13789					|	SET_ZVAL_LVAL res_addr, 0x00200000
13790					|	SET_ZVAL_W2 res_addr, 0xc1e00000
13791					|	SET_ZVAL_TYPE_INFO res_addr, IS_DOUBLE
13792			}
13793			|.endif
13794		}
13795		|	jmp >4
13796		|.code
13797		|4:
13798	}
13799
13800	if (needs_slow_path) {
13801		|.cold_code
13802		|7:
13803		|	SET_EX_OPLINE opline, r0
13804		|	// value = zobj->handlers->write_property(zobj, name, value, CACHE_ADDR(opline->extended_value));
13805		|	LOAD_ADDR FCARG2a, name
13806		|.if X64
13807			|	mov CARG3, EX->run_time_cache
13808			|	add CARG3, opline->extended_value
13809			if (opline->result_type == IS_UNUSED) {
13810				|	xor CARG4, CARG4
13811			} else {
13812				|	LOAD_ZVAL_ADDR CARG4, res_addr
13813			}
13814		|.else
13815			|	sub r4, 8
13816			if (opline->result_type == IS_UNUSED) {
13817				|	push 0
13818			} else {
13819				|	PUSH_ZVAL_ADDR res_addr, r0
13820			}
13821			|	mov r0, EX->run_time_cache
13822			|	add r0, opline->extended_value
13823			|	push r0
13824		|.endif
13825
13826		switch (opline->opcode) {
13827			case ZEND_PRE_INC_OBJ:
13828				|	EXT_CALL zend_jit_pre_inc_obj_helper, r0
13829				break;
13830			case ZEND_PRE_DEC_OBJ:
13831				|	EXT_CALL zend_jit_pre_dec_obj_helper, r0
13832				break;
13833			case ZEND_POST_INC_OBJ:
13834				|	EXT_CALL zend_jit_post_inc_obj_helper, r0
13835				break;
13836			case ZEND_POST_DEC_OBJ:
13837				|	EXT_CALL zend_jit_post_dec_obj_helper, r0
13838				break;
13839			default:
13840				ZEND_UNREACHABLE();
13841		}
13842
13843		|.if not(X64)
13844			|	add r4, 8
13845		|.endif
13846
13847		|	jmp >9
13848		|.code
13849	}
13850
13851	|9:
13852	if (opline->op1_type != IS_UNUSED && !use_this && !op1_indirect) {
13853		|	FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline
13854	}
13855
13856	if (may_throw) {
13857		if (!zend_jit_check_exception(Dst)) {
13858			return 0;
13859		}
13860	}
13861
13862	return 1;
13863}
13864
13865static int zend_jit_assign_obj_op(dasm_State          **Dst,
13866                                  const zend_op        *opline,
13867                                  const zend_op_array  *op_array,
13868                                  zend_ssa             *ssa,
13869                                  const zend_ssa_op    *ssa_op,
13870                                  uint32_t              op1_info,
13871                                  zend_jit_addr         op1_addr,
13872                                  uint32_t              val_info,
13873                                  zend_ssa_range       *val_range,
13874                                  zend_bool             op1_indirect,
13875                                  zend_class_entry     *ce,
13876                                  zend_bool             ce_is_instanceof,
13877                                  zend_bool             use_this,
13878                                  zend_class_entry     *trace_ce,
13879                                  int                   may_throw)
13880{
13881	zval *member;
13882	zend_string *name;
13883	zend_property_info *prop_info;
13884	zend_jit_addr val_addr = OP1_DATA_ADDR();
13885	zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
13886	zend_jit_addr prop_addr;
13887	zend_bool needs_slow_path = 0;
13888	binary_op_type binary_op = get_binary_op(opline->extended_value);
13889
13890	ZEND_ASSERT(opline->op2_type == IS_CONST);
13891	ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
13892	ZEND_ASSERT(opline->result_type == IS_UNUSED);
13893
13894	member = RT_CONSTANT(opline, opline->op2);
13895	ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
13896	name = Z_STR_P(member);
13897	prop_info = zend_get_known_property_info(ce, name, opline->op1_type == IS_UNUSED, op_array->filename);
13898
13899	if (opline->op1_type == IS_UNUSED || use_this) {
13900		|	GET_ZVAL_PTR FCARG1a, this_addr
13901	} else {
13902		if (opline->op1_type == IS_VAR
13903		 && (op1_info & MAY_BE_INDIRECT)
13904		 && Z_REG(op1_addr) == ZREG_FP) {
13905			|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
13906			|	IF_NOT_Z_TYPE FCARG1a, IS_INDIRECT, >1
13907			|	GET_Z_PTR FCARG1a, FCARG1a
13908			|1:
13909			op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
13910		}
13911		if (op1_info & MAY_BE_REF) {
13912			if (Z_REG(op1_addr) != ZREG_FCARG1a || Z_OFFSET(op1_addr) != 0) {
13913				|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
13914			}
13915			|	ZVAL_DEREF FCARG1a, op1_info
13916			op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
13917		}
13918		if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
13919			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
13920				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
13921				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
13922
13923				if (!exit_addr) {
13924					return 0;
13925				}
13926				|	IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, &exit_addr
13927			} else {
13928				|	IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, >1
13929				|.cold_code
13930				|1:
13931				|	SET_EX_OPLINE opline, r0
13932				if (Z_REG(op1_addr) != ZREG_FCARG1a || Z_OFFSET(op1_addr) != 0) {
13933					|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
13934				}
13935				|	LOAD_ADDR FCARG2a, ZSTR_VAL(name)
13936				if (op1_info & MAY_BE_UNDEF) {
13937					|	EXT_CALL zend_jit_invalid_property_assign_op, r0
13938				} else {
13939					|	EXT_CALL zend_jit_invalid_property_assign, r0
13940				}
13941				may_throw = 1;
13942				if (((opline+1)->op1_type & (IS_VAR|IS_TMP_VAR))
13943				 && (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
13944					|	jmp >8
13945				} else {
13946					|	jmp >9
13947				}
13948				|.code
13949			}
13950		}
13951		|	GET_ZVAL_PTR FCARG1a, op1_addr
13952	}
13953
13954	if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
13955		prop_info = zend_get_known_property_info(trace_ce, name, opline->op1_type == IS_UNUSED, op_array->filename);
13956		if (prop_info) {
13957			ce = trace_ce;
13958			ce_is_instanceof = 0;
13959			if (!(op1_info & MAY_BE_CLASS_GUARD)) {
13960				if (!zend_jit_class_guard(Dst, opline, trace_ce)) {
13961					return 0;
13962				}
13963				if (ssa->var_info && ssa_op->op1_use >= 0) {
13964					ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
13965					ssa->var_info[ssa_op->op1_use].ce = ce;
13966					ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
13967				}
13968				if (ssa->var_info && ssa_op->op1_def >= 0) {
13969					ssa->var_info[ssa_op->op1_def].type |= MAY_BE_CLASS_GUARD;
13970					ssa->var_info[ssa_op->op1_def].ce = ce;
13971					ssa->var_info[ssa_op->op1_def].is_instanceof = ce_is_instanceof;
13972				}
13973			}
13974		}
13975	}
13976
13977	if (!prop_info) {
13978		needs_slow_path = 1;
13979
13980		|	mov r0, EX->run_time_cache
13981		|	mov r2, aword [r0 + (opline+1)->extended_value]
13982		|	cmp r2, aword [FCARG1a + offsetof(zend_object, ce)]
13983		|	jne >7
13984		if (!ce || ce_is_instanceof || (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
13985			|	cmp aword [r0 + ((opline+1)->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2], 0
13986			|	jnz >7
13987		}
13988		|	mov r0, aword [r0 + (opline+1)->extended_value + sizeof(void*)]
13989		|	test r0, r0
13990		|	jl >7
13991		|	IF_TYPE byte [FCARG1a + r0 + 8], IS_UNDEF, >7
13992		|	add FCARG1a, r0
13993		prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
13994	} else {
13995		prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, prop_info->offset);
13996		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
13997			int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
13998			const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
13999
14000			if (!exit_addr) {
14001				return 0;
14002			}
14003			|	IF_TYPE byte [FCARG1a + prop_info->offset + 8], IS_UNDEF, &exit_addr
14004		} else {
14005			|	IF_TYPE byte [FCARG1a + prop_info->offset + 8], IS_UNDEF, >7
14006			needs_slow_path = 1;
14007		}
14008		if (ZEND_TYPE_IS_SET(prop_info->type)) {
14009			uint32_t info = val_info;
14010
14011			if (opline) {
14012				|	SET_EX_OPLINE opline, r0
14013			}
14014
14015			|	IF_ZVAL_TYPE prop_addr, IS_REFERENCE, >1
14016			|.cold_code
14017			|1:
14018			|	GET_ZVAL_PTR FCARG1a, prop_addr
14019			if (Z_MODE(val_addr) != IS_MEM_ZVAL || Z_REG(val_addr) != ZREG_FCARG2a || Z_OFFSET(val_addr) != 0) {
14020				|	LOAD_ZVAL_ADDR FCARG2a, val_addr
14021			}
14022			|.if X64
14023				|	LOAD_ADDR CARG3, binary_op
14024			|.else
14025				|	sub r4, 12
14026				|	PUSH_ADDR binary_op, r0
14027			|.endif
14028			if (((opline+1)->op1_type & (IS_TMP_VAR|IS_VAR))
14029			 && (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
14030				|	EXT_CALL zend_jit_assign_op_to_typed_ref_tmp, r0
14031			} else {
14032				|	EXT_CALL zend_jit_assign_op_to_typed_ref, r0
14033			}
14034			|.if not(X64)
14035				|	add r4, 12
14036			|.endif
14037			|	jmp >9
14038			|.code
14039
14040			|	// value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
14041
14042			if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
14043				|	LOAD_ADDR FCARG2a, prop_info
14044			} else {
14045				int prop_info_offset =
14046					(((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
14047
14048				|	mov r0, aword [FCARG1a + offsetof(zend_object, ce)]
14049				|	mov	r0, aword [r0 + offsetof(zend_class_entry, properties_info_table)]
14050				|	mov FCARG2a, aword[r0 + prop_info_offset]
14051			}
14052			|	LOAD_ZVAL_ADDR FCARG1a, prop_addr
14053			|.if X64
14054				|	LOAD_ZVAL_ADDR CARG3, val_addr
14055				|	LOAD_ADDR CARG4, binary_op
14056			|.else
14057				|	sub r4, 8
14058				|	PUSH_ADDR binary_op, r0
14059				|	PUSH_ZVAL_ADDR val_addr, r0
14060			|.endif
14061
14062			|	EXT_CALL zend_jit_assign_op_to_typed_prop, r0
14063
14064			|.if not(X64)
14065				|	add r4, 8
14066			|.endif
14067
14068			if (info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
14069				info |= MAY_BE_RC1|MAY_BE_RCN;
14070			}
14071
14072			|	FREE_OP (opline+1)->op1_type, (opline+1)->op1, info, 0, opline
14073		}
14074	}
14075
14076	if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) {
14077		zend_jit_addr var_addr = prop_addr;
14078		uint32_t var_info = MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN;
14079		uint32_t var_def_info = MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN;
14080
14081		var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0);
14082		|	LOAD_ZVAL_ADDR r0, prop_addr
14083
14084		|	IF_NOT_ZVAL_TYPE var_addr, IS_REFERENCE, >2
14085		|	GET_ZVAL_PTR FCARG1a, var_addr
14086		|	cmp aword [FCARG1a + offsetof(zend_reference, sources.ptr)], 0
14087		|	jnz >1
14088		|	lea r0, aword [FCARG1a + offsetof(zend_reference, val)]
14089		|.cold_code
14090		|1:
14091		if (Z_MODE(val_addr) != IS_MEM_ZVAL || Z_REG(val_addr) != ZREG_FCARG2a || Z_OFFSET(val_addr) != 0) {
14092			|	LOAD_ZVAL_ADDR FCARG2a, val_addr
14093		}
14094		if (opline) {
14095			|	SET_EX_OPLINE opline, r0
14096		}
14097		|.if X64
14098			|	LOAD_ADDR CARG3, binary_op
14099		|.else
14100			|	sub r4, 12
14101			|	PUSH_ADDR binary_op, r0
14102		|.endif
14103		if (((opline+1)->op1_type & (IS_TMP_VAR|IS_VAR))
14104		 && (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
14105			|	EXT_CALL zend_jit_assign_op_to_typed_ref_tmp, r0
14106		} else {
14107			|	EXT_CALL zend_jit_assign_op_to_typed_ref, r0
14108		}
14109		|.if not(X64)
14110			|	add r4, 12
14111		|.endif
14112		|	jmp >9
14113		|.code
14114		|2:
14115
14116		switch (opline->extended_value) {
14117			case ZEND_ADD:
14118			case ZEND_SUB:
14119			case ZEND_MUL:
14120			case ZEND_DIV:
14121				if (!zend_jit_math_helper(Dst, opline, opline->extended_value, IS_CV, opline->op1, var_addr, var_info, (opline+1)->op1_type, (opline+1)->op1, val_addr, val_info, 0, var_addr, var_def_info, var_info,
14122						1 /* may overflow */, 0)) {
14123					return 0;
14124				}
14125				break;
14126			case ZEND_BW_OR:
14127			case ZEND_BW_AND:
14128			case ZEND_BW_XOR:
14129			case ZEND_SL:
14130			case ZEND_SR:
14131			case ZEND_MOD:
14132				if (!zend_jit_long_math_helper(Dst, opline, opline->extended_value,
14133						IS_CV, opline->op1, var_addr, var_info, NULL,
14134						(opline+1)->op1_type, (opline+1)->op1, val_addr, val_info,
14135						val_range,
14136						0, var_addr, var_def_info, var_info, 0)) {
14137					return 0;
14138				}
14139				break;
14140			case ZEND_CONCAT:
14141				if (!zend_jit_concat_helper(Dst, opline, IS_CV, opline->op1, var_addr, var_info, (opline+1)->op1_type, (opline+1)->op1, val_addr, val_info, var_addr,
14142						0)) {
14143					return 0;
14144				}
14145				break;
14146			default:
14147				ZEND_UNREACHABLE();
14148		}
14149	}
14150
14151	if (needs_slow_path) {
14152		|.cold_code
14153		|7:
14154		|	SET_EX_OPLINE opline, r0
14155		|	// value = zobj->handlers->write_property(zobj, name, value, CACHE_ADDR(opline->extended_value));
14156		|	LOAD_ADDR FCARG2a, name
14157		|.if X64
14158			|	LOAD_ZVAL_ADDR CARG3, val_addr
14159			|	mov CARG4, EX->run_time_cache
14160			|	add CARG4, (opline+1)->extended_value
14161			|.if X64WIN
14162			|	LOAD_ADDR r0, binary_op
14163			|	mov aword A5, r0
14164			|.else
14165			|	LOAD_ADDR CARG5, binary_op
14166			|.endif
14167		|.else
14168			|	sub r4, 4
14169			|	PUSH_ADDR binary_op, r0
14170			|	mov r0, EX->run_time_cache
14171			|	add r0, (opline+1)->extended_value
14172			|	push r0
14173			|	PUSH_ZVAL_ADDR val_addr, r0
14174		|.endif
14175
14176		|	EXT_CALL zend_jit_assign_obj_op_helper, r0
14177
14178		|.if not(X64)
14179			|	add r4, 4
14180		|.endif
14181
14182		if (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
14183			val_info |= MAY_BE_RC1|MAY_BE_RCN;
14184		}
14185
14186		|8:
14187		|	// FREE_OP_DATA();
14188		|	FREE_OP (opline+1)->op1_type, (opline+1)->op1, val_info, 0, opline
14189		|	jmp >9
14190		|.code
14191	}
14192
14193	|9:
14194	if (opline->op1_type != IS_UNUSED && !use_this && !op1_indirect) {
14195		|	FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline
14196	}
14197
14198	if (may_throw) {
14199		if (!zend_jit_check_exception(Dst)) {
14200			return 0;
14201		}
14202	}
14203
14204	return 1;
14205}
14206
14207static int zend_jit_assign_obj(dasm_State          **Dst,
14208                               const zend_op        *opline,
14209                               const zend_op_array  *op_array,
14210                               zend_ssa             *ssa,
14211                               const zend_ssa_op    *ssa_op,
14212                               uint32_t              op1_info,
14213                               zend_jit_addr         op1_addr,
14214                               uint32_t              val_info,
14215                               zend_bool             op1_indirect,
14216                               zend_class_entry     *ce,
14217                               zend_bool             ce_is_instanceof,
14218                               zend_bool             use_this,
14219                               zend_class_entry     *trace_ce,
14220                               int                   may_throw)
14221{
14222	zval *member;
14223	zend_string *name;
14224	zend_property_info *prop_info;
14225	zend_jit_addr val_addr = OP1_DATA_ADDR();
14226	zend_jit_addr res_addr = 0;
14227	zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
14228	zend_jit_addr prop_addr;
14229	zend_bool needs_slow_path = 0;
14230	zend_bool needs_val_dtor = 0;
14231
14232	if (RETURN_VALUE_USED(opline)) {
14233		res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14234	}
14235
14236	ZEND_ASSERT(opline->op2_type == IS_CONST);
14237	ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
14238
14239	member = RT_CONSTANT(opline, opline->op2);
14240	ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
14241	name = Z_STR_P(member);
14242	prop_info = zend_get_known_property_info(ce, name, opline->op1_type == IS_UNUSED, op_array->filename);
14243
14244	if (opline->op1_type == IS_UNUSED || use_this) {
14245		|	GET_ZVAL_PTR FCARG1a, this_addr
14246	} else {
14247		if (opline->op1_type == IS_VAR
14248		 && (op1_info & MAY_BE_INDIRECT)
14249		 && Z_REG(op1_addr) == ZREG_FP) {
14250			|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
14251			|	IF_NOT_Z_TYPE FCARG1a, IS_INDIRECT, >1
14252			|	GET_Z_PTR FCARG1a, FCARG1a
14253			|1:
14254			op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
14255		}
14256		if (op1_info & MAY_BE_REF) {
14257			if (Z_REG(op1_addr) != ZREG_FCARG1a || Z_OFFSET(op1_addr) != 0) {
14258				|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
14259			}
14260			|	ZVAL_DEREF FCARG1a, op1_info
14261			op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
14262		}
14263		if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
14264			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14265				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14266				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14267
14268				if (!exit_addr) {
14269					return 0;
14270				}
14271				|	IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, &exit_addr
14272			} else {
14273				|	IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, >1
14274				|.cold_code
14275				|1:
14276				|	SET_EX_OPLINE opline, r0
14277				if (Z_REG(op1_addr) != ZREG_FCARG1a || Z_OFFSET(op1_addr) != 0) {
14278					|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
14279				}
14280				|	LOAD_ADDR FCARG2a, ZSTR_VAL(name)
14281				|	EXT_CALL zend_jit_invalid_property_assign, r0
14282				if (RETURN_VALUE_USED(opline)) {
14283					|	SET_ZVAL_TYPE_INFO res_addr, IS_NULL
14284				}
14285				if (((opline+1)->op1_type & (IS_VAR|IS_TMP_VAR))
14286				 && (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
14287				 	needs_val_dtor = 1;
14288					|	jmp >7
14289				} else {
14290					|	jmp >9
14291				}
14292				|.code
14293			}
14294		}
14295		|	GET_ZVAL_PTR FCARG1a, op1_addr
14296	}
14297
14298	if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
14299		prop_info = zend_get_known_property_info(trace_ce, name, opline->op1_type == IS_UNUSED, op_array->filename);
14300		if (prop_info) {
14301			ce = trace_ce;
14302			ce_is_instanceof = 0;
14303			if (!(op1_info & MAY_BE_CLASS_GUARD)) {
14304				if (!zend_jit_class_guard(Dst, opline, trace_ce)) {
14305					return 0;
14306				}
14307				if (ssa->var_info && ssa_op->op1_use >= 0) {
14308					ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
14309					ssa->var_info[ssa_op->op1_use].ce = ce;
14310					ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
14311				}
14312				if (ssa->var_info && ssa_op->op1_def >= 0) {
14313					ssa->var_info[ssa_op->op1_def].type |= MAY_BE_CLASS_GUARD;
14314					ssa->var_info[ssa_op->op1_def].ce = ce;
14315					ssa->var_info[ssa_op->op1_def].is_instanceof = ce_is_instanceof;
14316				}
14317			}
14318		}
14319	}
14320
14321	if (!prop_info) {
14322		needs_slow_path = 1;
14323
14324		|	mov r0, EX->run_time_cache
14325		|	mov r2, aword [r0 + opline->extended_value]
14326		|	cmp r2, aword [FCARG1a + offsetof(zend_object, ce)]
14327		|	jne >5
14328		if (!ce || ce_is_instanceof || (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
14329			|	mov FCARG2a, aword [r0 + (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2]
14330		}
14331		|	mov r0, aword [r0 + opline->extended_value + sizeof(void*)]
14332		|	test r0, r0
14333		|	jl >5
14334		|	IF_TYPE byte [FCARG1a + r0 + 8], IS_UNDEF, >5
14335		|	add FCARG1a, r0
14336		prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
14337		if (!ce || ce_is_instanceof || (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
14338			|	test FCARG2a, FCARG2a
14339			|	jnz >1
14340			|.cold_code
14341			|1:
14342			|	// value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
14343			|	SET_EX_OPLINE opline, r0
14344			|.if X64
14345				|	LOAD_ZVAL_ADDR CARG3, val_addr
14346				if (RETURN_VALUE_USED(opline)) {
14347					|	LOAD_ZVAL_ADDR CARG4, res_addr
14348				} else {
14349					|	xor CARG4, CARG4
14350				}
14351			|.else
14352				|	sub r4, 8
14353				if (RETURN_VALUE_USED(opline)) {
14354					|	PUSH_ZVAL_ADDR res_addr, r0
14355				} else {
14356					|	push 0
14357				}
14358				|	PUSH_ZVAL_ADDR val_addr, r0
14359			|.endif
14360
14361			|	EXT_CALL zend_jit_assign_to_typed_prop, r0
14362
14363			|.if not(X64)
14364				|	add r4, 8
14365			|.endif
14366
14367			if ((opline+1)->op1_type == IS_CONST) {
14368				|	// TODO: ???
14369				|	// if (Z_TYPE_P(value) == orig_type) {
14370				|	// CACHE_PTR_EX(cache_slot + 2, NULL);
14371			}
14372
14373			if (((opline+1)->op1_type & (IS_VAR|IS_TMP_VAR))
14374			 && (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
14375				|	jmp >7
14376			} else {
14377				|	jmp >9
14378			}
14379			|.code
14380		}
14381	} else {
14382		prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, prop_info->offset);
14383		if (!ce || ce_is_instanceof || !(ce->ce_flags & ZEND_ACC_IMMUTABLE) || ce->__get || ce->__set) {
14384			// Undefined property with magic __get()/__set()
14385			if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14386				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14387				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14388
14389				if (!exit_addr) {
14390					return 0;
14391				}
14392				|	IF_TYPE byte [FCARG1a + prop_info->offset + 8], IS_UNDEF, &exit_addr
14393			} else {
14394				|	IF_TYPE byte [FCARG1a + prop_info->offset + 8], IS_UNDEF, >5
14395				needs_slow_path = 1;
14396			}
14397		}
14398		if (ZEND_TYPE_IS_SET(prop_info->type)) {
14399			uint32_t info = val_info;
14400
14401			|	// value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
14402			|	SET_EX_OPLINE opline, r0
14403			if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
14404				|	LOAD_ADDR FCARG2a, prop_info
14405			} else {
14406				int prop_info_offset =
14407					(((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
14408
14409				|	mov r0, aword [FCARG1a + offsetof(zend_object, ce)]
14410				|	mov	r0, aword [r0 + offsetof(zend_class_entry, properties_info_table)]
14411				|	mov FCARG2a, aword[r0 + prop_info_offset]
14412			}
14413			|	LOAD_ZVAL_ADDR FCARG1a, prop_addr
14414			|.if X64
14415				|	LOAD_ZVAL_ADDR CARG3, val_addr
14416				if (RETURN_VALUE_USED(opline)) {
14417					|	LOAD_ZVAL_ADDR CARG4, res_addr
14418				} else {
14419					|	xor CARG4, CARG4
14420				}
14421			|.else
14422				|	sub r4, 8
14423				if (RETURN_VALUE_USED(opline)) {
14424					|	PUSH_ZVAL_ADDR res_addr, r0
14425				} else {
14426					|	push 0
14427				}
14428				|	PUSH_ZVAL_ADDR val_addr, r0
14429			|.endif
14430
14431			|	EXT_CALL zend_jit_assign_to_typed_prop, r0
14432
14433			|.if not(X64)
14434				|	add r4, 8
14435			|.endif
14436
14437			if (info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
14438				info |= MAY_BE_RC1|MAY_BE_RCN;
14439			}
14440
14441			|	FREE_OP (opline+1)->op1_type, (opline+1)->op1, info, 0, opline
14442		}
14443	}
14444
14445	if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) {
14446		// value = zend_assign_to_variable(property_val, value, OP_DATA_TYPE, EX_USES_STRICT_TYPES());
14447		if (opline->result_type == IS_UNUSED) {
14448			if (!zend_jit_assign_to_variable_call(Dst, opline, prop_addr, prop_addr, -1, -1, (opline+1)->op1_type, val_addr, val_info, res_addr, 0)) {
14449				return 0;
14450			}
14451		} else {
14452			if (!zend_jit_assign_to_variable(Dst, opline, prop_addr, prop_addr, -1, -1, (opline+1)->op1_type, val_addr, val_info, res_addr, 0)) {
14453				return 0;
14454			}
14455		}
14456	}
14457
14458	if (needs_slow_path) {
14459		|.cold_code
14460		|5:
14461		|	SET_EX_OPLINE opline, r0
14462		|	// value = zobj->handlers->write_property(zobj, name, value, CACHE_ADDR(opline->extended_value));
14463		|	LOAD_ADDR FCARG2a, name
14464		|.if X64
14465			|	LOAD_ZVAL_ADDR CARG3, val_addr
14466			|	mov CARG4, EX->run_time_cache
14467			|	add CARG4, opline->extended_value
14468			if (RETURN_VALUE_USED(opline)) {
14469				|.if X64WIN
14470				|	LOAD_ZVAL_ADDR r0, res_addr
14471				|	mov aword A5, r0
14472				|.else
14473				|	LOAD_ZVAL_ADDR CARG5, res_addr
14474				|.endif
14475			} else {
14476				|.if X64WIN
14477				|	mov aword A5, 0
14478				|.else
14479				|	xor CARG5, CARG5
14480				|.endif
14481			}
14482		|.else
14483			|	sub r4, 4
14484			if (RETURN_VALUE_USED(opline)) {
14485				|	PUSH_ZVAL_ADDR res_addr, r0
14486			} else {
14487				|	push 0
14488			}
14489			|	mov r0, EX->run_time_cache
14490			|	add r0, opline->extended_value
14491			|	push r0
14492			|	PUSH_ZVAL_ADDR val_addr, r0
14493		|.endif
14494
14495		|	EXT_CALL zend_jit_assign_obj_helper, r0
14496
14497		|.if not(X64)
14498			|	add r4, 4
14499		|.endif
14500
14501		if (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
14502			val_info |= MAY_BE_RC1|MAY_BE_RCN;
14503		}
14504
14505		|7:
14506		|	// FREE_OP_DATA();
14507		|	FREE_OP (opline+1)->op1_type, (opline+1)->op1, val_info, 0, opline
14508		|	jmp >9
14509		|.code
14510	} else if (needs_val_dtor) {
14511		|.cold_code
14512		|7:
14513		|	// FREE_OP_DATA();
14514		|	FREE_OP (opline+1)->op1_type, (opline+1)->op1, val_info, 0, opline
14515		|	jmp >9
14516		|.code
14517	}
14518
14519	|9:
14520	if (opline->op1_type != IS_UNUSED && !use_this && !op1_indirect) {
14521		|	FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline
14522	}
14523
14524	if (may_throw) {
14525		if (!zend_jit_check_exception(Dst)) {
14526			return 0;
14527		}
14528	}
14529
14530	return 1;
14531}
14532
14533static int zend_jit_free(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, int may_throw)
14534{
14535	zend_jit_addr op1_addr = OP1_ADDR();
14536
14537	if (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
14538		if (may_throw) {
14539			|	SET_EX_OPLINE opline, r0
14540		}
14541		if (opline->opcode == ZEND_FE_FREE && (op1_info & (MAY_BE_OBJECT|MAY_BE_REF))) {
14542			if (op1_info & MAY_BE_ARRAY) {
14543				|	IF_ZVAL_TYPE op1_addr, IS_ARRAY, >7
14544			}
14545			|	mov FCARG1d, dword [FP + opline->op1.var + offsetof(zval, u2.fe_iter_idx)]
14546			|	cmp FCARG1d, -1
14547			|	je >7
14548			|	EXT_CALL zend_hash_iterator_del, r0
14549			|7:
14550		}
14551		|	ZVAL_PTR_DTOR op1_addr, op1_info, 0, 0, opline
14552		if (may_throw) {
14553			if (!zend_jit_check_exception(Dst)) {
14554				return 0;
14555			}
14556		}
14557	}
14558
14559	return 1;
14560}
14561
14562static int zend_jit_echo(dasm_State **Dst, const zend_op *opline, uint32_t op1_info)
14563{
14564	if (opline->op1_type == IS_CONST) {
14565		zval *zv;
14566		size_t len;
14567
14568		zv = RT_CONSTANT(opline, opline->op1);
14569		ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
14570		len = Z_STRLEN_P(zv);
14571
14572		if (len > 0) {
14573			const char *str = Z_STRVAL_P(zv);
14574
14575			|	SET_EX_OPLINE opline, r0
14576			|.if X64
14577				|	LOAD_ADDR CARG1, str
14578				|	LOAD_ADDR CARG2, len
14579				|	EXT_CALL zend_write, r0
14580			|.else
14581				|	mov aword A2, len
14582				|	mov aword A1, str
14583				|	EXT_CALL zend_write, r0
14584			|.endif
14585			if (!zend_jit_check_exception(Dst)) {
14586				return 0;
14587			}
14588		}
14589	} else {
14590		zend_jit_addr op1_addr = OP1_ADDR();
14591
14592		ZEND_ASSERT((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_STRING);
14593
14594		|	SET_EX_OPLINE opline, r0
14595		|	GET_ZVAL_PTR r0, op1_addr
14596		|.if X64
14597		|	lea CARG1, aword [r0 + offsetof(zend_string, val)]
14598		|	mov CARG2, aword [r0 + offsetof(zend_string, len)]
14599		|	EXT_CALL zend_write, r0
14600		|.else
14601		|	add r0, offsetof(zend_string, val)
14602		|	mov aword A1, r0
14603		|	mov r0, aword [r0 + (offsetof(zend_string, len)-offsetof(zend_string, val))]
14604		|	mov aword A2, r0
14605		|	EXT_CALL zend_write, r0
14606		|.endif
14607		if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) {
14608			|	ZVAL_PTR_DTOR op1_addr, op1_info, 0, 0, opline
14609		}
14610		if (!zend_jit_check_exception(Dst)) {
14611			return 0;
14612		}
14613	}
14614	return 1;
14615}
14616
14617static int zend_jit_strlen(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr)
14618{
14619	zend_jit_addr res_addr = RES_ADDR();
14620
14621	if (opline->op1_type == IS_CONST) {
14622		zval *zv;
14623		size_t len;
14624
14625		zv = RT_CONSTANT(opline, opline->op1);
14626		ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
14627		len = Z_STRLEN_P(zv);
14628
14629		|	SET_ZVAL_LVAL res_addr, len
14630		|	SET_ZVAL_TYPE_INFO res_addr, IS_LONG
14631	} else {
14632		ZEND_ASSERT((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_STRING);
14633
14634		|	GET_ZVAL_PTR r0, op1_addr
14635		|	mov r0, aword [r0 + offsetof(zend_string, len)]
14636		|	SET_ZVAL_LVAL res_addr, r0
14637		|	SET_ZVAL_TYPE_INFO res_addr, IS_LONG
14638		|	FREE_OP opline->op1_type, opline->op1, op1_info, 0, opline
14639	}
14640	return 1;
14641}
14642
14643static int zend_jit_load_this(dasm_State **Dst, uint32_t var)
14644{
14645	zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
14646
14647	|	mov FCARG1a, aword EX->This.value.ptr
14648	|	SET_ZVAL_PTR var_addr, FCARG1a
14649	|	SET_ZVAL_TYPE_INFO var_addr, IS_OBJECT_EX
14650	|	GC_ADDREF FCARG1a
14651
14652	return 1;
14653}
14654
14655static int zend_jit_fetch_this(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, zend_bool check_only)
14656{
14657	if (!op_array->scope || (op_array->fn_flags & ZEND_ACC_STATIC)) {
14658		if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14659			if (!JIT_G(current_frame) ||
14660			    !TRACE_FRAME_IS_THIS_CHECKED(JIT_G(current_frame))) {
14661
14662				int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14663				const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14664
14665				|	cmp byte EX->This.u1.v.type, IS_OBJECT
14666				|	jne &exit_addr
14667
14668				if (JIT_G(current_frame)) {
14669					TRACE_FRAME_SET_THIS_CHECKED(JIT_G(current_frame));
14670				}
14671			}
14672		} else {
14673
14674			|	cmp byte EX->This.u1.v.type, IS_OBJECT
14675			|	jne >1
14676			|.cold_code
14677			|1:
14678			|	SET_EX_OPLINE opline, r0
14679			|	jmp ->invalid_this
14680			|.code
14681		}
14682	}
14683
14684	if (!check_only) {
14685		if (!zend_jit_load_this(Dst, opline->result.var)) {
14686			return 0;
14687		}
14688	}
14689
14690	return 1;
14691}
14692
14693static int zend_jit_hash_jmp(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa, HashTable *jumptable, int default_b, const void *default_label, const zend_op *next_opline, zend_jit_trace_info *trace_info)
14694{
14695	uint32_t count;
14696	Bucket *p;
14697	const zend_op *target;
14698	int b;
14699	int32_t exit_point;
14700	const void *exit_addr;
14701
14702	|	test r0, r0
14703	if (default_label) {
14704		|	jz &default_label
14705	} else if (next_opline) {
14706		|	jz >3
14707	} else {
14708		|	jz =>default_b
14709	}
14710	|	LOAD_ADDR FCARG1a, jumptable
14711	|	sub r0, aword [FCARG1a + offsetof(HashTable, arData)]
14712	|	mov FCARG1a, (sizeof(Bucket) / sizeof(void*))
14713	|.if X64
14714	|	cqo
14715	|.else
14716	|	cdq
14717	|.endif
14718	|	idiv FCARG1a
14719	|.if X64
14720	if (!IS_32BIT(dasm_end)) {
14721		|	lea FCARG1a, aword [>4]
14722		|	jmp aword [FCARG1a + r0]
14723	} else {
14724		|	jmp aword [r0 + >4]
14725	}
14726	|.else
14727	|	jmp aword [r0 + >4]
14728	|.endif
14729	|.jmp_table
14730	|.align aword
14731	|4:
14732	if (trace_info) {
14733		trace_info->jmp_table_size += zend_hash_num_elements(jumptable);
14734	}
14735
14736	count = jumptable->nNumUsed;
14737	p = jumptable->arData;
14738	do {
14739		if (Z_TYPE(p->val) == IS_UNDEF) {
14740			if (default_label) {
14741				|	.aword &default_label
14742			} else if (next_opline) {
14743				|	.aword >3
14744			} else {
14745				|	.aword =>default_b
14746			}
14747		} else {
14748			target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL(p->val));
14749			if (!next_opline) {
14750				b = ssa->cfg.map[target - op_array->opcodes];
14751				|	.aword =>b
14752			} else if (next_opline == target) {
14753				|	.aword >3
14754			} else {
14755				exit_point = zend_jit_trace_get_exit_point(target, 0);
14756				exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14757				|	.aword &exit_addr
14758			}
14759		}
14760		p++;
14761		count--;
14762	} while (count);
14763	|.code
14764
14765	return 1;
14766}
14767
14768static int zend_jit_switch(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa, zend_jit_trace_rec *trace, zend_jit_trace_info *trace_info)
14769{
14770	HashTable *jumptable = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2));
14771	const zend_op *next_opline = NULL;
14772
14773	if (trace) {
14774		ZEND_ASSERT(trace->op == ZEND_JIT_TRACE_VM || trace->op == ZEND_JIT_TRACE_END);
14775		ZEND_ASSERT(trace->opline != NULL);
14776		next_opline = trace->opline;
14777	}
14778
14779	if (opline->op1_type == IS_CONST) {
14780		zval *zv = RT_CONSTANT(opline, opline->op1);
14781		zval *jump_zv = NULL;
14782		int b;
14783
14784		if (opline->opcode == ZEND_SWITCH_LONG) {
14785			if (Z_TYPE_P(zv) == IS_LONG) {
14786				jump_zv = zend_hash_index_find(jumptable, Z_LVAL_P(zv));
14787			}
14788		} else if (opline->opcode == ZEND_SWITCH_STRING) {
14789			if (Z_TYPE_P(zv) == IS_STRING) {
14790				jump_zv = zend_hash_find_ex(jumptable, Z_STR_P(zv), 1);
14791			}
14792		} else if (opline->opcode == ZEND_MATCH) {
14793			if (Z_TYPE_P(zv) == IS_LONG) {
14794				jump_zv = zend_hash_index_find(jumptable, Z_LVAL_P(zv));
14795			} else if (Z_TYPE_P(zv) == IS_STRING) {
14796				jump_zv = zend_hash_find_ex(jumptable, Z_STR_P(zv), 1);
14797			}
14798		} else {
14799			ZEND_UNREACHABLE();
14800		}
14801		if (next_opline) {
14802			const zend_op *target;
14803
14804			if (jump_zv != NULL) {
14805				target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(jump_zv));
14806			} else {
14807				target = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
14808			}
14809			ZEND_ASSERT(target == next_opline);
14810		} else {
14811			if (jump_zv != NULL) {
14812				b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(jump_zv)) - op_array->opcodes];
14813			} else {
14814				b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) - op_array->opcodes];
14815			}
14816			|	jmp =>b
14817		}
14818	} else {
14819		zend_ssa_op *ssa_op = &ssa->ops[opline - op_array->opcodes];
14820		uint32_t op1_info = OP1_INFO();
14821		zend_jit_addr op1_addr = OP1_ADDR();
14822		const zend_op *default_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
14823		const zend_op *target;
14824		int default_b = next_opline ? -1 : ssa->cfg.map[default_opline - op_array->opcodes];
14825		int b;
14826		int32_t exit_point;
14827		const void *fallback_label = NULL;
14828		const void *default_label = NULL;
14829		const void *exit_addr;
14830
14831		if (next_opline) {
14832			if (next_opline != opline + 1) {
14833				exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
14834				fallback_label = zend_jit_trace_get_exit_addr(exit_point);
14835			}
14836			if (next_opline != default_opline) {
14837				exit_point = zend_jit_trace_get_exit_point(default_opline, 0);
14838				default_label = zend_jit_trace_get_exit_addr(exit_point);
14839			}
14840		}
14841
14842		if (opline->opcode == ZEND_SWITCH_LONG) {
14843			if (op1_info & MAY_BE_LONG) {
14844				if (op1_info & MAY_BE_REF) {
14845					|	IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >1
14846					|	GET_ZVAL_LVAL ZREG_FCARG2a, op1_addr
14847					|.cold_code
14848					|1:
14849					|	// ZVAL_DEREF(op)
14850					if (fallback_label) {
14851						|	IF_NOT_ZVAL_TYPE op1_addr, IS_REFERENCE, &fallback_label
14852					} else {
14853						|	IF_NOT_ZVAL_TYPE op1_addr, IS_REFERENCE, >3
14854					}
14855					|	GET_ZVAL_PTR FCARG2a, op1_addr
14856					if (fallback_label) {
14857						|	IF_NOT_Z_TYPE FCARG2a + offsetof(zend_reference, val), IS_LONG, &fallback_label
14858					} else {
14859						|	IF_NOT_Z_TYPE FCARG2a + offsetof(zend_reference, val), IS_LONG, >3
14860					}
14861					|	mov FCARG2a, aword [FCARG2a + offsetof(zend_reference, val.value.lval)]
14862					|	jmp >2
14863					|.code
14864					|2:
14865				} else {
14866					if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
14867						if (fallback_label) {
14868							|	IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, &fallback_label
14869						} else {
14870							|	IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >3
14871						}
14872					}
14873					|	GET_ZVAL_LVAL ZREG_FCARG2a, op1_addr
14874				}
14875				if (HT_IS_PACKED(jumptable)) {
14876					uint32_t count = jumptable->nNumUsed;
14877					Bucket *p = jumptable->arData;
14878
14879					|	cmp FCARG2a, jumptable->nNumUsed
14880					if (default_label) {
14881						|	jae &default_label
14882					} else if (next_opline) {
14883						|	jae >3
14884					} else {
14885						|	jae =>default_b
14886					}
14887					|.if X64
14888						if (!IS_32BIT(dasm_end)) {
14889							|	lea r0, aword [>4]
14890							|	jmp aword [r0 + FCARG2a * 8]
14891						} else {
14892							|	jmp aword [FCARG2a * 8 + >4]
14893						}
14894					|.else
14895					|	jmp aword [FCARG2a * 4 + >4]
14896					|.endif
14897					|.jmp_table
14898					|.align aword
14899					|4:
14900					if (trace_info) {
14901						trace_info->jmp_table_size += count;
14902					}
14903					p = jumptable->arData;
14904					do {
14905						if (Z_TYPE(p->val) == IS_UNDEF) {
14906							if (default_label) {
14907								|	.aword &default_label
14908							} else if (next_opline) {
14909								|	.aword >3
14910							} else {
14911								|	.aword =>default_b
14912							}
14913						} else {
14914							target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL(p->val));
14915							if (!next_opline) {
14916								b = ssa->cfg.map[target - op_array->opcodes];
14917								|	.aword =>b
14918							} else if (next_opline == target) {
14919								|	.aword >3
14920							} else {
14921								exit_point = zend_jit_trace_get_exit_point(target, 0);
14922								exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14923								|	.aword &exit_addr
14924							}
14925						}
14926						p++;
14927						count--;
14928					} while (count);
14929					|.code
14930					|3:
14931				} else {
14932					|	LOAD_ADDR FCARG1a, jumptable
14933					|	EXT_CALL zend_hash_index_find, r0
14934					if (!zend_jit_hash_jmp(Dst, opline, op_array, ssa, jumptable, default_b, default_label, next_opline, trace_info)) {
14935						return 0;
14936					}
14937					|3:
14938				}
14939			}
14940		} else if (opline->opcode == ZEND_SWITCH_STRING) {
14941			if (op1_info & MAY_BE_STRING) {
14942				if (op1_info & MAY_BE_REF) {
14943					|	IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, >1
14944					|	GET_ZVAL_PTR FCARG2a, op1_addr
14945					|.cold_code
14946					|1:
14947					|	// ZVAL_DEREF(op)
14948					if (fallback_label) {
14949						|	IF_NOT_ZVAL_TYPE op1_addr, IS_REFERENCE, &fallback_label
14950					} else {
14951						|	IF_NOT_ZVAL_TYPE op1_addr, IS_REFERENCE, >3
14952					}
14953					|	GET_ZVAL_PTR FCARG2a, op1_addr
14954					if (fallback_label) {
14955						|	IF_NOT_Z_TYPE FCARG2a + offsetof(zend_reference, val), IS_STRING, &fallback_label
14956					} else {
14957						|	IF_NOT_Z_TYPE FCARG2a + offsetof(zend_reference, val), IS_STRING, >3
14958					}
14959					|	mov FCARG2a, aword [FCARG2a + offsetof(zend_reference, val.value.ptr)]
14960					|	jmp >2
14961					|.code
14962					|2:
14963				} else {
14964					if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_STRING)) {
14965						if (fallback_label) {
14966							|	IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, &fallback_label
14967						} else {
14968							|	IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, >3
14969						}
14970					}
14971					|	GET_ZVAL_PTR FCARG2a, op1_addr
14972				}
14973				|	LOAD_ADDR FCARG1a, jumptable
14974				|	EXT_CALL zend_hash_find, r0
14975				if (!zend_jit_hash_jmp(Dst, opline, op_array, ssa, jumptable, default_b, default_label, next_opline, trace_info)) {
14976					return 0;
14977				}
14978				|3:
14979			}
14980		} else if (opline->opcode == ZEND_MATCH) {
14981			if (op1_info & (MAY_BE_LONG|MAY_BE_STRING)) {
14982				if (op1_info & MAY_BE_REF) {
14983					|	LOAD_ZVAL_ADDR FCARG2a, op1_addr
14984					|	ZVAL_DEREF FCARG2a, op1_info
14985					op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG2a, 0);
14986				}
14987				|	LOAD_ADDR FCARG1a, jumptable
14988				if (op1_info & MAY_BE_LONG) {
14989					if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
14990						if (op1_info & MAY_BE_STRING) {
14991							|	IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >5
14992						} else if (op1_info & MAY_BE_UNDEF) {
14993							|	IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >6
14994						} else if (default_label) {
14995							|	IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, &default_label
14996						} else if (next_opline) {
14997							|	IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >3
14998						} else {
14999							|	IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, =>default_b
15000						}
15001					}
15002					|	GET_ZVAL_LVAL ZREG_FCARG2a, op1_addr
15003					|	EXT_CALL zend_hash_index_find, r0
15004					if (op1_info & MAY_BE_STRING) {
15005						|	jmp >2
15006					}
15007				}
15008				if (op1_info & MAY_BE_STRING) {
15009					|5:
15010					if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_STRING))) {
15011						if (op1_info & MAY_BE_UNDEF) {
15012							|	IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, >6
15013						} else if (default_label) {
15014							|	IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, &default_label
15015						} else if (next_opline) {
15016							|	IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, >3
15017						} else {
15018							|	IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, =>default_b
15019						}
15020					}
15021					|	GET_ZVAL_PTR FCARG2a, op1_addr
15022					|	EXT_CALL zend_hash_find, r0
15023				}
15024				|2:
15025				if (!zend_jit_hash_jmp(Dst, opline, op_array, ssa, jumptable, default_b, default_label, next_opline, trace_info)) {
15026					return 0;
15027				}
15028			}
15029			if (op1_info & MAY_BE_UNDEF) {
15030				|6:
15031				if (op1_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_STRING))) {
15032					if (default_label) {
15033						|	IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, &default_label
15034					} else if (next_opline) {
15035						|	IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >3
15036					} else {
15037						|	IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, =>default_b
15038					}
15039				}
15040				|	// zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var))));
15041				|	SET_EX_OPLINE opline, r0
15042				|	mov FCARG1d, opline->op1.var
15043				|	EXT_CALL zend_jit_undefined_op_helper, r0
15044				if (!zend_jit_check_exception_undef_result(Dst, opline)) {
15045					return 0;
15046				}
15047			}
15048			if (default_label) {
15049				|	jmp &default_label
15050			} else if (next_opline) {
15051				|	jmp >3
15052			} else {
15053				|	jmp =>default_b
15054			}
15055			|3:
15056		} else {
15057			ZEND_UNREACHABLE();
15058		}
15059	}
15060	return 1;
15061}
15062
15063static zend_bool zend_jit_verify_return_type(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info)
15064{
15065	zend_arg_info *arg_info = &op_array->arg_info[-1];
15066	ZEND_ASSERT(ZEND_TYPE_IS_SET(arg_info->type));
15067	zend_jit_addr op1_addr = OP1_ADDR();
15068	zend_bool needs_slow_check = 1;
15069	zend_bool slow_check_in_cold = 1;
15070	uint32_t type_mask = ZEND_TYPE_PURE_MASK(arg_info->type) & MAY_BE_ANY;
15071
15072	if (type_mask == 0) {
15073		slow_check_in_cold = 0;
15074	} else {
15075		if (((op1_info & MAY_BE_ANY) & type_mask) == 0) {
15076			slow_check_in_cold = 0;
15077		} else if (((op1_info & MAY_BE_ANY) | type_mask) == type_mask) {
15078			needs_slow_check = 0;
15079		} else if (is_power_of_two(type_mask)) {
15080			uint32_t type_code = concrete_type(type_mask);
15081			|	IF_NOT_ZVAL_TYPE op1_addr, type_code, >6
15082		} else {
15083			|	mov edx, 1
15084			|	GET_ZVAL_TYPE cl, op1_addr
15085			|	shl edx, cl
15086			|	test edx, type_mask
15087			|	je >6
15088		}
15089	}
15090	if (needs_slow_check) {
15091		if (slow_check_in_cold) {
15092			|.cold_code
15093			|6:
15094		}
15095		|	SET_EX_OPLINE opline, r1
15096		if (op1_info & MAY_BE_UNDEF) {
15097			|	IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >7
15098			|	mov FCARG1a, opline->op1.var
15099			|	EXT_CALL zend_jit_undefined_op_helper, FCARG2a
15100			|	test r0, r0
15101			|	jz ->exception_handler
15102			|	LOAD_ADDR_ZTS FCARG1a, executor_globals, uninitialized_zval
15103			|	jmp >8
15104		}
15105		|7:
15106		|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
15107		|8:
15108		|	mov FCARG2a, EX->func
15109		|.if X64
15110			|	LOAD_ADDR CARG3, (ptrdiff_t)arg_info
15111			|	mov r0, EX->run_time_cache
15112			|	lea CARG4, aword [r0+opline->op2.num]
15113			|	EXT_CALL zend_jit_verify_return_slow, r0
15114		|.else
15115			|	sub r4, 8
15116			|	mov r0, EX->run_time_cache
15117			|	add r0, opline->op2.num
15118			|	push r0
15119			|	push (ptrdiff_t)arg_info
15120			|	EXT_CALL zend_jit_verify_return_slow, r0
15121			|	add r4, 8
15122		|.endif
15123		if (!zend_jit_check_exception(Dst)) {
15124			return 0;
15125		}
15126		if (slow_check_in_cold) {
15127			|	jmp >9
15128			|.code
15129		}
15130	}
15131	|9:
15132	return 1;
15133}
15134
15135static int zend_jit_isset_isempty_cv(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr,  zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
15136{
15137	zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
15138
15139	// TODO: support for empty() ???
15140	ZEND_ASSERT(!(opline->extended_value & ZEND_ISEMPTY));
15141
15142	if (op1_info & MAY_BE_REF) {
15143		if (Z_MODE(op1_addr) != IS_MEM_ZVAL || Z_REG(op1_addr) != ZREG_FCARG1a || Z_OFFSET(op1_addr) != 0) {
15144			|	LOAD_ZVAL_ADDR FCARG1a, op1_addr
15145			op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
15146		}
15147		|	ZVAL_DEREF FCARG1a, op1_info
15148		|1:
15149	}
15150
15151	if (!(op1_info & (MAY_BE_UNDEF|MAY_BE_NULL))) {
15152		if (exit_addr) {
15153			ZEND_ASSERT(smart_branch_opcode == ZEND_JMPZ);
15154		} else if (smart_branch_opcode) {
15155			if (smart_branch_opcode == ZEND_JMPNZ) {
15156				|	jmp =>target_label
15157			} else if (smart_branch_opcode == ZEND_JMPZNZ) {
15158				|	jmp =>target_label2
15159			}
15160		} else {
15161			|	SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
15162		}
15163	} else if (!(op1_info & (MAY_BE_ANY - MAY_BE_NULL))) {
15164		if (exit_addr) {
15165			ZEND_ASSERT(smart_branch_opcode == ZEND_JMPNZ);
15166		} else if (smart_branch_opcode) {
15167			if (smart_branch_opcode != ZEND_JMPNZ) {
15168				|	jmp =>target_label
15169			}
15170		} else {
15171			|	SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
15172		}
15173	} else {
15174		ZEND_ASSERT(Z_MODE(op1_addr) == IS_MEM_ZVAL);
15175		|	cmp byte [Ra(Z_REG(op1_addr))+Z_OFFSET(op1_addr)+offsetof(zval, u1.v.type)], IS_NULL
15176		if (exit_addr) {
15177			if (smart_branch_opcode == ZEND_JMPNZ) {
15178				|	jg &exit_addr
15179			} else {
15180				|	jle &exit_addr
15181			}
15182		} else if (smart_branch_opcode) {
15183			if (smart_branch_opcode == ZEND_JMPZ) {
15184				|	jle =>target_label
15185			} else if (smart_branch_opcode == ZEND_JMPNZ) {
15186				|	jg =>target_label
15187			} else if (smart_branch_opcode == ZEND_JMPZNZ) {
15188				|	jle =>target_label
15189				|	jmp =>target_label2
15190			} else {
15191				ZEND_UNREACHABLE();
15192			}
15193		} else {
15194			|	setg al
15195			|	movzx eax, al
15196			|	lea eax, [eax + IS_FALSE]
15197			|	SET_ZVAL_TYPE_INFO res_addr, eax
15198		}
15199	}
15200
15201	return 1;
15202}
15203
15204static int zend_jit_fe_reset(dasm_State **Dst, const zend_op *opline, uint32_t op1_info)
15205{
15206	zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
15207
15208	if (opline->op1_type == IS_CONST) {
15209		zval *zv = RT_CONSTANT(opline, opline->op1);
15210
15211		|	ZVAL_COPY_CONST res_addr, MAY_BE_ANY, MAY_BE_ANY, zv, ZREG_R0
15212		if (Z_REFCOUNTED_P(zv)) {
15213			|	ADDREF_CONST zv, r0
15214		}
15215	} else {
15216		zend_jit_addr op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
15217
15218		|	// ZVAL_COPY(res, value);
15219		|	ZVAL_COPY_VALUE res_addr, -1, op1_addr, op1_info, ZREG_R0, ZREG_FCARG1a
15220		if (opline->op1_type == IS_CV) {
15221			|	TRY_ADDREF op1_info, ah, FCARG1a
15222		}
15223	}
15224	|	// Z_FE_POS_P(res) = 0;
15225	|	mov dword [FP + opline->result.var + offsetof(zval, u2.fe_pos)], 0
15226
15227	return 1;
15228}
15229
15230static int zend_jit_fe_fetch(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, uint32_t op2_info, unsigned int target_label, zend_uchar exit_opcode, const void *exit_addr)
15231{
15232	zend_jit_addr op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
15233
15234	|	// array = EX_VAR(opline->op1.var);
15235	|	// fe_ht = Z_ARRVAL_P(array);
15236	|	GET_ZVAL_PTR FCARG2a, op1_addr
15237	|	// pos = Z_FE_POS_P(array);
15238	|	mov FCARG1d, dword [FP + opline->op1.var + offsetof(zval, u2.fe_pos)]
15239	|	// p = fe_ht->arData + pos;
15240	|.if X64
15241		||	ZEND_ASSERT(sizeof(Bucket) == 32);
15242		|	mov eax, FCARG1d
15243		|	shl r0, 5
15244	|.else
15245		|	imul r0, FCARG1a, sizeof(Bucket)
15246	|.endif
15247	|	add r0, aword [FCARG2a + offsetof(zend_array, arData)]
15248	|1:
15249	|	// if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
15250	|	cmp dword [FCARG2a + offsetof(zend_array, nNumUsed)], FCARG1d
15251	|	// ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value);
15252	|   // ZEND_VM_CONTINUE();
15253	if (exit_addr) {
15254		if (exit_opcode == ZEND_JMP) {
15255			|	jbe &exit_addr
15256		} else {
15257			|	jbe >3
15258		}
15259	} else {
15260		|	jbe =>target_label
15261	}
15262	|	// pos++;
15263	|	add FCARG1d, 1
15264	|	// value_type = Z_TYPE_INFO_P(value);
15265	|	// if (EXPECTED(value_type != IS_UNDEF)) {
15266	|	IF_Z_TYPE r0, IS_UNDEF, >2
15267	if (!exit_addr || exit_opcode == ZEND_JMP) {
15268		|	IF_NOT_Z_TYPE r0, IS_INDIRECT, >3
15269	} else {
15270		|	IF_NOT_Z_TYPE r0, IS_INDIRECT, &exit_addr
15271	}
15272	|	// value = Z_INDIRECT_P(value);
15273	|	GET_Z_PTR FCARG2a, r0
15274	|	// value_type = Z_TYPE_INFO_P(value);
15275	|	// if (EXPECTED(value_type != IS_UNDEF)) {
15276	if (!exit_addr || exit_opcode == ZEND_JMP) {
15277		|	IF_NOT_Z_TYPE FCARG2a, IS_UNDEF, >4
15278	} else {
15279		|	IF_NOT_Z_TYPE r0, IS_UNDEF, &exit_addr
15280	}
15281	|	GET_ZVAL_PTR FCARG2a, op1_addr // reload
15282	|2:
15283	|	// p++;
15284	|	add r0, sizeof(Bucket)
15285	|	jmp <1
15286	|3:
15287
15288	if (!exit_addr || exit_opcode == ZEND_JMP) {
15289		zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG2a, 0);
15290		zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
15291		uint32_t val_info;
15292
15293		|	mov	FCARG2a, r0
15294		|4:
15295		|	// Z_FE_POS_P(array) = pos + 1;
15296		|	mov dword [FP + opline->op1.var + offsetof(zval, u2.fe_pos)], FCARG1d
15297
15298		if (RETURN_VALUE_USED(opline)) {
15299			zend_jit_addr res_addr = RES_ADDR();
15300
15301			if ((op1_info & MAY_BE_ARRAY_KEY_LONG)
15302			 && (op1_info & MAY_BE_ARRAY_KEY_STRING)) {
15303				|	// if (!p->key) {
15304				|	cmp aword [r0 + offsetof(Bucket, key)], 0
15305				|	jz >2
15306			}
15307			if (op1_info & MAY_BE_ARRAY_KEY_STRING) {
15308				|	// ZVAL_STR_COPY(EX_VAR(opline->result.var), p->key);
15309				|	mov FCARG1a, aword [r0 + offsetof(Bucket, key)]
15310				|	SET_ZVAL_PTR res_addr, FCARG1a
15311				|	test dword [FCARG1a + offsetof(zend_refcounted, gc.u.type_info)], IS_STR_INTERNED
15312				|	jz >1
15313				|	SET_ZVAL_TYPE_INFO res_addr, IS_STRING
15314				|	jmp >3
15315				|1:
15316				|	GC_ADDREF FCARG1a
15317				|	SET_ZVAL_TYPE_INFO res_addr, IS_STRING_EX
15318
15319				if (op1_info & MAY_BE_ARRAY_KEY_LONG) {
15320				    |	jmp >3
15321					|2:
15322				}
15323			}
15324			if (op1_info & MAY_BE_ARRAY_KEY_LONG) {
15325				|	// ZVAL_LONG(EX_VAR(opline->result.var), p->h);
15326				|	mov FCARG1a, aword [r0 + offsetof(Bucket, h)]
15327				|	SET_ZVAL_LVAL res_addr, FCARG1a
15328				|	SET_ZVAL_TYPE_INFO res_addr, IS_LONG
15329			}
15330			|3:
15331		}
15332
15333		val_info = ((op1_info & MAY_BE_ARRAY_OF_ANY) >> MAY_BE_ARRAY_SHIFT);
15334		if (val_info & MAY_BE_ARRAY) {
15335			val_info |= MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
15336		}
15337		if (op1_info & MAY_BE_ARRAY_OF_REF) {
15338			val_info |= MAY_BE_REF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ANY |
15339				MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
15340		} else if (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
15341			val_info |= MAY_BE_RC1 | MAY_BE_RCN;
15342		}
15343
15344		if (opline->op2_type == IS_CV) {
15345			|	// zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES());
15346			if (!zend_jit_assign_to_variable(Dst, opline, var_addr, var_addr, op2_info, -1, IS_CV, val_addr, val_info, 0, 1)) {
15347				return 0;
15348			}
15349		} else {
15350			|	// ZVAL_COPY(res, value);
15351			|	ZVAL_COPY_VALUE var_addr, -1, val_addr, val_info, ZREG_R0, ZREG_FCARG1a
15352			|	TRY_ADDREF val_info, ah, FCARG1a
15353		}
15354	}
15355
15356	return 1;
15357}
15358
15359static int zend_jit_fetch_constant(dasm_State          **Dst,
15360                                   const zend_op        *opline,
15361                                   const zend_op_array  *op_array,
15362                                   zend_ssa             *ssa,
15363                                   const zend_ssa_op    *ssa_op)
15364{
15365	zval *zv = RT_CONSTANT(opline, opline->op2) + 1;
15366	zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
15367	zend_jit_addr const_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0);
15368	uint32_t res_info = RES_INFO();
15369
15370	|	// c = CACHED_PTR(opline->extended_value);
15371	|	mov FCARG1a, EX->run_time_cache
15372	|	mov r0, aword [FCARG1a + opline->extended_value]
15373	|	// if (c != NULL)
15374	|	test r0, r0
15375	|	jz >9
15376	|	// if (!IS_SPECIAL_CACHE_VAL(c))
15377	|	test r0, CACHE_SPECIAL
15378	|	jnz >9
15379	|8:
15380
15381	if ((res_info & MAY_BE_GUARD) && JIT_G(current_frame)) {
15382		zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
15383		uint32_t old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
15384		int32_t exit_point;
15385		const void *exit_addr = NULL;
15386
15387		SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN, 1);
15388		SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_ZVAL_COPY_R0);
15389		exit_point = zend_jit_trace_get_exit_point(opline+1, 0);
15390		SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_info);
15391		exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15392		if (!exit_addr) {
15393			return 0;
15394		}
15395		res_info &= ~MAY_BE_GUARD;
15396		ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
15397
15398		zend_uchar type = concrete_type(res_info);
15399
15400		if (type < IS_STRING) {
15401			|	IF_NOT_ZVAL_TYPE const_addr, type, &exit_addr
15402		} else {
15403			|	GET_ZVAL_TYPE_INFO edx, const_addr
15404			|	IF_NOT_TYPE dl, type, &exit_addr
15405		}
15406		|	ZVAL_COPY_VALUE_V res_addr, -1, const_addr, res_info, ZREG_R0, ZREG_R1
15407		if (type < IS_STRING) {
15408			|	SET_ZVAL_TYPE_INFO res_addr, type
15409		} else {
15410			|	SET_ZVAL_TYPE_INFO res_addr, edx
15411			|	TRY_ADDREF res_info, dh, r1
15412		}
15413	} else {
15414		|	// ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value); (no dup)
15415		|	ZVAL_COPY_VALUE res_addr, MAY_BE_ANY, const_addr, MAY_BE_ANY, ZREG_R0, ZREG_R1
15416		|	TRY_ADDREF MAY_BE_ANY, ah, r1
15417	}
15418
15419	|.cold_code
15420	|9:
15421	|	// SAVE_OPLINE();
15422	|	SET_EX_OPLINE opline, r0
15423	|	// zend_quick_get_constant(RT_CONSTANT(opline, opline->op2) + 1, opline->op1.num OPLINE_CC EXECUTE_DATA_CC);
15424	|	LOAD_ADDR FCARG1a, zv
15425	|	mov FCARG2a, opline->op1.num
15426	|	EXT_CALL zend_jit_get_constant, r0
15427	|	// ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
15428	|	test r0, r0
15429	|	jnz <8
15430	|	jmp ->exception_handler
15431	|.code
15432
15433	return 1;
15434}
15435
15436static int zend_jit_in_array(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr,  zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
15437{
15438	HashTable *ht = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2));
15439	zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
15440
15441	ZEND_ASSERT(opline->op1_type != IS_VAR && opline->op1_type != IS_TMP_VAR);
15442	ZEND_ASSERT((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) == MAY_BE_STRING);
15443
15444	|	// result = zend_hash_find_ex(ht, Z_STR_P(op1), OP1_TYPE == IS_CONST);
15445	|	LOAD_ADDR FCARG1a, ht
15446	if (opline->op1_type != IS_CONST) {
15447		|	GET_ZVAL_PTR FCARG2a, op1_addr
15448		|	EXT_CALL zend_hash_find, r0
15449	} else {
15450		zend_string *str = Z_STR_P(RT_CONSTANT(opline, opline->op1));
15451		|	LOAD_ADDR FCARG2a, str
15452		|	EXT_CALL _zend_hash_find_known_hash, r0
15453	}
15454	|	test r0, r0
15455	if (exit_addr) {
15456		if (smart_branch_opcode == ZEND_JMPZ) {
15457			|	jz &exit_addr
15458		} else {
15459			|	jnz &exit_addr
15460		}
15461	} else if (smart_branch_opcode) {
15462		if (smart_branch_opcode == ZEND_JMPZ) {
15463			|	jz =>target_label
15464		} else if (smart_branch_opcode == ZEND_JMPNZ) {
15465			|	jnz =>target_label
15466		} else if (smart_branch_opcode == ZEND_JMPZNZ) {
15467			|	jz =>target_label
15468			|	jmp =>target_label2
15469		} else {
15470			ZEND_UNREACHABLE();
15471		}
15472	} else {
15473		|	setnz al
15474		|	movzx eax, al
15475		|	lea eax, [eax + IS_FALSE]
15476		|	SET_ZVAL_TYPE_INFO res_addr, eax
15477	}
15478
15479	return 1;
15480}
15481
15482static zend_bool zend_jit_noref_guard(dasm_State **Dst, const zend_op *opline, zend_jit_addr var_addr)
15483{
15484	int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
15485	const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15486
15487	if (!exit_addr) {
15488		return 0;
15489	}
15490	|	IF_ZVAL_TYPE var_addr, IS_REFERENCE, &exit_addr
15491
15492	return 1;
15493}
15494
15495static zend_bool zend_jit_fetch_reference(dasm_State **Dst, const zend_op *opline, uint8_t var_type, uint32_t *var_info_ptr, zend_jit_addr *var_addr_ptr, zend_bool add_ref_guard, zend_bool add_type_guard)
15496{
15497	zend_jit_addr var_addr = *var_addr_ptr;
15498	uint32_t var_info = *var_info_ptr;
15499	const void *exit_addr = NULL;
15500
15501	if (add_ref_guard || add_type_guard) {
15502		int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
15503
15504		exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15505		if (!exit_addr) {
15506			return 0;
15507		}
15508	}
15509
15510	if (add_ref_guard) {
15511		|	IF_NOT_ZVAL_TYPE var_addr, IS_REFERENCE, &exit_addr
15512	}
15513	if (opline->opcode == ZEND_INIT_METHOD_CALL && opline->op1_type == IS_VAR) {
15514		/* Hack: Convert reference to regular value to simplify JIT code for INIT_METHOD_CALL */
15515		if (Z_REG(var_addr) != ZREG_FCARG1a || Z_OFFSET(var_addr) != 0) {
15516			|	LOAD_ZVAL_ADDR FCARG1a, var_addr
15517		}
15518		|	EXT_CALL zend_jit_unref_helper, r0
15519	} else {
15520		|	GET_ZVAL_PTR FCARG1a, var_addr
15521		var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, offsetof(zend_reference, val));
15522		*var_addr_ptr = var_addr;
15523	}
15524
15525	if (var_type != IS_UNKNOWN) {
15526		var_type &= ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED);
15527	}
15528	if (add_type_guard
15529	 && var_type != IS_UNKNOWN
15530	 && (var_info & (MAY_BE_ANY|MAY_BE_UNDEF)) != (1 << var_type)) {
15531		|	IF_NOT_ZVAL_TYPE var_addr, var_type, &exit_addr
15532
15533		ZEND_ASSERT(var_info & (1 << var_type));
15534		if (var_type < IS_STRING) {
15535			var_info = (1 << var_type);
15536		} else if (var_type != IS_ARRAY) {
15537			var_info = (1 << var_type) | (var_info & (MAY_BE_RC1|MAY_BE_RCN));
15538		} else {
15539			var_info = MAY_BE_ARRAY | (var_info & (MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF|MAY_BE_ARRAY_KEY_ANY|MAY_BE_RC1|MAY_BE_RCN));
15540		}
15541
15542		*var_info_ptr = var_info;
15543	} else {
15544		var_info &= ~MAY_BE_REF;
15545		*var_info_ptr = var_info;
15546	}
15547	*var_info_ptr |= MAY_BE_GUARD; /* prevent generation of specialized zval dtor */
15548
15549	return 1;
15550}
15551
15552static zend_bool zend_jit_fetch_indirect_var(dasm_State **Dst, const zend_op *opline, uint8_t var_type, uint32_t *var_info_ptr, zend_jit_addr *var_addr_ptr, zend_bool add_indirect_guard)
15553{
15554	zend_jit_addr var_addr = *var_addr_ptr;
15555	uint32_t var_info = *var_info_ptr;
15556	int32_t exit_point;
15557	const void *exit_addr;
15558
15559	if (add_indirect_guard) {
15560		int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
15561		const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15562
15563		if (!exit_addr) {
15564			return 0;
15565		}
15566		|	IF_NOT_ZVAL_TYPE var_addr, IS_INDIRECT, &exit_addr
15567		|	GET_ZVAL_PTR FCARG1a, var_addr
15568	} else {
15569		/* May be already loaded into FCARG1a or RAX by previus FETCH_OBJ_W/DIM_W */
15570		if (opline->op1_type != IS_VAR ||
15571				(opline-1)->result_type != IS_VAR  ||
15572				(opline-1)->result.var != opline->op1.var ||
15573				(opline-1)->op2_type == IS_VAR ||
15574				(opline-1)->op2_type == IS_TMP_VAR) {
15575			|	GET_ZVAL_PTR FCARG1a, var_addr
15576		} else if ((opline-1)->opcode == ZEND_FETCH_DIM_W || (opline-1)->opcode == ZEND_FETCH_DIM_RW) {
15577			|	mov FCARG1a, r0
15578		}
15579	}
15580	*var_info_ptr &= ~MAY_BE_INDIRECT;
15581	var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
15582	*var_addr_ptr = var_addr;
15583
15584	if (var_type != IS_UNKNOWN) {
15585		var_type &= ~(IS_TRACE_INDIRECT|IS_TRACE_PACKED);
15586	}
15587	if (!(var_type & IS_TRACE_REFERENCE)
15588	 && var_type != IS_UNKNOWN
15589	 && (var_info & (MAY_BE_ANY|MAY_BE_UNDEF)) != (1 << var_type)) {
15590		exit_point = zend_jit_trace_get_exit_point(opline, 0);
15591		exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15592
15593		if (!exit_addr) {
15594			return 0;
15595		}
15596
15597		|	IF_NOT_Z_TYPE FCARG1a, var_type, &exit_addr
15598
15599		//var_info = zend_jit_trace_type_to_info_ex(var_type, var_info);
15600		ZEND_ASSERT(var_info & (1 << var_type));
15601		if (var_type < IS_STRING) {
15602			var_info = (1 << var_type);
15603		} else if (var_type != IS_ARRAY) {
15604			var_info = (1 << var_type) | (var_info & (MAY_BE_RC1|MAY_BE_RCN));
15605		} else {
15606			var_info = MAY_BE_ARRAY | (var_info & (MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF|MAY_BE_ARRAY_KEY_ANY|MAY_BE_RC1|MAY_BE_RCN));
15607		}
15608
15609		*var_info_ptr = var_info;
15610	}
15611
15612	return 1;
15613}
15614
15615static zend_bool zend_jit_may_reuse_reg(const zend_op *opline, const zend_ssa_op *ssa_op, zend_ssa *ssa, int def_var, int use_var)
15616{
15617	if ((ssa->var_info[def_var].type & ~MAY_BE_GUARD) != (ssa->var_info[use_var].type & ~MAY_BE_GUARD)) {
15618		return 0;
15619	}
15620
15621	switch (opline->opcode) {
15622		case ZEND_QM_ASSIGN:
15623		case ZEND_SEND_VAR:
15624		case ZEND_ASSIGN:
15625		case ZEND_PRE_INC:
15626		case ZEND_PRE_DEC:
15627		case ZEND_POST_INC:
15628		case ZEND_POST_DEC:
15629			return 1;
15630		case ZEND_ADD:
15631		case ZEND_SUB:
15632		case ZEND_MUL:
15633		case ZEND_BW_OR:
15634		case ZEND_BW_AND:
15635		case ZEND_BW_XOR:
15636			if (def_var == ssa_op->result_def &&
15637			    use_var == ssa_op->op1_use) {
15638				return 1;
15639			}
15640			break;
15641		default:
15642			break;
15643	}
15644	return 0;
15645}
15646
15647static zend_bool zend_jit_opline_supports_reg(const zend_op_array *op_array, zend_ssa *ssa, const zend_op *opline, const zend_ssa_op *ssa_op, zend_jit_trace_rec *trace)
15648{
15649	uint32_t op1_info, op2_info;
15650
15651	switch (opline->opcode) {
15652		case ZEND_SEND_VAR:
15653		case ZEND_SEND_VAL:
15654		case ZEND_SEND_VAL_EX:
15655			return (opline->op2_type != IS_CONST);
15656		case ZEND_QM_ASSIGN:
15657		case ZEND_IS_SMALLER:
15658		case ZEND_IS_SMALLER_OR_EQUAL:
15659		case ZEND_IS_EQUAL:
15660		case ZEND_IS_NOT_EQUAL:
15661		case ZEND_IS_IDENTICAL:
15662		case ZEND_IS_NOT_IDENTICAL:
15663		case ZEND_CASE:
15664			return 1;
15665		case ZEND_RETURN:
15666			return (op_array->type != ZEND_EVAL_CODE && op_array->function_name);
15667		case ZEND_ASSIGN:
15668			op1_info = OP1_INFO();
15669			op2_info = OP2_INFO();
15670			return
15671				opline->op1_type == IS_CV &&
15672				!(op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_RESOURCE|MAY_BE_OBJECT|MAY_BE_REF)) &&
15673				!(op2_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)));
15674		case ZEND_ADD:
15675		case ZEND_SUB:
15676		case ZEND_MUL:
15677			op1_info = OP1_INFO();
15678			op2_info = OP2_INFO();
15679			return !((op1_info | op2_info) & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_DOUBLE)));
15680		case ZEND_BW_OR:
15681		case ZEND_BW_AND:
15682		case ZEND_BW_XOR:
15683		case ZEND_SL:
15684		case ZEND_SR:
15685		case ZEND_MOD:
15686			op1_info = OP1_INFO();
15687			op2_info = OP2_INFO();
15688			return !((op1_info | op2_info) & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF) - MAY_BE_LONG));
15689		case ZEND_PRE_INC:
15690		case ZEND_PRE_DEC:
15691		case ZEND_POST_INC:
15692		case ZEND_POST_DEC:
15693			op1_info = OP1_INFO();
15694			return opline->op1_type == IS_CV && !(op1_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF) - MAY_BE_LONG));
15695		case ZEND_JMPZ:
15696		case ZEND_JMPNZ:
15697			if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE) {
15698				if (!ssa->cfg.map) {
15699					return 0;
15700				}
15701				if (opline > op_array->opcodes + ssa->cfg.blocks[ssa->cfg.map[opline-op_array->opcodes]].start &&
15702				    ((opline-1)->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
15703					return 0;
15704				}
15705			}
15706			/* break missing intentionally */
15707		case ZEND_BOOL:
15708		case ZEND_BOOL_NOT:
15709		case ZEND_JMPZNZ:
15710		case ZEND_JMPZ_EX:
15711		case ZEND_JMPNZ_EX:
15712			return 1;
15713		case ZEND_FETCH_DIM_R:
15714			op1_info = OP1_INFO();
15715			op2_info = OP2_INFO();
15716			if (trace
15717			 && trace->op1_type != IS_UNKNOWN
15718			 && (trace->op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED)) == IS_ARRAY) {
15719				op1_info &= ~((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY);
15720			}
15721			return ((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) &&
15722				(!(opline->op1_type & (IS_TMP_VAR|IS_VAR)) || !(op1_info & MAY_BE_RC1)) &&
15723					(((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) ||
15724					 (((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_STRING) &&
15725						 (!(opline->op2_type & (IS_TMP_VAR|IS_VAR)) || !(op2_info & MAY_BE_RC1))));
15726	}
15727	return 0;
15728}
15729
15730static zend_bool zend_jit_var_supports_reg(zend_ssa *ssa, int var)
15731{
15732	if (ssa->vars[var].no_val) {
15733		/* we don't need the value */
15734		return 0;
15735	}
15736
15737	if (!(JIT_G(opt_flags) & ZEND_JIT_REG_ALLOC_GLOBAL)) {
15738		/* Disable global register allocation,
15739		 * register allocation for SSA variables connected through Phi functions
15740		 */
15741		if (ssa->vars[var].definition_phi) {
15742			return 0;
15743		}
15744		if (ssa->vars[var].phi_use_chain) {
15745			zend_ssa_phi *phi = ssa->vars[var].phi_use_chain;
15746			do {
15747				if (!ssa->vars[phi->ssa_var].no_val) {
15748					return 0;
15749				}
15750				phi = zend_ssa_next_use_phi(ssa, var, phi);
15751			} while (phi);
15752		}
15753	}
15754
15755	if (((ssa->var_info[var].type & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != MAY_BE_DOUBLE) &&
15756	    ((ssa->var_info[var].type & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != MAY_BE_LONG)) {
15757	    /* bad type */
15758		return 0;
15759	}
15760
15761	return 1;
15762}
15763
15764static zend_bool zend_jit_may_be_in_reg(const zend_op_array *op_array, zend_ssa *ssa, int var)
15765{
15766	if (!zend_jit_var_supports_reg(ssa, var)) {
15767		return 0;
15768	}
15769
15770	if (ssa->vars[var].definition >= 0) {
15771		uint32_t def = ssa->vars[var].definition;
15772		if (!zend_jit_opline_supports_reg(op_array, ssa, op_array->opcodes + def, ssa->ops + def, NULL)) {
15773			return 0;
15774		}
15775	}
15776
15777	if (ssa->vars[var].use_chain >= 0) {
15778		int use = ssa->vars[var].use_chain;
15779
15780		do {
15781			if (!zend_ssa_is_no_val_use(op_array->opcodes + use, ssa->ops + use, var) &&
15782			    !zend_jit_opline_supports_reg(op_array, ssa, op_array->opcodes + use, ssa->ops + use, NULL)) {
15783				return 0;
15784			}
15785			use = zend_ssa_next_use(ssa->ops, var, use);
15786		} while (use >= 0);
15787	}
15788
15789	return 1;
15790}
15791
15792static zend_bool zend_needs_extra_reg_for_const(const zend_op *opline, zend_uchar op_type, znode_op op)
15793{
15794|.if X64
15795||	if (op_type == IS_CONST) {
15796||		zval *zv = RT_CONSTANT(opline, op);
15797||		if (Z_TYPE_P(zv) == IS_DOUBLE && Z_DVAL_P(zv) != 0 && !IS_SIGNED_32BIT(zv)) {
15798||			return 1;
15799||		} else if (Z_TYPE_P(zv) == IS_LONG && !IS_SIGNED_32BIT(Z_LVAL_P(zv))) {
15800||			return 1;
15801||		}
15802||	}
15803|.endif
15804	return 0;
15805}
15806
15807static zend_regset zend_jit_get_def_scratch_regset(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_op_array *op_array, zend_ssa *ssa, int current_var, zend_bool last_use)
15808{
15809	uint32_t op1_info, op2_info;
15810
15811	switch (opline->opcode) {
15812		case ZEND_FETCH_DIM_R:
15813			op1_info = OP1_INFO();
15814			op2_info = OP2_INFO();
15815			if (((opline->op1_type & (IS_TMP_VAR|IS_VAR)) &&
15816			     (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) ||
15817			    ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) &&
15818			     (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)))) {
15819				return ZEND_REGSET(ZREG_FCARG1a);
15820			}
15821			break;
15822		default:
15823			break;
15824	}
15825
15826	return ZEND_REGSET_EMPTY;
15827}
15828
15829static zend_regset zend_jit_get_scratch_regset(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_op_array *op_array, zend_ssa *ssa, int current_var, zend_bool last_use)
15830{
15831	uint32_t op1_info, op2_info, res_info;
15832	zend_regset regset = ZEND_REGSET_SCRATCH;
15833
15834	switch (opline->opcode) {
15835		case ZEND_NOP:
15836		case ZEND_OP_DATA:
15837		case ZEND_JMP:
15838		case ZEND_RETURN:
15839			regset = ZEND_REGSET_EMPTY;
15840			break;
15841		case ZEND_QM_ASSIGN:
15842			if (ssa_op->op1_def == current_var ||
15843			    ssa_op->result_def == current_var) {
15844				regset = ZEND_REGSET_EMPTY;
15845				break;
15846			}
15847			/* break missing intentionally */
15848		case ZEND_SEND_VAL:
15849		case ZEND_SEND_VAL_EX:
15850			if (opline->op2_type == IS_CONST) {
15851				break;
15852			}
15853			if (ssa_op->op1_use == current_var) {
15854				regset = ZEND_REGSET(ZREG_R0);
15855				break;
15856			}
15857			op1_info = OP1_INFO();
15858			if (!(op1_info & MAY_BE_UNDEF)) {
15859				if ((op1_info & (MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_DOUBLE) {
15860					regset = ZEND_REGSET(ZREG_XMM0);
15861				} else if ((op1_info & (MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_LONG) {
15862					regset = ZEND_REGSET(ZREG_R0);
15863				} else {
15864					regset = ZEND_REGSET_UNION(ZEND_REGSET(ZREG_R0), ZEND_REGSET(ZREG_R2));
15865				}
15866			}
15867			break;
15868		case ZEND_SEND_VAR:
15869			if (opline->op2_type == IS_CONST) {
15870				break;
15871			}
15872			if (ssa_op->op1_use == current_var ||
15873			    ssa_op->op1_def == current_var) {
15874				regset = ZEND_REGSET_EMPTY;
15875				break;
15876			}
15877			op1_info = OP1_INFO();
15878			if (!(op1_info & MAY_BE_UNDEF)) {
15879				if ((op1_info & (MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_DOUBLE) {
15880					regset = ZEND_REGSET(ZREG_XMM0);
15881				} else if ((op1_info & (MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_LONG) {
15882				} else {
15883					regset = ZEND_REGSET_UNION(ZEND_REGSET(ZREG_R0), ZEND_REGSET(ZREG_R2));
15884					if (op1_info & MAY_BE_REF) {
15885						ZEND_REGSET_INCL(regset, ZREG_R1);
15886					}
15887				}
15888			}
15889			break;
15890		case ZEND_ASSIGN:
15891			if (ssa_op->op2_use == current_var ||
15892			    ssa_op->op2_def == current_var ||
15893			    ssa_op->op1_def == current_var ||
15894			    ssa_op->result_def == current_var) {
15895				regset = ZEND_REGSET_EMPTY;
15896				break;
15897			}
15898			op1_info = OP1_INFO();
15899			op2_info = OP2_INFO();
15900			if (opline->op1_type == IS_CV
15901			 && !(op2_info & MAY_BE_UNDEF)
15902			 && !(op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) {
15903				if ((op2_info & (MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_DOUBLE) {
15904					regset = ZEND_REGSET(ZREG_XMM0);
15905				} else if ((op2_info & (MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_LONG) {
15906					regset = ZEND_REGSET(ZREG_R0);
15907				} else {
15908					regset = ZEND_REGSET_UNION(ZEND_REGSET(ZREG_R0), ZEND_REGSET(ZREG_R2));
15909				}
15910			}
15911			break;
15912		case ZEND_PRE_INC:
15913		case ZEND_PRE_DEC:
15914		case ZEND_POST_INC:
15915		case ZEND_POST_DEC:
15916			if (ssa_op->op1_use == current_var ||
15917			    ssa_op->op1_def == current_var ||
15918			    ssa_op->result_def == current_var) {
15919				regset = ZEND_REGSET_EMPTY;
15920				break;
15921			}
15922			op1_info = OP1_INFO();
15923			if (opline->op1_type == IS_CV
15924			 && (op1_info & MAY_BE_LONG)
15925			 && !(op1_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)))) {
15926				regset = ZEND_REGSET_EMPTY;
15927				if (op1_info & MAY_BE_DOUBLE) {
15928					regset = ZEND_REGSET(ZREG_XMM0);
15929				}
15930				if (opline->result_type != IS_UNUSED && (op1_info & MAY_BE_LONG)) {
15931					ZEND_REGSET_INCL(regset, ZREG_R1);
15932				}
15933			}
15934			break;
15935		case ZEND_ADD:
15936		case ZEND_SUB:
15937		case ZEND_MUL:
15938			op1_info = OP1_INFO();
15939			op2_info = OP2_INFO();
15940			if (!(op1_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) &&
15941			    !(op2_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)))) {
15942
15943				regset = ZEND_REGSET_EMPTY;
15944				if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG)) {
15945					if (ssa_op->result_def != current_var &&
15946					    (ssa_op->op1_use != current_var || !last_use)) {
15947						ZEND_REGSET_INCL(regset, ZREG_R0);
15948					}
15949					res_info = RES_INFO();
15950					if (res_info & MAY_BE_DOUBLE) {
15951						ZEND_REGSET_INCL(regset, ZREG_R0);
15952						ZEND_REGSET_INCL(regset, ZREG_XMM0);
15953						ZEND_REGSET_INCL(regset, ZREG_XMM1);
15954					} else if (res_info & MAY_BE_GUARD) {
15955						ZEND_REGSET_INCL(regset, ZREG_R0);
15956					}
15957				}
15958				if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_DOUBLE)) {
15959					if (ssa_op->result_def != current_var) {
15960						ZEND_REGSET_INCL(regset, ZREG_XMM0);
15961					}
15962				}
15963				if ((op1_info & MAY_BE_DOUBLE) && (op2_info & MAY_BE_LONG)) {
15964					if (zend_is_commutative(opline->opcode)) {
15965						if (ssa_op->result_def != current_var) {
15966							ZEND_REGSET_INCL(regset, ZREG_XMM0);
15967						}
15968					} else {
15969						ZEND_REGSET_INCL(regset, ZREG_XMM0);
15970						if (ssa_op->result_def != current_var &&
15971						    (ssa_op->op1_use != current_var || !last_use)) {
15972							ZEND_REGSET_INCL(regset, ZREG_XMM1);
15973						}
15974					}
15975				}
15976				if ((op1_info & MAY_BE_DOUBLE) && (op2_info & MAY_BE_DOUBLE)) {
15977					if (ssa_op->result_def != current_var &&
15978					    (ssa_op->op1_use != current_var || !last_use) &&
15979					    (!zend_is_commutative(opline->opcode) || ssa_op->op2_use != current_var || !last_use)) {
15980						ZEND_REGSET_INCL(regset, ZREG_XMM0);
15981					}
15982				}
15983				if (zend_needs_extra_reg_for_const(opline, opline->op1_type, opline->op1) ||
15984				    zend_needs_extra_reg_for_const(opline, opline->op2_type, opline->op2)) {
15985					if (!ZEND_REGSET_IN(regset, ZREG_R0)) {
15986						ZEND_REGSET_INCL(regset, ZREG_R0);
15987					} else {
15988						ZEND_REGSET_INCL(regset, ZREG_R1);
15989					}
15990				}
15991			}
15992			break;
15993		case ZEND_BW_OR:
15994		case ZEND_BW_AND:
15995		case ZEND_BW_XOR:
15996			op1_info = OP1_INFO();
15997			op2_info = OP2_INFO();
15998			if (!(op1_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-MAY_BE_LONG)) &&
15999			    !(op2_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-MAY_BE_LONG))) {
16000				regset = ZEND_REGSET_EMPTY;
16001				if (ssa_op->result_def != current_var &&
16002				    (ssa_op->op1_use != current_var || !last_use)) {
16003					ZEND_REGSET_INCL(regset, ZREG_R0);
16004				}
16005				if (zend_needs_extra_reg_for_const(opline, opline->op1_type, opline->op1) ||
16006				    zend_needs_extra_reg_for_const(opline, opline->op2_type, opline->op2)) {
16007					if (!ZEND_REGSET_IN(regset, ZREG_R0)) {
16008						ZEND_REGSET_INCL(regset, ZREG_R0);
16009					} else {
16010						ZEND_REGSET_INCL(regset, ZREG_R1);
16011					}
16012				}
16013			}
16014			break;
16015		case ZEND_SL:
16016		case ZEND_SR:
16017			op1_info = OP1_INFO();
16018			op2_info = OP2_INFO();
16019			if (!(op1_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-MAY_BE_LONG)) &&
16020			    !(op2_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-MAY_BE_LONG))) {
16021				regset = ZEND_REGSET_EMPTY;
16022				if (ssa_op->result_def != current_var &&
16023				    (ssa_op->op1_use != current_var || !last_use)) {
16024					ZEND_REGSET_INCL(regset, ZREG_R0);
16025				}
16026				if (opline->op2_type != IS_CONST && ssa_op->op2_use != current_var) {
16027					ZEND_REGSET_INCL(regset, ZREG_R1);
16028				}
16029			}
16030			break;
16031		case ZEND_MOD:
16032			op1_info = OP1_INFO();
16033			op2_info = OP2_INFO();
16034			if (!(op1_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-MAY_BE_LONG)) &&
16035			    !(op2_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-MAY_BE_LONG))) {
16036				regset = ZEND_REGSET_EMPTY;
16037				if (opline->op2_type == IS_CONST &&
16038				    opline->op1_type != IS_CONST &&
16039				    Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_LONG &&
16040				    zend_long_is_power_of_two(Z_LVAL_P(RT_CONSTANT(opline, opline->op2))) &&
16041				    OP1_HAS_RANGE() &&
16042				    OP1_MIN_RANGE() >= 0) {
16043					if (ssa_op->result_def != current_var &&
16044					    (ssa_op->op1_use != current_var || !last_use)) {
16045						ZEND_REGSET_INCL(regset, ZREG_R0);
16046					}
16047					if (sizeof(void*) == 8
16048					 && !IS_SIGNED_32BIT(Z_LVAL_P(RT_CONSTANT(opline, opline->op2)) - 1)) {
16049						if (!ZEND_REGSET_IN(regset, ZREG_R0)) {
16050							ZEND_REGSET_INCL(regset, ZREG_R0);
16051						} else {
16052							ZEND_REGSET_INCL(regset, ZREG_R1);
16053						}
16054					}
16055				} else {
16056					ZEND_REGSET_INCL(regset, ZREG_R0);
16057					ZEND_REGSET_INCL(regset, ZREG_R2);
16058					if (opline->op2_type == IS_CONST) {
16059						ZEND_REGSET_INCL(regset, ZREG_R1);
16060					}
16061				}
16062			}
16063			break;
16064		case ZEND_IS_SMALLER:
16065		case ZEND_IS_SMALLER_OR_EQUAL:
16066		case ZEND_IS_EQUAL:
16067		case ZEND_IS_NOT_EQUAL:
16068		case ZEND_IS_IDENTICAL:
16069		case ZEND_IS_NOT_IDENTICAL:
16070		case ZEND_CASE:
16071			op1_info = OP1_INFO();
16072			op2_info = OP2_INFO();
16073			if (!(op1_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) &&
16074			    !(op2_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)))) {
16075				regset = ZEND_REGSET_EMPTY;
16076				if (!(opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ))) {
16077					ZEND_REGSET_INCL(regset, ZREG_R0);
16078				}
16079				if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG) &&
16080				    opline->op1_type != IS_CONST && opline->op2_type != IS_CONST) {
16081					if (ssa_op->op1_use != current_var &&
16082					    ssa_op->op2_use != current_var) {
16083						ZEND_REGSET_INCL(regset, ZREG_R0);
16084					}
16085				}
16086				if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_DOUBLE)) {
16087					ZEND_REGSET_INCL(regset, ZREG_XMM0);
16088				}
16089				if ((op1_info & MAY_BE_DOUBLE) && (op2_info & MAY_BE_LONG)) {
16090					ZEND_REGSET_INCL(regset, ZREG_XMM0);
16091				}
16092				if ((op1_info & MAY_BE_DOUBLE) && (op2_info & MAY_BE_DOUBLE)) {
16093					if (ssa_op->op1_use != current_var &&
16094					    ssa_op->op2_use != current_var) {
16095						ZEND_REGSET_INCL(regset, ZREG_XMM0);
16096					}
16097				}
16098				if (zend_needs_extra_reg_for_const(opline, opline->op1_type, opline->op1) ||
16099				    zend_needs_extra_reg_for_const(opline, opline->op2_type, opline->op2)) {
16100					ZEND_REGSET_INCL(regset, ZREG_R0);
16101				}
16102			}
16103			break;
16104		case ZEND_BOOL:
16105		case ZEND_BOOL_NOT:
16106		case ZEND_JMPZ:
16107		case ZEND_JMPNZ:
16108		case ZEND_JMPZNZ:
16109		case ZEND_JMPZ_EX:
16110		case ZEND_JMPNZ_EX:
16111			op1_info = OP1_INFO();
16112			if (!(op1_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE)))) {
16113				regset = ZEND_REGSET_EMPTY;
16114				if (op1_info & MAY_BE_DOUBLE) {
16115					ZEND_REGSET_INCL(regset, ZREG_XMM0);
16116				}
16117				if (opline->opcode == ZEND_BOOL ||
16118				    opline->opcode == ZEND_BOOL_NOT ||
16119				    opline->opcode == ZEND_JMPZ_EX ||
16120				    opline->opcode == ZEND_JMPNZ_EX) {
16121					ZEND_REGSET_INCL(regset, ZREG_R0);
16122				}
16123			}
16124			break;
16125		case ZEND_DO_UCALL:
16126		case ZEND_DO_FCALL:
16127		case ZEND_DO_FCALL_BY_NAME:
16128		case ZEND_INCLUDE_OR_EVAL:
16129		case ZEND_GENERATOR_CREATE:
16130		case ZEND_YIELD:
16131		case ZEND_YIELD_FROM:
16132			regset = ZEND_REGSET_UNION(ZEND_REGSET_GP, ZEND_REGSET_FP);
16133			break;
16134		default:
16135			break;
16136	}
16137
16138	if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
16139		if (ssa_op == ssa->ops
16140		 && JIT_G(current_trace)[ZEND_JIT_TRACE_START_REC_SIZE].op == ZEND_JIT_TRACE_INIT_CALL
16141		 && (JIT_G(current_trace)[ZEND_JIT_TRACE_START_REC_SIZE].info & ZEND_JIT_TRACE_FAKE_INIT_CALL)) {
16142			ZEND_REGSET_INCL(regset, ZREG_R0);
16143			ZEND_REGSET_INCL(regset, ZREG_R1);
16144		}
16145	}
16146
16147	/* %r0 is used to check EG(vm_interrupt) */
16148	if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
16149		if (ssa_op == ssa->ops
16150		 && (JIT_G(current_trace)->stop == ZEND_JIT_TRACE_STOP_LOOP ||
16151			 JIT_G(current_trace)->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL)) {
16152#if ZTS
16153			ZEND_REGSET_INCL(regset, ZREG_R0);
16154#else
16155			if ((sizeof(void*) == 8 && !IS_SIGNED_32BIT(&EG(vm_interrupt)))) {
16156				ZEND_REGSET_INCL(regset, ZREG_R0);
16157			}
16158#endif
16159		}
16160	} else  {
16161		uint32_t b = ssa->cfg.map[ssa_op - ssa->ops];
16162
16163		if ((ssa->cfg.blocks[b].flags & ZEND_BB_LOOP_HEADER) != 0
16164		 && ssa->cfg.blocks[b].start == ssa_op - ssa->ops) {
16165#if ZTS
16166			ZEND_REGSET_INCL(regset, ZREG_R0);
16167#else
16168			if ((sizeof(void*) == 8 && !IS_SIGNED_32BIT(&EG(vm_interrupt)))) {
16169				ZEND_REGSET_INCL(regset, ZREG_R0);
16170			}
16171#endif
16172		}
16173	}
16174
16175	return regset;
16176}
16177
16178#if defined(__clang__)
16179# pragma clang diagnostic pop
16180#endif
16181
16182/*
16183 * Local variables:
16184 * tab-width: 4
16185 * c-basic-offset: 4
16186 * indent-tabs-mode: t
16187 * End:
16188 */
16189