xref: /PHP-7.1/Zend/zend_vm_gen.php (revision 7f6387b5)
1<?php
2/*
3   +----------------------------------------------------------------------+
4   | Zend Engine                                                          |
5   +----------------------------------------------------------------------+
6   | Copyright (c) 1998-2018 Zend Technologies Ltd. (http://www.zend.com) |
7   +----------------------------------------------------------------------+
8   | This source file is subject to version 2.00 of the Zend license,     |
9   | that is bundled with this package in the file LICENSE, and is        |
10   | available through the world-wide-web at the following url:           |
11   | http://www.zend.com/license/2_00.txt.                                |
12   | If you did not receive a copy of the Zend license and are unable to  |
13   | obtain it through the world-wide-web, please send a note to          |
14   | license@zend.com so we can mail you a copy immediately.              |
15   +----------------------------------------------------------------------+
16   | Authors: Dmitry Stogov <dmitry@zend.com>                             |
17   +----------------------------------------------------------------------+
18
19	 $Id$
20*/
21
22const HEADER_TEXT = <<< DATA
23/*
24   +----------------------------------------------------------------------+
25   | Zend Engine                                                          |
26   +----------------------------------------------------------------------+
27   | Copyright (c) 1998-2018 Zend Technologies Ltd. (http://www.zend.com) |
28   +----------------------------------------------------------------------+
29   | This source file is subject to version 2.00 of the Zend license,     |
30   | that is bundled with this package in the file LICENSE, and is        |
31   | available through the world-wide-web at the following url:           |
32   | http://www.zend.com/license/2_00.txt.                                |
33   | If you did not receive a copy of the Zend license and are unable to  |
34   | obtain it through the world-wide-web, please send a note to          |
35   | license@zend.com so we can mail you a copy immediately.              |
36   +----------------------------------------------------------------------+
37   | Authors: Andi Gutmans <andi@zend.com>                                |
38   |          Zeev Suraski <zeev@zend.com>                                |
39   |          Dmitry Stogov <dmitry@zend.com>                             |
40   +----------------------------------------------------------------------+
41*/
42
43
44DATA;
45
46/*
47	This script creates zend_vm_execute.h and zend_vm_opcodes.h
48	from existing zend_vm_def.h and zend_vm_execute.skl
49*/
50
51error_reporting(E_ALL);
52
53const ZEND_VM_KIND_CALL   = 1;
54const ZEND_VM_KIND_SWITCH = 2;
55const ZEND_VM_KIND_GOTO   = 3;
56
57$vm_op_flags = array(
58	"ZEND_VM_OP_SPEC"         => 1<<0,
59	"ZEND_VM_OP_CONST"        => 1<<1,
60	"ZEND_VM_OP_TMPVAR"       => 1<<2,
61	"ZEND_VM_OP_TMPVARCV"     => 1<<3,
62	"ZEND_VM_OP_MASK"         => 0xf0,
63	"ZEND_VM_OP_NUM"          => 0x10,
64	"ZEND_VM_OP_JMP_ADDR"     => 0x20,
65	"ZEND_VM_OP_TRY_CATCH"    => 0x30,
66	"ZEND_VM_OP_LIVE_RANGE"   => 0x40,
67	"ZEND_VM_OP_THIS"         => 0x50,
68	"ZEND_VM_OP_NEXT"         => 0x60,
69	"ZEND_VM_OP_CLASS_FETCH"  => 0x70,
70	"ZEND_VM_OP_CONSTRUCTOR"  => 0x80,
71
72	"ZEND_VM_EXT_VAR_FETCH"   => 1<<16,
73	"ZEND_VM_EXT_ISSET"       => 1<<17,
74	"ZEND_VM_EXT_ARG_NUM"     => 1<<18,
75	"ZEND_VM_EXT_ARRAY_INIT"  => 1<<19,
76	"ZEND_VM_EXT_REF"         => 1<<20,
77	"ZEND_VM_EXT_MASK"        => 0x0f000000,
78	"ZEND_VM_EXT_NUM"         => 0x01000000,
79    // unused 0x2000000
80	"ZEND_VM_EXT_JMP_ADDR"    => 0x03000000,
81	"ZEND_VM_EXT_DIM_OBJ"     => 0x04000000,
82	"ZEND_VM_EXT_CLASS_FETCH" => 0x05000000,
83	"ZEND_VM_EXT_CONST_FETCH" => 0x06000000,
84	"ZEND_VM_EXT_TYPE"        => 0x07000000,
85	"ZEND_VM_EXT_EVAL"        => 0x08000000,
86	// unused 0x09000000,
87	// unused 0x0a000000,
88	"ZEND_VM_EXT_SRC"         => 0x0b000000,
89	// unused 0x0c000000,
90	"ZEND_VM_NO_CONST_CONST"  => 0x40000000,
91	"ZEND_VM_COMMUTATIVE"     => 0x80000000,
92);
93
94foreach ($vm_op_flags as $name => $val) {
95	define($name, $val);
96}
97
98$vm_op_decode = array(
99	"ANY"                  => 0,
100	"CONST"                => ZEND_VM_OP_SPEC | ZEND_VM_OP_CONST,
101	"TMP"                  => ZEND_VM_OP_SPEC,
102	"VAR"                  => ZEND_VM_OP_SPEC,
103	"UNUSED"               => ZEND_VM_OP_SPEC,
104	"CV"                   => ZEND_VM_OP_SPEC,
105	"TMPVAR"               => ZEND_VM_OP_SPEC | ZEND_VM_OP_TMPVAR,
106	"TMPVARCV"             => ZEND_VM_OP_SPEC | ZEND_VM_OP_TMPVARCV,
107	"NUM"                  => ZEND_VM_OP_NUM,
108	"JMP_ADDR"             => ZEND_VM_OP_JMP_ADDR,
109	"TRY_CATCH"            => ZEND_VM_OP_TRY_CATCH,
110	"LIVE_RANGE"           => ZEND_VM_OP_LIVE_RANGE,
111	"THIS"                 => ZEND_VM_OP_THIS,
112	"NEXT"                 => ZEND_VM_OP_NEXT,
113	"CLASS_FETCH"          => ZEND_VM_OP_CLASS_FETCH,
114	"CONSTRUCTOR"          => ZEND_VM_OP_CONSTRUCTOR,
115);
116
117$vm_ext_decode = array(
118	"NUM"                  => ZEND_VM_EXT_NUM,
119	"JMP_ADDR"             => ZEND_VM_EXT_JMP_ADDR,
120	"DIM_OBJ"              => ZEND_VM_EXT_DIM_OBJ,
121	"CLASS_FETCH"          => ZEND_VM_EXT_CLASS_FETCH,
122	"CONST_FETCH"          => ZEND_VM_EXT_CONST_FETCH,
123	"VAR_FETCH"            => ZEND_VM_EXT_VAR_FETCH,
124	"ARRAY_INIT"           => ZEND_VM_EXT_ARRAY_INIT,
125	"TYPE"                 => ZEND_VM_EXT_TYPE,
126	"EVAL"                 => ZEND_VM_EXT_EVAL,
127	"ISSET"                => ZEND_VM_EXT_ISSET,
128	"ARG_NUM"              => ZEND_VM_EXT_ARG_NUM,
129	"REF"                  => ZEND_VM_EXT_REF,
130	"SRC"                  => ZEND_VM_EXT_SRC,
131);
132
133$vm_kind_name = array(
134	ZEND_VM_KIND_CALL => "ZEND_VM_KIND_CALL",
135	ZEND_VM_KIND_SWITCH => "ZEND_VM_KIND_SWITCH",
136	ZEND_VM_KIND_GOTO => "ZEND_VM_KIND_GOTO",
137);
138
139$op_types = array(
140	"ANY",
141	"CONST",
142	"TMP",
143	"VAR",
144	"UNUSED",
145	"CV"
146);
147
148$op_types_ex = array(
149	"ANY",
150	"CONST",
151	"TMP",
152	"VAR",
153	"UNUSED",
154	"CV",
155	"TMPVAR",
156	"TMPVARCV",
157);
158
159$prefix = array(
160	"ANY"      => "",
161	"TMP"      => "_TMP",
162	"VAR"      => "_VAR",
163	"CONST"    => "_CONST",
164	"UNUSED"   => "_UNUSED",
165	"CV"       => "_CV",
166	"TMPVAR"   => "_TMPVAR",
167	"TMPVARCV" => "_TMPVARCV",
168);
169
170$typecode = array(
171	"ANY"      => 0,
172	"TMP"      => 1,
173	"VAR"      => 2,
174	"CONST"    => 0,
175	"UNUSED"   => 3,
176	"CV"       => 4,
177	"TMPVAR"   => 0,
178	"TMPVARCV" => 0,
179);
180
181$commutative_order = array(
182	"ANY"      => 0,
183	"TMP"      => 1,
184	"VAR"      => 2,
185	"CONST"    => 0,
186	"UNUSED"   => 0,
187	"CV"       => 4,
188	"TMPVAR"   => 2,
189	"TMPVARCV" => 4,
190);
191
192$op1_type = array(
193	"ANY"      => "opline->op1_type",
194	"TMP"      => "IS_TMP_VAR",
195	"VAR"      => "IS_VAR",
196	"CONST"    => "IS_CONST",
197	"UNUSED"   => "IS_UNUSED",
198	"CV"       => "IS_CV",
199	"TMPVAR"   => "(IS_TMP_VAR|IS_VAR)",
200	"TMPVARCV" => "(IS_TMP_VAR|IS_VAR|IS_CV)",
201);
202
203$op2_type = array(
204	"ANY"      => "opline->op2_type",
205	"TMP"      => "IS_TMP_VAR",
206	"VAR"      => "IS_VAR",
207	"CONST"    => "IS_CONST",
208	"UNUSED"   => "IS_UNUSED",
209	"CV"       => "IS_CV",
210	"TMPVAR"   => "(IS_TMP_VAR|IS_VAR)",
211	"TMPVARCV" => "(IS_TMP_VAR|IS_VAR|IS_CV)",
212);
213
214$op1_free = array(
215	"ANY"      => "(free_op1 != NULL)",
216	"TMP"      => "1",
217	"VAR"      => "(free_op1 != NULL)",
218	"CONST"    => "0",
219	"UNUSED"   => "0",
220	"CV"       => "0",
221	"TMPVAR"   => "???",
222	"TMPVARCV" => "???",
223);
224
225$op2_free = array(
226	"ANY"      => "(free_op2 != NULL)",
227	"TMP"      => "1",
228	"VAR"      => "(free_op2 != NULL)",
229	"CONST"    => "0",
230	"UNUSED"   => "0",
231	"CV"       => "0",
232	"TMPVAR"   => "???",
233	"TMPVARCV" => "???",
234);
235
236$op1_get_zval_ptr = array(
237	"ANY"      => "get_zval_ptr(opline->op1_type, opline->op1, execute_data, &free_op1, \\1)",
238	"TMP"      => "_get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1)",
239	"VAR"      => "_get_zval_ptr_var(opline->op1.var, execute_data, &free_op1)",
240	"CONST"    => "EX_CONSTANT(opline->op1)",
241	"UNUSED"   => "NULL",
242	"CV"       => "_get_zval_ptr_cv_\\1(execute_data, opline->op1.var)",
243	"TMPVAR"   => "_get_zval_ptr_var(opline->op1.var, execute_data, &free_op1)",
244	"TMPVARCV" => "???",
245);
246
247$op2_get_zval_ptr = array(
248	"ANY"      => "get_zval_ptr(opline->op2_type, opline->op2, execute_data, &free_op2, \\1)",
249	"TMP"      => "_get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2)",
250	"VAR"      => "_get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)",
251	"CONST"    => "EX_CONSTANT(opline->op2)",
252	"UNUSED"   => "NULL",
253	"CV"       => "_get_zval_ptr_cv_\\1(execute_data, opline->op2.var)",
254	"TMPVAR"   => "_get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)",
255	"TMPVARCV" => "???",
256);
257
258$op1_get_zval_ptr_ptr = array(
259	"ANY"      => "get_zval_ptr_ptr(opline->op1_type, opline->op1, execute_data, &free_op1, \\1)",
260	"TMP"      => "NULL",
261	"VAR"      => "_get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1)",
262	"CONST"    => "NULL",
263	"UNUSED"   => "NULL",
264	"CV"       => "_get_zval_ptr_cv_\\1(execute_data, opline->op1.var)",
265	"TMPVAR"   => "???",
266	"TMPVARCV" => "???",
267);
268
269$op2_get_zval_ptr_ptr = array(
270	"ANY"      => "get_zval_ptr_ptr(opline->op2_type, opline->op2, execute_data, &free_op2, \\1)",
271	"TMP"      => "NULL",
272	"VAR"      => "_get_zval_ptr_ptr_var(opline->op2.var, execute_data, &free_op2)",
273	"CONST"    => "NULL",
274	"UNUSED"   => "NULL",
275	"CV"       => "_get_zval_ptr_cv_\\1(execute_data, opline->op2.var)",
276	"TMPVAR"   => "???",
277	"TMPVARCV" => "???",
278);
279
280$op1_get_zval_ptr_deref = array(
281	"ANY"      => "get_zval_ptr_deref(opline->op1_type, opline->op1, execute_data, &free_op1, \\1)",
282	"TMP"      => "_get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1)",
283	"VAR"      => "_get_zval_ptr_var_deref(opline->op1.var, execute_data, &free_op1)",
284	"CONST"    => "EX_CONSTANT(opline->op1)",
285	"UNUSED"   => "NULL",
286	"CV"       => "_get_zval_ptr_cv_deref_\\1(execute_data, opline->op1.var)",
287	"TMPVAR"   => "???",
288	"TMPVARCV" => "???",
289);
290
291$op2_get_zval_ptr_deref = array(
292	"ANY"      => "get_zval_ptr_deref(opline->op2_type, opline->op2, execute_data, &free_op2, \\1)",
293	"TMP"      => "_get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2)",
294	"VAR"      => "_get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2)",
295	"CONST"    => "EX_CONSTANT(opline->op2)",
296	"UNUSED"   => "NULL",
297	"CV"       => "_get_zval_ptr_cv_deref_\\1(execute_data, opline->op2.var)",
298	"TMPVAR"   => "???",
299	"TMPVARCV" => "???",
300);
301
302$op1_get_zval_ptr_undef = array(
303	"ANY"      => "get_zval_ptr_undef(opline->op1_type, opline->op1, execute_data, &free_op1, \\1)",
304	"TMP"      => "_get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1)",
305	"VAR"      => "_get_zval_ptr_var(opline->op1.var, execute_data, &free_op1)",
306	"CONST"    => "EX_CONSTANT(opline->op1)",
307	"UNUSED"   => "NULL",
308	"CV"       => "_get_zval_ptr_cv_undef(execute_data, opline->op1.var)",
309	"TMPVAR"   => "_get_zval_ptr_var(opline->op1.var, execute_data, &free_op1)",
310	"TMPVARCV" => "EX_VAR(opline->op1.var)",
311);
312
313$op2_get_zval_ptr_undef = array(
314	"ANY"      => "get_zval_ptr_undef(opline->op2_type, opline->op2, execute_data, &free_op2, \\1)",
315	"TMP"      => "_get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2)",
316	"VAR"      => "_get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)",
317	"CONST"    => "EX_CONSTANT(opline->op2)",
318	"UNUSED"   => "NULL",
319	"CV"       => "_get_zval_ptr_cv_undef(execute_data, opline->op2.var)",
320	"TMPVAR"   => "_get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)",
321	"TMPVARCV" => "EX_VAR(opline->op2.var)",
322);
323
324$op1_get_zval_ptr_ptr_undef = array(
325	"ANY"      => "get_zval_ptr_ptr_undef(opline->op1_type, opline->op1, execute_data, &free_op1, \\1)",
326	"TMP"      => "NULL",
327	"VAR"      => "_get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1)",
328	"CONST"    => "NULL",
329	"UNUSED"   => "NULL",
330	"CV"       => "_get_zval_ptr_cv_undef_\\1(execute_data, opline->op1.var)",
331	"TMPVAR"   => "???",
332	"TMPVARCV" => "EX_VAR(opline->op1.var)",
333);
334
335$op2_get_zval_ptr_ptr_undef = array(
336	"ANY"      => "get_zval_ptr_ptr_undef(opline->op2_type, opline->op2, execute_data, &free_op2, \\1)",
337	"TMP"      => "NULL",
338	"VAR"      => "_get_zval_ptr_ptr_var(opline->op2.var, execute_data, &free_op2)",
339	"CONST"    => "NULL",
340	"UNUSED"   => "NULL",
341	"CV"       => "_get_zval_ptr_cv_undef_\\1(execute_data, opline->op2.var)",
342	"TMPVAR"   => "???",
343	"TMPVARCV" => "EX_VAR(opline->op2.var)",
344);
345
346$op1_get_obj_zval_ptr = array(
347	"ANY"      => "get_obj_zval_ptr(opline->op1_type, opline->op1, execute_data, &free_op1, \\1)",
348	"TMP"      => "_get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1)",
349	"VAR"      => "_get_zval_ptr_var(opline->op1.var, execute_data, &free_op1)",
350	"CONST"    => "EX_CONSTANT(opline->op1)",
351	"UNUSED"   => "_get_obj_zval_ptr_unused(execute_data)",
352	"CV"       => "_get_zval_ptr_cv_\\1(execute_data, opline->op1.var)",
353	"TMPVAR"   => "_get_zval_ptr_var(opline->op1.var, execute_data, &free_op1)",
354	"TMPVARCV" => "???",
355);
356
357$op2_get_obj_zval_ptr = array(
358	"ANY"      => "get_obj_zval_ptr(opline->op2_type, opline->op2, execute_data, &free_op2, \\1)",
359	"TMP"      => "_get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2)",
360	"VAR"      => "_get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)",
361	"CONST"    => "EX_CONSTANT(opline->op2)",
362	"UNUSED"   => "_get_obj_zval_ptr_unused(execute_data)",
363	"CV"       => "_get_zval_ptr_cv_\\1(execute_data, opline->op2.var)",
364	"TMPVAR"   => "_get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)",
365	"TMPVARCV" => "???",
366);
367
368$op1_get_obj_zval_ptr_undef = array(
369	"ANY"      => "get_obj_zval_ptr_undef(opline->op1_type, opline->op1, execute_data, &free_op1, \\1)",
370	"TMP"      => "_get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1)",
371	"VAR"      => "_get_zval_ptr_var(opline->op1.var, execute_data, &free_op1)",
372	"CONST"    => "EX_CONSTANT(opline->op1)",
373	"UNUSED"   => "_get_obj_zval_ptr_unused(execute_data)",
374	"CV"       => "_get_zval_ptr_cv_undef(execute_data, opline->op1.var)",
375	"TMPVAR"   => "_get_zval_ptr_var(opline->op1.var, execute_data, &free_op1)",
376	"TMPVARCV" => "EX_VAR(opline->op1.var)",
377);
378
379$op2_get_obj_zval_ptr_undef = array(
380	"ANY"      => "get_obj_zval_ptr_undef(opline->op2_type, opline->op2, execute_data, &free_op2, \\1)",
381	"TMP"      => "_get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2)",
382	"VAR"      => "_get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)",
383	"CONST"    => "EX_CONSTANT(opline->op2)",
384	"UNUSED"   => "_get_obj_zval_ptr_unused(execute_data)",
385	"CV"       => "_get_zval_ptr_cv_undef(execute_data, opline->op2.var)",
386	"TMPVAR"   => "_get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)",
387	"TMPVARCV" => "EX_VAR(opline->op2.var)",
388);
389
390$op1_get_obj_zval_ptr_deref = array(
391	"ANY"      => "get_obj_zval_ptr(opline->op1_type, opline->op1, execute_data, &free_op1, \\1)",
392	"TMP"      => "_get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1)",
393	"VAR"      => "_get_zval_ptr_var_deref(opline->op1.var, execute_data, &free_op1)",
394	"CONST"    => "EX_CONSTANT(opline->op1)",
395	"UNUSED"   => "_get_obj_zval_ptr_unused(execute_data)",
396	"CV"       => "_get_zval_ptr_cv_deref_\\1(execute_data, opline->op1.var)",
397	"TMPVAR"   => "???",
398	"TMPVARCV" => "???",
399);
400
401$op2_get_obj_zval_ptr_deref = array(
402	"ANY"      => "get_obj_zval_ptr(opline->op2_type, opline->op2, execute_data, &free_op2, \\1)",
403	"TMP"      => "_get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2)",
404	"VAR"      => "_get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2)",
405	"CONST"    => "EX_CONSTANT(opline->op2)",
406	"UNUSED"   => "_get_obj_zval_ptr_unused(execute_data)",
407	"CV"       => "_get_zval_ptr_cv_deref_\\1(execute_data, opline->op2.var)",
408	"TMPVAR"   => "???",
409	"TMPVARCV" => "???",
410);
411
412$op1_get_obj_zval_ptr_ptr = array(
413	"ANY"      => "get_obj_zval_ptr_ptr(opline->op1_type, opline->op1, execute_data, &free_op1, \\1)",
414	"TMP"      => "NULL",
415	"VAR"      => "_get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1)",
416	"CONST"    => "NULL",
417	"UNUSED"   => "_get_obj_zval_ptr_unused(execute_data)",
418	"CV"       => "_get_zval_ptr_cv_\\1(execute_data, opline->op1.var)",
419	"TMPVAR"   => "???",
420	"TMPVARCV" => "???",
421);
422
423$op2_get_obj_zval_ptr_ptr = array(
424	"ANY"      => "get_obj_zval_ptr_ptr(opline->op2_type, opline->op2, execute_data, &free_op2, \\1)",
425	"TMP"      => "NULL",
426	"VAR"      => "_get_zval_ptr_ptr_var(opline->op2.var, execute_data, &free_op2)",
427	"CONST"    => "NULL",
428	"UNUSED"   => "_get_obj_zval_ptr_unused(execute_data)",
429	"CV"       => "_get_zval_ptr_cv_\\1(execute_data, opline->op2.var)",
430	"TMPVAR"   => "???",
431	"TMPVARCV" => "???",
432);
433
434$op1_get_obj_zval_ptr_ptr_undef = array(
435	"ANY"      => "get_obj_zval_ptr_ptr(opline->op1_type, opline->op1, execute_data, &free_op1, \\1)",
436	"TMP"      => "NULL",
437	"VAR"      => "_get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1)",
438	"CONST"    => "NULL",
439	"UNUSED"   => "_get_obj_zval_ptr_unused(execute_data)",
440	"CV"       => "_get_zval_ptr_cv_undef_\\1(execute_data, opline->op1.var)",
441	"TMPVAR"   => "???",
442	"TMPVARCV" => "EX_VAR(opline->op1.var)",
443);
444
445$op2_get_obj_zval_ptr_ptr_undef = array(
446	"ANY"      => "get_obj_zval_ptr_ptr(opline->op2_type, opline->op2, execute_data, &free_op2, \\1)",
447	"TMP"      => "NULL",
448	"VAR"      => "_get_zval_ptr_ptr_var(opline->op2.var, execute_data, &free_op2)",
449	"CONST"    => "NULL",
450	"UNUSED"   => "_get_obj_zval_ptr_unused(execute_data)",
451	"CV"       => "_get_zval_ptr_cv_undef_\\1(execute_data, opline->op2.var)",
452	"TMPVAR"   => "???",
453	"TMPVARCV" => "EX_VAR(opline->op2.var)",
454);
455
456$op1_free_op = array(
457	"ANY"      => "FREE_OP(free_op1)",
458	"TMP"      => "zval_ptr_dtor_nogc(free_op1)",
459	"VAR"      => "zval_ptr_dtor_nogc(free_op1)",
460	"CONST"    => "",
461	"UNUSED"   => "",
462	"CV"       => "",
463	"TMPVAR"   => "zval_ptr_dtor_nogc(free_op1)",
464	"TMPVARCV" => "???",
465);
466
467$op2_free_op = array(
468	"ANY"      => "FREE_OP(free_op2)",
469	"TMP"      => "zval_ptr_dtor_nogc(free_op2)",
470	"VAR"      => "zval_ptr_dtor_nogc(free_op2)",
471	"CONST"    => "",
472	"UNUSED"   => "",
473	"CV"       => "",
474	"TMPVAR"   => "zval_ptr_dtor_nogc(free_op2)",
475	"TMPVARCV" => "???",
476);
477
478$op1_free_op_if_var = array(
479	"ANY"      => "if (opline->op1_type == IS_VAR) {zval_ptr_dtor_nogc(free_op1);}",
480	"TMP"      => "",
481	"VAR"      => "zval_ptr_dtor_nogc(free_op1)",
482	"CONST"    => "",
483	"UNUSED"   => "",
484	"CV"       => "",
485	"TMPVAR"   => "???",
486	"TMPVARCV" => "???",
487);
488
489$op2_free_op_if_var = array(
490	"ANY"      => "if (opline->op2_type == IS_VAR) {zval_ptr_dtor_nogc(free_op2);}",
491	"TMP"      => "",
492	"VAR"      => "zval_ptr_dtor_nogc(free_op2)",
493	"CONST"    => "",
494	"UNUSED"   => "",
495	"CV"       => "",
496	"TMPVAR"   => "???",
497	"TMPVARCV" => "???",
498);
499
500$op1_free_op_var_ptr = array(
501	"ANY"      => "if (free_op1) {zval_ptr_dtor_nogc(free_op1);}",
502	"TMP"      => "",
503	"VAR"      => "if (UNEXPECTED(free_op1)) {zval_ptr_dtor_nogc(free_op1);}",
504	"CONST"    => "",
505	"UNUSED"   => "",
506	"CV"       => "",
507	"TMPVAR"   => "???",
508	"TMPVARCV" => "???",
509);
510
511$op2_free_op_var_ptr = array(
512	"ANY"      => "if (free_op2) {zval_ptr_dtor_nogc(free_op2);}",
513	"TMP"      => "",
514	"VAR"      => "if (UNEXPECTED(free_op2)) {zval_ptr_dtor_nogc(free_op2);}",
515	"CONST"    => "",
516	"UNUSED"   => "",
517	"CV"       => "",
518	"TMPVAR"   => "???",
519	"TMPVARCV" => "???",
520);
521
522$op1_free_unfetched = array(
523	"ANY"      => "FREE_UNFETCHED_OP(opline->op1_type, opline->op1.var)",
524	"TMP"      => "zval_ptr_dtor_nogc(EX_VAR(opline->op1.var))",
525	"VAR"      => "zval_ptr_dtor_nogc(EX_VAR(opline->op1.var))",
526	"CONST"    => "",
527	"UNUSED"   => "",
528	"CV"       => "",
529	"TMPVAR"   => "zval_ptr_dtor_nogc(EX_VAR(opline->op1.var))",
530	"TMPVARCV" => "???",
531);
532
533$op2_free_unfetched = array(
534	"ANY"      => "FREE_UNFETCHED_OP(opline->op2_type, opline->op2.var)",
535	"TMP"      => "zval_ptr_dtor_nogc(EX_VAR(opline->op2.var))",
536	"VAR"      => "zval_ptr_dtor_nogc(EX_VAR(opline->op2.var))",
537	"CONST"    => "",
538	"UNUSED"   => "",
539	"CV"       => "",
540	"TMPVAR"   => "zval_ptr_dtor_nogc(EX_VAR(opline->op2.var))",
541	"TMPVARCV" => "???",
542);
543
544$op_data_type = array(
545	"ANY"      => "(opline+1)->op1_type",
546	"TMP"      => "IS_TMP_VAR",
547	"VAR"      => "IS_VAR",
548	"CONST"    => "IS_CONST",
549	"UNUSED"   => "IS_UNUSED",
550	"CV"       => "IS_CV",
551	"TMPVAR"   => "(IS_TMP_VAR|IS_VAR)",
552	"TMPVARCV" => "(IS_TMP_VAR|IS_VAR|IS_CV)",
553);
554
555$op_data_get_zval_ptr = array(
556	"ANY"      => "get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data, \\1)",
557	"TMP"      => "_get_zval_ptr_tmp((opline+1)->op1.var, execute_data, &free_op_data)",
558	"VAR"      => "_get_zval_ptr_var((opline+1)->op1.var, execute_data, &free_op_data)",
559	"CONST"    => "EX_CONSTANT((opline+1)->op1)",
560	"UNUSED"   => "NULL",
561	"CV"       => "_get_zval_ptr_cv_\\1(execute_data, (opline+1)->op1.var)",
562	"TMPVAR"   => "_get_zval_ptr_var((opline+1)->op1.var, execute_data, &free_op_data)",
563	"TMPVARCV" => "???",
564);
565
566$op_data_get_zval_ptr_deref = array(
567	"ANY"      => "get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data, \\1)",
568	"TMP"      => "_get_zval_ptr_tmp((opline+1)->op1.var, execute_data, &free_op_data)",
569	"VAR"      => "_get_zval_ptr_var_deref((opline+1)->op1.var, execute_data, &free_op_data)",
570	"CONST"    => "EX_CONSTANT((opline+1)->op1)",
571	"UNUSED"   => "NULL",
572	"CV"       => "_get_zval_ptr_cv_deref_\\1(execute_data, (opline+1)->op1.var)",
573	"TMPVAR"   => "???",
574	"TMPVARCV" => "???",
575);
576
577$op_data_free_op = array(
578	"ANY"      => "FREE_OP(free_op_data)",
579	"TMP"      => "zval_ptr_dtor_nogc(free_op_data)",
580	"VAR"      => "zval_ptr_dtor_nogc(free_op_data)",
581	"CONST"    => "",
582	"UNUSED"   => "",
583	"CV"       => "",
584	"TMPVAR"   => "zval_ptr_dtor_nogc(free_op_data)",
585	"TMPVARCV" => "???",
586);
587
588$op_data_free_unfetched = array(
589	"ANY"      => "FREE_UNFETCHED_OP((opline+1)->op1_type, (opline+1)->op1.var)",
590	"TMP"      => "zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var))",
591	"VAR"      => "zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var))",
592	"CONST"    => "",
593	"UNUSED"   => "",
594	"CV"       => "",
595	"TMPVAR"   => "zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var))",
596	"TMPVARCV" => "???",
597);
598
599$list    = array(); // list of opcode handlers and helpers in original order
600$opcodes = array(); // opcode handlers by code
601$helpers = array(); // opcode helpers by name
602$params  = array(); // parameters of helpers
603$opnames = array(); // opcode name to code mapping
604$line_no = 1;
605
606$used_extra_spec = array();
607
608// Writes $s into resulting executor
609function out($f, $s) {
610	global $line_no;
611
612	fputs($f,$s);
613	$line_no += substr_count($s, "\n");
614}
615
616// Resets #line directives in resulting executor
617function out_line($f) {
618	global $line_no, $executor_file;
619
620	fputs($f,"#line ".($line_no+1)." \"".$executor_file."\"\n");
621	++$line_no;
622}
623
624// Returns name of specialized helper
625function helper_name($name, $spec, $op1, $op2) {
626	global $prefix, $helpers;
627
628	if (isset($helpers[$name])) {
629		// If we haven't helper with specified spicialized operands then
630		// using unspecialized helper
631		if (!isset($helpers[$name]["op1"][$op1]) &&
632		    isset($helpers[$name]["op1"]["ANY"])) {
633			$op1 = "ANY";
634		}
635		if (!isset($helpers[$name]["op2"][$op2]) &&
636		    isset($helpers[$name]["op2"]["ANY"])) {
637			$op2 = "ANY";
638		}
639	}
640	return $name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2];
641}
642
643function opcode_name($name, $spec, $op1, $op2) {
644	global $prefix, $opnames, $opcodes;
645
646	if (isset($opnames[$name])) {
647		$opcode = $opcodes[$opnames[$name]];
648		// If we haven't helper with specified spicialized operands then
649		// using unspecialized helper
650		if (!isset($opcode["op1"][$op1]) &&
651		    isset($opcode["op1"]["ANY"])) {
652			$op1 = "ANY";
653		}
654		if (!isset($opcode["op2"][$op2]) &&
655		    isset($opcode["op2"]["ANY"])) {
656			$op2 = "ANY";
657		}
658	}
659	return $name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2];
660}
661
662// Formats condition, protecting it by parentheses when needed.
663function format_condition($condition) {
664	if ($condition === "") {
665		throw new InvalidArgumentException("A non empty string condition was expected.");
666	}
667
668	if ($condition[0] === "(" && substr($condition, -1) === ")") {
669		return $condition;
670	}
671
672	return "(".$condition.")";
673}
674
675// Generates code for opcode handler or helper
676function gen_code($f, $spec, $kind, $export, $code, $op1, $op2, $name, $extra_spec=null) {
677	global $op1_type, $op2_type, $op1_get_zval_ptr, $op2_get_zval_ptr,
678		$op1_get_zval_ptr_deref, $op2_get_zval_ptr_deref,
679		$op1_get_zval_ptr_undef, $op2_get_zval_ptr_undef,
680		$op1_get_zval_ptr_ptr, $op2_get_zval_ptr_ptr,
681		$op1_get_zval_ptr_ptr_undef, $op2_get_zval_ptr_ptr_undef,
682		$op1_get_obj_zval_ptr, $op2_get_obj_zval_ptr,
683		$op1_get_obj_zval_ptr_undef, $op2_get_obj_zval_ptr_undef,
684		$op1_get_obj_zval_ptr_deref, $op2_get_obj_zval_ptr_deref,
685		$op1_get_obj_zval_ptr_ptr, $op2_get_obj_zval_ptr_ptr,
686		$op1_get_obj_zval_ptr_ptr_undef, $op2_get_obj_zval_ptr_ptr_undef,
687		$op1_free, $op2_free, $op1_free_unfetched, $op2_free_unfetched,
688		$op1_free_op, $op2_free_op, $op1_free_op_if_var, $op2_free_op_if_var,
689		$op1_free_op_var_ptr, $op2_free_op_var_ptr, $prefix,
690		$op_data_type, $op_data_get_zval_ptr, $op_data_get_zval_ptr_deref,
691		$op_data_free_op, $op_data_free_unfetched;
692
693	// Specializing
694	$code = preg_replace(
695		array(
696			"/OP1_TYPE/",
697			"/OP2_TYPE/",
698			"/OP1_FREE/",
699			"/OP2_FREE/",
700			"/GET_OP1_ZVAL_PTR\(([^)]*)\)/",
701			"/GET_OP2_ZVAL_PTR\(([^)]*)\)/",
702			"/GET_OP1_ZVAL_PTR_DEREF\(([^)]*)\)/",
703			"/GET_OP2_ZVAL_PTR_DEREF\(([^)]*)\)/",
704			"/GET_OP1_ZVAL_PTR_UNDEF\(([^)]*)\)/",
705			"/GET_OP2_ZVAL_PTR_UNDEF\(([^)]*)\)/",
706			"/GET_OP1_ZVAL_PTR_PTR\(([^)]*)\)/",
707			"/GET_OP2_ZVAL_PTR_PTR\(([^)]*)\)/",
708			"/GET_OP1_ZVAL_PTR_PTR_UNDEF\(([^)]*)\)/",
709			"/GET_OP2_ZVAL_PTR_PTR_UNDEF\(([^)]*)\)/",
710			"/GET_OP1_OBJ_ZVAL_PTR\(([^)]*)\)/",
711			"/GET_OP2_OBJ_ZVAL_PTR\(([^)]*)\)/",
712			"/GET_OP1_OBJ_ZVAL_PTR_UNDEF\(([^)]*)\)/",
713			"/GET_OP2_OBJ_ZVAL_PTR_UNDEF\(([^)]*)\)/",
714			"/GET_OP1_OBJ_ZVAL_PTR_DEREF\(([^)]*)\)/",
715			"/GET_OP2_OBJ_ZVAL_PTR_DEREF\(([^)]*)\)/",
716			"/GET_OP1_OBJ_ZVAL_PTR_PTR\(([^)]*)\)/",
717			"/GET_OP2_OBJ_ZVAL_PTR_PTR\(([^)]*)\)/",
718			"/GET_OP1_OBJ_ZVAL_PTR_PTR_UNDEF\(([^)]*)\)/",
719			"/GET_OP2_OBJ_ZVAL_PTR_PTR_UNDEF\(([^)]*)\)/",
720			"/FREE_OP1\(\)/",
721			"/FREE_OP2\(\)/",
722			"/FREE_OP1_IF_VAR\(\)/",
723			"/FREE_OP2_IF_VAR\(\)/",
724			"/FREE_OP1_VAR_PTR\(\)/",
725			"/FREE_OP2_VAR_PTR\(\)/",
726			"/FREE_UNFETCHED_OP1\(\)/",
727			"/FREE_UNFETCHED_OP2\(\)/",
728			"/^#(\s*)ifdef\s+ZEND_VM_SPEC\s*\n/m",
729			"/^#(\s*)ifndef\s+ZEND_VM_SPEC\s*\n/m",
730			"/\!defined\(ZEND_VM_SPEC\)/m",
731			"/defined\(ZEND_VM_SPEC\)/m",
732			"/ZEND_VM_C_LABEL\(\s*([A-Za-z_]*)\s*\)/m",
733			"/ZEND_VM_C_GOTO\(\s*([A-Za-z_]*)\s*\)/m",
734			"/^#(\s*)if\s+1\s*\\|\\|.*[^\\\\]$/m",
735			"/^#(\s*)if\s+0\s*&&.*[^\\\\]$/m",
736			"/^#(\s*)ifdef\s+ZEND_VM_EXPORT\s*\n/m",
737			"/^#(\s*)ifndef\s+ZEND_VM_EXPORT\s*\n/m",
738			"/OP_DATA_TYPE/",
739			"/GET_OP_DATA_ZVAL_PTR\(([^)]*)\)/",
740			"/GET_OP_DATA_ZVAL_PTR_DEREF\(([^)]*)\)/",
741			"/FREE_OP_DATA\(\)/",
742			"/FREE_UNFETCHED_OP_DATA\(\)/",
743			"/RETURN_VALUE_USED\(opline\)/",
744			"/arg_num <= MAX_ARG_FLAG_NUM/",
745			"/ZEND_VM_SMART_BRANCH\(\s*([^,)]*)\s*,\s*([^)]*)\s*\)/",
746			"/opline->extended_value\s*==\s*0/",
747			"/opline->extended_value\s*==\s*ZEND_ASSIGN_DIM/",
748			"/opline->extended_value\s*==\s*ZEND_ASSIGN_OBJ/",
749		),
750		array(
751			$op1_type[$op1],
752			$op2_type[$op2],
753			$op1_free[$op1],
754			$op2_free[$op2],
755			$op1_get_zval_ptr[$op1],
756			$op2_get_zval_ptr[$op2],
757			$op1_get_zval_ptr_deref[$op1],
758			$op2_get_zval_ptr_deref[$op2],
759			$op1_get_zval_ptr_undef[$op1],
760			$op2_get_zval_ptr_undef[$op2],
761			$op1_get_zval_ptr_ptr[$op1],
762			$op2_get_zval_ptr_ptr[$op2],
763			$op1_get_zval_ptr_ptr_undef[$op1],
764			$op2_get_zval_ptr_ptr_undef[$op2],
765			$op1_get_obj_zval_ptr[$op1],
766			$op2_get_obj_zval_ptr[$op2],
767			$op1_get_obj_zval_ptr_undef[$op1],
768			$op2_get_obj_zval_ptr_undef[$op2],
769			$op1_get_obj_zval_ptr_deref[$op1],
770			$op2_get_obj_zval_ptr_deref[$op2],
771			$op1_get_obj_zval_ptr_ptr[$op1],
772			$op2_get_obj_zval_ptr_ptr[$op2],
773			$op1_get_obj_zval_ptr_ptr_undef[$op1],
774			$op2_get_obj_zval_ptr_ptr_undef[$op2],
775			$op1_free_op[$op1],
776			$op2_free_op[$op2],
777			$op1_free_op_if_var[$op1],
778			$op2_free_op_if_var[$op2],
779			$op1_free_op_var_ptr[$op1],
780			$op2_free_op_var_ptr[$op2],
781			$op1_free_unfetched[$op1],
782			$op2_free_unfetched[$op2],
783			($op1!="ANY"||$op2!="ANY")?"#\\1if 1\n":"#\\1if 0\n",
784			($op1!="ANY"||$op2!="ANY")?"#\\1if 0\n":"#\\1if 1\n",
785			($op1!="ANY"||$op2!="ANY")?"0":"1",
786			($op1!="ANY"||$op2!="ANY")?"1":"0",
787			"\\1".(($spec && $kind != ZEND_VM_KIND_CALL)?("_SPEC".$prefix[$op1].$prefix[$op2].extra_spec_name($extra_spec)):""),
788			"goto \\1".(($spec && $kind != ZEND_VM_KIND_CALL)?("_SPEC".$prefix[$op1].$prefix[$op2].extra_spec_name($extra_spec)):""),
789			"#\\1if 1",
790			"#\\1if 0",
791			$export?"#\\1if 1\n":"#\\1if 0\n",
792			$export?"#\\1if 0\n":"#\\1if 1\n",
793			$op_data_type[isset($extra_spec['OP_DATA']) ? $extra_spec['OP_DATA'] : "ANY"],
794			$op_data_get_zval_ptr[isset($extra_spec['OP_DATA']) ? $extra_spec['OP_DATA'] : "ANY"],
795			$op_data_get_zval_ptr_deref[isset($extra_spec['OP_DATA']) ? $extra_spec['OP_DATA'] : "ANY"],
796			$op_data_free_op[isset($extra_spec['OP_DATA']) ? $extra_spec['OP_DATA'] : "ANY"],
797			$op_data_free_unfetched[isset($extra_spec['OP_DATA']) ? $extra_spec['OP_DATA'] : "ANY"],
798			isset($extra_spec['RETVAL']) ? $extra_spec['RETVAL'] : "RETURN_VALUE_USED(opline)",
799			isset($extra_spec['QUICK_ARG']) ? $extra_spec['QUICK_ARG'] : "arg_num <= MAX_ARG_FLAG_NUM",
800			isset($extra_spec['SMART_BRANCH']) ?
801				($extra_spec['SMART_BRANCH'] == 1 ?
802						"ZEND_VM_SMART_BRANCH_JMPZ(\\1, \\2)"
803					:	($extra_spec['SMART_BRANCH'] == 2 ?
804							"ZEND_VM_SMART_BRANCH_JMPNZ(\\1, \\2)" : ""))
805				: 	"ZEND_VM_SMART_BRANCH(\\1, \\2)",
806			isset($extra_spec['DIM_OBJ']) ?
807				($extra_spec['DIM_OBJ'] == 0 ? "1" : "0")
808				: "\\0",
809			isset($extra_spec['DIM_OBJ']) ?
810				($extra_spec['DIM_OBJ'] == 1 ? "1" : "0")
811				: "\\0",
812			isset($extra_spec['DIM_OBJ']) ?
813				($extra_spec['DIM_OBJ'] == 2 ? "1" : "0")
814				: "\\0",
815		),
816		$code);
817
818	if (0 && strpos($code, '{') === 0) {
819		$code = "{\n\tfprintf(stderr, \"$name\\n\");\n" . substr($code, 1);
820	}
821	// Updating code according to selected threading model
822	switch($kind) {
823		case ZEND_VM_KIND_CALL:
824			$code = preg_replace_callback(
825				array(
826					"/EXECUTE_DATA/m",
827					"/ZEND_VM_DISPATCH_TO_HANDLER\(\s*([A-Z_]*)\s*\)/m",
828					"/ZEND_VM_DISPATCH_TO_HELPER\(\s*([A-Za-z_]*)\s*(,[^)]*)?\)/m",
829				),
830				function($matches) use ($spec, $prefix, $op1, $op2) {
831					if (strncasecmp($matches[0], "EXECUTE_DATA", strlen("EXECUTE_DATA")) == 0) {
832						return "execute_data";
833					} else if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HANDLER", strlen("ZEND_VM_DISPATCH_TO_HANDLER")) == 0) {
834						return "ZEND_VM_TAIL_CALL(" . opcode_name($matches[1], $spec, $op1, $op2) . "_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU))";
835					} else {
836						// ZEND_VM_DISPATCH_TO_HELPER
837						if (isset($matches[2])) {
838							// extra args
839							$args = substr(preg_replace("/,\s*[A-Za-z_]*\s*,\s*([^,)\s]*)\s*/", ", $1", $matches[2]), 2);
840							return "ZEND_VM_TAIL_CALL(" . helper_name($matches[1], $spec, $op1, $op2) . "(" . $args. " ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC))";
841						}
842						return "ZEND_VM_TAIL_CALL(" . helper_name($matches[1], $spec, $op1, $op2) . "(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU))";
843					}
844				},
845				$code);
846			break;
847		case ZEND_VM_KIND_SWITCH:
848			$code = preg_replace_callback(
849				array(
850					"/EXECUTE_DATA/m",
851					"/ZEND_VM_DISPATCH_TO_HANDLER\(\s*([A-Z_]*)\s*\)/m",
852					"/ZEND_VM_DISPATCH_TO_HELPER\(\s*([A-Za-z_]*)\s*(,[^)]*)?\)/m",
853				),
854				function($matches) use ($spec, $prefix, $op1, $op2) {
855					if (strncasecmp($matches[0], "EXECUTE_DATA", strlen("EXECUTE_DATA")) == 0) {
856						return "execute_data";
857					} else if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HANDLER", strlen("ZEND_VM_DISPATCH_TO_HANDLER")) == 0) {
858						return "goto " . opcode_name($matches[1], $spec, $op1, $op2) . "_LABEL";
859					} else {
860						// ZEND_VM_DISPATCH_TO_HELPER
861						if (isset($matches[2])) {
862							// extra args
863							$args = preg_replace("/,\s*([A-Za-z_]*)\s*,\s*([^,)\s]*)\s*/", "$1 = $2; ", $matches[2]);
864							return $args .  "goto " . helper_name($matches[1], $spec, $op1, $op2);
865						}
866						return "goto " . helper_name($matches[1], $spec, $op1, $op2);
867					}
868				},
869					$code);
870			break;
871		case ZEND_VM_KIND_GOTO:
872			$code = preg_replace_callback(
873				array(
874					"/EXECUTE_DATA/m",
875					"/ZEND_VM_DISPATCH_TO_HANDLER\(\s*([A-Z_]*)\s*\)/m",
876					"/ZEND_VM_DISPATCH_TO_HELPER\(\s*([A-Za-z_]*)\s*(,[^)]*)?\)/m",
877				),
878				function($matches) use ($spec, $prefix, $op1, $op2) {
879					if (strncasecmp($matches[0], "EXECUTE_DATA", strlen("EXECUTE_DATA")) == 0) {
880						return "execute_data";
881					} else if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HANDLER", strlen("ZEND_VM_DISPATCH_TO_HANDLER")) == 0) {
882						return "goto " . opcode_name($matches[1], $spec, $op1, $op2) . "_HANDLER";
883					} else {
884						// ZEND_VM_DISPATCH_TO_HELPER
885						if (isset($matches[2])) {
886							// extra args
887							$args = preg_replace("/,\s*([A-Za-z_]*)\s*,\s*([^,)\s]*)\s*/", "$1 = $2; ", $matches[2]);
888							return $args .  "goto " . helper_name($matches[1], $spec, $op1, $op2);
889						}
890						return "goto " . helper_name($matches[1], $spec, $op1, $op2);
891					}
892				},
893					$code);
894			break;
895	}
896
897	/* Remove unused free_op1 and free_op2 declarations */
898	if ($spec && preg_match_all('/^\s*zend_free_op\s+[^;]+;\s*$/me', $code, $matches, PREG_SET_ORDER)) {
899		$n = 0;
900		foreach ($matches as $match) {
901		  $code = preg_replace('/'.preg_quote($match[0],'/').'/', "\$D$n", $code);
902		  ++$n;
903		}
904		$del_free_op1 = (strpos($code, "free_op1") === false);
905		$del_free_op2 = (strpos($code, "free_op2") === false);
906		$del_free_op_data = (strpos($code, "free_op_data") === false);
907		$n = 0;
908		foreach ($matches as $match) {
909			$dcl = $match[0];
910			$changed = 0;
911			if ($del_free_op1 && strpos($dcl, "free_op1") !== false) {
912				$dcl = preg_replace("/free_op1\s*,\s*/", "", $dcl);
913				$dcl = preg_replace("/free_op1\s*;/", ";", $dcl);
914				$changed = 1;
915			}
916			if ($del_free_op2 && strpos($dcl, "free_op2") !== false) {
917				$dcl = preg_replace("/free_op2\s*,\s*/", "", $dcl);
918				$dcl = preg_replace("/free_op2\s*;/", ";", $dcl);
919				$changed = 1;
920			}
921			if ($del_free_op_data && strpos($dcl, "free_op_data") !== false) {
922				$dcl = preg_replace("/free_op_data\s*,\s*/", "", $dcl);
923				$dcl = preg_replace("/free_op_data\s*;/", ";", $dcl);
924				$changed = 1;
925			}
926			if ($changed) {
927				$dcl = preg_replace("/,\s*;/", ";", $dcl);
928				$dcl = preg_replace("/zend_free_op\s*;/", "", $dcl);
929			}
930		  $code = preg_replace("/\\\$D$n/", $dcl, $code);
931		  ++$n;
932		}
933	}
934
935	/* Remove unnecessary ';' */
936	$code = preg_replace('/^\s*;\s*$/m', '', $code);
937
938	/* Remove WS */
939	$code = preg_replace('/[ \t]+\n/m', "\n", $code);
940
941	out($f, $code);
942}
943
944// Generates opcode handler
945function gen_handler($f, $spec, $kind, $name, $op1, $op2, $use, $code, $lineno, $extra_spec = null, &$switch_labels = array()) {
946	global $definition_file, $prefix, $typecode, $opnames, $commutative_order;
947
948	if ($spec &&
949	    isset($extra_spec["NO_CONST_CONST"]) &&
950	    $op1 == "CONST" && $op2 == "CONST") {
951	    // Skip useless constant handlers
952		return;
953	}
954
955	if ($spec &&
956	    isset($extra_spec["COMMUTATIVE"]) &&
957	    $commutative_order[$op1] > $commutative_order[$op2]) {
958	    // Skip duplicate commutative handlers
959		return;
960	}
961
962	if ($spec &&
963	    isset($extra_spec["DIM_OBJ"]) &&
964		(($op2 == "UNUSED" && $extra_spec["DIM_OBJ"] != 1) ||
965		 ($op1 == "UNUSED" && $extra_spec["DIM_OBJ"] != 2))) {
966	    // Skip useless handlers
967		return;
968	}
969
970	if (ZEND_VM_LINES) {
971		out($f, "#line $lineno \"$definition_file\"\n");
972	}
973
974	// Generate opcode handler's entry point according to selected threading model
975	$spec_name = $name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2].($spec?extra_spec_name($extra_spec):"");
976	switch($kind) {
977		case ZEND_VM_KIND_CALL:
978			out($f,"static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL {$spec_name}_HANDLER(ZEND_OPCODE_HANDLER_ARGS)\n");
979			break;
980		case ZEND_VM_KIND_SWITCH:
981			if ($spec) {
982				$cur = $switch_labels ? end($switch_labels) + 1 : 0;
983				out($f,"case $cur: /* $spec_name */");
984				$switch_labels[$spec_name] = $cur;
985			} else {
986				out($f,"case ".$name.":");
987			}
988			if ($use) {
989				// This handler is used by other handlers. We will add label to call it.
990				out($f," {$spec_name}_LABEL:\n");
991			} else {
992				out($f,"\n");
993			}
994			break;
995		case ZEND_VM_KIND_GOTO:
996			out($f,"{$spec_name}_HANDLER: ZEND_VM_GUARD($spec_name);\n");
997			break;
998	}
999
1000	// Generate opcode handler's code
1001	gen_code($f, $spec, $kind, 0, $code, $op1, $op2, $name, $extra_spec);
1002}
1003
1004// Generates helper
1005function gen_helper($f, $spec, $kind, $name, $op1, $op2, $param, $code, $lineno, $inline) {
1006	global $definition_file, $prefix;
1007
1008	if (ZEND_VM_LINES) {
1009		out($f, "#line $lineno \"$definition_file\"\n");
1010	}
1011
1012	// Generate helper's entry point according to selected threading model
1013	switch($kind) {
1014		case ZEND_VM_KIND_CALL:
1015			if ($inline) {
1016				$zend_always_inline = " zend_always_inline";
1017				$zend_fastcall = "";
1018			} else {
1019				$zend_always_inline = "";
1020				$zend_fastcall = " ZEND_FASTCALL";
1021			}
1022			if ($param == null) {
1023			  // Helper without parameters
1024				out($f, "static$zend_always_inline ZEND_OPCODE_HANDLER_RET$zend_fastcall ".$name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2]."(ZEND_OPCODE_HANDLER_ARGS)\n");
1025			} else {
1026			  // Helper with parameter
1027				out($f, "static$zend_always_inline ZEND_OPCODE_HANDLER_RET$zend_fastcall ".$name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2]."(".$param." ZEND_OPCODE_HANDLER_ARGS_DC)\n");
1028			}
1029			break;
1030		case ZEND_VM_KIND_SWITCH:
1031			out($f, $name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2].":\n");
1032			break;
1033		case ZEND_VM_KIND_GOTO:
1034			out($f, $name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2].":\n");
1035			break;
1036	}
1037
1038	// Generate helper's code
1039	gen_code($f, $spec, $kind, 0, $code, $op1, $op2, $name);
1040}
1041
1042
1043function gen_null_label($f, $kind, $prolog) {
1044	switch ($kind) {
1045		case ZEND_VM_KIND_CALL:
1046			out($f,$prolog."ZEND_NULL_HANDLER,\n");
1047			break;
1048		case ZEND_VM_KIND_SWITCH:
1049			out($f,$prolog."(void*)(uintptr_t)-1,\n");
1050			break;
1051		case ZEND_VM_KIND_GOTO:
1052			out($f,$prolog."(void*)&&ZEND_NULL_HANDLER,\n");
1053			break;
1054	}
1055}
1056
1057// Generates array of opcode handlers (specialized or unspecialized)
1058function gen_labels($f, $spec, $kind, $prolog, &$specs, $switch_labels = array()) {
1059	global $opcodes, $op_types, $prefix;
1060
1061	$next = 0;
1062	$label = 0;
1063	if ($spec) {
1064	  // Emit labels for specialized executor
1065
1066	  // For each opcode in opcode number order
1067		foreach($opcodes as $num => $dsc) {
1068			$specs[$num] = "$label";
1069			$spec_op1 = $spec_op2 = $spec_extra = false;
1070			$next = $num + 1;
1071			$diff = array_diff_key(array_flip($op_types), isset($dsc["op1"]) ? $dsc["op1"] : array());
1072			if ((count($diff) == count($op_types) - 1 ? isset($diff["ANY"]) : count($diff) != count($op_types)) || isset($dsc["op1"]["TMPVAR"]) || isset($dsc["op1"]["TMPVARCV"])) {
1073				$spec_op1 = true;
1074				$specs[$num] .= " | SPEC_RULE_OP1";
1075			}
1076			$diff = array_diff_key(array_flip($op_types), isset($dsc["op2"]) ? $dsc["op2"] : array());
1077			if ((count($diff) == count($op_types) - 1 ? isset($diff["ANY"]) : count($diff) != count($op_types)) || isset($dsc["op2"]["TMPVAR"]) || isset($dsc["op2"]["TMPVARCV"])) {
1078				$spec_op2 = true;
1079				$specs[$num] .= " | SPEC_RULE_OP2";
1080			}
1081			$spec_extra = call_user_func_array("array_merge", extra_spec_handler($dsc) ?: array(array()));
1082			$flags = extra_spec_flags($spec_extra);
1083			if ($flags) {
1084				$specs[$num] .= " | ".implode("|", $flags);
1085			}
1086			if ($num >= 256) {
1087				$opcodes[$num]['spec_code'] = $specs[$num];
1088				unset($specs[$num]);
1089			}
1090
1091			$foreach_op1 = function($do) use ($dsc, $op_types) {
1092				return function() use ($do, $dsc, $op_types) {
1093					// For each op1.op_type except ANY
1094					foreach($op_types as $op1) {
1095						if ($op1 != "ANY") {
1096							if (!isset($dsc["op1"][$op1])) {
1097								if ($op1 == "TMP" || $op1 == "VAR") {
1098									if (isset($dsc["op1"]["TMPVAR"])) {
1099										$op1 = "TMPVAR";
1100									} else if (isset($dsc["op1"]["TMPVARCV"])) {
1101										$op1 = "TMPVARCV";
1102									} else {
1103										$op1 = "ANY";
1104									}
1105								} else if ($op1 == "CV" && isset($dsc["op1"]["TMPVARCV"])) {
1106									$op1 = "TMPVARCV";
1107								} else {
1108									// Try to use unspecialized handler
1109									$op1 = "ANY";
1110								}
1111							}
1112							$do($op1, "ANY");
1113						}
1114					}
1115				};
1116			};
1117			$foreach_op2 = function($do) use ($dsc, $op_types) {
1118				return function($op1) use ($do, $dsc, $op_types) {
1119					// For each op2.op_type except ANY
1120					foreach($op_types as $op2) {
1121						if ($op2 != "ANY") {
1122							if (!isset($dsc["op2"][$op2])) {
1123								if ($op2 == "TMP" || $op2 == "VAR") {
1124									if (isset($dsc["op2"]["TMPVAR"])) {
1125										$op2 = "TMPVAR";
1126									} else if (isset($dsc["op2"]["TMPVARCV"])) {
1127										$op2 = "TMPVARCV";
1128									} else {
1129										$op2 = "ANY";
1130									}
1131								} else if ($op2 == "CV" && isset($dsc["op2"]["TMPVARCV"])) {
1132									$op2 = "TMPVARCV";
1133								} else {
1134									// Try to use unspecialized handler
1135									$op2 = "ANY";
1136								}
1137							}
1138							$do($op1, $op2);
1139						}
1140					}
1141				};
1142			};
1143			$foreach_op_data = function($do) use ($dsc, $op_types) {
1144				return function($op1, $op2, $extra_spec = array()) use ($do, $dsc, $op_types) {
1145					// For each op_data.op_type except ANY
1146					foreach($op_types as $op_data) {
1147						if ($op_data != "ANY") {
1148							if (!isset($dsc["spec"]["OP_DATA"][$op_data])) {
1149								if ($op_data == "TMP" || $op_data == "VAR") {
1150									if (isset($dsc["spec"]["OP_DATA"]["TMPVAR"])) {
1151										$op_data = "TMPVAR";
1152									} else if (isset($dsc["spec"]["OP_DATA"]["TMPVARCV"])) {
1153										$op_data = "TMPVARCV";
1154									} else {
1155										// Try to use unspecialized handler
1156										$op_data = "ANY";
1157									}
1158								} else if ($op_data == "CV" && isset($dsc["OP_DATA"]["TMPVARCV"])) {
1159									$op_data = "TMPVARCV";
1160								} else {
1161									// Try to use unspecialized handler
1162									$op_data = "ANY";
1163								}
1164							}
1165							$do($op1, $op2, array("OP_DATA" => $op_data) + $extra_spec);
1166						}
1167					}
1168				};
1169			};
1170			$foreach_extra_spec = function($do, $spec) use ($dsc) {
1171				return function($op1, $op2, $extra_spec = array()) use ($do, $spec, $dsc) {
1172					foreach ($dsc["spec"][$spec] as $val) {
1173						$do($op1, $op2, array($spec => $val) + $extra_spec);
1174					}
1175				};
1176			};
1177			$generate = function ($op1, $op2, $extra_spec = array()) use ($f, $kind, $dsc, $prefix, $prolog, $num, $switch_labels, &$label) {
1178				global $typecode, $commutative_order;
1179
1180				// Check if specialized handler is defined
1181				/* TODO: figure out better way to signal "specialized and not defined" than an extra lookup */
1182				if (isset($dsc["op1"][$op1]) &&
1183				    isset($dsc["op2"][$op2]) &&
1184				    (!isset($extra_spec["OP_DATA"]) || isset($dsc["spec"]["OP_DATA"][$extra_spec["OP_DATA"]]))) {
1185
1186					if (isset($extra_spec["NO_CONST_CONST"]) &&
1187					    $op1 == "CONST" && $op2 == "CONST") {
1188					    // Skip useless constant handlers
1189						gen_null_label($f, $kind, $prolog);
1190						$label++;
1191						return;
1192					} else if (isset($extra_spec["COMMUTATIVE"]) &&
1193					    $commutative_order[$op1] > $commutative_order[$op2]) {
1194					    // Skip duplicate commutative handlers
1195						gen_null_label($f, $kind, $prolog);
1196						$label++;
1197						return;
1198					} else if (isset($extra_spec["DIM_OBJ"]) &&
1199						(($op2 == "UNUSED" && $extra_spec["DIM_OBJ"] != 1) ||
1200						 ($op1 == "UNUSED" && $extra_spec["DIM_OBJ"] != 2))) {
1201					    // Skip useless handlers
1202						gen_null_label($f, $kind, $prolog);
1203						$label++;
1204						return;
1205					}
1206
1207					// Emit pointer to specialized handler
1208					$spec_name = $dsc["op"]."_SPEC".$prefix[$op1].$prefix[$op2].extra_spec_name($extra_spec);
1209					switch ($kind) {
1210						case ZEND_VM_KIND_CALL:
1211							out($f,"$prolog{$spec_name}_HANDLER,\n");
1212							$label++;
1213							break;
1214						case ZEND_VM_KIND_SWITCH:
1215							out($f,$prolog."(void*)(uintptr_t)$switch_labels[$spec_name],\n");
1216							$label++;
1217							break;
1218						case ZEND_VM_KIND_GOTO:
1219							out($f,$prolog."(void*)&&{$spec_name}_HANDLER,\n");
1220							$label++;
1221							break;
1222					}
1223				} else {
1224					// Emit pointer to handler of undefined opcode
1225					gen_null_label($f, $kind, $prolog);
1226					$label++;
1227				}
1228			};
1229
1230			$do = $generate;
1231			if ($spec_extra) {
1232				foreach ($spec_extra as $extra => $devnull) {
1233					if ($extra == "OP_DATA") {
1234						$do = $foreach_op_data($do);
1235					} else {
1236						$do = $foreach_extra_spec($do, $extra);
1237					}
1238				}
1239			}
1240			if ($spec_op2) {
1241				$do = $foreach_op2($do);
1242			}
1243			if ($spec_op1) {
1244				$do = $foreach_op1($do);
1245			}
1246
1247			$do("ANY", "ANY");
1248		}
1249	} else {
1250	  // Emit labels for unspecialized executor
1251
1252	  // For each opcode in opcode number order
1253		foreach($opcodes as $num => $dsc) {
1254			while ($next != $num) {
1255			  // If some opcode numbers are not used then fill hole with pointers
1256			  // to handler of undefined opcode
1257				switch ($kind) {
1258					case ZEND_VM_KIND_CALL:
1259						out($f,$prolog."ZEND_NULL_HANDLER,\n");
1260						break;
1261					case ZEND_VM_KIND_SWITCH:
1262						out($f,$prolog."(void*)(uintptr_t)-1,\n");
1263						break;
1264					case ZEND_VM_KIND_GOTO:
1265						out($f,$prolog."(void*)&&ZEND_NULL_HANDLER,\n");
1266						break;
1267				}
1268				$next++;
1269			}
1270			if ($num >= 256) {
1271				continue;
1272			}
1273			$next = $num+1;
1274
1275			//ugly trick for ZEND_VM_DEFINE_OP
1276			if ($dsc["code"]) {
1277				// Emit pointer to unspecialized handler
1278				switch ($kind) {
1279				case ZEND_VM_KIND_CALL:
1280					out($f,$prolog.$dsc["op"]."_HANDLER,\n");
1281					break;
1282				case ZEND_VM_KIND_SWITCH:
1283					out($f,$prolog."(void*)(uintptr_t)".((string)$num).",\n");
1284					break;
1285				case ZEND_VM_KIND_GOTO:
1286					out($f,$prolog."(void*)&&".$dsc["op"]."_HANDLER,\n");
1287					break;
1288				}
1289			} else {
1290				switch ($kind) {
1291					case ZEND_VM_KIND_CALL:
1292						out($f,$prolog."ZEND_NULL_HANDLER,\n");
1293						break;
1294					case ZEND_VM_KIND_SWITCH:
1295						out($f,$prolog."(void*)(uintptr_t)-1,\n");
1296						break;
1297					case ZEND_VM_KIND_GOTO:
1298						out($f,$prolog."(void*)&&ZEND_NULL_HANDLER,\n");
1299						break;
1300				}
1301			}
1302		}
1303	}
1304
1305	// Emit last handler's label (undefined opcode)
1306	switch ($kind) {
1307		case ZEND_VM_KIND_CALL:
1308			out($f,$prolog."ZEND_NULL_HANDLER\n");
1309			break;
1310		case ZEND_VM_KIND_SWITCH:
1311			out($f,$prolog."(void*)(uintptr_t)-1\n");
1312			break;
1313		case ZEND_VM_KIND_GOTO:
1314			out($f,$prolog."(void*)&&ZEND_NULL_HANDLER\n");
1315			break;
1316	}
1317	$specs[$num + 1] = "$label";
1318}
1319
1320// Generates specialized offsets
1321function gen_specs($f, $spec, $kind, $prolog, $specs) {
1322	$lastdef = array_pop($specs);
1323	$last = 0;
1324	foreach ($specs as $num => $def) {
1325		while (++$last < $num) {
1326			out($f, "$prolog$lastdef,\n");
1327		}
1328		$last = $num;
1329		out($f, "$prolog$def,\n");
1330	}
1331	out($f, "$prolog$lastdef\n");
1332}
1333
1334// Generates handler for undefined opcodes (CALL threading model)
1335function gen_null_handler($f) {
1336	static $done = 0;
1337
1338	// New and all executors with CALL threading model can use the same handler
1339	// for undefined opcodes, do we emit code for it only once
1340	if (!$done) {
1341		$done = 1;
1342		out($f,"static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NULL_HANDLER(ZEND_OPCODE_HANDLER_ARGS)\n");
1343		out($f,"{\n");
1344		out($f,"\tUSE_OPLINE\n");
1345		out($f,"\n");
1346		out($f,"\tzend_error_noreturn(E_ERROR, \"Invalid opcode %d/%d/%d.\", OPLINE->opcode, OPLINE->op1_type, OPLINE->op2_type);\n");
1347		out($f,"\tZEND_VM_NEXT_OPCODE(); /* Never reached */\n");
1348		out($f,"}\n\n");
1349	}
1350}
1351
1352function extra_spec_name($extra_spec) {
1353	global $prefix;
1354
1355	$s = "";
1356	if (isset($extra_spec["OP_DATA"])) {
1357		$s .= "_OP_DATA" . $prefix[$extra_spec["OP_DATA"]];
1358	}
1359	if (isset($extra_spec["RETVAL"])) {
1360		$s .= "_RETVAL_".($extra_spec["RETVAL"] ? "USED" : "UNUSED");
1361	}
1362	if (isset($extra_spec["QUICK_ARG"])) {
1363		if ($extra_spec["QUICK_ARG"]) {
1364			$s .= "_QUICK";
1365		}
1366	}
1367	if (isset($extra_spec["SMART_BRANCH"])) {
1368		if ($extra_spec["SMART_BRANCH"] == 1) {
1369			$s .= "_JMPZ";
1370		} else if ($extra_spec["SMART_BRANCH"] == 2) {
1371			$s .= "_JMPNZ";
1372		}
1373	}
1374	if (isset($extra_spec["DIM_OBJ"])) {
1375		if ($extra_spec["DIM_OBJ"] == 1) {
1376			$s .= "_DIM";
1377		} else if ($extra_spec["DIM_OBJ"] == 2) {
1378			$s .= "_OBJ";
1379		}
1380	}
1381	return $s;
1382}
1383
1384function extra_spec_flags($extra_spec) {
1385	$s = array();
1386	if (isset($extra_spec["OP_DATA"])) {
1387		$s[] = "SPEC_RULE_OP_DATA";
1388	}
1389	if (isset($extra_spec["RETVAL"])) {
1390		$s[] = "SPEC_RULE_RETVAL";
1391	}
1392	if (isset($extra_spec["QUICK_ARG"])) {
1393		$s[] = "SPEC_RULE_QUICK_ARG";
1394	}
1395	if (isset($extra_spec["SMART_BRANCH"])) {
1396		$s[] = "SPEC_RULE_SMART_BRANCH";
1397	}
1398	if (isset($extra_spec["DIM_OBJ"])) {
1399		$s[] = "SPEC_RULE_DIM_OBJ";
1400	}
1401	return $s;
1402}
1403
1404function extra_spec_handler($dsc) {
1405	global $op_types_ex;
1406
1407	if (!isset($dsc["spec"])) {
1408		return array(array());
1409	}
1410	$specs = $dsc["spec"];
1411
1412	if (isset($specs["OP_DATA"])) {
1413		$op_data_specs = $specs["OP_DATA"];
1414		$specs["OP_DATA"] = array();
1415		foreach($op_types_ex as $op_data) {
1416			if (isset($dsc["spec"]["OP_DATA"][$op_data])) {
1417				$specs["OP_DATA"][] = $op_data;
1418			}
1419		}
1420	}
1421
1422	$f = function($specs) use (&$f) {
1423		$spec = key($specs);
1424		$top = array_shift($specs);
1425		if ($specs) {
1426			$next = $f($specs);
1427		} else {
1428			$next = array(array());
1429		}
1430		$ret = array();
1431		foreach ($next as $existing) {
1432			foreach ($top as $mode) {
1433				$ret[] = array($spec => $mode) + $existing;
1434			}
1435		}
1436		return $ret;
1437	};
1438	return $f($specs);
1439}
1440
1441// Generates all opcode handlers and helpers (specialized or unspecilaized)
1442function gen_executor_code($f, $spec, $kind, $prolog, &$switch_labels = array()) {
1443	global $list, $opcodes, $helpers, $op_types_ex;
1444
1445	if ($spec) {
1446		// Produce specialized executor
1447		$op1t = $op_types_ex;
1448		// for each op1.op_type
1449		foreach($op1t as $op1) {
1450			$op2t = $op_types_ex;
1451			// for each op2.op_type
1452			foreach($op2t as $op2) {
1453				// for each handlers in helpers in original order
1454				foreach ($list as $lineno => $dsc) {
1455					if (isset($dsc["handler"])) {
1456						$num = $dsc["handler"];
1457						foreach (extra_spec_handler($opcodes[$num]) as $extra_spec) {
1458							// Check if handler accepts such types of operands (op1 and op2)
1459							if (isset($opcodes[$num]["op1"][$op1]) &&
1460							    isset($opcodes[$num]["op2"][$op2])) {
1461							  // Generate handler code
1462								gen_handler($f, 1, $kind, $opcodes[$num]["op"], $op1, $op2, isset($opcodes[$num]["use"]), $opcodes[$num]["code"], $lineno, $extra_spec, $switch_labels);
1463							}
1464						}
1465					} else if (isset($dsc["helper"])) {
1466						$num = $dsc["helper"];
1467						// Check if handler accepts such types of operands (op1 and op2)
1468						if (isset($helpers[$num]["op1"][$op1]) &&
1469						    isset($helpers[$num]["op2"][$op2])) {
1470						  // Generate helper code
1471							gen_helper($f, 1, $kind, $num, $op1, $op2, $helpers[$num]["param"], $helpers[$num]["code"], $lineno, $helpers[$num]["inline"]);
1472						}
1473					} else {
1474						var_dump($dsc);
1475						die("??? $kind:$num\n");
1476					}
1477				}
1478			}
1479		}
1480	} else {
1481		// Produce unspecialized executor
1482
1483		// for each handlers in helpers in original order
1484		foreach ($list as $lineno => $dsc) {
1485			if (isset($dsc["handler"])) {
1486				$num = $dsc["handler"];
1487				// Generate handler code
1488				if ($num < 256) {
1489					gen_handler($f, 0, $kind, $opcodes[$num]["op"], "ANY", "ANY", isset($opcodes[$num]["use"]), $opcodes[$num]["code"], $lineno);
1490				}
1491			} else if (isset($dsc["helper"])) {
1492				$num = $dsc["helper"];
1493				// Generate helper code
1494				gen_helper($f, 0, $kind, $num, "ANY", "ANY", $helpers[$num]["param"], $helpers[$num]["code"], $lineno, $helpers[$num]["inline"]);
1495			} else {
1496				var_dump($dsc);
1497				die("??? $kind:$num\n");
1498			}
1499		}
1500	}
1501
1502	if (ZEND_VM_LINES) {
1503		// Reset #line directives
1504		out_line($f);
1505	}
1506
1507	// Generate handler for undefined opcodes
1508	switch ($kind) {
1509		case ZEND_VM_KIND_CALL:
1510			gen_null_handler($f);
1511			break;
1512		case ZEND_VM_KIND_SWITCH:
1513			out($f,"default:\n");
1514			out($f,"\tzend_error_noreturn(E_ERROR, \"Invalid opcode %d/%d/%d.\", OPLINE->opcode, OPLINE->op1_type, OPLINE->op2_type);\n");
1515			out($f,"\tZEND_VM_NEXT_OPCODE(); /* Never reached */\n");
1516			break;
1517		case ZEND_VM_KIND_GOTO:
1518			out($f,"ZEND_NULL_HANDLER:\n");
1519			out($f,"\tzend_error_noreturn(E_ERROR, \"Invalid opcode %d/%d/%d.\", OPLINE->opcode, OPLINE->op1_type, OPLINE->op2_type);\n");
1520			out($f,"\tZEND_VM_NEXT_OPCODE(); /* Never reached */\n");
1521			break;
1522	}
1523}
1524
1525function skip_blanks($f, $prolog, $epilog) {
1526	if (trim($prolog) != "" || trim($epilog) != "") {
1527		out($f, $prolog.$epilog);
1528	}
1529}
1530
1531// Generates executor from skeleton file and definition (specialized or unspecialized)
1532function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) {
1533	global $params, $skeleton_file, $line_no;
1534
1535	$switch_labels = array();
1536	$lineno = 0;
1537	foreach ($skl as $line) {
1538	  // Skeleton file contains special markers in form %NAME% those are
1539	  // substituted by custom code
1540		if (preg_match("/(.*)[{][%]([A-Z_]*)[%][}](.*)/", $line, $m)) {
1541			switch ($m[2]) {
1542				case "DEFINES":
1543					out($f,"#define SPEC_START_MASK        0x0000ffff\n");
1544					out($f,"#define SPEC_RULE_OP1          0x00010000\n");
1545					out($f,"#define SPEC_RULE_OP2          0x00020000\n");
1546					out($f,"#define SPEC_RULE_OP_DATA      0x00040000\n");
1547					out($f,"#define SPEC_RULE_RETVAL       0x00080000\n");
1548					out($f,"#define SPEC_RULE_QUICK_ARG    0x00100000\n");
1549					out($f,"#define SPEC_RULE_SMART_BRANCH 0x00200000\n");
1550					out($f,"#define SPEC_RULE_DIM_OBJ      0x00400000\n");
1551					out($f,"\n");
1552					out($f,"static const uint32_t *zend_spec_handlers;\n");
1553					out($f,"static const void **zend_opcode_handlers;\n");
1554					out($f,"static int zend_handlers_count;\n");
1555					out($f,"static const void *zend_vm_get_opcode_handler(zend_uchar opcode, const zend_op* op);\n\n");
1556					switch ($kind) {
1557						case ZEND_VM_KIND_CALL:
1558							out($f,"\n");
1559							out($f,"#ifdef ZEND_VM_FP_GLOBAL_REG\n");
1560							out($f,"#pragma GCC diagnostic ignored \"-Wvolatile-register-var\"\n");
1561							out($f,"register zend_execute_data* volatile execute_data __asm__(ZEND_VM_FP_GLOBAL_REG);\n");
1562							out($f,"#pragma GCC diagnostic warning \"-Wvolatile-register-var\"\n");
1563							out($f,"#endif\n");
1564							out($f,"\n");
1565							out($f,"#ifdef ZEND_VM_IP_GLOBAL_REG\n");
1566							out($f,"#pragma GCC diagnostic ignored \"-Wvolatile-register-var\"\n");
1567							out($f,"register const zend_op* volatile opline __asm__(ZEND_VM_IP_GLOBAL_REG);\n");
1568							out($f,"#pragma GCC diagnostic warning \"-Wvolatile-register-var\"\n");
1569							out($f,"#endif\n");
1570							out($f,"\n");
1571							out($f,"#ifdef ZEND_VM_FP_GLOBAL_REG\n");
1572							out($f,"# define ZEND_OPCODE_HANDLER_ARGS void\n");
1573							out($f,"# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU\n");
1574							out($f,"# define ZEND_OPCODE_HANDLER_ARGS_DC\n");
1575							out($f,"# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC\n");
1576							out($f,"#else\n");
1577							out($f,"# define ZEND_OPCODE_HANDLER_ARGS zend_execute_data *execute_data\n");
1578							out($f,"# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU execute_data\n");
1579							out($f,"# define ZEND_OPCODE_HANDLER_ARGS_DC , ZEND_OPCODE_HANDLER_ARGS\n");
1580							out($f,"# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC , ZEND_OPCODE_HANDLER_ARGS_PASSTHRU\n");
1581							out($f,"#endif\n");
1582							out($f,"\n");
1583							out($f,"#if defined(ZEND_VM_FP_GLOBAL_REG) && defined(ZEND_VM_IP_GLOBAL_REG)\n");
1584							out($f,"# define ZEND_OPCODE_HANDLER_RET void\n");
1585							out($f,"# define ZEND_VM_TAIL_CALL(call) call; return\n");
1586							out($f,"# ifdef ZEND_VM_TAIL_CALL_DISPATCH\n");
1587							out($f,"#  define ZEND_VM_CONTINUE()     ((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); return\n");
1588							out($f,"# else\n");
1589							out($f,"#  define ZEND_VM_CONTINUE()     return\n");
1590							out($f,"# endif\n");
1591							out($f,"# define ZEND_VM_RETURN()        opline = NULL; return\n");
1592							out($f,"#else\n");
1593							out($f,"# define ZEND_OPCODE_HANDLER_RET int\n");
1594							out($f,"# define ZEND_VM_TAIL_CALL(call) return call\n");
1595							out($f,"# define ZEND_VM_CONTINUE()      return  0\n");
1596							out($f,"# define ZEND_VM_RETURN()        return -1\n");
1597							out($f,"#endif\n");
1598							out($f,"\n");
1599							out($f,"typedef ZEND_OPCODE_HANDLER_RET (ZEND_FASTCALL *opcode_handler_t) (ZEND_OPCODE_HANDLER_ARGS);\n");
1600							out($f,"\n");
1601							out($f,"#undef OPLINE\n");
1602							out($f,"#undef DCL_OPLINE\n");
1603							out($f,"#undef USE_OPLINE\n");
1604							out($f,"#undef LOAD_OPLINE\n");
1605							out($f,"#undef LOAD_OPLINE_EX\n");
1606							out($f,"#undef SAVE_OPLINE\n");
1607							out($f,"#define DCL_OPLINE\n");
1608							out($f,"#ifdef ZEND_VM_IP_GLOBAL_REG\n");
1609							out($f,"# define OPLINE opline\n");
1610							out($f,"# define USE_OPLINE\n");
1611							out($f,"# define LOAD_OPLINE() opline = EX(opline)\n");
1612							out($f,"# define LOAD_NEXT_OPLINE() opline = EX(opline) + 1\n");
1613							out($f,"# define SAVE_OPLINE() EX(opline) = opline\n");
1614							out($f,"#else\n");
1615							out($f,"# define OPLINE EX(opline)\n");
1616							out($f,"# define USE_OPLINE const zend_op *opline = EX(opline);\n");
1617							out($f,"# define LOAD_OPLINE()\n");
1618							out($f,"# define LOAD_NEXT_OPLINE() ZEND_VM_INC_OPCODE()\n");
1619							out($f,"# define SAVE_OPLINE()\n");
1620							out($f,"#endif\n");
1621							out($f,"#undef HANDLE_EXCEPTION\n");
1622							out($f,"#undef HANDLE_EXCEPTION_LEAVE\n");
1623							out($f,"#define HANDLE_EXCEPTION() LOAD_OPLINE(); ZEND_VM_CONTINUE()\n");
1624							out($f,"#define HANDLE_EXCEPTION_LEAVE() LOAD_OPLINE(); ZEND_VM_LEAVE()\n");
1625							out($f,"#if defined(ZEND_VM_FP_GLOBAL_REG)\n");
1626							out($f,"# define ZEND_VM_ENTER()           execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_INTERRUPT_CHECK(); ZEND_VM_CONTINUE()\n");
1627							out($f,"# define ZEND_VM_LEAVE()           ZEND_VM_CONTINUE()\n");
1628							out($f,"#elif defined(ZEND_VM_IP_GLOBAL_REG)\n");
1629							out($f,"# define ZEND_VM_ENTER()           opline = EG(current_execute_data)->opline; return 1\n");
1630							out($f,"# define ZEND_VM_LEAVE()           return  2\n");
1631							out($f,"#else\n");
1632							out($f,"# define ZEND_VM_ENTER()           return  1\n");
1633							out($f,"# define ZEND_VM_LEAVE()           return  2\n");
1634							out($f,"#endif\n");
1635							out($f,"#define ZEND_VM_INTERRUPT()      ZEND_VM_TAIL_CALL(zend_interrupt_helper".($spec?"_SPEC":"")."(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));\n");
1636							out($f,"#define ZEND_VM_LOOP_INTERRUPT() zend_interrupt_helper".($spec?"_SPEC":"")."(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n");
1637							out($f,"#define ZEND_VM_DISPATCH(opcode, opline) ZEND_VM_TAIL_CALL(((opcode_handler_t)zend_vm_get_opcode_handler(opcode, opline))(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));\n");
1638							out($f,"\n");
1639							out($f,"static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_interrupt_helper".($spec?"_SPEC":"")."(ZEND_OPCODE_HANDLER_ARGS);");
1640							out($f,"\n");
1641							break;
1642						case ZEND_VM_KIND_SWITCH:
1643							out($f,"\n");
1644							out($f,"#undef OPLINE\n");
1645							out($f,"#undef DCL_OPLINE\n");
1646							out($f,"#undef USE_OPLINE\n");
1647							out($f,"#undef LOAD_OPLINE\n");
1648							out($f,"#undef LOAD_NEXT_OPLINE\n");
1649							out($f,"#undef SAVE_OPLINE\n");
1650							out($f,"#define OPLINE opline\n");
1651							out($f,"#ifdef ZEND_VM_IP_GLOBAL_REG\n");
1652							out($f,"# define DCL_OPLINE register const zend_op *opline __asm__(ZEND_VM_IP_GLOBAL_REG);\n");
1653							out($f,"#else\n");
1654							out($f,"# define DCL_OPLINE const zend_op *opline;\n");
1655							out($f,"#endif\n");
1656							out($f,"#define USE_OPLINE\n");
1657							out($f,"#define LOAD_OPLINE() opline = EX(opline)\n");
1658							out($f,"#define LOAD_NEXT_OPLINE() opline = EX(opline) + 1\n");
1659							out($f,"#define SAVE_OPLINE() EX(opline) = opline\n");
1660							out($f,"#undef HANDLE_EXCEPTION\n");
1661							out($f,"#undef HANDLE_EXCEPTION_LEAVE\n");
1662							out($f,"#define HANDLE_EXCEPTION() LOAD_OPLINE(); ZEND_VM_CONTINUE()\n");
1663							out($f,"#define HANDLE_EXCEPTION_LEAVE() LOAD_OPLINE(); ZEND_VM_LEAVE()\n");
1664							out($f,"#define ZEND_VM_CONTINUE() goto zend_vm_continue\n");
1665							out($f,"#define ZEND_VM_RETURN()   return\n");
1666							out($f,"#define ZEND_VM_ENTER()    execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_INTERRUPT_CHECK(); ZEND_VM_CONTINUE()\n");
1667							out($f,"#define ZEND_VM_LEAVE()    ZEND_VM_CONTINUE()\n");
1668							out($f,"#define ZEND_VM_INTERRUPT()              goto zend_interrupt_helper".($spec?"_SPEC":"").";\n");
1669							out($f,"#define ZEND_VM_LOOP_INTERRUPT()         goto zend_interrupt_helper".($spec?"_SPEC":"").";\n");
1670							out($f,"#define ZEND_VM_DISPATCH(opcode, opline) dispatch_handler = zend_vm_get_opcode_handler(opcode, opline); goto zend_vm_dispatch;\n");
1671							out($f,"\n");
1672							break;
1673						case ZEND_VM_KIND_GOTO:
1674							out($f,"\n");
1675							out($f,"#undef OPLINE\n");
1676							out($f,"#undef DCL_OPLINE\n");
1677							out($f,"#undef USE_OPLINE\n");
1678							out($f,"#undef LOAD_OPLINE\n");
1679							out($f,"#undef LOAD_NEXT_OPLINE\n");
1680							out($f,"#undef SAVE_OPLINE\n");
1681							out($f,"#define OPLINE opline\n");
1682							out($f,"#ifdef ZEND_VM_IP_GLOBAL_REG\n");
1683							out($f,"# define DCL_OPLINE register const zend_op *opline __asm__(ZEND_VM_IP_GLOBAL_REG);\n");
1684							out($f,"#else\n");
1685							out($f,"# define DCL_OPLINE const zend_op *opline;\n");
1686							out($f,"#endif\n");
1687							out($f,"#define USE_OPLINE\n");
1688							out($f,"#define LOAD_OPLINE() opline = EX(opline)\n");
1689							out($f,"#define LOAD_NEXT_OPLINE() opline = EX(opline) + 1\n");
1690							out($f,"#define SAVE_OPLINE() EX(opline) = opline\n");
1691							out($f,"#undef HANDLE_EXCEPTION\n");
1692							out($f,"#undef HANDLE_EXCEPTION_LEAVE\n");
1693							if (ZEND_VM_SPEC) {
1694								out($f,"#define HANDLE_EXCEPTION() goto ZEND_HANDLE_EXCEPTION_SPEC_HANDLER\n");
1695								out($f,"#define HANDLE_EXCEPTION_LEAVE() goto ZEND_HANDLE_EXCEPTION_SPEC_HANDLER\n");
1696							} else {
1697								out($f,"#define HANDLE_EXCEPTION() goto ZEND_HANDLE_EXCEPTION_HANDLER\n");
1698								out($f,"#define HANDLE_EXCEPTION_LEAVE() goto ZEND_HANDLE_EXCEPTION_HANDLER\n");
1699							}
1700							out($f,"#define ZEND_VM_CONTINUE() goto *(void**)(OPLINE->handler)\n");
1701							out($f,"#define ZEND_VM_RETURN()   return\n");
1702							out($f,"#define ZEND_VM_ENTER()    execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_INTERRUPT_CHECK(); ZEND_VM_CONTINUE()\n");
1703							out($f,"#define ZEND_VM_LEAVE()    ZEND_VM_CONTINUE()\n");
1704							out($f,"#define ZEND_VM_INTERRUPT()              goto zend_interrupt_helper".($spec?"_SPEC":"").";\n");
1705							out($f,"#define ZEND_VM_LOOP_INTERRUPT()         goto zend_interrupt_helper".($spec?"_SPEC":"").";\n");
1706							out($f,"#define ZEND_VM_DISPATCH(opcode, opline) goto *(void**)(zend_vm_get_opcode_handler(opcode, opline));\n");
1707							out($f,"\n");
1708							break;
1709					}
1710					break;
1711				case "EXECUTOR_NAME":
1712					out($f, $m[1].$executor_name.$m[3]."\n");
1713					break;
1714				case "HELPER_VARS":
1715					if ($kind != ZEND_VM_KIND_CALL) {
1716						if ($kind == ZEND_VM_KIND_SWITCH) {
1717							out($f,$m[1]."const void *dispatch_handler;\n");
1718						}
1719						// Emit local variables those are used for helpers' parameters
1720						foreach ($params as $param => $x) {
1721							out($f,$m[1].$param.";\n");
1722						}
1723						out($f,"#ifdef ZEND_VM_FP_GLOBAL_REG\n");
1724						out($f,$m[1]."register zend_execute_data *execute_data __asm__(ZEND_VM_FP_GLOBAL_REG) = ex;\n");
1725						out($f,"#else\n");
1726						out($f,$m[1]."zend_execute_data *execute_data = ex;\n");
1727						out($f,"#endif\n");
1728					} else {
1729						out($f,"#ifdef ZEND_VM_IP_GLOBAL_REG\n");
1730						out($f,$m[1]."const zend_op *orig_opline = opline;\n");
1731						out($f,"#endif\n");
1732						out($f,"#ifdef ZEND_VM_FP_GLOBAL_REG\n");
1733						out($f,$m[1]."zend_execute_data *orig_execute_data = execute_data;\n");
1734						out($f,$m[1]."execute_data = ex;\n");
1735						out($f,"#else\n");
1736						out($f,$m[1]."zend_execute_data *execute_data = ex;\n");
1737						out($f,"#endif\n");
1738					}
1739					break;
1740				case "INTERNAL_LABELS":
1741					if ($kind == ZEND_VM_KIND_GOTO) {
1742					  // Emit array of labels of opcode handlers and code for
1743					  // zend_opcode_handlers initialization
1744						$prolog = $m[1];
1745						out($f,$prolog."if (UNEXPECTED(execute_data == NULL)) {\n");
1746						out($f,$prolog."\tstatic const void* labels[] = {\n");
1747						gen_labels($f, $spec, $kind, $prolog."\t\t", $specs);
1748						out($f,$prolog."\t};\n");
1749						out($f,$prolog."static const uint32_t specs[] = {\n");
1750						gen_specs($f, $spec, $kind, $prolog."\t", $specs);
1751						out($f,$prolog."};\n");
1752						out($f,$prolog."\tzend_opcode_handlers = (const void **) labels;\n");
1753						out($f,$prolog."\tzend_handlers_count = sizeof(labels) / sizeof(void*);\n");
1754						out($f,$prolog."\tzend_spec_handlers = (const uint32_t *) specs;\n");
1755						out($f,$prolog."\treturn;\n");
1756						out($f,$prolog."}\n");
1757					} else {
1758						skip_blanks($f, $m[1], $m[3]);
1759					}
1760					break;
1761				case "ZEND_VM_CONTINUE_LABEL":
1762					if ($kind == ZEND_VM_KIND_CALL) {
1763					  // Only SWITCH dispatch method use it
1764						out($f,"#if !defined(ZEND_VM_FP_GLOBAL_REG) || !defined(ZEND_VM_IP_GLOBAL_REG)\n");
1765						out($f,$m[1]."\tint ret;".$m[3]."\n");
1766						out($f,"#endif\n");
1767					} else if ($kind == ZEND_VM_KIND_SWITCH) {
1768					  // Only SWITCH dispatch method use it
1769						out($f,"zend_vm_continue:".$m[3]."\n");
1770					} else {
1771						skip_blanks($f, $m[1], $m[3]);
1772					}
1773					break;
1774				case "ZEND_VM_DISPATCH":
1775				  // Emit code that dispatches to opcode handler
1776					switch ($kind) {
1777						case ZEND_VM_KIND_CALL:
1778							out($f,"#if defined(ZEND_VM_FP_GLOBAL_REG) && defined(ZEND_VM_IP_GLOBAL_REG)\n");
1779							out($f, $m[1]."((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n");
1780							out($f, $m[1]."if (UNEXPECTED(!OPLINE))".$m[3]."\n");
1781							out($f,"#else\n");
1782							out($f, $m[1]."if (UNEXPECTED((ret = ((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)) != 0))".$m[3]."\n");
1783							out($f,"#endif\n");
1784							break;
1785						case ZEND_VM_KIND_SWITCH:
1786							out($f, $m[1]."dispatch_handler = OPLINE->handler;\nzend_vm_dispatch:\n".$m[1]."switch ((int)(uintptr_t)dispatch_handler)".$m[3]."\n");
1787							break;
1788						case ZEND_VM_KIND_GOTO:
1789							out($f, $m[1]."goto *(void**)(OPLINE->handler);".$m[3]."\n");
1790							break;
1791					}
1792					break;
1793				case "INTERNAL_EXECUTOR":
1794					if ($kind == ZEND_VM_KIND_CALL) {
1795					  // Executor is defined as a set of functions
1796						out($f,
1797								"#ifdef ZEND_VM_FP_GLOBAL_REG\n" .
1798								$m[1]."execute_data = orig_execute_data;\n" .
1799								"# ifdef ZEND_VM_IP_GLOBAL_REG\n" .
1800								$m[1]."opline = orig_opline;\n" .
1801								"# endif\n" .
1802								$m[1]."return;\n" .
1803								"#else\n" .
1804								$m[1]."if (EXPECTED(ret > 0)) {\n" .
1805						        $m[1]."\texecute_data = EG(current_execute_data);\n".
1806								$m[1]."\tZEND_VM_LOOP_INTERRUPT_CHECK();\n".
1807						        $m[1]."} else {\n" .
1808								"# ifdef ZEND_VM_IP_GLOBAL_REG\n" .
1809						        $m[1]."\topline = orig_opline;\n" .
1810								"# endif\n".
1811						        $m[1]."\treturn;\n".
1812						        $m[1]."}\n".
1813								"#endif\n");
1814					} else {
1815					  // Emit executor code
1816						gen_executor_code($f, $spec, $kind, $m[1], $switch_labels);
1817					}
1818					break;
1819				case "EXTERNAL_EXECUTOR":
1820					if ($kind == ZEND_VM_KIND_CALL) {
1821						gen_executor_code($f, $spec, $kind, $m[1]);
1822					}
1823					break;
1824				case "INITIALIZER_NAME":
1825					out($f, $m[1].$initializer_name.$m[3]."\n");
1826					break;
1827				case "EXTERNAL_LABELS":
1828				  // Emit code that initializes zend_opcode_handlers array
1829					$prolog = $m[1];
1830					if ($kind == ZEND_VM_KIND_GOTO) {
1831					  // Labels are defined in the executor itself, so we call it
1832					  // with execute_data NULL and it sets zend_opcode_handlers array
1833						out($f,$prolog."");
1834						out($f,$prolog.$executor_name."_ex(NULL);\n");
1835					} else {
1836						out($f,$prolog."static const void *labels[] = {\n");
1837						gen_labels($f, $spec, $kind, $prolog."\t", $specs, $switch_labels);
1838						out($f,$prolog."};\n");
1839						out($f,$prolog."static const uint32_t specs[] = {\n");
1840						gen_specs($f, $spec, $kind, $prolog."\t", $specs);
1841						out($f,$prolog."};\n");
1842						out($f,$prolog."zend_opcode_handlers = labels;\n");
1843						out($f,$prolog."zend_handlers_count = sizeof(labels) / sizeof(void*);\n");
1844						out($f,$prolog."zend_spec_handlers = specs;\n");
1845					}
1846					break;
1847				default:
1848					die("ERROR: Unknown keyword ".$m[2]." in skeleton file.\n");
1849			}
1850		} else {
1851		  // Copy the line as is
1852			out($f, $line);
1853		}
1854	}
1855}
1856
1857function parse_operand_spec($def, $lineno, $str, &$flags) {
1858	global $vm_op_decode;
1859
1860	$flags = 0;
1861	$a = explode("|",$str);
1862	foreach($a as $val) {
1863		if (isset($vm_op_decode[$val])) {
1864			$flags |= $vm_op_decode[$val];
1865		} else {
1866			die("ERROR ($def:$lineno): Wrong operand type '$str'\n");
1867		}
1868	}
1869	if (!($flags & ZEND_VM_OP_SPEC)) {
1870		if (count($a) != 1) {
1871			die("ERROR ($def:$lineno): Wrong operand type '$str'\n");
1872		}
1873		$a = array("ANY");
1874	}
1875	return array_flip($a);
1876}
1877
1878function parse_ext_spec($def, $lineno, $str) {
1879	global $vm_ext_decode;
1880
1881	$flags = 0;
1882	$a = explode("|",$str);
1883	foreach($a as $val) {
1884		if (isset($vm_ext_decode[$val])) {
1885			$flags |= $vm_ext_decode[$val];
1886		} else {
1887			die("ERROR ($def:$lineno): Wrong extended_value type '$str'\n");
1888		}
1889	}
1890	return $flags;
1891}
1892
1893function parse_spec_rules($def, $lineno, $str) {
1894	global $used_extra_spec;
1895
1896	$ret = array();
1897	$a = explode(",", $str);
1898	foreach($a as $rule) {
1899		$n = strpos($rule, "=");
1900		if ($n !== false) {
1901			$id = trim(substr($rule, 0, $n));
1902			$val = trim(substr($rule, $n+1));
1903			switch ($id) {
1904				case "OP_DATA":
1905					$ret["OP_DATA"] = parse_operand_spec($def, $lineno, $val, $devnull);
1906					break;
1907				default:
1908					die("ERROR ($def:$lineno): Wrong specialization rules '$str'\n");
1909			}
1910			$used_extra_spec[$id] = 1;
1911		} else {
1912			switch ($rule) {
1913				case "RETVAL":
1914					$ret["RETVAL"] = array(0, 1);
1915					break;
1916				case "QUICK_ARG":
1917					$ret["QUICK_ARG"] = array(0, 1);
1918					break;
1919				case "SMART_BRANCH":
1920					$ret["SMART_BRANCH"] = array(0, 1, 2);
1921					break;
1922				case "DIM_OBJ":
1923					$ret["DIM_OBJ"] = array(0, 1, 2);
1924					break;
1925				case "NO_CONST_CONST":
1926					$ret["NO_CONST_CONST"] = array(1);
1927					break;
1928				case "COMMUTATIVE":
1929					$ret["COMMUTATIVE"] = array(1);
1930					break;
1931				default:
1932					die("ERROR ($def:$lineno): Wrong specialization rules '$str'\n");
1933			}
1934			$used_extra_spec[$rule] = 1;
1935		}
1936	}
1937	return $ret;
1938}
1939
1940function gen_vm($def, $skel) {
1941	global $definition_file, $skeleton_file, $executor_file,
1942		$op_types, $list, $opcodes, $helpers, $params, $opnames,
1943		$vm_op_flags, $used_extra_spec;
1944
1945	// Load definition file
1946	$in = @file($def);
1947	if (!$in) {
1948		die("ERROR: Can not open definition file '$def'\n");
1949	}
1950	// We need absolute path to definition file to use it in #line directives
1951	$definition_file = realpath($def);
1952
1953	// Load skeleton file
1954	$skl = @file($skel);
1955	if (!$skl) {
1956		die("ERROR: Can not open skeleton file '$skel'\n");
1957	}
1958	// We need absolute path to skeleton file to use it in #line directives
1959	$skeleton_file = realpath($skel);
1960
1961	// Parse definition file into tree
1962	$lineno         = 0;
1963	$handler        = null;
1964	$helper         = null;
1965	$max_opcode_len = 0;
1966	$max_opcode     = 0;
1967	$extra_num      = 256;
1968	$export         = array();
1969	foreach ($in as $line) {
1970		++$lineno;
1971		if (strpos($line,"ZEND_VM_HANDLER(") === 0) {
1972		  // Parsing opcode handler's definition
1973			if (preg_match(
1974					"/^ZEND_VM_HANDLER\(\s*([0-9]+)\s*,\s*([A-Z_]+)\s*,\s*([A-Z_|]+)\s*,\s*([A-Z_|]+)\s*(,\s*([A-Z_|]+)\s*)?(,\s*SPEC\(([A-Z_|=,]+)\)\s*)?\)/",
1975					$line,
1976					$m) == 0) {
1977				die("ERROR ($def:$lineno): Invalid ZEND_VM_HANDLER definition.\n");
1978			}
1979			$code = (int)$m[1];
1980			$op   = $m[2];
1981			$len  = strlen($op);
1982			$op1  = parse_operand_spec($def, $lineno, $m[3], $flags1);
1983			$op2  = parse_operand_spec($def, $lineno, $m[4], $flags2);
1984			$flags = $flags1 | ($flags2 << 8);
1985			if (!empty($m[6])) {
1986				$flags |= parse_ext_spec($def, $lineno, $m[6]);
1987			}
1988
1989			if ($len > $max_opcode_len) {
1990				$max_opcode_len = $len;
1991			}
1992			if ($code > $max_opcode) {
1993				$max_opcode = $code;
1994			}
1995			if (isset($opcodes[$code])) {
1996				die("ERROR ($def:$lineno): Opcode with code '$code' is already defined.\n");
1997			}
1998			if (isset($opnames[$op])) {
1999				die("ERROR ($def:$lineno): Opcode with name '$op' is already defined.\n");
2000			}
2001			$opcodes[$code] = array("op"=>$op,"op1"=>$op1,"op2"=>$op2,"code"=>"","flags"=>$flags);
2002			if (isset($m[8])) {
2003				$opcodes[$code]["spec"] = parse_spec_rules($def, $lineno, $m[8]);
2004				if (isset($opcodes[$code]["spec"]["NO_CONST_CONST"])) {
2005					$opcodes[$code]["flags"] |= $vm_op_flags["ZEND_VM_NO_CONST_CONST"];
2006				}
2007				if (isset($opcodes[$code]["spec"]["COMMUTATIVE"])) {
2008					$opcodes[$code]["flags"] |= $vm_op_flags["ZEND_VM_COMMUTATIVE"];
2009				}
2010			}
2011			$opnames[$op] = $code;
2012			$handler = $code;
2013			$helper = null;
2014			$list[$lineno] = array("handler"=>$handler);
2015		} else if (strpos($line,"ZEND_VM_TYPE_SPEC_HANDLER(") === 0) {
2016		  // Parsing opcode handler's definition
2017			if (preg_match(
2018					"/^ZEND_VM_TYPE_SPEC_HANDLER\(\s*([A-Z_]+)\s*,\s*([^,]+),\s*([A-Za-z_]+)\s*,\s*([A-Z_|]+)\s*,\s*([A-Z_|]+)\s*(,\s*([A-Z_|]+)\s*)?(,\s*SPEC\(([A-Z_|=,]+)\)\s*)?\)/",
2019					$line,
2020					$m) == 0) {
2021				die("ERROR ($def:$lineno): Invalid ZEND_VM_TYPE_HANDLER_HANDLER definition.\n");
2022			}
2023			$orig_op = $m[1];
2024			if (!isset($opnames[$orig_op])) {
2025				die("ERROR ($def:$lineno): Opcode with name '$orig_op' is not defined.\n");
2026			}
2027			$orig_code = $opnames[$orig_op];
2028			$condition = $m[2];
2029			$code = $extra_num++;
2030			$op = $m[3];
2031			$op1  = parse_operand_spec($def, $lineno, $m[4], $flags1);
2032			$op2  = parse_operand_spec($def, $lineno, $m[5], $flags2);
2033			$flags = $flags1 | ($flags2 << 8);
2034			if (!empty($m[7])) {
2035				$flags |= parse_ext_spec($def, $lineno, $m[7]);
2036			}
2037
2038			if (isset($opcodes[$code])) {
2039				die("ERROR ($def:$lineno): Opcode with name '$code' is already defined.\n");
2040			}
2041			$opcodes[$orig_code]['type_spec'][$code] = $condition;
2042			$used_extra_spec["TYPE"] = 1;
2043			$opcodes[$code] = array("op"=>$op,"op1"=>$op1,"op2"=>$op2,"code"=>"","flags"=>$flags);
2044			if (isset($m[9])) {
2045				$opcodes[$code]["spec"] = parse_spec_rules($def, $lineno, $m[9]);
2046				if (isset($opcodes[$code]["spec"]["NO_CONST_CONST"])) {
2047					$opcodes[$code]["flags"] |= $vm_op_flags["ZEND_VM_NO_CONST_CONST"];
2048				}
2049				if (isset($opcodes[$code]["spec"]["COMMUTATIVE"])) {
2050					$opcodes[$code]["flags"] |= $vm_op_flags["ZEND_VM_COMMUTATIVE"];
2051				}
2052			}
2053			$opnames[$op] = $code;
2054			$handler = $code;
2055			$helper = null;
2056			$list[$lineno] = array("handler"=>$handler);
2057		} else if (strpos($line,"ZEND_VM_HELPER(") === 0 || strpos($line,"ZEND_VM_INLINE_HELPER(") === 0) {
2058		  // Parsing helper's definition
2059			if (preg_match(
2060					"/^ZEND_VM(_INLINE)?_HELPER\(\s*([A-Za-z_]+)\s*,\s*([A-Z_|]+)\s*,\s*([A-Z_|]+)\s*(?:,\s*([^)]*))?\s*\)/",
2061					$line,
2062					$m) == 0) {
2063				die("ERROR ($def:$lineno): Invalid ZEND_VM_HELPER definition.\n");
2064			}
2065			$inline = !empty($m[1]);
2066			$helper = $m[2];
2067			$op1    = parse_operand_spec($def, $lineno, $m[3], $flags1);
2068			$op2    = parse_operand_spec($def, $lineno, $m[4], $flags2);
2069			$param  = isset($m[5]) ? $m[5] : null;
2070			if (isset($helpers[$helper])) {
2071				die("ERROR ($def:$lineno): Helper with name '$helper' is already defined.\n");
2072			}
2073
2074			// Store parameters
2075			foreach (explode(",", $param) as $p) {
2076				$p = trim($p);
2077				if ($p !== "") {
2078					$params[$p] = 1;
2079				}
2080			}
2081
2082			$helpers[$helper] = array("op1"=>$op1,"op2"=>$op2,"param"=>$param,"code"=>"","inline"=>$inline);
2083			$handler = null;
2084			$list[$lineno] = array("helper"=>$helper);
2085		} else if (strpos($line,"ZEND_VM_EXPORT_HANDLER(") === 0) {
2086			if (preg_match(
2087					"/^ZEND_VM_EXPORT_HANDLER\(\s*([A-Za-z_]+)\s*,\s*([A-Z_]+)\s*\)/",
2088					$line,
2089					$m) == 0) {
2090				die("ERROR ($def:$lineno): Invalid ZEND_VM_EXPORT_HANDLER definition.\n");
2091			}
2092			if (!isset($opnames[$m[2]])) {
2093				die("ERROR ($def:$lineno): opcode '{$m[2]}' is not defined.\n");
2094			}
2095			$export[] = array("handler",$m[1],$m[2]);
2096		} else if (strpos($line,"ZEND_VM_EXPORT_HELPER(") === 0) {
2097			if (preg_match(
2098					"/^ZEND_VM_EXPORT_HELPER\(\s*([A-Za-z_]+)\s*,\s*([A-Za-z_]+)\s*\)/",
2099					$line,
2100					$m) == 0) {
2101				die("ERROR ($def:$lineno): Invalid ZEND_VM_EXPORT_HELPER definition.\n");
2102			}
2103			if (!isset($helpers[$m[2]])) {
2104				die("ERROR ($def:$lineno): helper '{$m[2]}' is not defined.\n");
2105			}
2106			$export[] = array("helper",$m[1],$m[2]);
2107		} else if (strpos($line,"ZEND_VM_DEFINE_OP(") === 0) {
2108			if (preg_match(
2109					"/^ZEND_VM_DEFINE_OP\(\s*([0-9]+)\s*,\s*([A-Z_]+)\s*\);/",
2110					$line,
2111					$m) == 0) {
2112				die("ERROR ($def:$lineno): Invalid ZEND_VM_DEFINE_OP definition.\n");
2113			}
2114			$code = (int)$m[1];
2115			$op   = $m[2];
2116			$len  = strlen($op);
2117
2118			if ($len > $max_opcode_len) {
2119				$max_opcode_len = $len;
2120			}
2121			if ($code > $max_opcode) {
2122				$max_opcode = $code;
2123			}
2124			if (isset($opcodes[$code])) {
2125				die("ERROR ($def:$lineno): Opcode with code '$code' is already defined.\n");
2126			}
2127			if (isset($opnames[$op])) {
2128				die("ERROR ($def:$lineno): Opcode with name '$op' is already defined.\n");
2129			}
2130			$opcodes[$code] = array("op"=>$op,"code"=>"");
2131			$opnames[$op] = $code;
2132		} else if ($handler !== null) {
2133		  // Add line of code to current opcode handler
2134			$opcodes[$handler]["code"] .= $line;
2135		} else if ($helper !== null) {
2136		  // Add line of code to current helper
2137			$helpers[$helper]["code"] .= $line;
2138		}
2139	}
2140
2141	ksort($opcodes);
2142
2143	// Search for opcode handlers those are used by other opcode handlers
2144	foreach ($opcodes as $dsc) {
2145		if (preg_match("/ZEND_VM_DISPATCH_TO_HANDLER\(\s*([A-Z_]*)\s*\)/m", $dsc["code"], $m)) {
2146			$op = $m[1];
2147			if (!isset($opnames[$op])) {
2148				die("ERROR ($def:$lineno): Opcode with name '$op' is not defined.\n");
2149			}
2150			$code = $opnames[$op];
2151			$opcodes[$code]['use'] = 1;
2152		}
2153	}
2154
2155	// Generate opcode #defines (zend_vm_opcodes.h)
2156	$code_len = strlen((string)$max_opcode);
2157	$f = fopen(__DIR__ . "/zend_vm_opcodes.h", "w+") or die("ERROR: Cannot create zend_vm_opcodes.h\n");
2158
2159	// Insert header
2160	out($f, HEADER_TEXT);
2161	fputs($f, "#ifndef ZEND_VM_OPCODES_H\n#define ZEND_VM_OPCODES_H\n\n");
2162	fputs($f, "#define ZEND_VM_SPEC\t\t" . ZEND_VM_SPEC . "\n");
2163	fputs($f, "#define ZEND_VM_LINES\t\t" . ZEND_VM_LINES . "\n");
2164	fputs($f, "#define ZEND_VM_KIND_CALL\t" . ZEND_VM_KIND_CALL . "\n");
2165	fputs($f, "#define ZEND_VM_KIND_SWITCH\t" . ZEND_VM_KIND_SWITCH . "\n");
2166	fputs($f, "#define ZEND_VM_KIND_GOTO\t" . ZEND_VM_KIND_GOTO . "\n");
2167	fputs($f, "#define ZEND_VM_KIND\t\t" . $GLOBALS["vm_kind_name"][ZEND_VM_KIND] . "\n");
2168	fputs($f, "\n");
2169	foreach($vm_op_flags as $name => $val) {
2170		fprintf($f, "#define %-24s 0x%08x\n", $name, $val);
2171	}
2172	fputs($f, "#define ZEND_VM_OP1_FLAGS(flags) (flags & 0xff)\n");
2173	fputs($f, "#define ZEND_VM_OP2_FLAGS(flags) ((flags >> 8) & 0xff)\n");
2174	fputs($f, "\n");
2175	fputs($f, "BEGIN_EXTERN_C()\n\n");
2176	fputs($f, "ZEND_API const char *zend_get_opcode_name(zend_uchar opcode);\n");
2177	fputs($f, "ZEND_API uint32_t zend_get_opcode_flags(zend_uchar opcode);\n\n");
2178	fputs($f, "END_EXTERN_C()\n\n");
2179
2180	foreach ($opcodes as $code => $dsc) {
2181		$code = str_pad((string)$code,$code_len," ",STR_PAD_LEFT);
2182		$op = str_pad($dsc["op"],$max_opcode_len);
2183		if ($code <= $max_opcode) {
2184			fputs($f,"#define $op $code\n");
2185		}
2186	}
2187
2188	$code = str_pad((string)$max_opcode,$code_len," ",STR_PAD_LEFT);
2189	$op = str_pad("ZEND_VM_LAST_OPCODE",$max_opcode_len);
2190	fputs($f,"\n#define $op $code\n");
2191
2192	fputs($f, "\n#endif\n");
2193	fclose($f);
2194	echo "zend_vm_opcodes.h generated successfully.\n";
2195
2196	// zend_vm_opcodes.c
2197	$f = fopen(__DIR__ . "/zend_vm_opcodes.c", "w+") or die("ERROR: Cannot create zend_vm_opcodes.c\n");
2198
2199	// Insert header
2200	out($f, HEADER_TEXT);
2201	fputs($f,"#include <stdio.h>\n");
2202	fputs($f,"#include <zend.h>\n\n");
2203
2204	fputs($f,"static const char *zend_vm_opcodes_names[".($max_opcode + 1)."] = {\n");
2205	for ($i = 0; $i <= $max_opcode; $i++) {
2206		fputs($f,"\t".(isset($opcodes[$i]["op"])?'"'.$opcodes[$i]["op"].'"':"NULL").",\n");
2207	}
2208	fputs($f, "};\n\n");
2209
2210	fputs($f,"static uint32_t zend_vm_opcodes_flags[".($max_opcode + 1)."] = {\n");
2211	for ($i = 0; $i <= $max_opcode; $i++) {
2212		fprintf($f, "\t0x%08x,\n", isset($opcodes[$i]["flags"]) ? $opcodes[$i]["flags"] : 0);
2213	}
2214	fputs($f, "};\n\n");
2215
2216	fputs($f, "ZEND_API const char* zend_get_opcode_name(zend_uchar opcode) {\n");
2217	fputs($f, "\treturn zend_vm_opcodes_names[opcode];\n");
2218	fputs($f, "}\n");
2219
2220	fputs($f, "ZEND_API uint32_t zend_get_opcode_flags(zend_uchar opcode) {\n");
2221	fputs($f, "\treturn zend_vm_opcodes_flags[opcode];\n");
2222	fputs($f, "}\n");
2223
2224	fclose($f);
2225	echo "zend_vm_opcodes.c generated successfully.\n";
2226
2227	// Generate zend_vm_execute.h
2228	$f = fopen(__DIR__ . "/zend_vm_execute.h", "w+") or die("ERROR: Cannot create zend_vm_execute.h\n");
2229	$executor_file = realpath(__DIR__ . "/zend_vm_execute.h");
2230
2231	// Insert header
2232	out($f, HEADER_TEXT);
2233
2234	out($f, "#ifdef ZEND_WIN32\n");
2235	// Suppress free_op1 warnings on Windows
2236	out($f, "# pragma warning(once : 4101)\n");
2237	if (ZEND_VM_SPEC) {
2238		// Suppress (<non-zero constant> || <expression>) warnings on windows
2239		out($f, "# pragma warning(once : 6235)\n");
2240		// Suppress (<zero> && <expression>) warnings on windows
2241		out($f, "# pragma warning(once : 6237)\n");
2242		// Suppress (<non-zero constant> && <expression>) warnings on windows
2243		out($f, "# pragma warning(once : 6239)\n");
2244		// Suppress (<expression> && <non-zero constant>) warnings on windows
2245		out($f, "# pragma warning(once : 6240)\n");
2246		// Suppress (<non-zero constant> || <non-zero constant>) warnings on windows
2247		out($f, "# pragma warning(once : 6285)\n");
2248		// Suppress (<non-zero constant> || <expression>) warnings on windows
2249		out($f, "# pragma warning(once : 6286)\n");
2250		// Suppress constant with constant comparison warnings on windows
2251		out($f, "# pragma warning(once : 6326)\n");
2252	}
2253	out($f, "#endif\n");
2254
2255	// Support for ZEND_USER_OPCODE
2256	out($f, "static user_opcode_handler_t zend_user_opcode_handlers[256] = {\n");
2257	for ($i = 0; $i < 255; ++$i) {
2258		out($f, "\t(user_opcode_handler_t)NULL,\n");
2259	}
2260	out($f, "\t(user_opcode_handler_t)NULL\n};\n\n");
2261
2262	out($f, "static zend_uchar zend_user_opcodes[256] = {");
2263	for ($i = 0; $i < 255; ++$i) {
2264		if ($i % 16 == 1) out($f, "\n\t");
2265		out($f, "$i,");
2266	}
2267	out($f, "255\n};\n\n");
2268
2269	// Generate specialized executor
2270	gen_executor($f, $skl, ZEND_VM_SPEC, ZEND_VM_KIND, "execute", "zend_init_opcodes_handlers");
2271
2272	// Generate zend_vm_get_opcode_handler() function
2273	out($f, "static const void *zend_vm_get_opcode_handler_ex(uint32_t spec, const zend_op* op)\n");
2274	out($f, "{\n");
2275	if (!ZEND_VM_SPEC) {
2276		out($f, "\treturn zend_opcode_handlers[spec];\n");
2277	} else {
2278		out($f, "\tstatic const int zend_vm_decode[] = {\n");
2279		out($f, "\t\t_UNUSED_CODE, /* 0              */\n");
2280		out($f, "\t\t_CONST_CODE,  /* 1 = IS_CONST   */\n");
2281		out($f, "\t\t_TMP_CODE,    /* 2 = IS_TMP_VAR */\n");
2282		out($f, "\t\t_UNUSED_CODE, /* 3              */\n");
2283		out($f, "\t\t_VAR_CODE,    /* 4 = IS_VAR     */\n");
2284		out($f, "\t\t_UNUSED_CODE, /* 5              */\n");
2285		out($f, "\t\t_UNUSED_CODE, /* 6              */\n");
2286		out($f, "\t\t_UNUSED_CODE, /* 7              */\n");
2287		out($f, "\t\t_UNUSED_CODE, /* 8 = IS_UNUSED  */\n");
2288		out($f, "\t\t_UNUSED_CODE, /* 9              */\n");
2289		out($f, "\t\t_UNUSED_CODE, /* 10             */\n");
2290		out($f, "\t\t_UNUSED_CODE, /* 11             */\n");
2291		out($f, "\t\t_UNUSED_CODE, /* 12             */\n");
2292		out($f, "\t\t_UNUSED_CODE, /* 13             */\n");
2293		out($f, "\t\t_UNUSED_CODE, /* 14             */\n");
2294		out($f, "\t\t_UNUSED_CODE, /* 15             */\n");
2295		out($f, "\t\t_CV_CODE      /* 16 = IS_CV     */\n");
2296		out($f, "\t};\n");
2297		out($f, "\tuint32_t offset = 0;\n");
2298		out($f, "\tif (spec & SPEC_RULE_OP1) offset = offset * 5 + zend_vm_decode[op->op1_type];\n");
2299		out($f, "\tif (spec & SPEC_RULE_OP2) offset = offset * 5 + zend_vm_decode[op->op2_type];\n");
2300		if (isset($used_extra_spec["OP_DATA"])) {
2301			out($f, "\tif (spec & SPEC_RULE_OP_DATA) offset = offset * 5 + zend_vm_decode[(op + 1)->op1_type];\n");
2302		}
2303		if (isset($used_extra_spec["RETVAL"])) {
2304			out($f, "\tif (spec & SPEC_RULE_RETVAL) offset = offset * 2 + (op->result_type != IS_UNUSED);\n");
2305		}
2306		if (isset($used_extra_spec["QUICK_ARG"])) {
2307			out($f, "\tif (spec & SPEC_RULE_QUICK_ARG) offset = offset * 2 + (op->op2.num < MAX_ARG_FLAG_NUM);\n");
2308		}
2309		if (isset($used_extra_spec["SMART_BRANCH"])) {
2310			out($f, "\tif (spec & SPEC_RULE_SMART_BRANCH) {\n");
2311			out($f,	"\t\toffset = offset * 3;\n");
2312			out($f, "\t\tif ((op+1)->opcode == ZEND_JMPZ) {\n");
2313			out($f,	"\t\t\toffset += 1;\n");
2314			out($f, "\t\t} else if ((op+1)->opcode == ZEND_JMPNZ) {\n");
2315			out($f,	"\t\t\toffset += 2;\n");
2316			out($f, "\t\t}\n");
2317			out($f, "\t}\n");
2318		}
2319		if (isset($used_extra_spec["DIM_OBJ"])) {
2320			out($f, "\tif (spec & SPEC_RULE_DIM_OBJ) {\n");
2321			out($f,	"\t\toffset = offset * 3;\n");
2322			out($f, "\t\tif (op->extended_value == ZEND_ASSIGN_DIM) {\n");
2323			out($f,	"\t\t\toffset += 1;\n");
2324			out($f, "\t\t} else if (op->extended_value == ZEND_ASSIGN_OBJ) {\n");
2325			out($f,	"\t\t\toffset += 2;\n");
2326			out($f, "\t\t}\n");
2327			out($f, "\t}\n");
2328		}
2329		out($f, "\treturn zend_opcode_handlers[(spec & SPEC_START_MASK) + offset];\n");
2330	}
2331	out($f, "}\n\n");
2332	out($f, "static const void *zend_vm_get_opcode_handler(zend_uchar opcode, const zend_op* op)\n");
2333	out($f, "{\n");
2334	if (!ZEND_VM_SPEC) {
2335		out($f, "\treturn zend_vm_get_opcode_handler_ex(opcode, op);\n");
2336	} else {
2337		out($f, "\treturn zend_vm_get_opcode_handler_ex(zend_spec_handlers[opcode], op);\n");
2338	}
2339	out($f, "}\n\n");
2340
2341	// Generate zend_vm_get_opcode_handler() function
2342	out($f, "ZEND_API void zend_vm_set_opcode_handler(zend_op* op)\n");
2343	out($f, "{\n");
2344	out($f, "\top->handler = zend_vm_get_opcode_handler(zend_user_opcodes[op->opcode], op);\n");
2345	out($f, "}\n\n");
2346
2347	// Generate zend_vm_set_opcode_handler_ex() function
2348	out($f, "ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint32_t op2_info, uint32_t res_info)\n");
2349	out($f, "{\n");
2350	out($f, "\tzend_uchar opcode = zend_user_opcodes[op->opcode];\n");
2351	if (!ZEND_VM_SPEC) {
2352		out($f, "\top->handler = zend_vm_get_opcode_handler_ex(opcode, op);\n");
2353	} else {
2354		out($f, "\tuint32_t spec = zend_spec_handlers[opcode];\n");
2355		if (isset($used_extra_spec["TYPE"])) {
2356			out($f, "\tswitch (opcode) {\n");
2357			foreach($opcodes as $code => $dsc) {
2358				if (isset($dsc['type_spec'])) {
2359					$orig_op = $dsc['op'];
2360					out($f, "\t\tcase $orig_op:\n");
2361					$first = true;
2362					foreach($dsc['type_spec'] as $code => $condition) {
2363						$condition = format_condition($condition);
2364						if ($first) {
2365							out($f, "\t\t\tif $condition {\n");
2366							$first = false;
2367						} else {
2368							out($f, "\t\t\t} else if $condition {\n");
2369						}
2370						$spec_dsc = $opcodes[$code];
2371						if (isset($spec_dsc["spec"]["NO_CONST_CONST"])) {
2372							out($f, "\t\t\t\tif (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {\n");
2373							out($f, "\t\t\t\t\tbreak;\n");
2374							out($f, "\t\t\t\t}\n");
2375						}
2376						out($f, "\t\t\t\tspec = ${spec_dsc['spec_code']};\n");
2377						if (isset($spec_dsc["spec"]["COMMUTATIVE"])) {
2378							out($f, "\t\t\t\tif (op->op1_type > op->op2_type) {\n");
2379							out($f, "\t\t\t\t\tzend_swap_operands(op);\n");
2380							out($f, "\t\t\t\t}\n");
2381						}
2382					}
2383					if (!$first) {
2384						out($f, "\t\t\t}\n");
2385					}
2386					out($f, "\t\t\tbreak;\n");
2387				}
2388			}
2389			out($f, "\t\tdefault:\n");
2390			out($f, "\t\t\tbreak;\n");
2391			out($f, "\t}\n");
2392		}
2393		out($f, "\top->handler = zend_vm_get_opcode_handler_ex(spec, op);\n");
2394	}
2395	out($f, "}\n\n");
2396
2397	// Generate zend_vm_call_opcode_handler() function
2398	if (ZEND_VM_KIND == ZEND_VM_KIND_CALL) {
2399		out($f, "ZEND_API int zend_vm_call_opcode_handler(zend_execute_data* ex)\n");
2400		out($f, "{\n");
2401		out($f, "\tint ret;\n");
2402		out($f, "#ifdef ZEND_VM_IP_GLOBAL_REG\n");
2403		out($f, "\tconst zend_op *orig_opline = opline;\n");
2404		out($f, "#endif\n");
2405		out($f, "#ifdef ZEND_VM_FP_GLOBAL_REG\n");
2406		out($f, "\tzend_execute_data *orig_execute_data = execute_data;\n");
2407		out($f, "\texecute_data = ex;\n");
2408		out($f, "#else\n");
2409		out($f, "\tzend_execute_data *execute_data = ex;\n");
2410		out($f, "#endif\n");
2411		out($f, "\n");
2412		out($f, "\tLOAD_OPLINE();\n");
2413		out($f,"#if defined(ZEND_VM_FP_GLOBAL_REG) && defined(ZEND_VM_IP_GLOBAL_REG)\n");
2414		out($f, "\t((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n");
2415		out($f, "\tif (EXPECTED(opline)) {\n");
2416		out($f, "\t\tret = execute_data != ex ? (int)(execute_data->prev_execute_data != ex) + 1 : 0;\n");
2417		out($f, "\t\tSAVE_OPLINE();\n");
2418		out($f, "\t} else {\n");
2419		out($f, "\t\tret = -1;\n");
2420		out($f, "\t}\n");
2421		out($f, "#else\n");
2422		out($f, "\tret = ((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n");
2423		out($f, "\tSAVE_OPLINE();\n");
2424		out($f, "#endif\n");
2425		out($f, "#ifdef ZEND_VM_FP_GLOBAL_REG\n");
2426		out($f, "\texecute_data = orig_execute_data;\n");
2427		out($f, "#endif\n");
2428		out($f, "#ifdef ZEND_VM_IP_GLOBAL_REG\n");
2429		out($f, "\topline = orig_opline;\n");
2430		out($f, "#endif\n");
2431		out($f, "\treturn ret;\n");
2432		out($f, "}\n\n");
2433	} else {
2434		out($f, "ZEND_API int zend_vm_call_opcode_handler(zend_execute_data* ex)\n");
2435		out($f, "{\n");
2436		out($f, "\tzend_error_noreturn(E_CORE_ERROR, \"zend_vm_call_opcode_handler() is not supported\");\n");
2437		out($f, "\treturn 0;\n");
2438		out($f, "}\n\n");
2439	}
2440
2441	// Export handlers and helpers
2442	if (count($export) > 0 &&
2443	    ZEND_VM_KIND != ZEND_VM_KIND_CALL) {
2444		out($f,"#undef OPLINE\n");
2445		out($f,"#undef DCL_OPLINE\n");
2446		out($f,"#undef USE_OPLINE\n");
2447		out($f,"#undef LOAD_OPLINE\n");
2448		out($f,"#undef LOAD_NEXT_OPLINE\n");
2449		out($f,"#undef SAVE_OPLINE\n");
2450		out($f,"#define OPLINE EX(opline)\n");
2451		out($f,"#define DCL_OPLINE\n");
2452		out($f,"#define USE_OPLINE const zend_op *opline = EX(opline);\n");
2453		out($f,"#define LOAD_OPLINE()\n");
2454		out($f,"#define LOAD_NEXT_OPLINE() ZEND_VM_INC_OPCODE()\n");
2455		out($f,"#define SAVE_OPLINE()\n");
2456		out($f,"#undef HANDLE_EXCEPTION\n");
2457		out($f,"#undef HANDLE_EXCEPTION_LEAVE\n");
2458		out($f,"#define HANDLE_EXCEPTION() LOAD_OPLINE(); ZEND_VM_CONTINUE()\n");
2459		out($f,"#define HANDLE_EXCEPTION_LEAVE() LOAD_OPLINE(); ZEND_VM_LEAVE()\n");
2460		out($f,"#undef ZEND_VM_CONTINUE\n");
2461		out($f,"#undef ZEND_VM_RETURN\n");
2462		out($f,"#undef ZEND_VM_ENTER\n");
2463		out($f,"#undef ZEND_VM_LEAVE\n");
2464		out($f,"#undef ZEND_VM_DISPATCH\n");
2465		out($f,"#define ZEND_VM_CONTINUE()   return  0\n");
2466		out($f,"#define ZEND_VM_RETURN()     return -1\n");
2467		out($f,"#define ZEND_VM_ENTER()      return  1\n");
2468		out($f,"#define ZEND_VM_LEAVE()      return  2\n");
2469		out($f,"#define ZEND_VM_INTERRUPT()  return zend_interrupt_helper(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n");
2470		out($f,"#define ZEND_VM_DISPATCH(opcode, opline) return zend_vm_get_opcode_handler(opcode, opline)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n\n");
2471		out($f,"\n");
2472	}
2473	foreach ($export as $dsk) {
2474		list($kind, $func, $name) = $dsk;
2475		out($f, "ZEND_API int $func(");
2476		if ($kind == "handler") {
2477			out($f, "ZEND_OPCODE_HANDLER_ARGS)\n");
2478			$code = $opcodes[$opnames[$name]]['code'];
2479		} else {
2480			$h = $helpers[$name];
2481			if ($h['param'] == null) {
2482				out($f, "ZEND_OPCODE_HANDLER_ARGS)\n");
2483			} else {
2484				out($f, $h['param']. " ZEND_OPCODE_HANDLER_ARGS_DC)\n");
2485			}
2486			$code = $h['code'];
2487		}
2488		$done = 0;
2489		if (ZEND_VM_KIND == ZEND_VM_KIND_CALL) {
2490			if ($kind == "handler") {
2491				$op = $opcodes[$opnames[$name]];
2492				if (isset($op['op1']["ANY"]) && isset($op['op2']["ANY"])) {
2493					out($f, "{\n\treturn ".$name.(ZEND_VM_SPEC?"_SPEC":"")."_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n}\n\n");
2494					$done = 1;
2495				}
2496			} else if ($helpers[$name]["param"] == null) {
2497				$h = $helpers[$name];
2498				if (isset($h['op1']["ANY"]) && isset($h['op2']["ANY"])) {
2499					out($f, "{\n\treturn ".$name.(ZEND_VM_SPEC?"_SPEC":"")."(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n}\n\n");
2500					$done = 1;
2501				}
2502			}
2503		}
2504		if (!$done) {
2505			gen_code($f, 0, ZEND_VM_KIND_CALL, 1, $code, 'ANY', 'ANY', $name);
2506		}
2507	}
2508
2509	fclose($f);
2510	echo "zend_vm_execute.h generated successfully.\n";
2511}
2512
2513function usage() {
2514	echo("\nUsage: php zend_vm_gen.php [options]\n".
2515	     "\nOptions:".
2516	     "\n  --with-vm-kind=CALL|SWITCH|GOTO - select threading model (default is CALL)".
2517	     "\n  --without-specializer           - disable executor specialization".
2518	     "\n  --with-lines                    - enable #line directives".
2519	     "\n\n");
2520}
2521
2522// Parse arguments
2523for ($i = 1; $i < $argc; $i++) {
2524	if (strpos($argv[$i],"--with-vm-kind=") === 0) {
2525		$kind = substr($argv[$i], strlen("--with-vm-kind="));
2526		switch ($kind) {
2527			case "CALL":
2528				define("ZEND_VM_KIND", ZEND_VM_KIND_CALL);
2529				break;
2530			case "SWITCH":
2531				define("ZEND_VM_KIND", ZEND_VM_KIND_SWITCH);
2532				break;
2533			case "GOTO":
2534				define("ZEND_VM_KIND", ZEND_VM_KIND_GOTO);
2535				break;
2536			default:
2537				echo("ERROR: Invalid vm kind '$kind'\n");
2538				usage();
2539				die();
2540		}
2541	} else if ($argv[$i] == "--without-specializer") {
2542		// Disabling specialization
2543		define("ZEND_VM_SPEC", 0);
2544	} else if ($argv[$i] == "--with-lines") {
2545		// Enabling debugging using original zend_vm_def.h
2546		define("ZEND_VM_LINES", 1);
2547	} else if ($argv[$i] == "--help") {
2548		usage();
2549		exit();
2550	} else {
2551		echo("ERROR: Invalid option '".$argv[$i]."'\n");
2552		usage();
2553		die();
2554	}
2555}
2556
2557// Using defaults
2558if (!defined("ZEND_VM_KIND")) {
2559	// Using CALL threading by default
2560	define("ZEND_VM_KIND", ZEND_VM_KIND_CALL);
2561}
2562if (!defined("ZEND_VM_SPEC")) {
2563	// Using specialized executor by default
2564	define("ZEND_VM_SPEC", 1);
2565}
2566if (!defined("ZEND_VM_LINES")) {
2567	// Disabling #line directives
2568	define("ZEND_VM_LINES", 0);
2569}
2570
2571gen_vm(__DIR__ . "/zend_vm_def.h", __DIR__ . "/zend_vm_execute.skl");
2572