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