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