3939                               (1<<(16+6)) | (1<<(16+7)) | (1<<(16+8)) | (1<<(16+9)) | (1<<(16+10)) | \
4040                               (1<<(16+11)) | (1<<(16+12)) | (1<<(16+13)) | (1<<(16+14)) | (1<<(16+15)))
4141*/
42+ #  define IR_SHADOW_ARGS     32
4243# else
4344#  define IR_REGSET_PRESERVED ((1<<3) | (1<<5) | (1<<12) | (1<<13) | (1<<14) | (1<<15)) /* all preserved registers */
4445# endif
@@ -2709,7 +2710,11 @@ static void zend_jit_init_ctx(zend_jit_ctx *jit, uint32_t flags)
27092710//				jit->ctx.fixed_save_regset &= 0xffff; // TODO: don't save FP registers ???
27102711//#endif
27112712			}
2713+ #ifdef _WIN64
2714+ 			jit->ctx.fixed_call_stack_size = 16 + IR_SHADOW_ARGS;
2715+ #else
27122716			jit->ctx.fixed_call_stack_size = 16;
2717+ #endif
27132718		} else {
27142719#ifdef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE
27152720			jit->ctx.fixed_stack_red_zone = ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE;
@@ -3212,7 +3217,93 @@ static zend_never_inline void zend_jit_set_sp_adj_vm(void)
32123217}
32133218#endif
32143219
3215- static void zend_jit_setup(void)
3220+ #ifdef _WIN64
3221+ /*
3222+  * We use a single unwind entry for the whole JIT buffer.
3223+  * This works, because all the JIT-ed PHP functions have the same "fixed stack frame".
3224+  */
3225+ static PRUNTIME_FUNCTION zend_jit_uw_func = NULL;
3226+ 
3227+ #ifdef ZEND_JIT_RT_UNWINDER
3228+ static PRUNTIME_FUNCTION zend_jit_unwind_callback(DWORD64 pc, PVOID context)
3229+ {
3230+ 	return zend_jit_uw_func;
3231+ }
3232+ #endif
3233+ 
3234+ static void zend_jit_setup_unwinder(void)
3235+ {
3236+ 	/* Hardcoded SEH unwind data for JIT-ed PHP functions with "fixed stack frame" */
3237+ 	static const unsigned char uw_data[] = {
3238+ 		0x01, // UBYTE: 3 Version , UBYTE: 5 Flags
3239+ 		0x10, // UBYTE Size of prolog
3240+ 		0x09, // UBYTE Count of unwind codes
3241+ 		0x00, // UBYTE: 4 Frame Register, UBYTE: 4 Frame Register offset (scaled)
3242+ 		// USHORT * n Unwind codes array
3243+ 		0x10, 0x82, // c: subq $0x48, %rsp
3244+ 		0x0c, 0xf0, // a: pushq %r15
3245+ 		0x0a, 0xe0, // 8: pushq %r14
3246+ 		0x08, 0xd0, // 6: pushq %r13
3247+ 		0x06, 0xc0, // 4: pushq %r12
3248+ 		0x04, 0x70, // 3: pushq %rdi
3249+ 		0x03, 0x60, // 2: pushq %rsi
3250+ 		0x02, 0x50, // 1: pushq %rbp
3251+ 		0x01, 0x30, // 0: pushq %rbx
3252+ 		0x00, 0x00,
3253+ 	};
3254+ 	static const unsigned char uw_data_exitcall[] = {
3255+ 		0x01, // UBYTE: 3 Version , UBYTE: 5 Flags
3256+ 		0x10, // UBYTE Size of prolog
3257+ 		0x0a, // UBYTE Count of unwind codes
3258+ 		0x00, // UBYTE: 4 Frame Register, UBYTE: 4 Frame Register offset (scaled)
3259+ 		// USHORT * n Unwind codes array
3260+ 		0x10, 0x01, 0x2f, 0x00, // c: subq 376, %rsp ; 0x48 + 32+16*8+16*8+8+8
3261+ 		0x0c, 0xf0, // a: pushq %r15
3262+ 		0x0a, 0xe0, // 8: pushq %r14
3263+ 		0x08, 0xd0, // 6: pushq %r13
3264+ 		0x06, 0xc0, // 4: pushq %r12
3265+ 		0x04, 0x70, // 3: pushq %rdi
3266+ 		0x03, 0x60, // 2: pushq %rsi
3267+ 		0x02, 0x50, // 1: pushq %rbp
3268+ 		0x01, 0x30, // 0: pushq %rbx
3269+ 	};
3270+ 
3271+ 	zend_jit_uw_func = (PRUNTIME_FUNCTION)*dasm_ptr;
3272+ 	*dasm_ptr = (char*)*dasm_ptr + ZEND_MM_ALIGNED_SIZE_EX(sizeof(RUNTIME_FUNCTION) * 4 +
3273+ 		sizeof(uw_data) + sizeof(uw_data_exitcall) + sizeof(uw_data), 16);
3274+ 
3275+ 	zend_jit_uw_func[0].BeginAddress = 0;
3276+ 	zend_jit_uw_func[1].BeginAddress = (uintptr_t)zend_jit_stub_handlers[jit_stub_trace_exit] - (uintptr_t)dasm_buf;
3277+ 	zend_jit_uw_func[2].BeginAddress = (uintptr_t)zend_jit_stub_handlers[jit_stub_undefined_offset] - (uintptr_t)dasm_buf;
3278+ 
3279+ 	zend_jit_uw_func[0].EndAddress = zend_jit_uw_func[1].BeginAddress;
3280+ 	zend_jit_uw_func[1].EndAddress = zend_jit_uw_func[2].BeginAddress;
3281+ 	zend_jit_uw_func[2].EndAddress = (uintptr_t)dasm_end - (uintptr_t)dasm_buf;
3282+ 
3283+ 	zend_jit_uw_func[0].UnwindData = (uintptr_t)zend_jit_uw_func  - (uintptr_t)dasm_buf + sizeof(RUNTIME_FUNCTION) * 4;
3284+ 	zend_jit_uw_func[1].UnwindData = zend_jit_uw_func[0].UnwindData + sizeof(uw_data);
3285+ 	zend_jit_uw_func[2].UnwindData = zend_jit_uw_func[1].UnwindData + sizeof(uw_data_exitcall);
3286+ 
3287+ 	memcpy((char*)dasm_buf + zend_jit_uw_func[0].UnwindData, uw_data, sizeof(uw_data));
3288+ 	memcpy((char*)dasm_buf + zend_jit_uw_func[1].UnwindData, uw_data_exitcall, sizeof(uw_data_exitcall));
3289+ 	memcpy((char*)dasm_buf + zend_jit_uw_func[2].UnwindData, uw_data, sizeof(uw_data));
3290+ 
3291+ #ifdef ZEND_JIT_RT_UNWINDER
3292+ 	RtlInstallFunctionTableCallback(
3293+ 		(uintptr_t)dasm_buf | 3,
3294+ 		(uintptr_t) dasm_buf,
3295+ 		(uintptr_t)dasm_end - (uintptr_t)dasm_buf,
3296+ 		zend_jit_unwind_callback,
3297+ 		NULL,
3298+ 		NULL);
3299+ #else
3300+ 	RtlAddFunctionTable(zend_jit_uw_func, 3, (uintptr_t)dasm_buf);
3301+ #endif
3302+ }
3303+ #endif
3304+ 
3305+ 
3306+ static void zend_jit_setup(bool reattached)
32163307{
32173308#if defined(IR_TARGET_X86)
32183309	if (!zend_cpu_supports_sse2()) {
@@ -3417,8 +3508,14 @@ static void zend_jit_setup(void)
34173508	}
34183509
34193510	zend_jit_calc_trace_prologue_size();
3420- 	zend_jit_setup_stubs();
3511+ 	if (!reattached) {
3512+ 		zend_jit_setup_stubs();
3513+ 	}
34213514	JIT_G(debug) = debug;
3515+ 
3516+ #ifdef _WIN64
3517+ 	zend_jit_setup_unwinder();
3518+ #endif
34223519}
34233520
34243521static void zend_jit_shutdown_ir(void)
@@ -8993,7 +9090,11 @@ static int zend_jit_init_method_call(zend_jit_ctx         *jit,
89939090			// JIT: alloca(sizeof(void*));
89949091			this_ref2 = ir_ALLOCA(ir_CONST_ADDR(0x10));
89959092		} else {
9093+ #ifdef _WIN64
9094+ 			this_ref2 = ir_HARD_COPY_A(jit_ADD_OFFSET(jit, ir_RLOAD_A(IR_REG_SP), IR_SHADOW_ARGS));
9095+ #else
89969096			this_ref2 = ir_HARD_COPY_A(ir_RLOAD_A(IR_REG_SP));
9097+ #endif
89979098		}
89989099		ir_STORE(this_ref2, this_ref);
89999100
@@ -9009,10 +9110,17 @@ static int zend_jit_init_method_call(zend_jit_ctx         *jit,
90099110					this_ref2);
90109111		}
90119112
9012- 		this_ref2 = ir_LOAD_A(ir_RLOAD_A(IR_REG_SP)); 
9113+ 
90139114		if (!jit->ctx.fixed_call_stack_size) {
9115+ 			this_ref2 = ir_LOAD_A(ir_RLOAD_A(IR_REG_SP));
90149116			// JIT: revert alloca
90159117			ir_AFREE(ir_CONST_ADDR(0x10));
9118+ 		} else {
9119+ #ifdef _WIN64
9120+ 			this_ref2 = ir_LOAD_A(jit_ADD_OFFSET(jit, ir_RLOAD_A(IR_REG_SP), IR_SHADOW_ARGS));
9121+ #else
9122+ 			this_ref2 = ir_LOAD_A(ir_RLOAD_A(IR_REG_SP));
9123+ #endif
90169124		}
90179125
90189126		ir_GUARD(ref2, jit_STUB_ADDR(jit, jit_stub_exception_handler));
@@ -10439,7 +10547,11 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
1043910547				// JIT: alloca(sizeof(void*));
1044010548				ptr = ir_ALLOCA(ir_CONST_ADDR(sizeof(zval)));
1044110549			} else {
10550+ #ifdef _WIN64
10551+ 				ptr = ir_HARD_COPY_A(jit_ADD_OFFSET(jit, ir_RLOAD_A(IR_REG_SP), IR_SHADOW_ARGS));
10552+ #else
1044210553				ptr = ir_HARD_COPY_A(ir_RLOAD_A(IR_REG_SP));
10554+ #endif
1044310555			}
1044410556			res_addr = ZEND_ADDR_REF_ZVAL(ptr);
1044510557		}
@@ -10567,7 +10679,16 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
1056710679			func_info |= MAY_BE_NULL;
1056810680
1056910681			if (func_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
10570- 				ir_ref sp = ir_RLOAD_A(IR_REG_SP);
10682+ 				ir_ref sp;
10683+ 				if (!jit->ctx.fixed_call_stack_size) {
10684+ 					sp = ir_RLOAD_A(IR_REG_SP);
10685+ 				} else {
10686+ #ifdef _WIN64
10687+ 					sp = jit_ADD_OFFSET(jit, ir_RLOAD_A(IR_REG_SP), IR_SHADOW_ARGS);
10688+ #else
10689+ 					sp = ir_RLOAD_A(IR_REG_SP);
10690+ #endif
10691+ 				}
1057110692				res_addr = ZEND_ADDR_REF_ZVAL(sp);
1057210693				jit_ZVAL_PTR_DTOR(jit, res_addr, func_info, 1, opline);
1057310694			}
0 commit comments