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