summaryrefslogtreecommitdiff
path: root/Zend/zend_vm_execute.skl
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2012-11-30 13:39:23 +0400
committerDmitry Stogov <dmitry@zend.com>2012-11-30 13:39:23 +0400
commit70f83f35d089d0cafae12ae231a38541f5c8e41c (patch)
tree1dee0f4716d742a57558d59a9285392805b25a9b /Zend/zend_vm_execute.skl
parent9f7e53fde8b0feac271230cbc6731e9de90f2a03 (diff)
downloadphp-git-70f83f35d089d0cafae12ae231a38541f5c8e41c.tar.gz
. The VM stacks for passing function arguments and syntaticaly nested calls were merged into a single stack. The stack size needed for op_array execution is calculated at compile time and preallocated at once. As result all the stack push operatins don't require checks for stack overflow any more.
. Generators implementation was improved using the new VM stack. Now it's a bit more clear and faster.
Diffstat (limited to 'Zend/zend_vm_execute.skl')
-rw-r--r--Zend/zend_vm_execute.skl102
1 files changed, 91 insertions, 11 deletions
diff --git a/Zend/zend_vm_execute.skl b/Zend/zend_vm_execute.skl
index e2d5dd12b0..85d3dfb04f 100644
--- a/Zend/zend_vm_execute.skl
+++ b/Zend/zend_vm_execute.skl
@@ -1,6 +1,49 @@
{%DEFINES%}
-zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_array, zend_bool nested TSRMLS_DC) {
+/*
+ * Stack Frame Layout (the whole stack frame is allocated at once)
+ * ==================
+ *
+ * +========================================+
+ * | zend_execute_data |<---+
+ * | EX(function_state).arguments |--+ |
+ * | ... | | |
+ * | ARGUMENT [1] | | |
+ * | ... | | |
+ * | ARGUMENT [ARGS_NUMBER] | | |
+ * | ARGS_NUMBER |<-+ |
+ * +========================================+ |
+ * |
+ * +========================================+ |
+ * EG(current_execute_data) -> | zend_execute_data | |
+ * | EX(prev_execute_data) |----+
+ * +----------------------------------------+
+ * EX(Ts) ---------> | EX(Ts)[0] |
+ * | ... |
+ * | EX(Tx)[op_arrat->T] |
+ * +----------------------------------------+
+ * EX(CVs) --------> | EX(CVs)[0] |--+
+ * | ... | |
+ * | EX(CVs)[op_array->last_var] | |
+ * +----------------------------------------+ |
+ * | Optional slot for CV[0] zval* |<-+
+ * | ... |
+ * | ... for CV [op_array->last_var] zval* |
+ * +----------------------------------------+
+ * EX(call_slots) -> | EX(call_slots)[0] |
+ * | ... |
+ * | EX(call_slots)[op_array->nested_calls] |
+ * +----------------------------------------+
+ * zend_vm_stack_frame_base -> | ARGUMENTS STACK [0] |
+ * | ... |
+ * zend_vm_stack_top --------> | ... |
+ * | ... |
+ * | ARGUMENTS STACK [op_array->used_stack] |
+ * +----------------------------------------+
+ */
+
+zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_array, zend_bool nested TSRMLS_DC)
+{
zend_execute_data *execute_data;
/*
@@ -15,7 +58,9 @@ zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_arra
size_t execute_data_size = ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data));
size_t CVs_size = ZEND_MM_ALIGNED_SIZE(sizeof(zval **) * op_array->last_var * (EG(active_symbol_table) ? 1 : 2));
size_t Ts_size = ZEND_MM_ALIGNED_SIZE(sizeof(temp_variable)) * op_array->T;
- size_t total_size = execute_data_size + CVs_size + Ts_size;
+ size_t call_slots_size = ZEND_MM_ALIGNED_SIZE(sizeof(call_slot)) * op_array->nested_calls;
+ size_t stack_size = ZEND_MM_ALIGNED_SIZE(sizeof(zval*)) * op_array->used_stack;
+ size_t total_size = execute_data_size + Ts_size + CVs_size + call_slots_size + stack_size;
/*
* Normally the execute_data is allocated on the VM stack (because it does
@@ -27,23 +72,58 @@ zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_arra
* by replacing a pointer.
*/
if (op_array->fn_flags & ZEND_ACC_GENERATOR) {
- execute_data = emalloc(total_size);
+ /* Prepend the regular stack frame with copy on prev_execute_data
+ * and passed arguments
+ */
+ int args_count = zend_vm_stack_get_args_count_ex(EG(current_execute_data));
+ size_t args_size = ZEND_MM_ALIGNED_SIZE(sizeof(zval*)) * (args_count + 1);
+
+ total_size += args_size + execute_data_size;
+
+ EG(argument_stack) = zend_vm_stack_new_page((total_size + (sizeof(void*) - 1)) / sizeof(void*));
+ EG(argument_stack)->prev = NULL;
+ execute_data = (zend_execute_data*)((char*)ZEND_VM_STACK_ELEMETS(EG(argument_stack)) + args_size + execute_data_size);
+
+ /* copy prev_execute_data */
+ EX(prev_execute_data) = (zend_execute_data*)((char*)ZEND_VM_STACK_ELEMETS(EG(argument_stack)) + args_size);
+ memset(EX(prev_execute_data), 0, sizeof(zend_execute_data));
+ EX(prev_execute_data)->function_state.function = (zend_function*)op_array;
+ EX(prev_execute_data)->function_state.arguments = (void**)((char*)ZEND_VM_STACK_ELEMETS(EG(argument_stack)) + ZEND_MM_ALIGNED_SIZE(sizeof(zval*)) * args_count);
+
+ /* copy arguemnts */
+ *EX(prev_execute_data)->function_state.arguments = (void*)(zend_uintptr_t)args_count;
+ if (args_count > 0) {
+ zval **arg_src = (zval**)zend_vm_stack_get_arg_ex(EG(current_execute_data), 1);
+ zval **arg_dst = (zval**)zend_vm_stack_get_arg_ex(EX(prev_execute_data), 1);
+ int i;
+
+ for (i = 0; i < args_count; i++) {
+ arg_dst[i] = arg_src[i];
+ Z_ADDREF_P(arg_dst[i]);
+ }
+ }
} else {
execute_data = zend_vm_stack_alloc(total_size TSRMLS_CC);
+ EX(prev_execute_data) = EG(current_execute_data);
}
- EX(CVs) = (zval ***) ((char *) execute_data + execute_data_size);
+ EX(Ts) = (temp_variable *) ((char *) execute_data + execute_data_size);
+
+ EX(CVs) = (zval ***) ((char *) EX(Ts) + Ts_size);
memset(EX(CVs), 0, sizeof(zval **) * op_array->last_var);
- EX(Ts) = (temp_variable *) ((char *) EX(CVs) + CVs_size);
+ EX(call_slots) = (call_slot*)((char *) EX(CVs) + CVs_size);
+
+
+ EX(op_array) = op_array;
+
+ EG(argument_stack)->top = zend_vm_stack_frame_base(execute_data);
- EX(fbc) = NULL;
- EX(called_scope) = NULL;
EX(object) = NULL;
+ EX(current_this) = NULL;
EX(old_error_reporting) = NULL;
- EX(op_array) = op_array;
EX(symbol_table) = EG(active_symbol_table);
- EX(prev_execute_data) = EG(current_execute_data);
+ EX(call) = NULL;
EG(current_execute_data) = execute_data;
EX(nested) = nested;
@@ -103,12 +183,12 @@ ZEND_API void {%EXECUTOR_NAME%}_ex(zend_execute_data *execute_data TSRMLS_DC)
zend_error_noreturn(E_ERROR, "Arrived at end of main loop which shouldn't happen");
}
-ZEND_API void {%EXECUTOR_NAME%}(zend_op_array *op_array TSRMLS_DC)
+ZEND_API void zend_{%EXECUTOR_NAME%}(zend_op_array *op_array TSRMLS_DC)
{
if (EG(exception)) {
return;
}
- {%EXECUTOR_NAME%}_ex(zend_create_execute_data_from_op_array(op_array, 0 TSRMLS_CC) TSRMLS_CC);
+ zend_{%EXECUTOR_NAME%}_ex(zend_create_execute_data_from_op_array(op_array, 0 TSRMLS_CC) TSRMLS_CC);
}
{%EXTERNAL_EXECUTOR%}