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