Skip to content
Permalink
Browse files

Added JIT compiler for x86 and x86_64

  • Loading branch information
dstogov committed Apr 1, 2019
1 parent a0fbb64 commit 9a06876072b9ccb023d4a14426ccb587f10882f3
Showing with 51,909 additions and 36 deletions.
  1. +20 −0 TSRM/TSRM.c
  2. +1 −0 TSRM/TSRM.h
  3. +140 −0 Zend/zend_gdb.c
  4. +27 −0 Zend/zend_gdb.h
  5. +1 −1 configure.ac
  6. +72 −1 ext/opcache/ZendAccelerator.c
  7. +5 −0 ext/opcache/ZendAccelerator.h
  8. +60 −1 ext/opcache/config.m4
  9. +23 −2 ext/opcache/config.w32
  10. +17 −0 ext/opcache/jit/Makefile.frag
  11. +16 −0 ext/opcache/jit/Makefile.frag.w32
  12. +456 −0 ext/opcache/jit/dynasm/dasm_arm.h
  13. +1,125 −0 ext/opcache/jit/dynasm/dasm_arm.lua
  14. +518 −0 ext/opcache/jit/dynasm/dasm_arm64.h
  15. +1,166 −0 ext/opcache/jit/dynasm/dasm_arm64.lua
  16. +419 −0 ext/opcache/jit/dynasm/dasm_mips.h
  17. +1,008 −0 ext/opcache/jit/dynasm/dasm_mips.lua
  18. +12 −0 ext/opcache/jit/dynasm/dasm_mips64.lua
  19. +419 −0 ext/opcache/jit/dynasm/dasm_ppc.h
  20. +1,919 −0 ext/opcache/jit/dynasm/dasm_ppc.lua
  21. +83 −0 ext/opcache/jit/dynasm/dasm_proto.h
  22. +12 −0 ext/opcache/jit/dynasm/dasm_x64.lua
  23. +498 −0 ext/opcache/jit/dynasm/dasm_x86.h
  24. +2,274 −0 ext/opcache/jit/dynasm/dasm_x86.lua
  25. +1,094 −0 ext/opcache/jit/dynasm/dynasm.lua
  26. +7,770 −0 ext/opcache/jit/dynasm/minilua.c
  27. +22 −0 ext/opcache/jit/libudis86/LICENSE
  28. +1,266 −0 ext/opcache/jit/libudis86/decode.c
  29. +197 −0 ext/opcache/jit/libudis86/decode.h
  30. +113 −0 ext/opcache/jit/libudis86/extern.h
  31. +5,946 −0 ext/opcache/jit/libudis86/itab.c
  32. +939 −0 ext/opcache/jit/libudis86/itab.h
  33. +228 −0 ext/opcache/jit/libudis86/syn-att.c
  34. +224 −0 ext/opcache/jit/libudis86/syn-intel.c
  35. +258 −0 ext/opcache/jit/libudis86/syn.c
  36. +53 −0 ext/opcache/jit/libudis86/syn.h
  37. +260 −0 ext/opcache/jit/libudis86/types.h
  38. +99 −0 ext/opcache/jit/libudis86/udint.h
  39. +458 −0 ext/opcache/jit/libudis86/udis86.c
  40. +596 −0 ext/opcache/jit/vtune/ittnotify_config.h
  41. +115 −0 ext/opcache/jit/vtune/ittnotify_types.h
  42. +315 −0 ext/opcache/jit/vtune/jitprofiling.c
  43. +694 −0 ext/opcache/jit/vtune/jitprofiling.h
  44. +90 −0 ext/opcache/jit/zend_elf.c
  45. +115 −0 ext/opcache/jit/zend_elf.h
  46. +3,233 −0 ext/opcache/jit/zend_jit.c
  47. +109 −0 ext/opcache/jit/zend_jit.h
  48. +469 −0 ext/opcache/jit/zend_jit_disasm_x86.c
  49. +493 −0 ext/opcache/jit/zend_jit_gdb.c
  50. +2,227 −0 ext/opcache/jit/zend_jit_helpers.c
  51. +96 −0 ext/opcache/jit/zend_jit_internal.h
  52. +50 −0 ext/opcache/jit/zend_jit_oprofile.c
  53. +207 −0 ext/opcache/jit/zend_jit_perf_dump.c
  54. +287 −0 ext/opcache/jit/zend_jit_vm_helpers.c
  55. +42 −0 ext/opcache/jit/zend_jit_vtune.c
  56. +10,453 −0 ext/opcache/jit/zend_jit_x86.dasc
  57. +256 −0 ext/opcache/jit/zend_jit_x86.h
  58. +45 −17 ext/opcache/shared_alloc_mmap.c
  59. +24 −6 ext/opcache/shared_alloc_win32.c
  60. +27 −0 ext/opcache/tests/jit/assign_001.phpt
  61. +29 −0 ext/opcache/tests/jit/assign_002.phpt
  62. +21 −0 ext/opcache/tests/jit/assign_003.phpt
  63. +24 −0 ext/opcache/tests/jit/assign_004.phpt
  64. +24 −0 ext/opcache/tests/jit/assign_005.phpt
  65. +22 −0 ext/opcache/tests/jit/assign_006.phpt
  66. +21 −0 ext/opcache/tests/jit/assign_007.phpt
  67. +21 −0 ext/opcache/tests/jit/assign_008.phpt
  68. +21 −0 ext/opcache/tests/jit/assign_009.phpt
  69. +21 −0 ext/opcache/tests/jit/assign_010.phpt
  70. +28 −0 ext/opcache/tests/jit/assign_011.phpt
  71. +28 −0 ext/opcache/tests/jit/assign_012.phpt
  72. +21 −0 ext/opcache/tests/jit/assign_013.phpt
  73. +22 −0 ext/opcache/tests/jit/assign_014.phpt
  74. +21 −0 ext/opcache/tests/jit/assign_015.phpt
  75. +21 −0 ext/opcache/tests/jit/assign_016.phpt
  76. +21 −0 ext/opcache/tests/jit/assign_017.phpt
  77. +26 −0 ext/opcache/tests/jit/assign_018.phpt
  78. +24 −0 ext/opcache/tests/jit/assign_019.phpt
  79. +22 −0 ext/opcache/tests/jit/assign_020.phpt
  80. +24 −0 ext/opcache/tests/jit/assign_021.phpt
  81. +24 −0 ext/opcache/tests/jit/assign_022.phpt
  82. +24 −0 ext/opcache/tests/jit/assign_023.phpt
  83. +23 −0 ext/opcache/tests/jit/assign_024.phpt
  84. +24 −0 ext/opcache/tests/jit/assign_025.phpt
  85. +25 −0 ext/opcache/tests/jit/assign_026.phpt
  86. +22 −0 ext/opcache/tests/jit/assign_027.phpt
  87. +21 −0 ext/opcache/tests/jit/assign_028.phpt
  88. +22 −0 ext/opcache/tests/jit/assign_029.phpt
  89. +23 −0 ext/opcache/tests/jit/assign_030.phpt
  90. +19 −0 ext/opcache/tests/jit/assign_031.phpt
  91. +27 −0 ext/opcache/tests/jit/assign_032.phpt
  92. +24 −0 ext/opcache/tests/jit/assign_033.phpt
  93. +21 −0 ext/opcache/tests/jit/assign_034.phpt
  94. +39 −0 ext/opcache/tests/jit/assign_035.phpt
  95. +43 −0 ext/opcache/tests/jit/assign_036.phpt
  96. +128 −0 ext/opcache/tests/jit/assign_dim_002.phpt
  97. +24 −0 ext/opcache/tests/jit/cmp_001.phpt
  98. +24 −0 ext/opcache/tests/jit/cmp_002.phpt
  99. +169 −0 ext/opcache/tests/jit/cmp_003.phpt
  100. +26 −0 ext/opcache/tests/jit/const_001.phpt
  101. +26 −0 ext/opcache/tests/jit/fetch_dim_func_args_001.phpt
  102. +45 −0 ext/opcache/tests/jit/fetch_dim_r_001.phpt
  103. +45 −0 ext/opcache/tests/jit/fetch_dim_r_002.phpt
  104. +61 −0 ext/opcache/tests/jit/fetch_dim_r_003.phpt
  105. +61 −0 ext/opcache/tests/jit/fetch_dim_r_004.phpt
  106. +27 −0 ext/opcache/tests/jit/fetch_dim_rw_001.phpt
  107. +135 −0 ext/opcache/tests/jit/fetch_obj_001.phpt
  108. +41 −0 ext/opcache/tests/jit/fetch_obj_002.phpt
  109. +46 −0 ext/opcache/tests/jit/fetch_obj_003.phpt
  110. +43 −0 ext/opcache/tests/jit/fetch_obj_004.phpt
  111. +22 −0 ext/opcache/tests/jit/inc_001.phpt
  112. +21 −0 ext/opcache/tests/jit/inc_002.phpt
  113. +22 −0 ext/opcache/tests/jit/inc_003.phpt
  114. +21 −0 ext/opcache/tests/jit/inc_004.phpt
  115. +23 −0 ext/opcache/tests/jit/inc_005.phpt
  116. +22 −0 ext/opcache/tests/jit/inc_006.phpt
  117. +21 −0 ext/opcache/tests/jit/inc_007.phpt
  118. +20 −0 ext/opcache/tests/jit/inc_008.phpt
  119. +22 −0 ext/opcache/tests/jit/inc_009.phpt
  120. +21 −0 ext/opcache/tests/jit/inc_010.phpt
  121. +22 −0 ext/opcache/tests/jit/inc_011.phpt
  122. +21 −0 ext/opcache/tests/jit/inc_012.phpt
  123. +23 −0 ext/opcache/tests/jit/inc_013.phpt
  124. +22 −0 ext/opcache/tests/jit/inc_014.phpt
  125. +21 −0 ext/opcache/tests/jit/inc_015.phpt
  126. +20 −0 ext/opcache/tests/jit/inc_016.phpt
  127. +20 −0 ext/opcache/tests/jit/inc_017.phpt
  128. +20 −0 ext/opcache/tests/jit/inc_018.phpt
  129. +27 −0 ext/opcache/tests/jit/inc_019.phpt
  130. +26 −0 ext/opcache/tests/jit/jmpz_001.phpt
  131. +41 −0 ext/opcache/tests/jit/mod_001.phpt
  132. +53 −0 ext/opcache/tests/jit/mod_002.phpt
  133. +34 −0 ext/opcache/tests/jit/noval_001.phpt
  134. +23 −0 ext/opcache/tests/jit/recv_001.phpt
  135. +39 −0 ext/opcache/tests/jit/reg_alloc_001.phpt
  136. +28 −0 ext/opcache/tests/jit/reg_alloc_002.phpt
  137. +30 −0 ext/opcache/tests/jit/send_var_ex_001.phpt
  138. +37 −0 ext/opcache/tests/jit/shift_left_001.phpt
  139. +49 −0 ext/opcache/tests/jit/shift_left_002.phpt
  140. +43 −0 ext/opcache/tests/jit/shift_right_001.phpt
  141. +55 −0 ext/opcache/tests/jit/shift_right_002.phpt
  142. +26 −0 ext/opcache/tests/jit/shift_right_003.phpt
  143. +25 −0 ext/opcache/tests/jit/unreachable_block.phpt
  144. +12 −0 ext/opcache/zend_accelerator_module.c
  145. +5 −0 ext/opcache/zend_file_cache.c
  146. +37 −0 ext/opcache/zend_persist.c
  147. +24 −7 ext/opcache/zend_shared_alloc.c
  148. +6 −1 ext/opcache/zend_shared_alloc.h
