Commit graph

85 commits

Author SHA1 Message Date
Dmitry Stogov
7ff71a0a55 Merge branch 'PHP-8.0' into PHP-8.1
* PHP-8.0:
  Tracing: Prevent recording types of variables used to pass zend_class_entry
2022-08-01 17:03:56 +03:00
Dmitry Stogov
2758ff2a77 Tracing: Prevent recording types of variables used to pass zend_class_entry 2022-08-01 17:02:53 +03:00
Dmitry Stogov
11dd5e6e08 Merge branch 'PHP-8.0' into PHP-8.1
* PHP-8.0:
  Use right frame
2021-10-20 23:51:04 +03:00
Dmitry Stogov
b69c6ba9df Use right frame 2021-10-20 23:50:33 +03:00
Dmitry Stogov
7e53b08cb1 Merge branch 'PHP-8.0' into PHP-8.1
* PHP-8.0:
  JIT: Fixed megamorphic call detection
2021-10-20 22:31:05 +03:00
Dmitry Stogov
95c0dfc57f JIT: Fixed megamorphic call detection 2021-10-20 22:16:25 +03:00
Dmitry Stogov
757c1277eb Merge branch 'PHP-8.0' into PHP-8.1
* PHP-8.0:
  Tracing JIT: Fixed possible stack-buffer-overflow.
2021-09-23 10:52:17 +03:00
Dmitry Stogov
08100e81e5 Tracing JIT: Fixed possible stack-buffer-overflow. 2021-09-23 10:51:20 +03:00
Dmitry Stogov
f2ceb639b8 Tracing JIT: Record information about types of defined object properties and use it to optimize code for ASSIGN_OBJ_OP, PRE/POST_INC/DEC_OBJ and FETCH_OBJ_R/IS 2021-09-22 14:08:31 +03:00
Dmitry Stogov
ceaefdb01b Fixed support for numeric string keys 2021-09-16 11:33:01 +03:00
Dmitry Stogov
12f9dad185 Tracing JIT: Record information about elements of arrays and use it to improve generated code (ASSIGN_DIM). 2021-09-16 10:32:08 +03:00
Dmitry Stogov
971142a12a Merge branch 'PHP-8.0' into PHP-8.1
* PHP-8.0:
  JIT: Fixed exit from CALL VM with GCC Global Register Variables
2021-09-13 11:40:45 +03:00
Hao Sun
cfb21e8dc1 JIT: Fixed exit from CALL VM with GCC Global Register Variables
PHP JIT supports three configurations: HYRBID, CALL with global register
variables feature(CALL+GRV for short), and CALL+noGRV.

CALL+GRV mode can be built with the following commands:

```
  php Zend/zend_vm_gen.php --with-vm-kind=CALL
  ./buildconf -f; ./configure; make
```

About 230 test cases failed for tracing JIT under CALL+GRV mode on both
x86 and arm64 machines.

For CALL+GRV mode, the condition to determine whether the execution of
an oparray is finished, is "opline == NULL". See function execute_ex()
around line "if (UNEXPECTED(!OPLINE)) {".

However, such cleanup operation is missing for the JIT wrapper
zend_jit_trace_counter_helper(), and the trace_halt stub function.

Tests:
1. test cases: all .phpt test cases under "Zend/tests/ tests/
ext/opcache/tests/jit/".
2. both JIT/x86 and JIT/arm64: function JIT, tracing JIT and tracing JIT
with "--repeat 3"
3. execution modes: NTS/ZTS, HYBRID/CALL+GRV/CALL+noGRV

