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