@@ -761,6 +761,26 @@ TSRM_API void *tsrm_get_ls_cache(void)
return tsrm_tls_get();
}/*}}}*/

/* Returns offset of tsrm_ls_cache slot from Thread Control Block address */
TSRM_API size_t tsrm_get_ls_cache_tcb_offset(void)
{/*{{{*/
#if defined(__x86_64__) && defined(__GNUC__)
size_t ret;

asm ("movq _tsrm_ls_cache@gottpoff(%%rip),%0"
: "=r" (ret));
return ret;
#elif defined(__i386__) && defined(__GNUC__)
size_t ret;

asm ("leal _tsrm_ls_cache@ntpoff,%0"
: "=r" (ret));
return ret;
#else
return 0;
#endif
}/*}}}*/

TSRM_API uint8_t tsrm_is_main_thread(void)
{/*{{{*/
return in_main_thread;
@@ -137,6 +137,7 @@ TSRM_API void *tsrm_set_new_thread_end_handler(tsrm_thread_end_func_t new_thread
TSRM_API void *tsrm_set_shutdown_handler(tsrm_shutdown_func_t shutdown_handler);

TSRM_API void *tsrm_get_ls_cache(void);
TSRM_API size_t tsrm_get_ls_cache_tcb_offset(void);
TSRM_API uint8_t tsrm_is_main_thread(void);
TSRM_API const char *tsrm_api_name(void);

@@ -0,0 +1,140 @@
/*
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
| Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 2.00 of the Zend license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.zend.com/license/2_00.txt. |
| If you did not receive a copy of the Zend license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@zend.com so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov <dmitry@zend.com> |
| Xinchen Hui <xinchen.h@zend.com> |
+----------------------------------------------------------------------+
*/

#include "zend.h"
#include "zend_gdb.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

enum {
ZEND_GDBJIT_NOACTION,
ZEND_GDBJIT_REGISTER,
ZEND_GDBJIT_UNREGISTER
};

typedef struct _zend_gdbjit_code_entry {
struct _zend_gdbjit_code_entry *next_entry;
struct _zend_gdbjit_code_entry *prev_entry;
const char *symfile_addr;
uint64_t symfile_size;
} zend_gdbjit_code_entry;

typedef struct _zend_gdbjit_descriptor {
uint32_t version;
uint32_t action_flag;
struct _zend_gdbjit_code_entry *relevant_entry;
struct _zend_gdbjit_code_entry *first_entry;
} zend_gdbjit_descriptor;

ZEND_API zend_gdbjit_descriptor __jit_debug_descriptor = {
1, ZEND_GDBJIT_NOACTION, NULL, NULL
};

ZEND_API zend_never_inline void __jit_debug_register_code()
{
__asm__ __volatile__("");
}

ZEND_API int zend_gdb_register_code(const void *object, size_t size)
{
zend_gdbjit_code_entry *entry;

entry = malloc(sizeof(zend_gdbjit_code_entry) + size);
if (entry == NULL) {
return 0;
}

entry->symfile_addr = ((char*)entry) + sizeof(zend_gdbjit_code_entry);
entry->symfile_size = size;

memcpy((char *)entry->symfile_addr, object, size);

entry->prev_entry = NULL;
entry->next_entry = __jit_debug_descriptor.first_entry;

if (entry->next_entry) {
entry->next_entry->prev_entry = entry;
}
__jit_debug_descriptor.first_entry = entry;

/* Notify GDB */
__jit_debug_descriptor.relevant_entry = entry;
__jit_debug_descriptor.action_flag = ZEND_GDBJIT_REGISTER;
__jit_debug_register_code();

return 1;
}

ZEND_API void zend_gdb_unregister_all(void)
{
zend_gdbjit_code_entry *entry;

__jit_debug_descriptor.action_flag = ZEND_GDBJIT_UNREGISTER;
while ((entry = __jit_debug_descriptor.first_entry)) {
__jit_debug_descriptor.first_entry = entry->next_entry;
if (entry->next_entry) {
entry->next_entry->prev_entry = NULL;
}
/* Notify GDB */
__jit_debug_descriptor.relevant_entry = entry;
__jit_debug_register_code();

free(entry);
}
}

ZEND_API int zend_gdb_present(void)
{
int ret = 0;
int fd = open("/proc/self/status", O_RDONLY);

if (fd > 0) {
char buf[1024];
ssize_t n = read(fd, buf, sizeof(buf) - 1);
char *s;
pid_t pid;

if (n > 0) {
buf[n] = 0;
s = strstr(buf, "TracerPid:");
if (s) {
s += sizeof("TracerPid:") - 1;
while (*s == ' ' || *s == '\t') {
s++;
}
pid = atoi(s);
if (pid) {
sprintf(buf, "/proc/%d/exe", (int)pid);
if (readlink(buf, buf, sizeof(buf) - 1) > 0) {
if (strstr(buf, "gdb")) {
ret = 1;
}
}
}
}
}

close(fd);
}

return ret;
}
@@ -0,0 +1,27 @@
/*
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
| Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 2.00 of the Zend license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.zend.com/license/2_00.txt. |
| If you did not receive a copy of the Zend license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@zend.com so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Dmitry Stogov <dmitry@zend.com> |
| Xinchen Hui <xinchen.h@zend.com> |
+----------------------------------------------------------------------+
*/

#ifndef ZEND_GDB
#define ZEND_GDB

ZEND_API int zend_gdb_register_code(const void *object, size_t size);
ZEND_API void zend_gdb_unregister_all(void);
ZEND_API int zend_gdb_present(void);

#endif
@@ -1554,7 +1554,7 @@ PHP_ADD_SOURCES(Zend, \
zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c zend_gc.c \
zend_closures.c zend_weakrefs.c zend_float.c zend_string.c zend_signal.c zend_generators.c \
zend_virtual_cwd.c zend_ast.c zend_objects.c zend_object_handlers.c zend_objects_API.c \
zend_default_classes.c zend_inheritance.c zend_smart_str.c zend_cpuinfo.c, \
zend_default_classes.c zend_inheritance.c zend_smart_str.c zend_cpuinfo.c zend_gdb.c, \
-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)

dnl Selectively disable optimization due to high RAM usage during
@@ -46,6 +46,10 @@
#include "ext/pcre/php_pcre.h"
#include "ext/standard/md5.h"

#ifdef HAVE_JIT
# include "jit/zend_jit.h"
#endif

#ifndef ZEND_WIN32
#include <netdb.h>
#endif
@@ -2394,13 +2398,25 @@ int accel_activate(INIT_FUNC_ARGS)
accel_reset_pcre_cache();
}


#ifdef HAVE_JIT
zend_jit_activate();
#endif

if (ZCSG(preload_script)) {
preload_activate();
}

return SUCCESS;
}

