Skip to content

Commit 46368eb

Browse files
committed
Tail call VM
1 parent 7f7b3cd commit 46368eb

12 files changed

+60660
-1726
lines changed

Zend/Zend.m4

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ ZEND_CHECK_STACK_DIRECTION
170170
ZEND_CHECK_FLOAT_PRECISION
171171
ZEND_DLSYM_CHECK
172172
ZEND_CHECK_GLOBAL_REGISTER_VARIABLES
173+
ZEND_CHECK_PRESERVE_NONE
173174
ZEND_CHECK_CPUID_COUNT
174175
175176
AC_MSG_CHECKING([whether to enable thread safety])
@@ -471,3 +472,103 @@ AS_VAR_IF([ZEND_MAX_EXECUTION_TIMERS], [yes],
471472
AC_MSG_CHECKING([whether to enable Zend max execution timers])
472473
AC_MSG_RESULT([$ZEND_MAX_EXECUTION_TIMERS])
473474
])
475+
476+
dnl
477+
dnl ZEND_CHECK_PRESERVE_NONE
478+
dnl
479+
dnl Check if the preserve_none calling convention is supported and matches our
480+
dnl expectations.
481+
dnl
482+
AC_DEFUN([ZEND_CHECK_PRESERVE_NONE], [dnl
483+
AC_CACHE_CHECK([for preserve_none calling convention],
484+
[php_cv_preverve_none],
485+
[AC_RUN_IFELSE([AC_LANG_SOURCE([[
486+
#include <stdio.h>
487+
#include <stdint.h>
488+
489+
const char * const1 = "str1";
490+
const char * const2 = "str2";
491+
const char * const3 = "str3";
492+
uint64_t key = UINT64_C(0x9d7f71d2bd296364);
493+
494+
uintptr_t _a = 0;
495+
uintptr_t _b = 0;
496+
497+
uintptr_t __attribute__((preserve_none)) fun(uintptr_t a, uintptr_t b) {
498+
_a = a;
499+
_b = b;
500+
return (uintptr_t)const3;
501+
}
502+
503+
uintptr_t __attribute__((preserve_none)) test(void) {
504+
uintptr_t ret;
505+
506+
#if defined(__x86_64__)
507+
__asm__ __volatile__(
508+
/* XORing to make it unlikely the value exists in any other register */
509+
"movq %1, %%r12\n"
510+
"xorq %3, %%r12\n"
511+
"movq %2, %%r13\n"
512+
"xorq %3, %%r13\n"
513+
"xorq %%rax, %%rax\n"
514+
"call fun\n"
515+
: "=a" (ret)
516+
: "r" (const1), "r" (const2), "r" (key)
517+
: "r12", "r13"
518+
);
519+
#elif defined(__aarch64__)
520+
__asm__ __volatile__(
521+
/* XORing to make it unlikely the value exists in any other register */
522+
"eor x20, %1, %3\n"
523+
"eor x21, %2, %3\n"
524+
"eor x0, x0, x0\n"
525+
"bl fun\n"
526+
"mov %0, x0\n"
527+
: "=r" (ret)
528+
: "r" (const1), "r" (const2), "r" (key)
529+
: "x0", "x21", "x22", "x30"
530+
);
531+
#else
532+
# error
533+
#endif
534+
535+
return ret;
536+
}
537+
538+
int main(void) {
539+
540+
/* JIT is making the following expectations about preserve_none:
541+
* - The registers used for integer args 1 and 2
542+
* - The register used for a single integer return value
543+
*
544+
* We check these expectations here:
545+
*/
546+
547+
uintptr_t ret = test();
548+
549+
if (_a != ((uintptr_t)const1 ^ key)) {
550+
fprintf(stderr, "arg1 mismatch\n");
551+
return 1;
552+
}
553+
if (_b != ((uintptr_t)const2 ^ key)) {
554+
fprintf(stderr, "arg2 mismatch\n");
555+
return 2;
556+
}
557+
if (ret != (uintptr_t)const3) {
558+
fprintf(stderr, "ret mismatch\n");
559+
return 3;
560+
}
561+
562+
fprintf(stderr, "OK\n");
563+
564+
return 0;
565+
}]])],
566+
[php_cv_preserve_none=yes],
567+
[php_cv_preserve_none=no],
568+
[php_cv_preserve_none=no])
569+
])
570+
AS_VAR_IF([php_cv_preserve_none], [yes], [
571+
AC_DEFINE([HAVE_PRESERVE_NONE], [1],
572+
[Define to 1 if you have preserve_none support.])
573+
])
574+
])

Zend/zend_portability.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,20 @@ char *alloca();
321321
# define ZEND_FASTCALL
322322
#endif
323323

324+
#ifdef HAVE_PRESERVE_NONE
325+
# define ZEND_PRESERVE_NONE __attribute__((preserve_none))
326+
#endif
327+
328+
#if __has_attribute(musttail)
329+
# define HAVE_MUSTTAIL
330+
# define ZEND_MUSTTAIL __attribute__((musttail))
331+
#endif
332+
333+
#if __has_attribute(sysv_abi)
334+
# define HAVE_SYSV_ABI
335+
# define ZEND_SYSV_ABI __attribute__((sysv_abi))
336+
#endif
337+
324338
#if (defined(__GNUC__) && __GNUC__ >= 3 && !defined(__INTEL_COMPILER) && !defined(__APPLE__) && !defined(__hpux) && !defined(_AIX) && !defined(__osf__)) || __has_attribute(noreturn)
325339
# define HAVE_NORETURN
326340
# define ZEND_NORETURN __attribute__((noreturn))

Zend/zend_vm_def.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4917,7 +4917,7 @@ ZEND_VM_HOT_SEND_HANDLER(116, ZEND_SEND_VAL_EX, CONST|TMP, CONST|UNUSED|NUM, SPE
49174917
ZEND_VM_C_GOTO(send_val_by_ref);
49184918
}
49194919
} else if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
4920-
ZEND_VM_C_LABEL(send_val_by_ref):
4920+
ZEND_VM_C_LABEL(send_val_by_ref):;
49214921
ZEND_VM_DISPATCH_TO_HELPER(zend_cannot_pass_by_ref_helper, _arg_num, arg_num, _arg, arg);
49224922
}
49234923
value = GET_OP1_ZVAL_PTR(BP_VAR_R);
@@ -8235,9 +8235,9 @@ ZEND_VM_HANDLER(150, ZEND_USER_OPCODE, ANY, ANY)
82358235
case ZEND_USER_OPCODE_LEAVE:
82368236
ZEND_VM_LEAVE();
82378237
case ZEND_USER_OPCODE_DISPATCH:
8238-
ZEND_VM_DISPATCH(opline->opcode, opline);
8238+
ZEND_VM_DISPATCH_OPCODE(opline->opcode, opline);
82398239
default:
8240-
ZEND_VM_DISPATCH((uint8_t)(ret & 0xff), opline);
8240+
ZEND_VM_DISPATCH_OPCODE((uint8_t)(ret & 0xff), opline);
82418241
}
82428242
}
82438243

0 commit comments

Comments
 (0)