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