#ifdef HAVE_JIT
void accel_deactivate(void)
{
zend_jit_deactivate();
}
#endif

int accel_post_deactivate(void)
{
if (ZCG(cwd)) {
@@ -2813,12 +2829,46 @@ static int accel_post_startup(void)
}
}

/* Initialize zend_func_info_rid */
zend_optimizer_startup();

/********************************************/
/* End of non-SHM dependent initializations */
/********************************************/
file_cache_only = ZCG(accel_directives).file_cache_only;
if (!file_cache_only) {
switch (zend_shared_alloc_startup(ZCG(accel_directives).memory_consumption)) {
size_t shm_size = ZCG(accel_directives).memory_consumption;
#ifdef HAVE_JIT
size_t jit_size = 0;
zend_bool reattached = 0;

if (ZCG(accel_directives).jit &&
ZCG(accel_directives).jit_buffer_size) {
size_t page_size;

# ifdef _WIN32
SYSTEM_INFO system_info;
GetSystemInfo(&system_info);
page_size = system_info.dwPageSize;
# else
page_size = getpagesize();
# endif
if (!page_size || (page_size & (page_size - 1))) {
zend_accel_error(ACCEL_LOG_FATAL, "Failure to initialize shared memory structures - can't get page size.");
abort();
}
jit_size = ZCG(accel_directives).jit_buffer_size;
jit_size = ZEND_MM_ALIGNED_SIZE_EX(jit_size, page_size);
shm_size += jit_size;
} else {
ZCG(accel_directives).jit = 0;
ZCG(accel_directives).jit_buffer_size = 0;
}

switch (zend_shared_alloc_startup(shm_size, jit_size)) {
#else
switch (zend_shared_alloc_startup(shm_size, 0)) {
#endif
case ALLOC_SUCCESS:
if (zend_accel_init_shm() == FAILURE) {
accel_startup_ok = 0;
@@ -2830,6 +2880,9 @@ static int accel_post_startup(void)
zend_accel_error(ACCEL_LOG_FATAL, "Failure to initialize shared memory structures - probably not enough shared memory.");
return SUCCESS;
case SUCCESSFULLY_REATTACHED:
#ifdef HAVE_JIT
reattached = 1;
#endif
zend_shared_alloc_lock();
accel_shared_globals = (zend_accel_shared_globals *) ZSMMG(app_shared_globals);
zend_interned_strings_set_request_storage_handlers(accel_new_interned_string_for_php, accel_init_interned_string_for_php);
@@ -2861,6 +2914,16 @@ static int accel_post_startup(void)
zend_accel_init_auto_globals();

zend_shared_alloc_lock();
#ifdef HAVE_JIT
if (ZCG(accel_directives).jit &&
ZCG(accel_directives).jit_buffer_size &&
ZSMMG(reserved)) {
zend_jit_startup(ZCG(accel_directives).jit, ZSMMG(reserved), jit_size, reattached);
} else {
ZCG(accel_directives).jit = 0;
ZCG(accel_directives).jit_buffer_size = 0;
}
#endif
zend_shared_alloc_save_state();
zend_shared_alloc_unlock();

@@ -2944,6 +3007,10 @@ void accel_shutdown(void)
zend_ini_entry *ini_entry;
zend_bool _file_cache_only = 0;

#ifdef HAVE_JIT
zend_jit_shutdown();
#endif

zend_optimizer_shutdown();

zend_accel_blacklist_shutdown(&accel_blacklist);
@@ -4244,7 +4311,11 @@ ZEND_EXT_API zend_extension zend_extension_entry = {
accel_startup, /* startup */
NULL, /* shutdown */
NULL, /* per-script activation */
#ifdef HAVE_JIT
accel_deactivate, /* per-script deactivation */
#else
NULL, /* per-script deactivation */
#endif
NULL, /* message handler */
NULL, /* op_array handler */
NULL, /* extended statement handler */
@@ -185,6 +185,11 @@ typedef struct _zend_accel_directives {
zend_bool huge_code_pages;
#endif
char *preload;
#ifdef HAVE_JIT
zend_long jit;
zend_long jit_buffer_size;
zend_long jit_debug;
#endif
} zend_accel_directives;

typedef struct _zend_accel_globals {

1 comment on commit 9a06876

@odahcam

This comment has been minimized.

Copy link

odahcam commented on 9a06876 Aug 16, 2019

I'd just like to remind that this is one of the most important commits in PHP's codebase.

Please sign in to comment.
You can’t perform that action at this time.