1ZEND_VM 2======= 3 4ZEND_VM architecture allows specializing opcode handlers according to op_type 5fields and using different execution methods (call threading, switch threading 6and direct threading). As a result ZE2 got more than 20% speedup on raw PHP 7code execution (with specialized executor and direct threading execution 8method). As in most PHP applications raw execution speed isn't the limiting 9factor but system calls and database calls are, your mileage with this patch 10will vary. 11 12Most parts of the old zend_execute.c go into zend_vm_def.h. Here you can 13find opcode handlers and helpers. The typical opcode handler template looks 14like this: 15 16ZEND_VM_HANDLER(<OPCODE-NUMBER>, <OPCODE>, <OP1_TYPES>, <OP2_TYPES>) 17{ 18 <HANDLER'S CODE> 19} 20 21<OPCODE-NUMBER> is a opcode number (0, 1, ...) 22<OPCODE> is an opcode name (ZEN_NOP, ZEND_ADD, :) 23<OP1_TYPES> & <OP2_TYPES> are masks for allowed operand op_types. Specializer 24will generate code only for defined combination of types. You can use any 25combination of the following op_types UNUSED, CONST, VAR, TMP and CV also 26you can use ANY mask to disable specialization according operand's op_type. 27<HANDLER'S CODE> is a handler's code itself. For most handlers it stills the 28same as in old zend_execute.c, but now it uses macros to access opcode operands 29and some internal executor data. 30 31You can see the conformity of new macros to old code in the following list: 32 33EXECUTE_DATA 34 execute_data 35ZEND_VM_DISPATCH_TO_HANDLER(<OP>) 36 return <OP>_helper(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU) 37ZEND_VM_DISPATCH_TO_HELPER(<NAME>) 38 return <NAME>(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU) 39ZEND_VM_DISPATCH_TO_HELPER_EX(<NAME>,<PARAM>,<VAL>) 40 return <NAME>(<VAL>, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU) 41ZEND_VM_CONTINUE() 42 return 0 43ZEND_VM_NEXT_OPCODE() 44 NEXT_OPCODE() 45ZEND_VM_SET_OPCODE(<TARGET> 46 SET_OPCODE(<TARGET> 47ZEND_VM_INC_OPCODE() 48 INC_OPCOD() 49ZEND_VM_RETURN_FROM_EXECUTE_LOOP() 50 RETURN_FROM_EXECUTE_LOOP() 51ZEND_VM_C_LABEL(<LABEL>): 52 <LABEL>: 53ZEND_VM_C_GOTO(<LABEL>) 54 goto <LABEL> 55OP<X>_TYPE 56 opline->op<X>.op_type 57GET_OP<X>_ZVAL_PTR(<TYPE>) 58 get_zval_ptr(&opline->op<X>, EX(Ts), &free_op<X>, <TYPE>) 59GET_OP<X>_ZVAL_PTR_PTR(<TYPE>) 60 get_zval_ptr_ptr(&opline->op<X>, EX(Ts), &free_op<X>, <TYPE>) 61GET_OP<X>_OBJ_ZVAL_PTR(<TYPE>) 62 get_obj_zval_ptr(&opline->op<X>, EX(Ts), &free_op<X>, <TYPE>) 63GET_OP<X>_OBJ_ZVAL_PTR_PTR(<TYPE>) 64 get_obj_zval_ptr_ptr(&opline->op<X>, EX(Ts), &free_op<X>, <TYPE>) 65IS_OP<X>_TMP_FREE() 66 IS_TMP_FREE(free_op<X>) 67FREE_OP<X>() 68 FREE_OP(free_op<X>) 69FREE_OP<X>_IF_VAR() 70 FREE_VAR(free_op<X>) 71FREE_OP<X>_VAR_PTR() 72 FREE_VAR_PTR(free_op<X>) 73 74 75Executor's helpers can be defined without parameters or with one parameter. 76This is done with the following constructs: 77 78ZEND_VM_HELPER(<HELPER-NAME>, <OP1_TYPES>, <OP2_TYPES>) 79{ 80 <HELPER'S CODE> 81} 82 83ZEND_VM_HELPER_EX(<HELPER-NAME>, <OP1_TYPES>, <OP2_TYPES>, <PARAM_SPEC>) 84{ 85 <HELPER'S CODE> 86} 87 88Executor's code is generated by PHP script zend_vm_gen.php it uses zend_vm_def.h 89and zend_vm_execute.skl as input and produces zend_vm_opcodes.h and 90zend_vm_execute.h. The first file is a list of opcode definitions. It is 91included from zend_compile.h. The second one is an executor code itself. It is 92included from zend_execute.c. 93 94zend_vm_gen.php can produce different kind of executors. You can select 95different opcode threading model using --with-vm-kind=CALL|SWITCH|GOTO. You can 96disable opcode specialization using --without-specializer. You can include or 97exclude old executor together with specialized one using --without-old-executor. 98At last you can debug executor using original zend_vm_def.h or generated file 99zend_vm_execute.h. Debugging with original file requires --with-lines 100option. By default ZE2 uses the following command to generate executor: 101 102$ php zend_vm_gen.php --with-vm-kind=CALL 103