In my local test, these test cases passed under all JIT configrations.
2021-09-13 11:35:12 +03:00
Dmitry Stogov
1c9f8eb7b9 JIT/x86: Merge load and test of EX_CALL_INFO() into single instruction 2021-08-25 14:36:06 +03:00
Levi Morrison
ae8647d9d3
Remove leading underscore for _zend_hash_find_known_hash (#7260)
Convert zend_hash_find_ex(..., 1) to zend_hash_find_known_hash(...)
Convert zend_hash_find_ex(..., 0) to zend_hash_find(...)

Also add serializable changes to UPGRADING.INTERNALS summary
2021-07-20 17:07:17 -06:00
Joe Watkins
d0b09a7be4 Add first-class callables
Support acquiring a Closure to a callable using the syntax
func(...), $obj->method(...), etc. This is essentially a
shortcut for Closure::fromCallable().

RFC: https://wiki.php.net/rfc/first_class_callable_syntax

Closes GH-7019.

Co-Authored-By: Nikita Popov <nikita.ppv@gmail.com>
2021-07-14 14:37:25 +02:00
Patrick Allaert
aff365871a Fixed some spaces used instead of tabs 2021-06-29 11:30:26 +02:00
sy-records
9333a22fa4 Fix typo 2021-06-10 10:24:41 +02:00
Dmitry Stogov
767a4af2c7 Introduce and use ZEND_JIT_TARGET_X86 and ZEND_JIT_TARGET_ARM64 macros.
Remove x86 specific code from ext/opcache/jit/zend_jit_arm64.dasc.
Fixed ARM64 build without libcapstone.
2021-05-18 21:59:32 +03:00
Dmitry Stogov
412c172ac6 Attempt to fix Windows build 2021-05-18 15:32:32 +03:00
Hao Sun
0de9494464 Initial support of JIT/arm64
SUMMARY

We implemented a prototype of PHP JIT/arm64. Briefly speaking,

1. build system
Changes to the build system are made so that PHP JIT can be successfully
built and run on ARM-based machine.
Major change lies in file zend_jit_arm64.dasc, where the handler for
each opcode is generated into machine code. Note that this file is just
copied from zend_jit_x86.dasc and the *unimplemented* parts are
substitued with 'brk' instruction for future work.

2. registers
AArch64 registers are defined in file zend_jit_arm64.h. From our
perspectives, the register usage is quite different from the x86
implementation due to the different ABI, number of registers and
addressing modes.
We had many confusions on this part, and will discuss it in details in
the final section.

3. opcodes
Several opcodes are partially supported, including INIT_FCALL, DO_UCALL,
DO_ICALL, RETURN, ADD, PRE_INC, JMP, QM_ASSIGN, etc. Hence, simple use
scenarios such as user function call, loops, addition with integer and
floating point numbers can be supported.
18 micro test cases are added under 'ext/opcache/tests/jit/arm64/'. Note
that majority of these test cases are design for functional JIT, and
cases 'hot_func_*.phpt' and 'loop_002.phpt' can trigger tracing JIT.

4. test
Our local test environment is an ARM-based server with Ubuntu 20.04 and
GCC-10. Note that both HYBRID and CALL VM modes are supported. We
suggest running the JIT test cases using the following command. Out of
all 130 test cases, 66 cases can be passed currently.
```
  $ make test TESTS='-d opcache.jit=1203 ext/opcache/tests/jit/'
```

DETAILS

1. I-cache flush
Instruction cache must be flushed for the JIT-ed code on AArch64. See
macro JIT_CACHE_FLUSH in file 'zend_jit_internal.h'.

2. Disassembler
Add initialization and jump target parse operations for AArch64 backed.
See the updates in file 'zend_jit_disasm.c'.

3. redzone
Enable redzone for AArch64. See the update in zend_vm_opcodes.h.
Redzone is designated to prevent 'vm_stack_data' from being optimized
out by compilers. It's worth noting that this 16-byte redzone might be
reused as temporary use(treated as extra stack space) for HYBRID mode.

4. stack space reservation
The definitions of HYBRID_SPAD, SPAD and NR_SPAD are a bit tricky for
x86/64.
In AArch64, HYBRID_SPAD and SPAD are both defined as 16. These 16 bytes
are pre-allocated for tempoerary usage along the exuection of JIT-ed
code. Take line 4185 in file zend_jit_arm64.dasc as an example. NR_SPAD
is defined as 48, out of which 32 bytes to save FP/IP/LR registers.
Note that we choose to always reserve HYBRID_SPAD bytes in HYBRID mode,
no matter whether redzone is used or not, for the sake of safety.

5. stack alignment
In AArch64 the stack pointer should be 16-byte aligned. Since shadow
stack is used for JIT, it's easy to guarantee the stack alignment, via
simply moving SP with an offset like 16 or a multiple of 16. That's why
NR_SPAD is defined as 48 and we use 32 of them to save FP/IP/LR
registers which only occupies 24 bytes.

6. global registers
x27 and x28 are reserved as global registers. See the updates in file
zend_jit_vm_helpers.c

7. function prologue for CALL mode
Two callee-saved registers x27 and x28 should saved in function
zend_jit_prologue() in file zend_jit_arm64.dasc. Besides the LR, i.e.
x30, should also be saved since runtime C helper functions(such as
zend_jit_find_func_helper) might be invoked along the execution of
JIT-ed code.

8. regset
Minor changes are done to regset operations particularly for AArch64.
See the updates in file zend_jit_internal.h.

REGISTER USAGE

In this section, we will first talk about our understanding on register
usage and then demonstrate our design.

1. Register usage for HYBRID/CALL modes
Registers are used similarly between HYBRID mode and CALL mode.

One difference is how FP and IP are saved. In HYBRID mode, they are
assigned to global registers, while in CALL mode they are saved/restored
on the VM stack explicitly in prologue/epilogue.

The other difference is that LR register should also be saved/restored
in CALL mode since JIT-ed code are invoked as normal functions.

2. Register usage for functional/tracing JIT
The way registers are used differs a lot between functional JIT and
tracing JIT.

For functional JIT, runtime C code (e.g. helper functions) would be
invoked along the execution of JIT-ed code. As the operands for *most*
opcodes are accessed via the stack slot, i.e. FP + offset. Hence there
is no need to save/restore local(caller-saved) registers before/after
invoking runtime C code.
Exception lies in Phi node and registers might be allocated for these
nodes. Currently I don't fully understand the reason, why registers are
allocated for Phi functions, because I suppose for different versions of
SSA variables at the Phi function, their postions on the stack slot
should be identical(in other words, access via the stack slot is enough
and there is no need to allocate registers).

For tracing JIT, runtime information are recorded for traces(before the
JIT compilation), and the data types and control flows are concrete as
well. Hence it's would be faster to conduct operations and computations
via registers rather than stack slots(as functional JIT does) for these
collected hot paths. Besides, runtime C code can be invoked for tracing
JIT, however this only happends for deoptimization and all registers are
saved to stack in advance.

3. Candidates for register allocator
1) opcode candidates
Function zend_jit_opline_supports_reg() determines the candidate opcodes
which can use CPU registers.

