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