1# Zend Engine 2 3## Zend memory manager 4 5### General 6 7The goal of the new memory manager (available since PHP 5.2) is to reduce memory 8allocation overhead and speedup memory management. 9 10### Debugging 11 12Normal: 13 14```bash 15sapi/cli/php -r 'leak();' 16``` 17 18Zend MM disabled: 19 20```bash 21USE_ZEND_ALLOC=0 valgrind --leak-check=full sapi/cli/php -r 'leak();' 22``` 23 24### Shared extensions 25 26Since PHP 5.3.11 it is possible to prevent shared extensions from unloading so 27that valgrind can correctly track the memory leaks in shared extensions. For 28this there is the `ZEND_DONT_UNLOAD_MODULES` environment variable. If set, then 29`DL_UNLOAD()` is skipped during the shutdown of shared extensions. 30 31## ZEND_VM 32 33`ZEND_VM` architecture allows specializing opcode handlers according to 34`op_type` fields and using different execution methods (call threading, switch 35threading and direct threading). As a result ZE2 got more than 20% speedup on 36raw PHP code execution (with specialized executor and direct threading execution 37method). As in most PHP applications raw execution speed isn't the limiting 38factor but system calls and database calls are, your mileage with this patch 39will vary. 40 41Most parts of the old zend_execute.c go into `zend_vm_def.h`. Here you can find 42opcode handlers and helpers. The typical opcode handler template looks like 43this: 44 45```c 46ZEND_VM_HANDLER(<OPCODE-NUMBER>, <OPCODE>, <OP1_TYPES>, <OP2_TYPES>) 47{ 48 <HANDLER'S CODE> 49} 50``` 51 52`<OPCODE-NUMBER>` is a opcode number (0, 1, ...) 53`<OPCODE>` is an opcode name (ZEN_NOP, ZEND_ADD, :) 54`<OP1_TYPES>` and `<OP2_TYPES>` are masks for allowed operand op_types. 55Specializer will generate code only for defined combination of types. You can 56use any combination of the following op_types UNUSED, CONST, VAR, TMP and CV 57also you can use ANY mask to disable specialization according operand's op_type. 58`<HANDLER'S CODE>` is a handler's code itself. For most handlers it stills the 59same as in old `zend_execute.c`, but now it uses macros to access opcode 60operands and some internal executor data. 61 62You can see the conformity of new macros to old code in the following list: 63 64```c 65EXECUTE_DATA 66 execute_data 67ZEND_VM_DISPATCH_TO_HANDLER(<OP>) 68 return <OP>_helper(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU) 69ZEND_VM_DISPATCH_TO_HELPER(<NAME>) 70 return <NAME>(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU) 71ZEND_VM_DISPATCH_TO_HELPER_EX(<NAME>,<PARAM>,<VAL>) 72 return <NAME>(<VAL>, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU) 73ZEND_VM_CONTINUE() 74 return 0 75ZEND_VM_NEXT_OPCODE() 76 NEXT_OPCODE() 77ZEND_VM_SET_OPCODE(<TARGET> 78 SET_OPCODE(<TARGET> 79ZEND_VM_INC_OPCODE() 80 INC_OPCOD() 81ZEND_VM_RETURN_FROM_EXECUTE_LOOP() 82 RETURN_FROM_EXECUTE_LOOP() 83ZEND_VM_C_LABEL(<LABEL>): 84 <LABEL>: 85ZEND_VM_C_GOTO(<LABEL>) 86 goto <LABEL> 87OP<X>_TYPE 88 opline->op<X>.op_type 89GET_OP<X>_ZVAL_PTR(<TYPE>) 90 get_zval_ptr(&opline->op<X>, EX(Ts), &free_op<X>, <TYPE>) 91GET_OP<X>_ZVAL_PTR_PTR(<TYPE>) 92 get_zval_ptr_ptr(&opline->op<X>, EX(Ts), &free_op<X>, <TYPE>) 93GET_OP<X>_OBJ_ZVAL_PTR(<TYPE>) 94 get_obj_zval_ptr(&opline->op<X>, EX(Ts), &free_op<X>, <TYPE>) 95GET_OP<X>_OBJ_ZVAL_PTR_PTR(<TYPE>) 96 get_obj_zval_ptr_ptr(&opline->op<X>, EX(Ts), &free_op<X>, <TYPE>) 97IS_OP<X>_TMP_FREE() 98 IS_TMP_FREE(free_op<X>) 99FREE_OP<X>() 100 FREE_OP(free_op<X>) 101FREE_OP<X>_IF_VAR() 102 FREE_VAR(free_op<X>) 103FREE_OP<X>_VAR_PTR() 104 FREE_VAR_PTR(free_op<X>) 105``` 106 107Executor's helpers can be defined without parameters or with one parameter. This 108is done with the following constructs: 109 110```c 111ZEND_VM_HELPER(<HELPER-NAME>, <OP1_TYPES>, <OP2_TYPES>) 112{ 113 <HELPER'S CODE> 114} 115 116ZEND_VM_HELPER_EX(<HELPER-NAME>, <OP1_TYPES>, <OP2_TYPES>, <PARAM_SPEC>) 117{ 118 <HELPER'S CODE> 119} 120``` 121 122Executor's code is generated by PHP script zend_vm_gen.php it uses 123`zend_vm_def.h` and `zend_vm_execute.skl` as input and produces 124`zend_vm_opcodes.h` and `zend_vm_execute.h`. The first file is a list of opcode 125definitions. It is included from `zend_compile.h`. The second one is an executor 126code itself. It is included from `zend_execute.c`. 127 128`zend_vm_gen.php` can produce different kind of executors. You can select 129different opcode threading model using `--with-vm-kind=CALL|SWITCH|GOTO`. You 130can disable opcode specialization using `--without-specializer`. You can include 131or exclude old executor together with specialized one using 132`--without-old-executor`. At last you can debug executor using original 133`zend_vm_def.h` or generated file `zend_vm_execute.h`. Debugging with original 134file requires `--with-lines` option. By default ZE2 uses the following command 135to generate executor: 136 137```bash 138php zend_vm_gen.php --with-vm-kind=CALL 139``` 140