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