2) register candidates
Registers in set "ZEND_REGSET_FP + ZEND_REGSET_GP - ZEND_REGSET_FIXED -
ZEND_REGSET_PRESERVED" are available for register allocator.
Note that registers from ZEND_REGSET_FIXED are reserved for special
purpose, such as the stack pointer, and they are excluded from register
allocation process.
Note that registers from ZEND_REGSET_PRESERVED are callee-saved based on
the ABI and it's safe to not use them either.

4. Temporary registers
Temporary registers are needed by some opcodes to save intermediate
computation results.

1) Functions zend_jit_get_def_scratch_regset() and
zend_jit_get_scratch_regset() return which registers might be clobbered
by some opcodes. Hence register allocator would spill these scratch
registers if necessary when encountering these opcodes.

2) Macro ZEND_REGSET_LOW_PRIORITY denotes a set of registers which would
be allocated with low priority, and these registers can be used as
temporary usage to avoid conflicts to its best.

5. Compared to the x86 implementation, in JIT/arm64
1) Called-saved FP registers are included into ZEND_REGSET_PRESERVED for
AArch64.

2) We follow the logic of function zend_jit_opline_supports_reg().

3) We reserve 4 GPRs and 2 FPRs out from register allocator and use them
as temporary registers in particular. Note that these 6 registers are
included in set ZEND_REGSET_FIXED.
Since they are reserved, may-clobbered registers can be removed for most
opcodes except for function calls. Besides, low-priority registers are
defined as empty since all candidate registers are of the same priority.
See the updates in function zend_jit_get_scratch_regset() and macro
ZEND_REGSET_LOW_PRIORITY.

6. Why we reserve registers for temporary usage?
1) Addressing mode in AArch64 needs more temporary registers.
The addressing mode is different from x86 and tempory registers might be
*always* needed for most opcodes. For instance, an immediate must be
first moved into one register before storing into memory in AArch64,
whereas in x86 this immediate can be stored directly.

2) There are more registers in AArch64.
Compared to the solution in JIT/x86(that is, temporary registers are
reserved on demand, i.e. different registers for different opcodes under
different conditions), our solution seems a coarse-granularity and
brute-force solution, and the execution performance might be downgraded
to some extent since the number of candidate registers used for
allocation becomes less.
We suppose the performance loss might be acceptable since there are more
registers in AArch64.

3) Based on my understanding, scratch registers defined in x86 are
excluded from candidates for register allocator with *low possibility*,
and it can still allocate these registers. Special handling should be
conducted, such as checking 'reg != ZREG_R0'.
Hence, as we see it, it's simpler to reserve some temporary registers
exclusively. See the updates in function zend_jit_math_long_long() for
instance. TMP1 can be used directly without checking.

