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