1 / 31

Zend Engine изнутри

Zend Engine изнутри. Дмитрий Стогов. Немного истории. Zend Engine была разработана в качестве ядра для PHP 4 Andi Gutmans и Zeev Suraski в 1999 PHP 5.0 основан на Zend Engine 2 с новой объектной моделью PHP 5.1 основан на Zend Engine 2.1 со специализированной VM

iago
Download Presentation

Zend Engine изнутри

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Zend Engine изнутри Дмитрий Стогов

  2. Немного истории • Zend Engine была разработана в качестве ядра для PHP 4 Andi Gutmans и Zeev Suraski в 1999 • PHP 5.0 основан на Zend Engine 2 с новой объектной моделью • PHP 5.1 основан на Zend Engine 2.1 со специализированной VM • PHP 5.2 основан на Zend Engine 2.2 с новым менеджером памяти • PHP 5.3 основан на Zend Engine 2.3 которая включает большинство улучшений и нововведений из PHP6, за исключением Unicode, (namespace-ы, сборщик мусора, LSB, оператор goto, ленивая инициализация таблиц символов, новый сканнер основанный на re2c) • PHP 6 основан на Zend Engine 3 с поддержкой Unicode

  3. Подсистемы ZE • Менеджер памяти • API для доступа к внутренним структурам данных • Компилятор PHP • Виртуальная машина PHP • API для ресурсов (файлы, DB коннекшены) • API для внешних расширений PHP • Набор внутренних функций • Сборщик мусора (5.3)

  4. Стадии работы PHP

  5. Thread Safe Resource Manager • non-ZTS-build (single-thread) • ZTS-build (thread-safe) • Каждый thread работает со своими глобальными данными • ZE использует compiler_globals (CG) и executor_globals (EG) • Любое расширение PHP может определить свои глобальные данные, которые должны быть уникальными для разных thread-ов

  6. TSRM макросы • void some_function(void) {process(EG(symbol_table));// compilation error}

  7. TSRM макросы • void some_function(void) { int some_local_variable;TSRMLS_FETCH();process(EG(symbol_table));} • void some_function(TSRMLS_D) {process(EG(symbol_table));} some_function(TSRMLS_C); • void some_function(int some_paremeterTSRMLS_DC) {process(EG(symbol_table));} some_function(0TSRMLS_CC);

  8. Менеджер памяти emalloc() efree() erealloc() estrdup() estrndup() ecalloc() $ USE_ZEND_ALLOC=0 valgrind php test.php

  9. typedef struct _zval_struct { zend_uchar type; zvalue_value value; zend_uchar is_ref; zebd_uint refcount; } zval; Значения (zval-коетейнер)

  10. typedef struct _zval_struct { zend_uchar type; zvalue_value value; zend_uchar is_ref; zebd_uint refcount; } zval; IS_NULL IS_LONG IS_DOUBLE IS_BOOL IS_ARRAY IS_OBJECT IS_STRING IS_RESOURCE IS_CONSTANT IS_CONSTANT_ARRAY Значения (zval-коетейнер)

  11. typedef struct _zval_struct { zend_uchar type; zvalue_value value; zend_uchar is_ref; zebd_uint refcount; } zval; typedef union _zvalue_value { long lval; double dval; struct { char *val; int len; } str; HashTable *ht; zend_object_value obj; } zvalue_value; Значения (zval-коетейнер)

  12. <?php $a = 10; $b =& $b; Ссылки EG(symbol_table) HashTable $a zval type IS_LONG $b value 10 is_ref 1 … refcount 2

  13. <?php $a = 1; $b = $a; $b = 2; $b =& $a; $b = 3; $b =& $c; // $a = {1, refcount=1, is_ref=0} // $a = {1, refcount=2, is_ref=0} // $b = {1, refcount=2, is_ref=0} // $a = {1, refcount=1, is_ref=0} // $b = {2, refcount=1, is_ref=0} // $a = {1, refcount=2, is_ref=1} // $b = {1, refcount=2, is_ref=1} // $a = {3, refcount=2, is_ref=1} // $b = {3, refcount=2, is_ref=1} // $a = {3, refcount=1, is_ref=0} // $b = {?, refcount=?, is_ref=1} Присваивание и копирование при записи

  14. Компилятор • Основан на flex/bison based (основан на re2c/bison начиная с 5.3) • Однопроходная компиляция (на самом деле два прохода) • AST не создается • Прямая компиляция в байт-кодVM • Быстрая компиляция • Оптимизация практически не выполняется

  15. Глобальные данные компилятора (CG) • struct _zend_compiler_globals { … HashTable *function_table; HashTable *class_table; zend_class_entry *active_class_entry; zend_op_array *active_op_array; … }; • CG(function_table)

  16. typedef struct _zend_op_array { zend_uchar type; char *function_name; zend_class_entry *scope; zend_uint fn_flags; zend_op *opcodes; zend_compiled_variables *vars; zend_uint last, lat_var, T; HashTable *static_variables; … } zend_op_array; Функции PHP (op_array)

  17. typedef struct _zend_op { zend_uchar opcode; ulong extended_value; znode op1; znode op2; znode result; uint lineno; opcode_handler_t handler; } zend_op; Инструкции VM (zend_op)

  18. typedef struct _zend_op { zend_uchar opcode; ulong extended_value; znode op1; znode op2; znode result; uint lineno; opcode_handler_t handler; } zend_op; ZEND_NOP ZEND_ADD ZEND_SUB ZEND_IS_EQUAL ZEND_JMP ZEND_JMPZ ZEND_ASSIGN ZEND_DO_FCALL ZEND_RETURN ~150 opcodes in zend_vm_opcodes.h Инструкции VM (zend_op)

  19. typedef struct _zend_op { zend_uchar opcode; ulong extended_value; znode op1; znode op2; znode result; uint lineno; opcode_handler_t handler; } zend_op; typedef struct _znode { int op_type; union { zval constant; zend_uint var; zend_uint opline_num; zend_op *jmp_addr; struct { zend_uint var; zend_uint type; } EA; } u; } znode; Инструкции VM (zend_op)

  20. typedef struct _znode { int op_type; union { zval constant; zend_uint var; zend_uint opline_num; zend_op *jmp_addr; struct { zend_uint var; zend_uint type; } EA; } u; } znode; IS_CONST IS_CV IS_TMP_VAR IS_VAR IS_UNUSED Операнды (znode)

  21. <?php $a = “Hello”; $b = “World”; echo $a .” “. $b; ?> // FETCH_WC(“a”) -> V(0) // ASSIGNV(0), C(“Hello”) // FETCH_WC(“b”) -> V(1) // ASSIGNV(1), C(“World”) // FETCH_RC(“a”) -> V(2) // CONCATV(2), C(“ “) -> T(3) // FETCH_RC(“b”) -> V(4) // CONCATT(3), V(4) -> T(5) // ECHOT(5) // RETURNC(NULL) Пример компиляции (5.0)

  22. <?php $a = “Hello”; $b = “World”; echo $a .” “. $b; ?> // // ASSIGN CV(0)[“a”], C(“Hello”) // // ASSIGN CV(1)[“b”], C(“World”) // // CONCAT CV(0)[“a”], C(“ “) -> T(0) // CONCAT T(0), CV(1)[“b”] -> T(1) // ECHO T(1) // // // RETURN C(NULL) Пример компиляции (5.1)

  23. Глобальные данные VM (EG) • struct _zend_executor_globals { … HashTable *active_symbol_table; HashTable symbol_table; // $GLOBALS[] HashTable *function_table; HashTable *class_table; HashTable *zend_constants; zval *This; zend_class_entry *scope; zend_op_array *active_op_array; zend_op **opline_ptr; struct _zend_execute_data *current_execute_data; … }; • EG(symbol_table)

  24. Switch-threaded Executor (4.*) void execute(zend_op_array *op_arrayTSRMLS_DC) { zend_execute_data execute_data; // initialization EX(opline) = op_array->opcodes; while (1) { switch (EX(opline)->opcode) { … case ZEND_RETURN; … return; } } }

  25. Call-threaded Executor (5.*) void execute(zend_op_array *op_arrayTSRMLS_DC) { zend_execute_data execute_data; // initialization EX(opline) = op_array->opcodes; while (1) { if (EX(opline)->handler(&execute_dataTSRMLS_CC)) { return; } } }

  26. Call-threaded Executor (5.0) int zend_concat_handler(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); concat_function(&EX_T(opline->result.u.var).tmp_var, get_zval_ptr(&opline->op1, EX(Ts), &EG(free_op1), BP_VAR_R), get_zval_ptr(&opline->op2, EX(Ts), &EG(free_op2), BP_VAR_R)); FREE_OP1(EX(Ts), &opline->op1, EG(free_op1)); FREE_OP2(EX(Ts), &opline->op2, EG(free_op2)); EX(opline)++; return 0; }

  27. Специализация в VM (5.1) ZEND_VM_HANDLER(8, ZEND_CONCAT, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV) { zend_op *opline = EX(opline); zend_free_op free_op1, free_op2; concat_function(&EX_T(opline->result.u.var).tmp_var, GET_OP1_ZVAL_PTR(BP_VAR_R), GET_OP2_ZVAL_PTR(BP_VAR_R)); FREE_OP1(); FREE_OP2(); EX(opline)++; return 0; }

  28. Специализация в VM (5.1) int ZEND_CONCAT_SPEC_CV_CONST_HANDLER( ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); concat_function(&EX_T(opline->result.u.var).tmp_var, _get_zval_ptr_cv(&opline->op1, EX(Ts), BP_VAR_R), &opline->op2.u.constant); EX(opline)++; return 0; }

  29. Классы typrdef struct _zend_class_entry { char type; char *name; zend_class_entry *parent; zend_uint ce_flags; HashTable function_table; HashTable default_properties; HashTable properties_info; HashTable *static_members; HashTable constants_table; zend_class_entry **interfaces; … } zend_class_entry;

  30. Объекты typedef struct _zend_object_value { zend_uint handle; // Z_OBJ_HANDLE(zval) zend_object_handlers *handlers; // Z_OBJ_HT(zval) } zend_object_value; typedef struct _zend_object { zend_class_entry *ce; // Z_OBJCE(zval) HashTable *properties; // Z_OBJPROP(zval) } zend_object;

  31. Вопросы?

More Related