diff options
| author | Dmitry Stogov <dmitry@zend.com> | 2012-12-04 10:42:19 +0400 |
|---|---|---|
| committer | Dmitry Stogov <dmitry@zend.com> | 2012-12-04 10:42:19 +0400 |
| commit | 61dbf35cfced88201050484a31785183209e1b4f (patch) | |
| tree | 42e0faad5d5e66d42a07ca670fee97dc961e3421 /Zend/zend_execute.c | |
| parent | 7651d64556ebe223261c73325620c9d4b8d68aff (diff) | |
| download | php-git-61dbf35cfced88201050484a31785183209e1b4f.tar.gz | |
Moved zend_create_execute_data_from_op_array() implementation from zend_vm_execute.skl to zend_execute.c
Diffstat (limited to 'Zend/zend_execute.c')
| -rw-r--r-- | Zend/zend_execute.c | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index e5198ebfcb..1c8e61cc3a 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1569,6 +1569,157 @@ void zend_free_compiled_variables(zend_execute_data *execute_data) /* {{{ */ } /* }}} */ +/* + * 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 |<-+ | + * +========================================+ | + * | + * +========================================+ | + * | TMP_VAR[op_arrat->T-1] | | + * | ... | | + * EX_TMP_VAR_NUM(0) ----> | TMP_VAR[0] | | + * +----------------------------------------+ | + * EG(current_execute_data) -> | zend_execute_data | | + * | EX(prev_execute_data) |----+ + * +----------------------------------------+ + * EX_CV_NUM(0) ---------> | CV[0] |--+ + * | ... | | + * | CV[op_array->last_var-1] | | + * +----------------------------------------+ | + * | Optional slot for CV[0] zval* |<-+ + * | ... | + * | ...for CV [op_array->last_var-1] zval* | + * +----------------------------------------+ + * EX(call_slots) -> | CALL_SLOT[0] | + * | ... | + * | CALL_SLOT[op_array->nested_calls-1] | + * +----------------------------------------+ + * 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; + + /* + * 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). + */ + 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 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 + * 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) { + /* 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 + Ts_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); + execute_data = (zend_execute_data*)((char*)execute_data + Ts_size); + EX(prev_execute_data) = EG(current_execute_data); + } + + memset(EX_CV_NUM(execute_data, 0), 0, sizeof(zval **) * op_array->last_var); + + EX(call_slots) = (call_slot*)((char *)execute_data + execute_data_size + CVs_size); + + + EX(op_array) = op_array; + + EG(argument_stack)->top = zend_vm_stack_frame_base(execute_data); + + EX(object) = NULL; + EX(current_this) = NULL; + EX(old_error_reporting) = NULL; + EX(symbol_table) = EG(active_symbol_table); + EX(call) = NULL; + EG(current_execute_data) = execute_data; + EX(nested) = nested; + + if (!op_array->run_time_cache && op_array->last_cache_slot) { + op_array->run_time_cache = ecalloc(op_array->last_cache_slot, sizeof(void*)); + } + + if (op_array->this_var != -1 && EG(This)) { + Z_ADDREF_P(EG(This)); /* For $this pointer */ + if (!EG(active_symbol_table)) { + EX_CV(op_array->this_var) = (zval **) EX_CV_NUM(execute_data, op_array->last_var + op_array->this_var); + *EX_CV(op_array->this_var) = EG(This); + } else { + if (zend_hash_add(EG(active_symbol_table), "this", sizeof("this"), &EG(This), sizeof(zval *), (void **) EX_CV_NUM(execute_data, op_array->this_var))==FAILURE) { + Z_DELREF_P(EG(This)); + } + } + } + + EX(opline) = UNEXPECTED((op_array->fn_flags & ZEND_ACC_INTERACTIVE) != 0) && EG(start_op) ? EG(start_op) : op_array->opcodes; + EG(opline_ptr) = &EX(opline); + + EX(function_state).function = (zend_function *) op_array; + EX(function_state).arguments = NULL; + + return execute_data; +} +/* }}} */ + /* * Local variables: * tab-width: 4 |
