summaryrefslogtreecommitdiff
path: root/Zend/zend_vm_execute.skl
diff options
context:
space:
mode:
authorNikita Popov <nikic@php.net>2012-05-22 23:14:36 +0200
committerNikita Popov <nikic@php.net>2012-05-22 23:17:59 +0200
commit5e763d9420cbccbd8ee4f14a263b2439e6c5ae88 (patch)
tree958dbb49d8094a6a3188ba0ef58a4dc92c76cf3c /Zend/zend_vm_execute.skl
parent46fa26ab853b766c9222e49dbe7555de360b42f4 (diff)
downloadphp-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.skl36
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);