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