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;
@@ -3208,7 +3213,93 @@ static zend_never_inline void zend_jit_set_sp_adj_vm(void)
32083213}
32093214#endif
32103215
3211- static void zend_jit_setup(void)
3216+ #ifdef _WIN64
3217+ /*
3218+ * We use a single unwind entry for the whole JIT buffer.
3219+ * This works, because all the JIT-ed PHP functions have the same "fixed stack frame".
3220+ */
3221+ static PRUNTIME_FUNCTION zend_jit_uw_func = NULL;
3222+
3223+ #ifdef ZEND_JIT_RT_UNWINDER
3224+ static PRUNTIME_FUNCTION zend_jit_unwind_callback(DWORD64 pc, PVOID context)
3225+ {
3226+ return zend_jit_uw_func;
3227+ }
3228+ #endif
3229+
3230+ static void zend_jit_setup_unwinder(void)
3231+ {
3232+ /* Hardcoded SEH unwind data for JIT-ed PHP functions with "fixed stack frame" */
3233+ static const unsigned char uw_data[] = {
3234+ 0x01, // UBYTE: 3 Version , UBYTE: 5 Flags
3235+ 0x10, // UBYTE Size of prolog
3236+ 0x09, // UBYTE Count of unwind codes
3237+ 0x00, // UBYTE: 4 Frame Register, UBYTE: 4 Frame Register offset (scaled)
3238+ // USHORT * n Unwind codes array
3239+ 0x10, 0x82, // c: subq $0x48, %rsp
3240+ 0x0c, 0xf0, // a: pushq %r15
3241+ 0x0a, 0xe0, // 8: pushq %r14
3242+ 0x08, 0xd0, // 6: pushq %r13
3243+ 0x06, 0xc0, // 4: pushq %r12
3244+ 0x04, 0x70, // 3: pushq %rdi
3245+ 0x03, 0x60, // 2: pushq %rsi
3246+ 0x02, 0x50, // 1: pushq %rbp
3247+ 0x01, 0x30, // 0: pushq %rbx
3248+ 0x00, 0x00,
3249+ };
3250+ static const unsigned char uw_data_exitcall[] = {
3251+ 0x01, // UBYTE: 3 Version , UBYTE: 5 Flags
3252+ 0x10, // UBYTE Size of prolog
3253+ 0x0a, // UBYTE Count of unwind codes
3254+ 0x00, // UBYTE: 4 Frame Register, UBYTE: 4 Frame Register offset (scaled)
3255+ // USHORT * n Unwind codes array
3256+ 0x10, 0x01, 0x2f, 0x00, // c: subq 376, %rsp ; 0x48 + 32+16*8+16*8+8+8
3257+ 0x0c, 0xf0, // a: pushq %r15
3258+ 0x0a, 0xe0, // 8: pushq %r14
3259+ 0x08, 0xd0, // 6: pushq %r13
3260+ 0x06, 0xc0, // 4: pushq %r12
3261+ 0x04, 0x70, // 3: pushq %rdi
3262+ 0x03, 0x60, // 2: pushq %rsi
3263+ 0x02, 0x50, // 1: pushq %rbp
3264+ 0x01, 0x30, // 0: pushq %rbx
3265+ };
3266+
3267+ zend_jit_uw_func = (PRUNTIME_FUNCTION)*dasm_ptr;
3268+ *dasm_ptr = (char*)*dasm_ptr + ZEND_MM_ALIGNED_SIZE_EX(sizeof(RUNTIME_FUNCTION) * 4 +
3269+ sizeof(uw_data) + sizeof(uw_data_exitcall) + sizeof(uw_data), 16);
3270+
3271+ zend_jit_uw_func[0].BeginAddress = 0;
3272+ zend_jit_uw_func[1].BeginAddress = (uintptr_t)zend_jit_stub_handlers[jit_stub_trace_exit] - (uintptr_t)dasm_buf;
3273+ zend_jit_uw_func[2].BeginAddress = (uintptr_t)zend_jit_stub_handlers[jit_stub_undefined_offset] - (uintptr_t)dasm_buf;
3274+
3275+ zend_jit_uw_func[0].EndAddress = zend_jit_uw_func[1].BeginAddress;
3276+ zend_jit_uw_func[1].EndAddress = zend_jit_uw_func[2].BeginAddress;
3277+ zend_jit_uw_func[2].EndAddress = (uintptr_t)dasm_end - (uintptr_t)dasm_buf;
3278+
3279+ zend_jit_uw_func[0].UnwindData = (uintptr_t)zend_jit_uw_func - (uintptr_t)dasm_buf + sizeof(RUNTIME_FUNCTION) * 4;
3280+ zend_jit_uw_func[1].UnwindData = zend_jit_uw_func[0].UnwindData + sizeof(uw_data);
3281+ zend_jit_uw_func[2].UnwindData = zend_jit_uw_func[1].UnwindData + sizeof(uw_data_exitcall);
3282+
3283+ memcpy((char*)dasm_buf + zend_jit_uw_func[0].UnwindData, uw_data, sizeof(uw_data));
3284+ memcpy((char*)dasm_buf + zend_jit_uw_func[1].UnwindData, uw_data_exitcall, sizeof(uw_data_exitcall));
3285+ memcpy((char*)dasm_buf + zend_jit_uw_func[2].UnwindData, uw_data, sizeof(uw_data));
3286+
3287+ #ifdef ZEND_JIT_RT_UNWINDER
3288+ RtlInstallFunctionTableCallback(
3289+ (uintptr_t)dasm_buf | 3,
3290+ (uintptr_t) dasm_buf,
3291+ (uintptr_t)dasm_end - (uintptr_t)dasm_buf,
3292+ zend_jit_unwind_callback,
3293+ NULL,
3294+ NULL);
3295+ #else
3296+ RtlAddFunctionTable(zend_jit_uw_func, 3, (uintptr_t)dasm_buf);
3297+ #endif
3298+ }
3299+ #endif
3300+
3301+
3302+ static void zend_jit_setup(bool reattached)
32123303{
32133304#if defined(IR_TARGET_X86)
32143305 if (!zend_cpu_supports_sse2()) {
@@ -3413,8 +3504,14 @@ static void zend_jit_setup(void)
34133504 }
34143505
34153506 zend_jit_calc_trace_prologue_size();
3416- zend_jit_setup_stubs();
3507+ if (!reattached) {
3508+ zend_jit_setup_stubs();
3509+ }
34173510 JIT_G(debug) = debug;
3511+
3512+ #ifdef _WIN64
3513+ zend_jit_setup_unwinder();
3514+ #endif
34183515}
34193516
34203517static void zend_jit_shutdown_ir(void)
@@ -8978,7 +9075,11 @@ static int zend_jit_init_method_call(zend_jit_ctx *jit,
89789075 // JIT: alloca(sizeof(void*));
89799076 this_ref2 = ir_ALLOCA(ir_CONST_ADDR(0x10));
89809077 } else {
9078+ #ifdef _WIN64
9079+ this_ref2 = ir_HARD_COPY_A(jit_ADD_OFFSET(jit, ir_RLOAD_A(IR_REG_SP), IR_SHADOW_ARGS));
9080+ #else
89819081 this_ref2 = ir_HARD_COPY_A(ir_RLOAD_A(IR_REG_SP));
9082+ #endif
89829083 }
89839084 ir_STORE(this_ref2, this_ref);
89849085
@@ -8994,10 +9095,17 @@ static int zend_jit_init_method_call(zend_jit_ctx *jit,
89949095 this_ref2);
89959096 }
89969097
8997- this_ref2 = ir_LOAD_A(ir_RLOAD_A(IR_REG_SP));
9098+
89989099 if (!jit->ctx.fixed_call_stack_size) {
9100+ this_ref2 = ir_LOAD_A(ir_RLOAD_A(IR_REG_SP));
89999101 // JIT: revert alloca
90009102 ir_AFREE(ir_CONST_ADDR(0x10));
9103+ } else {
9104+ #ifdef _WIN64
9105+ this_ref2 = ir_LOAD_A(jit_ADD_OFFSET(jit, ir_RLOAD_A(IR_REG_SP), IR_SHADOW_ARGS));
9106+ #else
9107+ this_ref2 = ir_LOAD_A(ir_RLOAD_A(IR_REG_SP));
9108+ #endif
90019109 }
90029110
90039111 ir_GUARD(ref2, jit_STUB_ADDR(jit, jit_stub_exception_handler));
@@ -10257,7 +10365,11 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
1025710365 // JIT: alloca(sizeof(void*));
1025810366 ptr = ir_ALLOCA(ir_CONST_ADDR(sizeof(zval)));
1025910367 } else {
10368+ #ifdef _WIN64
10369+ ptr = ir_HARD_COPY_A(jit_ADD_OFFSET(jit, ir_RLOAD_A(IR_REG_SP), IR_SHADOW_ARGS));
10370+ #else
1026010371 ptr = ir_HARD_COPY_A(ir_RLOAD_A(IR_REG_SP));
10372+ #endif
1026110373 }
1026210374 res_addr = ZEND_ADDR_REF_ZVAL(ptr);
1026310375 }
@@ -10385,7 +10497,16 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
1038510497 func_info |= MAY_BE_NULL;
1038610498
1038710499 if (func_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
10388- ir_ref sp = ir_RLOAD_A(IR_REG_SP);
10500+ ir_ref sp;
10501+ if (!jit->ctx.fixed_call_stack_size) {
10502+ sp = ir_RLOAD_A(IR_REG_SP);
10503+ } else {
10504+ #ifdef _WIN64
10505+ sp = jit_ADD_OFFSET(jit, ir_RLOAD_A(IR_REG_SP), IR_SHADOW_ARGS);
10506+ #else
10507+ sp = ir_RLOAD_A(IR_REG_SP);
10508+ #endif
10509+ }
1038910510 res_addr = ZEND_ADDR_REF_ZVAL(sp);
1039010511 jit_ZVAL_PTR_DTOR(jit, res_addr, func_info, 1, opline);
1039110512 }
0 commit comments