diff options
| author | Nikita Popov <nikic@php.net> | 2012-05-22 23:14:36 +0200 |
|---|---|---|
| committer | Nikita Popov <nikic@php.net> | 2012-05-22 23:17:59 +0200 |
| commit | 5e763d9420cbccbd8ee4f14a263b2439e6c5ae88 (patch) | |
| tree | 958dbb49d8094a6a3188ba0ef58a4dc92c76cf3c /Zend/zend_vm_execute.skl | |
| parent | 46fa26ab853b766c9222e49dbe7555de360b42f4 (diff) | |
| download | php-git-5e763d9420cbccbd8ee4f14a263b2439e6c5ae88.tar.gz | |
Allocate execute_data using malloc for generators
Generators need to switch the execute_data very often. If the execute_data
is allocated on the VM stack this operation would require to always copy
the structure (which is quite large). That's why the execution context is
allocated on the heap instead (only for generators obviously).
Diffstat (limited to 'Zend/zend_vm_execute.skl')
| -rw-r--r-- | Zend/zend_vm_execute.skl | 36 |
1 files changed, 32 insertions, 4 deletions
diff --git a/Zend/zend_vm_execute.skl b/Zend/zend_vm_execute.skl index 426f689795..359e052008 100644 --- a/Zend/zend_vm_execute.skl +++ b/Zend/zend_vm_execute.skl @@ -3,9 +3,13 @@ ZEND_API void {%EXECUTOR_NAME%}(zend_op_array *op_array TSRMLS_DC) { DCL_OPLINE + zend_execute_data *execute_data; + size_t execute_data_size; + zend_bool nested = 0; zend_bool original_in_execution = EG(in_execution); + {%HELPER_VARS%} {%INTERNAL_LABELS%} @@ -17,11 +21,35 @@ ZEND_API void {%EXECUTOR_NAME%}(zend_op_array *op_array TSRMLS_DC) EG(in_execution) = 1; zend_vm_enter: - /* Initialize execute_data */ - execute_data = (zend_execute_data *)zend_vm_stack_alloc( + /* + * When allocating the execute_data, memory for compiled variables and + * temporary variables is also allocated after the actual zend_execute_data + * struct. op_array->last_var specifies the number of compiled variables and + * op_array->T is the number of temporary variables. If there is no symbol + * table, then twice as much memory is allocated for compiled variables. + * In that case the first half contains zval**s and the second half the + * actual zval*s (which would otherwise be in the symbol table). + */ + execute_data_size = ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data)) + - ZEND_MM_ALIGNED_SIZE(sizeof(zval**) * op_array->last_var * (EG(active_symbol_table) ? 1 : 2)) + - ZEND_MM_ALIGNED_SIZE(sizeof(temp_variable)) * op_array->T TSRMLS_CC); + ZEND_MM_ALIGNED_SIZE(sizeof(zval **) * op_array->last_var * (EG(active_symbol_table) ? 1 : 2)) + + ZEND_MM_ALIGNED_SIZE(sizeof(temp_variable)) * op_array->T + ; + + /* + * Normally the execute_data is allocated on the VM stack (because it does + * not actually do any allocation and thus is faster). For generators + * though this behavior would be suboptimal, because the (rather large) + * structure would have to be copied back and forth every time execution is + * suspended or resumed. That's why for generators the execution context + * is allocated using emalloc, thus allowing to save and restore it simply + * by replacing a pointer. + */ + if (op_array->fn_flags & ZEND_ACC_GENERATOR) { + execute_data = emalloc(execute_data_size); + } else { + execute_data = zend_vm_stack_alloc(execute_data_size TSRMLS_CC); + } EX(CVs) = (zval***)((char*)execute_data + ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data))); memset(EX(CVs), 0, sizeof(zval**) * op_array->last_var); |
