summaryrefslogtreecommitdiff
path: root/Zend/zend_vm_execute.skl
blob: e2d5dd12b039b2c9e917b40a1991e4b1737d72dc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
{%DEFINES%}

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 total_size = execute_data_size + CVs_size + Ts_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) {
		execute_data = emalloc(total_size);
	} else {
		execute_data = zend_vm_stack_alloc(total_size TSRMLS_CC);
	}

	EX(CVs) = (zval ***) ((char *) execute_data + execute_data_size);
	memset(EX(CVs), 0, sizeof(zval **) * op_array->last_var);

	EX(Ts) = (temp_variable *) ((char *) EX(CVs) + CVs_size);

	EX(fbc) = NULL;
	EX(called_scope) = NULL;
	EX(object) = 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);
	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(CVs)[op_array->this_var] = (zval **) EX(CVs) + op_array->last_var + op_array->this_var;
			*EX(CVs)[op_array->this_var] = EG(This);
		} else {
			if (zend_hash_add(EG(active_symbol_table), "this", sizeof("this"), &EG(This), sizeof(zval *), (void **) &EX(CVs)[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;
}

ZEND_API void {%EXECUTOR_NAME%}_ex(zend_execute_data *execute_data TSRMLS_DC)
{
	DCL_OPLINE
	zend_bool original_in_execution;

	{%HELPER_VARS%}

	{%INTERNAL_LABELS%}

	original_in_execution = EG(in_execution);
	EG(in_execution) = 1;

	LOAD_REGS();
	LOAD_OPLINE();

	while (1) {
    {%ZEND_VM_CONTINUE_LABEL%}
#ifdef ZEND_WIN32
		if (EG(timed_out)) {
			zend_timeout(0);
		}
#endif

		{%ZEND_VM_DISPATCH%} {
			{%INTERNAL_EXECUTOR%}
		}

	}
	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)
{
	if (EG(exception)) {
		return;
	} 
	{%EXECUTOR_NAME%}_ex(zend_create_execute_data_from_op_array(op_array, 0 TSRMLS_CC) TSRMLS_CC);
}

{%EXTERNAL_EXECUTOR%}

void {%INITIALIZER_NAME%}(void)
{
  {%EXTERNAL_LABELS%}
}