Co-Developed-by: Nick Gasson <Nick.Gasson@arm.com>
2021-05-18 15:32:23 +03:00
KsaR
01b3fc03c3
Update http->https in license (#6945)
1. Update: http://www.php.net/license/3_01.txt to https, as there is anyway server header "Location:" to https.
2. Update few license 3.0 to 3.01 as 3.0 states "php 5.1.1, 4.1.1, and earlier".
3. In some license comments is "at through the world-wide-web" while most is without "at", so deleted.
4. fixed indentation in some files before |
2021-05-06 12:16:35 +02:00
Nikita Popov
3e01f5afb1 Replace zend_bool uses with bool
We're starting to see a mix between uses of zend_bool and bool.
Replace all usages with the standard bool type everywhere.

Of course, zend_bool is retained as an alias.
2021-01-15 12:33:06 +01:00
Dmitry Stogov
e9f9e9f863 Perform early guard type check for result of FETCH_CONSTANT 2020-12-09 22:24:03 +03:00
Dmitry Stogov
64dc79f906 Trampoline cleanup 2020-11-16 12:05:45 +03:00
Dmitry Stogov
de359c00b4 Stop on fake frame 2020-11-11 14:54:54 +03:00
Dmitry Stogov
11c4821ba9 [Observer+JIT] Save opline before calling begin/end handlers 2020-11-11 13:50:53 +03:00
Nikita Popov
0571f09424 Rename opcache.jit_max_loops_unroll to opcache.jit_max_loop_unrolls 2020-11-02 12:25:21 +01:00
Dmitry Stogov
aecb05f5e7 Give preference to ENTER->RECURSIVE_CALL trace over ENTER->RETURN 2020-09-30 12:21:15 +03:00
Dmitry Stogov
b44cf93774 Allow tracing JIT cooperate with function JIT. 2020-09-29 16:33:32 +03:00
Dmitry Stogov
2a71cb3ce1 Improved trace selection rules 2020-09-28 17:04:34 +03:00
Dmitry Stogov
5783e611a2 Improve trace selection (avoid blacklisting of trace that may be linked). 2020-09-23 23:50:44 +03:00
Dmitry Stogov
3c4fb70f2b Replace ZEND_JIT_TRACE_STOP_RETURN_HALT and ZEND_JIT_TRACE_STOP_HALT by separate ZEND_JIT_TRACE_HALT flag. 2020-09-23 15:44:04 +03:00
Dmitry Stogov
f5bbb0480e Tracing JIT for INIT_DYNAMIC_CALL (closure only) 2020-09-15 15:57:57 +03:00
Dmitry Stogov
6b521a98d4 Fixed support for deprecated constants (Zend/tests/const_deprecation.phpt failure) 2020-09-03 10:49:58 +03:00
Dmitry Stogov
91edb90767 JIT for FETCH_CONSTANT 2020-09-03 00:51:43 +03:00
Dmitry Stogov
91d7e872e0 Fixed nested init fcall guards. 2020-09-01 12:24:11 +03:00
Dmitry Stogov
e86b5c872d Record information about packed arrays 2020-08-25 19:39:42 +03:00
Nikita Popov
d92229d8c7 Implement named parameters
From an engine perspective, named parameters mainly add three
concepts:

 * The SEND_* opcodes now accept a CONST op2, which is the
   argument name. For now, it is looked up by linear scan and
   runtime cached.
 * This may leave UNDEF arguments on the stack. To avoid having
   to deal with them in other places, a CHECK_UNDEF_ARGS opcode
   is used to either replace them with defaults, or error.
 * For variadic functions, EX(extra_named_params) are collected
   and need to be freed based on ZEND_CALL_HAS_EXTRA_NAMED_PARAMS.

RFC: https://wiki.php.net/rfc/named_params

Closes GH-5357.
2020-07-31 15:53:36 +02:00
Dmitry Stogov
fd56fd2279 Always record ZEND_JIT_TRACE_START and ZEND_JIT_TRACE_END 2020-07-28 03:23:28 +03:00
Dmitry Stogov
96a1b409df Don't record "fake" closures 2020-07-23 15:18:28 +03:00
Dmitry Stogov
7686118212 Fix type recording and side exit information for FE_FETCH_* instructions 2020-07-21 15:39:13 +03:00
Dmitry Stogov
be0d912674 Avoid recording of uninitialized variable 2020-07-21 14:11:19 +03:00
Dmitry Stogov
774bc760af Fixed VM interrupt handling 2020-07-20 23:14:23 +03:00
Dmitry Stogov
2b7035e824 Fixed tracing JIT for VM without global register variables 2020-07-20 20:59:31 +03:00
Máté Kocsis
d30cd7d7e7
Review the usage of apostrophes in error messages
Closes GH-5590
2020-07-10 21:05:28 +02:00
Dmitry Stogov
8d15a2bc8e Restore registers 2020-07-10 12:51:19 +03:00
Dmitry Stogov
9d14bdb377 Bad function detection 2020-07-09 17:24:35 +03:00
Dmitry Stogov
24a8065f8b Tracing JIT support for include() and generators 2020-06-29 21:40:49 +03:00
Dmitry Stogov
1ca2fd2b16 Don't record "fake" closures 2020-06-29 20:37:50 +03:00