1<?php 2/* 3 +----------------------------------------------------------------------+ 4 | Zend Engine | 5 +----------------------------------------------------------------------+ 6 | Copyright (c) 1998-2017 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 22$header_text = <<< DATA 23/* 24 +----------------------------------------------------------------------+ 25 | Zend Engine | 26 +----------------------------------------------------------------------+ 27 | Copyright (c) 1998-2017 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 53define("ZEND_VM_KIND_CALL", 1); 54define("ZEND_VM_KIND_SWITCH", 2); 55define("ZEND_VM_KIND_GOTO", 3); 56 57$vm_kind_name = array( 58 ZEND_VM_KIND_CALL => "ZEND_VM_KIND_CALL", 59 ZEND_VM_KIND_SWITCH => "ZEND_VM_KIND_SWITCH", 60 ZEND_VM_KIND_GOTO => "ZEND_VM_KIND_GOTO", 61); 62 63$op_types = array( 64 "ANY", 65 "CONST", 66 "TMP", 67 "VAR", 68 "UNUSED", 69 "CV" 70); 71 72$op_types_ex = array( 73 "ANY", 74 "CONST", 75 "TMP", 76 "VAR", 77 "UNUSED", 78 "CV", 79 "TMPVAR", 80); 81 82$prefix = array( 83 "ANY" => "", 84 "TMP" => "_TMP", 85 "VAR" => "_VAR", 86 "CONST" => "_CONST", 87 "UNUSED" => "_UNUSED", 88 "CV" => "_CV", 89 "TMPVAR" => "_TMPVAR", 90); 91 92$typecode = array( 93 "ANY" => 0, 94 "TMP" => 1, 95 "VAR" => 2, 96 "CONST" => 0, 97 "UNUSED" => 3, 98 "CV" => 4, 99 "TMPVAR" => 0, 100); 101 102$op1_type = array( 103 "ANY" => "opline->op1_type", 104 "TMP" => "IS_TMP_VAR", 105 "VAR" => "IS_VAR", 106 "CONST" => "IS_CONST", 107 "UNUSED" => "IS_UNUSED", 108 "CV" => "IS_CV", 109 "TMPVAR" => "(IS_TMP_VAR|IS_VAR)", 110); 111 112$op2_type = array( 113 "ANY" => "opline->op2_type", 114 "TMP" => "IS_TMP_VAR", 115 "VAR" => "IS_VAR", 116 "CONST" => "IS_CONST", 117 "UNUSED" => "IS_UNUSED", 118 "CV" => "IS_CV", 119 "TMPVAR" => "(IS_TMP_VAR|IS_VAR)", 120); 121 122$op1_free = array( 123 "ANY" => "(free_op1 != NULL)", 124 "TMP" => "1", 125 "VAR" => "(free_op1 != NULL)", 126 "CONST" => "0", 127 "UNUSED" => "0", 128 "CV" => "0", 129 "TMPVAR" => "???", 130); 131 132$op2_free = array( 133 "ANY" => "(free_op2 != NULL)", 134 "TMP" => "1", 135 "VAR" => "(free_op2 != NULL)", 136 "CONST" => "0", 137 "UNUSED" => "0", 138 "CV" => "0", 139 "TMPVAR" => "???", 140); 141 142$op1_get_zval_ptr = array( 143 "ANY" => "get_zval_ptr(opline->op1_type, opline->op1, execute_data, &free_op1, \\1)", 144 "TMP" => "_get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1)", 145 "VAR" => "_get_zval_ptr_var(opline->op1.var, execute_data, &free_op1)", 146 "CONST" => "EX_CONSTANT(opline->op1)", 147 "UNUSED" => "NULL", 148 "CV" => "_get_zval_ptr_cv_\\1(execute_data, opline->op1.var)", 149 "TMPVAR" => "_get_zval_ptr_var(opline->op1.var, execute_data, &free_op1)", 150); 151 152$op2_get_zval_ptr = array( 153 "ANY" => "get_zval_ptr(opline->op2_type, opline->op2, execute_data, &free_op2, \\1)", 154 "TMP" => "_get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2)", 155 "VAR" => "_get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)", 156 "CONST" => "EX_CONSTANT(opline->op2)", 157 "UNUSED" => "NULL", 158 "CV" => "_get_zval_ptr_cv_\\1(execute_data, opline->op2.var)", 159 "TMPVAR" => "_get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)", 160); 161 162$op1_get_zval_ptr_ptr = array( 163 "ANY" => "get_zval_ptr_ptr(opline->op1_type, opline->op1, execute_data, &free_op1, \\1)", 164 "TMP" => "NULL", 165 "VAR" => "_get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1)", 166 "CONST" => "NULL", 167 "UNUSED" => "NULL", 168 "CV" => "_get_zval_ptr_cv_\\1(execute_data, opline->op1.var)", 169 "TMPVAR" => "???", 170); 171 172$op2_get_zval_ptr_ptr = array( 173 "ANY" => "get_zval_ptr_ptr(opline->op2_type, opline->op2, execute_data, &free_op2, \\1)", 174 "TMP" => "NULL", 175 "VAR" => "_get_zval_ptr_ptr_var(opline->op2.var, execute_data, &free_op2)", 176 "CONST" => "NULL", 177 "UNUSED" => "NULL", 178 "CV" => "_get_zval_ptr_cv_\\1(execute_data, opline->op2.var)", 179 "TMPVAR" => "???", 180); 181 182$op1_get_zval_ptr_deref = array( 183 "ANY" => "get_zval_ptr_deref(opline->op1_type, opline->op1, execute_data, &free_op1, \\1)", 184 "TMP" => "_get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1)", 185 "VAR" => "_get_zval_ptr_var_deref(opline->op1.var, execute_data, &free_op1)", 186 "CONST" => "EX_CONSTANT(opline->op1)", 187 "UNUSED" => "NULL", 188 "CV" => "_get_zval_ptr_cv_deref_\\1(execute_data, opline->op1.var)", 189 "TMPVAR" => "???", 190); 191 192$op2_get_zval_ptr_deref = array( 193 "ANY" => "get_zval_ptr_deref(opline->op2_type, opline->op2, execute_data, &free_op2, \\1)", 194 "TMP" => "_get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2)", 195 "VAR" => "_get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2)", 196 "CONST" => "EX_CONSTANT(opline->op2)", 197 "UNUSED" => "NULL", 198 "CV" => "_get_zval_ptr_cv_deref_\\1(execute_data, opline->op2.var)", 199 "TMPVAR" => "???", 200); 201 202$op1_get_zval_ptr_undef = array( 203 "ANY" => "get_zval_ptr_undef(opline->op1_type, opline->op1, execute_data, &free_op1, \\1)", 204 "TMP" => "_get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1)", 205 "VAR" => "_get_zval_ptr_var(opline->op1.var, execute_data, &free_op1)", 206 "CONST" => "EX_CONSTANT(opline->op1)", 207 "UNUSED" => "NULL", 208 "CV" => "_get_zval_ptr_cv_undef(execute_data, opline->op1.var)", 209 "TMPVAR" => "_get_zval_ptr_var(opline->op1.var, execute_data, &free_op1)", 210); 211 212$op2_get_zval_ptr_undef = array( 213 "ANY" => "get_zval_ptr_undef(opline->op2_type, opline->op2, execute_data, &free_op2, \\1)", 214 "TMP" => "_get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2)", 215 "VAR" => "_get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)", 216 "CONST" => "EX_CONSTANT(opline->op2)", 217 "UNUSED" => "NULL", 218 "CV" => "_get_zval_ptr_cv_undef(execute_data, opline->op2.var)", 219 "TMPVAR" => "_get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)", 220); 221 222$op1_get_zval_ptr_ptr_undef = array( 223 "ANY" => "get_zval_ptr_ptr_undef(opline->op1_type, opline->op1, execute_data, &free_op1, \\1)", 224 "TMP" => "NULL", 225 "VAR" => "_get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1)", 226 "CONST" => "NULL", 227 "UNUSED" => "NULL", 228 "CV" => "_get_zval_ptr_cv_undef_\\1(execute_data, opline->op1.var)", 229 "TMPVAR" => "???", 230); 231 232$op2_get_zval_ptr_ptr_undef = array( 233 "ANY" => "get_zval_ptr_ptr_undef(opline->op2_type, opline->op2, execute_data, &free_op2, \\1)", 234 "TMP" => "NULL", 235 "VAR" => "_get_zval_ptr_ptr_var(opline->op2.var, execute_data, &free_op2)", 236 "CONST" => "NULL", 237 "UNUSED" => "NULL", 238 "CV" => "_get_zval_ptr_cv_undef_\\1(execute_data, opline->op2.var)", 239 "TMPVAR" => "???", 240); 241 242$op1_get_obj_zval_ptr = array( 243 "ANY" => "get_obj_zval_ptr(opline->op1_type, opline->op1, execute_data, &free_op1, \\1)", 244 "TMP" => "_get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1)", 245 "VAR" => "_get_zval_ptr_var(opline->op1.var, execute_data, &free_op1)", 246 "CONST" => "EX_CONSTANT(opline->op1)", 247 "UNUSED" => "_get_obj_zval_ptr_unused(execute_data)", 248 "CV" => "_get_zval_ptr_cv_\\1(execute_data, opline->op1.var)", 249 "TMPVAR" => "_get_zval_ptr_var(opline->op1.var, execute_data, &free_op1)", 250); 251 252$op2_get_obj_zval_ptr = array( 253 "ANY" => "get_obj_zval_ptr(opline->op2_type, opline->op2, execute_data, &free_op2, \\1)", 254 "TMP" => "_get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2)", 255 "VAR" => "_get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)", 256 "CONST" => "EX_CONSTANT(opline->op2)", 257 "UNUSED" => "_get_obj_zval_ptr_unused(execute_data)", 258 "CV" => "_get_zval_ptr_cv_\\1(execute_data, opline->op2.var)", 259 "TMPVAR" => "_get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)", 260); 261 262$op1_get_obj_zval_ptr_undef = array( 263 "ANY" => "get_obj_zval_ptr_undef(opline->op1_type, opline->op1, execute_data, &free_op1, \\1)", 264 "TMP" => "_get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1)", 265 "VAR" => "_get_zval_ptr_var(opline->op1.var, execute_data, &free_op1)", 266 "CONST" => "EX_CONSTANT(opline->op1)", 267 "UNUSED" => "_get_obj_zval_ptr_unused(execute_data)", 268 "CV" => "_get_zval_ptr_cv_undef(execute_data, opline->op1.var)", 269 "TMPVAR" => "_get_zval_ptr_var(opline->op1.var, execute_data, &free_op1)", 270); 271 272$op2_get_obj_zval_ptr_undef = array( 273 "ANY" => "get_obj_zval_ptr_undef(opline->op2_type, opline->op2, execute_data, &free_op2, \\1)", 274 "TMP" => "_get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2)", 275 "VAR" => "_get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)", 276 "CONST" => "EX_CONSTANT(opline->op2)", 277 "UNUSED" => "_get_obj_zval_ptr_unused(execute_data)", 278 "CV" => "_get_zval_ptr_cv_undef(execute_data, opline->op2.var)", 279 "TMPVAR" => "_get_zval_ptr_var(opline->op2.var, execute_data, &free_op2)", 280); 281 282$op1_get_obj_zval_ptr_deref = array( 283 "ANY" => "get_obj_zval_ptr(opline->op1_type, opline->op1, execute_data, &free_op1, \\1)", 284 "TMP" => "_get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1)", 285 "VAR" => "_get_zval_ptr_var_deref(opline->op1.var, execute_data, &free_op1)", 286 "CONST" => "EX_CONSTANT(opline->op1)", 287 "UNUSED" => "_get_obj_zval_ptr_unused(execute_data)", 288 "CV" => "_get_zval_ptr_cv_deref_\\1(execute_data, opline->op1.var)", 289 "TMPVAR" => "???", 290); 291 292$op2_get_obj_zval_ptr_deref = array( 293 "ANY" => "get_obj_zval_ptr(opline->op2_type, opline->op2, execute_data, &free_op2, \\1)", 294 "TMP" => "_get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2)", 295 "VAR" => "_get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2)", 296 "CONST" => "EX_CONSTANT(opline->op2)", 297 "UNUSED" => "_get_obj_zval_ptr_unused(execute_data)", 298 "CV" => "_get_zval_ptr_cv_deref_\\1(execute_data, opline->op2.var)", 299 "TMPVAR" => "???", 300); 301 302$op1_get_obj_zval_ptr_ptr = array( 303 "ANY" => "get_obj_zval_ptr_ptr(opline->op1_type, opline->op1, execute_data, &free_op1, \\1)", 304 "TMP" => "NULL", 305 "VAR" => "_get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1)", 306 "CONST" => "NULL", 307 "UNUSED" => "_get_obj_zval_ptr_unused(execute_data)", 308 "CV" => "_get_zval_ptr_cv_\\1(execute_data, opline->op1.var)", 309 "TMPVAR" => "???", 310); 311 312$op2_get_obj_zval_ptr_ptr = array( 313 "ANY" => "get_obj_zval_ptr_ptr(opline->op2_type, opline->op2, execute_data, &free_op2, \\1)", 314 "TMP" => "NULL", 315 "VAR" => "_get_zval_ptr_ptr_var(opline->op2.var, execute_data, &free_op2)", 316 "CONST" => "NULL", 317 "UNUSED" => "_get_obj_zval_ptr_unused(execute_data)", 318 "CV" => "_get_zval_ptr_cv_\\1(execute_data, opline->op2.var)", 319 "TMPVAR" => "???", 320); 321 322$op1_get_obj_zval_ptr_ptr_undef = array( 323 "ANY" => "get_obj_zval_ptr_ptr(opline->op1_type, opline->op1, execute_data, &free_op1, \\1)", 324 "TMP" => "NULL", 325 "VAR" => "_get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1)", 326 "CONST" => "NULL", 327 "UNUSED" => "_get_obj_zval_ptr_unused(execute_data)", 328 "CV" => "_get_zval_ptr_cv_undef_\\1(execute_data, opline->op1.var)", 329 "TMPVAR" => "???", 330); 331 332$op2_get_obj_zval_ptr_ptr_undef = array( 333 "ANY" => "get_obj_zval_ptr_ptr(opline->op2_type, opline->op2, execute_data, &free_op2, \\1)", 334 "TMP" => "NULL", 335 "VAR" => "_get_zval_ptr_ptr_var(opline->op2.var, execute_data, &free_op2)", 336 "CONST" => "NULL", 337 "UNUSED" => "_get_obj_zval_ptr_unused(execute_data)", 338 "CV" => "_get_zval_ptr_cv_undef_\\1(execute_data, opline->op2.var)", 339 "TMPVAR" => "???", 340); 341 342$op1_free_op = array( 343 "ANY" => "FREE_OP(free_op1)", 344 "TMP" => "zval_ptr_dtor_nogc(free_op1)", 345 "VAR" => "zval_ptr_dtor_nogc(free_op1)", 346 "CONST" => "", 347 "UNUSED" => "", 348 "CV" => "", 349 "TMPVAR" => "zval_ptr_dtor_nogc(free_op1)", 350); 351 352$op2_free_op = array( 353 "ANY" => "FREE_OP(free_op2)", 354 "TMP" => "zval_ptr_dtor_nogc(free_op2)", 355 "VAR" => "zval_ptr_dtor_nogc(free_op2)", 356 "CONST" => "", 357 "UNUSED" => "", 358 "CV" => "", 359 "TMPVAR" => "zval_ptr_dtor_nogc(free_op2)", 360); 361 362$op1_free_op_if_var = array( 363 "ANY" => "if (opline->op1_type == IS_VAR) {zval_ptr_dtor_nogc(free_op1);}", 364 "TMP" => "", 365 "VAR" => "zval_ptr_dtor_nogc(free_op1)", 366 "CONST" => "", 367 "UNUSED" => "", 368 "CV" => "", 369 "TMPVAR" => "???", 370); 371 372$op2_free_op_if_var = array( 373 "ANY" => "if (opline->op2_type == IS_VAR) {zval_ptr_dtor_nogc(free_op2);}", 374 "TMP" => "", 375 "VAR" => "zval_ptr_dtor_nogc(free_op2)", 376 "CONST" => "", 377 "UNUSED" => "", 378 "CV" => "", 379 "TMPVAR" => "???", 380); 381 382$op1_free_op_var_ptr = array( 383 "ANY" => "if (free_op1) {zval_ptr_dtor_nogc(free_op1);}", 384 "TMP" => "", 385 "VAR" => "if (UNEXPECTED(free_op1)) {zval_ptr_dtor_nogc(free_op1);}", 386 "CONST" => "", 387 "UNUSED" => "", 388 "CV" => "", 389 "TMPVAR" => "???", 390); 391 392$op2_free_op_var_ptr = array( 393 "ANY" => "if (free_op2) {zval_ptr_dtor_nogc(free_op2);}", 394 "TMP" => "", 395 "VAR" => "if (UNEXPECTED(free_op2)) {zval_ptr_dtor_nogc(free_op2);}", 396 "CONST" => "", 397 "UNUSED" => "", 398 "CV" => "", 399 "TMPVAR" => "???", 400); 401 402$op1_free_unfetched = array( 403 "ANY" => "FREE_UNFETCHED_OP(opline->op1_type, opline->op1.var)", 404 "TMP" => "zval_ptr_dtor_nogc(EX_VAR(opline->op1.var))", 405 "VAR" => "zval_ptr_dtor_nogc(EX_VAR(opline->op1.var))", 406 "CONST" => "", 407 "UNUSED" => "", 408 "CV" => "", 409 "TMPVAR" => "zval_ptr_dtor_nogc(EX_VAR(opline->op1.var))", 410); 411 412$op2_free_unfetched = array( 413 "ANY" => "FREE_UNFETCHED_OP(opline->op2_type, opline->op2.var)", 414 "TMP" => "zval_ptr_dtor_nogc(EX_VAR(opline->op2.var))", 415 "VAR" => "zval_ptr_dtor_nogc(EX_VAR(opline->op2.var))", 416 "CONST" => "", 417 "UNUSED" => "", 418 "CV" => "", 419 "TMPVAR" => "zval_ptr_dtor_nogc(EX_VAR(opline->op2.var))", 420); 421 422$list = array(); // list of opcode handlers and helpers in original order 423$opcodes = array(); // opcode handlers by code 424$helpers = array(); // opcode helpers by name 425$params = array(); // parameters of helpers 426$opnames = array(); // opcode name to code mapping 427$line_no = 1; 428 429// Writes $s into resulting executor 430function out($f, $s) { 431 global $line_no; 432 433 fputs($f,$s); 434 $line_no += substr_count($s, "\n"); 435} 436 437// Resets #line directives in resulting executor 438function out_line($f) { 439 global $line_no, $executor_file; 440 441 fputs($f,"#line ".($line_no+1)." \"".$executor_file."\"\n"); 442 ++$line_no; 443} 444 445// Returns name of specialized helper 446function helper_name($name, $spec, $op1, $op2) { 447 global $prefix, $helpers; 448 449 if (isset($helpers[$name])) { 450 // If we haven't helper with specified spicialized operands then 451 // using unspecialized helper 452 if (!isset($helpers[$name]["op1"][$op1]) && 453 isset($helpers[$name]["op1"]["ANY"])) { 454 $op1 = "ANY"; 455 } 456 if (!isset($helpers[$name]["op2"][$op2]) && 457 isset($helpers[$name]["op2"]["ANY"])) { 458 $op2 = "ANY"; 459 } 460 } 461 return $name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2]; 462} 463 464// Generates code for opcode handler or helper 465function gen_code($f, $spec, $kind, $export, $code, $op1, $op2, $name) { 466 global $op1_type, $op2_type, $op1_get_zval_ptr, $op2_get_zval_ptr, 467 $op1_get_zval_ptr_deref, $op2_get_zval_ptr_deref, 468 $op1_get_zval_ptr_undef, $op2_get_zval_ptr_undef, 469 $op1_get_zval_ptr_ptr, $op2_get_zval_ptr_ptr, 470 $op1_get_zval_ptr_ptr_undef, $op2_get_zval_ptr_ptr_undef, 471 $op1_get_obj_zval_ptr, $op2_get_obj_zval_ptr, 472 $op1_get_obj_zval_ptr_undef, $op2_get_obj_zval_ptr_undef, 473 $op1_get_obj_zval_ptr_deref, $op2_get_obj_zval_ptr_deref, 474 $op1_get_obj_zval_ptr_ptr, $op2_get_obj_zval_ptr_ptr, 475 $op1_get_obj_zval_ptr_ptr_undef, $op2_get_obj_zval_ptr_ptr_undef, 476 $op1_free, $op2_free, $op1_free_unfetched, $op2_free_unfetched, 477 $op1_free_op, $op2_free_op, $op1_free_op_if_var, $op2_free_op_if_var, 478 $op1_free_op_var_ptr, $op2_free_op_var_ptr, $prefix; 479 480 // Specializing 481 $code = preg_replace( 482 array( 483 "/OP1_TYPE/", 484 "/OP2_TYPE/", 485 "/OP1_FREE/", 486 "/OP2_FREE/", 487 "/GET_OP1_ZVAL_PTR\(([^)]*)\)/", 488 "/GET_OP2_ZVAL_PTR\(([^)]*)\)/", 489 "/GET_OP1_ZVAL_PTR_DEREF\(([^)]*)\)/", 490 "/GET_OP2_ZVAL_PTR_DEREF\(([^)]*)\)/", 491 "/GET_OP1_ZVAL_PTR_UNDEF\(([^)]*)\)/", 492 "/GET_OP2_ZVAL_PTR_UNDEF\(([^)]*)\)/", 493 "/GET_OP1_ZVAL_PTR_PTR\(([^)]*)\)/", 494 "/GET_OP2_ZVAL_PTR_PTR\(([^)]*)\)/", 495 "/GET_OP1_ZVAL_PTR_PTR_UNDEF\(([^)]*)\)/", 496 "/GET_OP2_ZVAL_PTR_PTR_UNDEF\(([^)]*)\)/", 497 "/GET_OP1_OBJ_ZVAL_PTR\(([^)]*)\)/", 498 "/GET_OP2_OBJ_ZVAL_PTR\(([^)]*)\)/", 499 "/GET_OP1_OBJ_ZVAL_PTR_UNDEF\(([^)]*)\)/", 500 "/GET_OP2_OBJ_ZVAL_PTR_UNDEF\(([^)]*)\)/", 501 "/GET_OP1_OBJ_ZVAL_PTR_DEREF\(([^)]*)\)/", 502 "/GET_OP2_OBJ_ZVAL_PTR_DEREF\(([^)]*)\)/", 503 "/GET_OP1_OBJ_ZVAL_PTR_PTR\(([^)]*)\)/", 504 "/GET_OP2_OBJ_ZVAL_PTR_PTR\(([^)]*)\)/", 505 "/GET_OP1_OBJ_ZVAL_PTR_PTR_UNDEF\(([^)]*)\)/", 506 "/GET_OP2_OBJ_ZVAL_PTR_PTR_UNDEF\(([^)]*)\)/", 507 "/FREE_OP1\(\)/", 508 "/FREE_OP2\(\)/", 509 "/FREE_OP1_IF_VAR\(\)/", 510 "/FREE_OP2_IF_VAR\(\)/", 511 "/FREE_OP1_VAR_PTR\(\)/", 512 "/FREE_OP2_VAR_PTR\(\)/", 513 "/FREE_UNFETCHED_OP1\(\)/", 514 "/FREE_UNFETCHED_OP2\(\)/", 515 "/^#(\s*)ifdef\s+ZEND_VM_SPEC\s*\n/m", 516 "/^#(\s*)ifndef\s+ZEND_VM_SPEC\s*\n/m", 517 "/\!defined\(ZEND_VM_SPEC\)/m", 518 "/defined\(ZEND_VM_SPEC\)/m", 519 "/ZEND_VM_C_LABEL\(\s*([A-Za-z_]*)\s*\)/m", 520 "/ZEND_VM_C_GOTO\(\s*([A-Za-z_]*)\s*\)/m", 521 "/^#(\s*)if\s+1\s*\\|\\|.*[^\\\\]$/m", 522 "/^#(\s*)if\s+0\s*&&.*[^\\\\]$/m", 523 "/^#(\s*)ifdef\s+ZEND_VM_EXPORT\s*\n/m", 524 "/^#(\s*)ifndef\s+ZEND_VM_EXPORT\s*\n/m" 525 ), 526 array( 527 $op1_type[$op1], 528 $op2_type[$op2], 529 $op1_free[$op1], 530 $op2_free[$op2], 531 $op1_get_zval_ptr[$op1], 532 $op2_get_zval_ptr[$op2], 533 $op1_get_zval_ptr_deref[$op1], 534 $op2_get_zval_ptr_deref[$op2], 535 $op1_get_zval_ptr_undef[$op1], 536 $op2_get_zval_ptr_undef[$op2], 537 $op1_get_zval_ptr_ptr[$op1], 538 $op2_get_zval_ptr_ptr[$op2], 539 $op1_get_zval_ptr_ptr_undef[$op1], 540 $op2_get_zval_ptr_ptr_undef[$op2], 541 $op1_get_obj_zval_ptr[$op1], 542 $op2_get_obj_zval_ptr[$op2], 543 $op1_get_obj_zval_ptr_undef[$op1], 544 $op2_get_obj_zval_ptr_undef[$op2], 545 $op1_get_obj_zval_ptr_deref[$op1], 546 $op2_get_obj_zval_ptr_deref[$op2], 547 $op1_get_obj_zval_ptr_ptr[$op1], 548 $op2_get_obj_zval_ptr_ptr[$op2], 549 $op1_get_obj_zval_ptr_ptr_undef[$op1], 550 $op2_get_obj_zval_ptr_ptr_undef[$op2], 551 $op1_free_op[$op1], 552 $op2_free_op[$op2], 553 $op1_free_op_if_var[$op1], 554 $op2_free_op_if_var[$op2], 555 $op1_free_op_var_ptr[$op1], 556 $op2_free_op_var_ptr[$op2], 557 $op1_free_unfetched[$op1], 558 $op2_free_unfetched[$op2], 559 ($op1!="ANY"||$op2!="ANY")?"#\\1if 1\n":"#\\1if 0\n", 560 ($op1!="ANY"||$op2!="ANY")?"#\\1if 0\n":"#\\1if 1\n", 561 ($op1!="ANY"||$op2!="ANY")?"0":"1", 562 ($op1!="ANY"||$op2!="ANY")?"1":"0", 563 "\\1".(($spec && $kind != ZEND_VM_KIND_CALL)?("_SPEC".$prefix[$op1].$prefix[$op2]):""), 564 "goto \\1".(($spec && $kind != ZEND_VM_KIND_CALL)?("_SPEC".$prefix[$op1].$prefix[$op2]):""), 565 "#\\1if 1", 566 "#\\1if 0", 567 $export?"#\\1if 1\n":"#\\1if 0\n", 568 $export?"#\\1if 0\n":"#\\1if 1\n" 569 ), 570 $code); 571 572 if (0 && strpos($code, '{') === 0) { 573 $code = "{\n\tfprintf(stderr, \"$name\\n\");\n" . substr($code, 1); 574 } 575 // Updating code according to selected threading model 576 switch($kind) { 577 case ZEND_VM_KIND_CALL: 578 $code = preg_replace_callback( 579 array( 580 "/EXECUTE_DATA/m", 581 "/ZEND_VM_DISPATCH_TO_HANDLER\(\s*([A-Z_]*)\s*\)/m", 582 "/ZEND_VM_DISPATCH_TO_HELPER\(\s*([A-Za-z_]*)\s*\)/m", 583 "/ZEND_VM_DISPATCH_TO_HELPER_EX\(\s*([A-Za-z_]*)\s*,\s*[A-Za-z_]*\s*,\s*(.*)\s*\);/m", 584 ), 585 function($matches) use ($spec, $prefix, $op1, $op2) { 586 if (strncasecmp($matches[0], "EXECUTE_DATA", strlen("EXECUTE_DATA")) == 0) { 587 return "execute_data"; 588 } else if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HANDLER", strlen("ZEND_VM_DISPATCH_TO_HANDLER")) == 0) { 589 return "ZEND_VM_TAIL_CALL(" . $matches[1] . ($spec?"_SPEC":"") . $prefix[$op1] . $prefix[$op2] . "_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU))"; 590 } else if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HELPER_EX", strlen("ZEND_VM_DISPATCH_TO_HELPER_EX")) == 0) { 591 return "ZEND_VM_TAIL_CALL(" . helper_name($matches[1], $spec, $op1, $op2) . "(" . $matches[2]. " ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC));"; 592 } else { 593 return "ZEND_VM_TAIL_CALL(" . helper_name($matches[1], $spec, $op1, $op2) . "(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU))"; 594 } 595 }, 596 $code); 597 break; 598 case ZEND_VM_KIND_SWITCH: 599 $code = preg_replace_callback( 600 array( 601 "/EXECUTE_DATA/m", 602 "/ZEND_VM_DISPATCH_TO_HANDLER\(\s*([A-Z_]*)\s*\)/m", 603 "/ZEND_VM_DISPATCH_TO_HELPER\(\s*([A-Za-z_]*)\s*\)/m", 604 "/ZEND_VM_DISPATCH_TO_HELPER_EX\(\s*([A-Za-z_]*)\s*,\s*([A-Za-z_]*)\s*,\s*(.*)\s*\);/m", 605 ), 606 function($matches) use ($spec, $prefix, $op1, $op2) { 607 if (strncasecmp($matches[0], "EXECUTE_DATA", strlen("EXECUTE_DATA")) == 0) { 608 return "execute_data"; 609 } else if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HANDLER", strlen("ZEND_VM_DISPATCH_TO_HANDLER")) == 0) { 610 return "goto " . $matches[1] . ($spec?"_SPEC":"") . $prefix[$op1] . $prefix[$op2] . "_LABEL"; 611 } else if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HELPER_EX", strlen("ZEND_VM_DISPATCH_TO_HELPER_EX")) == 0) { 612 return $matches[2] . " = " . $matches[3] . "; goto " . helper_name($matches[1], $spec, $op1, $op2) . ";"; 613 } else { 614 return "goto " . helper_name($matches[1], $spec, $op1, $op2); 615 } 616 }, 617 $code); 618 break; 619 case ZEND_VM_KIND_GOTO: 620 $code = preg_replace_callback( 621 array( 622 "/EXECUTE_DATA/m", 623 "/ZEND_VM_DISPATCH_TO_HANDLER\(\s*([A-Z_]*)\s*\)/m", 624 "/ZEND_VM_DISPATCH_TO_HELPER\(\s*([A-Za-z_]*)\s*\)/m", 625 "/ZEND_VM_DISPATCH_TO_HELPER_EX\(\s*([A-Za-z_]*)\s*,\s*([A-Za-z_]*)\s*,\s*(.*)\s*\);/m", 626 ), 627 function($matches) use ($spec, $prefix, $op1, $op2) { 628 if (strncasecmp($matches[0], "EXECUTE_DATA", strlen("EXECUTE_DATA")) == 0) { 629 return "execute_data"; 630 } else if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HANDLER", strlen("ZEND_VM_DISPATCH_TO_HANDLER")) == 0) { 631 return "goto " . $matches[1] . ($spec?"_SPEC":"") . $prefix[$op1] . $prefix[$op2] . "_HANDLER"; 632 } else if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HELPER_EX", strlen("ZEND_VM_DISPATCH_TO_HELPER_EX")) == 0) { 633 return $matches[2] . " = " . $matches[3] . "; goto " . helper_name($matches[1], $spec, $op1, $op2) . ";"; 634 } else { 635 return "goto " . helper_name($matches[1], $spec, $op1, $op2); 636 } 637 }, 638 $code); 639 break; 640 } 641 642 /* Remove unused free_op1 and free_op2 declarations */ 643 if ($spec && preg_match_all('/^\s*zend_free_op\s+[^;]+;\s*$/me', $code, $matches, PREG_SET_ORDER)) { 644 $n = 0; 645 foreach ($matches as $match) { 646 $code = preg_replace('/'.preg_quote($match[0],'/').'/', "\$D$n", $code); 647 ++$n; 648 } 649 $del_free_op1 = (strpos($code, "free_op1") === false); 650 $del_free_op2 = (strpos($code, "free_op2") === false); 651 $n = 0; 652 foreach ($matches as $match) { 653 $dcl = $match[0]; 654 $changed = 0; 655 if ($del_free_op1 && strpos($dcl, "free_op1") !== false) { 656 $dcl = preg_replace("/free_op1\s*,\s*/", "", $dcl); 657 $dcl = preg_replace("/free_op1\s*;/", ";", $dcl); 658 $changed = 1; 659 } 660 if ($del_free_op2 && strpos($dcl, "free_op2") !== false) { 661 $dcl = preg_replace("/free_op2\s*,\s*/", "", $dcl); 662 $dcl = preg_replace("/free_op2\s*;/", ";", $dcl); 663 $changed = 1; 664 } 665 if ($changed) { 666 $dcl = preg_replace("/,\s*;/", ";", $dcl); 667 $dcl = preg_replace("/zend_free_op\s*;/", "", $dcl); 668 } 669 $code = preg_replace("/\\\$D$n/", $dcl, $code); 670 ++$n; 671 } 672 } 673 674 /* Remove unnecessary ';' */ 675 $code = preg_replace('/^\s*;\s*$/m', '', $code); 676 677 /* Remove WS */ 678 $code = preg_replace('/[ \t]+\n/m', "\n", $code); 679 680 out($f, $code); 681} 682 683// Generates opcode handler 684function gen_handler($f, $spec, $kind, $name, $op1, $op2, $use, $code, $lineno) { 685 global $definition_file, $prefix, $typecode, $opnames; 686 687 if (ZEND_VM_LINES) { 688 out($f, "#line $lineno \"$definition_file\"\n"); 689 } 690 691 // Generate opcode handler's entry point according to selected threading model 692 switch($kind) { 693 case ZEND_VM_KIND_CALL: 694 out($f,"static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ".$name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2]."_HANDLER(ZEND_OPCODE_HANDLER_ARGS)\n"); 695 break; 696 case ZEND_VM_KIND_SWITCH: 697 if ($spec) { 698 out($f,"case ".((string)($opnames[$name]*25+($typecode[$op1=="TMPVAR"?"TMP":$op1]*5)+$typecode[$op2=="TMPVAR"?"TMP":$op2])).": /*".$name."_SPEC".$prefix[$op1].$prefix[$op2]."_HANDLER*/"); 699 } else { 700 out($f,"case ".$name.":"); 701 } 702 if ($use) { 703 // This handler is used by other handlers. We will add label to call it. 704 out($f," ".$name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2]."_LABEL:\n"); 705 } else { 706 out($f,"\n"); 707 } 708 break; 709 case ZEND_VM_KIND_GOTO: 710 out($f,$name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2]."_HANDLER: ZEND_VM_GUARD(".$name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2].");\n"); 711 break; 712 } 713 714 // Generate opcode handler's code 715 gen_code($f, $spec, $kind, 0, $code, $op1, $op2, $name); 716} 717 718// Generates helper 719function gen_helper($f, $spec, $kind, $name, $op1, $op2, $param, $code, $lineno) { 720 global $definition_file, $prefix; 721 722 if (ZEND_VM_LINES) { 723 out($f, "#line $lineno \"$definition_file\"\n"); 724 } 725 726 // Generate helper's entry point according to selected threading model 727 switch($kind) { 728 case ZEND_VM_KIND_CALL: 729 if ($param == null) { 730 // Helper without parameters 731 out($f, "static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ".$name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2]."(ZEND_OPCODE_HANDLER_ARGS)\n"); 732 } else { 733 // Helper with parameter 734 out($f, "static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ".$name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2]."(".$param." ZEND_OPCODE_HANDLER_ARGS_DC)\n"); 735 } 736 break; 737 case ZEND_VM_KIND_SWITCH: 738 out($f, $name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2].":\n"); 739 break; 740 case ZEND_VM_KIND_GOTO: 741 out($f, $name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2].":\n"); 742 break; 743 } 744 745 // Generate helper's code 746 gen_code($f, $spec, $kind, 0, $code, $op1, $op2, $name); 747} 748 749// Generates array of opcode handlers (specialized or unspecialized) 750function gen_labels($f, $spec, $kind, $prolog) { 751 global $opcodes, $op_types, $prefix, $typecode; 752 753 $next = 0; 754 if ($spec) { 755 // Emit labels for specialized executor 756 757 // For each opcode in opcode number order 758 foreach($opcodes as $num => $dsc) { 759 while ($next != $num) { 760 // If some opcode numbers are not used then fill hole with pointers 761 // to handler of undefined opcode 762 $op1t = $op_types; 763 // For each op1.op_type except ANY 764 foreach($op1t as $op1) { 765 if ($op1 != "ANY") { 766 $op2t = $op_types; 767 // For each op2.op_type except ANY 768 foreach($op2t as $op2) { 769 if ($op2 != "ANY") { 770 // Emit pointer to handler of undefined opcode 771 switch ($kind) { 772 case ZEND_VM_KIND_CALL: 773 out($f,$prolog."ZEND_NULL_HANDLER,\n"); 774 break; 775 case ZEND_VM_KIND_SWITCH: 776 out($f,$prolog."(void*)(uintptr_t)-1,\n"); 777 break; 778 case ZEND_VM_KIND_GOTO: 779 out($f,$prolog."(void*)&&ZEND_NULL_HANDLER,\n"); 780 break; 781 } 782 } 783 } 784 } 785 } 786 $next++; 787 } 788 $next = $num + 1; 789 $op1t = $op_types; 790 // For each op1.op_type except ANY 791 foreach($op1t as $op1) { 792 if ($op1 != "ANY") { 793 if (!isset($dsc["op1"][$op1])) { 794 if (($op1 == "TMP" || $op1 == "VAR") && isset($dsc["op1"]["TMPVAR"])) { 795 $op1 = "TMPVAR"; 796 } else { 797 // Try to use unspecialized handler 798 $op1 = "ANY"; 799 } 800 } 801 $op2t = $op_types; 802 // For each op2.op_type except ANY 803 foreach($op2t as $op2) { 804 if ($op2 != "ANY") { 805 if (!isset($dsc["op2"][$op2])) { 806 if (($op2 == "TMP" || $op2 == "VAR") && isset($dsc["op2"]["TMPVAR"])) { 807 $op2 = "TMPVAR"; 808 } else { 809 // Try to use unspecialized handler 810 $op2 = "ANY"; 811 } 812 } 813 // Check if specialized handler is defined 814 if (isset($dsc["op1"][$op1]) && 815 isset($dsc["op2"][$op2])) { 816 // Emit pointer to specialized handler 817 switch ($kind) { 818 case ZEND_VM_KIND_CALL: 819 out($f,$prolog.$dsc["op"]."_SPEC".$prefix[$op1].$prefix[$op2]."_HANDLER,\n"); 820 break; 821 case ZEND_VM_KIND_SWITCH: 822 out($f,$prolog."(void*)(uintptr_t)".((string)($num*25+$typecode[$op1=="TMPVAR"?"TMP":$op1]*5+$typecode[$op2=="TMPVAR"?"TMP":$op2])).",\n"); 823 break; 824 case ZEND_VM_KIND_GOTO: 825 out($f,$prolog."(void*)&&".$dsc["op"]."_SPEC".$prefix[$op1].$prefix[$op2]."_HANDLER,\n"); 826 break; 827 } 828 } else { 829 // Emit pinter to handler of undefined opcode 830 switch ($kind) { 831 case ZEND_VM_KIND_CALL: 832 out($f,$prolog."ZEND_NULL_HANDLER,\n"); 833 break; 834 case ZEND_VM_KIND_SWITCH: 835 out($f,$prolog."(void*)(uintptr_t)-1,\n"); 836 break; 837 case ZEND_VM_KIND_GOTO: 838 out($f,$prolog."(void*)&&ZEND_NULL_HANDLER,\n"); 839 break; 840 } 841 } 842 } 843 } 844 } 845 } 846 } 847 } else { 848 // Emit labels for unspecialized executor 849 850 // For each opcode in opcode number order 851 foreach($opcodes as $num => $dsc) { 852 while ($next != $num) { 853 // If some opcode numbers are not used then fill hole with pointers 854 // to handler of undefined opcode 855 switch ($kind) { 856 case ZEND_VM_KIND_CALL: 857 out($f,$prolog."ZEND_NULL_HANDLER,\n"); 858 break; 859 case ZEND_VM_KIND_SWITCH: 860 out($f,$prolog."(void*)(uintptr_t)-1,\n"); 861 break; 862 case ZEND_VM_KIND_GOTO: 863 out($f,$prolog."(void*)&&ZEND_NULL_HANDLER,\n"); 864 break; 865 } 866 $next++; 867 } 868 $next = $num+1; 869 870 //ugly trick for ZEND_VM_DEFINE_OP 871 if ($dsc["code"]) { 872 // Emit pointer to unspecialized handler 873 switch ($kind) { 874 case ZEND_VM_KIND_CALL: 875 out($f,$prolog.$dsc["op"]."_HANDLER,\n"); 876 break; 877 case ZEND_VM_KIND_SWITCH: 878 out($f,$prolog."(void*)(uintptr_t)".((string)$num).",\n"); 879 break; 880 case ZEND_VM_KIND_GOTO: 881 out($f,$prolog."(void*)&&".$dsc["op"]."_HANDLER,\n"); 882 break; 883 } 884 } else { 885 switch ($kind) { 886 case ZEND_VM_KIND_CALL: 887 out($f,$prolog."ZEND_NULL_HANDLER,\n"); 888 break; 889 case ZEND_VM_KIND_SWITCH: 890 out($f,$prolog."(void*)(uintptr_t)-1,\n"); 891 break; 892 case ZEND_VM_KIND_GOTO: 893 out($f,$prolog."(void*)&&ZEND_NULL_HANDLER,\n"); 894 break; 895 } 896 } 897 } 898 } 899 900 // Emit last handler's label (undefined opcode) 901 switch ($kind) { 902 case ZEND_VM_KIND_CALL: 903 out($f,$prolog."ZEND_NULL_HANDLER\n"); 904 break; 905 case ZEND_VM_KIND_SWITCH: 906 out($f,$prolog."(void*)(uintptr_t)-1\n"); 907 break; 908 case ZEND_VM_KIND_GOTO: 909 out($f,$prolog."(void*)&&ZEND_NULL_HANDLER\n"); 910 break; 911 } 912} 913 914// Generates handler for undefined opcodes (CALL threading model) 915function gen_null_handler($f) { 916 static $done = 0; 917 918 // New and all executors with CALL threading model can use the same handler 919 // for undefined opcodes, do we emit code for it only once 920 if (!$done) { 921 $done = 1; 922 out($f,"static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NULL_HANDLER(ZEND_OPCODE_HANDLER_ARGS)\n"); 923 out($f,"{\n"); 924 out($f,"\tUSE_OPLINE\n"); 925 out($f,"\n"); 926 out($f,"\tzend_error_noreturn(E_ERROR, \"Invalid opcode %d/%d/%d.\", OPLINE->opcode, OPLINE->op1_type, OPLINE->op2_type);\n"); 927 out($f,"\tZEND_VM_NEXT_OPCODE(); /* Never reached */\n"); 928 out($f,"}\n\n"); 929 } 930} 931 932// Generates all opcode handlers and helpers (specialized or unspecilaized) 933function gen_executor_code($f, $spec, $kind, $prolog) { 934 global $list, $opcodes, $helpers, $op_types_ex; 935 936 if ($spec) { 937 // Produce specialized executor 938 $op1t = $op_types_ex; 939 // for each op1.op_type 940 foreach($op1t as $op1) { 941 $op2t = $op_types_ex; 942 // for each op2.op_type 943 foreach($op2t as $op2) { 944 // for each handlers in helpers in original order 945 foreach ($list as $lineno => $dsc) { 946 if (isset($dsc["handler"])) { 947 $num = $dsc["handler"]; 948 // Check if handler accepts such types of operands (op1 and op2) 949 if (isset($opcodes[$num]["op1"][$op1]) && 950 isset($opcodes[$num]["op2"][$op2])) { 951 // Generate handler code 952 gen_handler($f, 1, $kind, $opcodes[$num]["op"], $op1, $op2, isset($opcodes[$num]["use"]), $opcodes[$num]["code"], $lineno); 953 } 954 } else if (isset($dsc["helper"])) { 955 $num = $dsc["helper"]; 956 // Check if handler accepts such types of operands (op1 and op2) 957 if (isset($helpers[$num]["op1"][$op1]) && 958 isset($helpers[$num]["op2"][$op2])) { 959 // Generate helper code 960 gen_helper($f, 1, $kind, $num, $op1, $op2, $helpers[$num]["param"], $helpers[$num]["code"], $lineno); 961 } 962 } else { 963 var_dump($dsc); 964 die("??? $kind:$num\n"); 965 } 966 } 967 } 968 } 969 } else { 970 // Produce unspecialized executor 971 972 // for each handlers in helpers in original order 973 foreach ($list as $lineno => $dsc) { 974 if (isset($dsc["handler"])) { 975 $num = $dsc["handler"]; 976 // Generate handler code 977 gen_handler($f, 0, $kind, $opcodes[$num]["op"], "ANY", "ANY", isset($opcodes[$num]["use"]), $opcodes[$num]["code"], $lineno); 978 } else if (isset($dsc["helper"])) { 979 $num = $dsc["helper"]; 980 // Generate helper code 981 gen_helper($f, 0, $kind, $num, "ANY", "ANY", $helpers[$num]["param"], $helpers[$num]["code"], $lineno); 982 } else { 983 var_dump($dsc); 984 die("??? $kind:$num\n"); 985 } 986 } 987 } 988 989 if (ZEND_VM_LINES) { 990 // Reset #line directives 991 out_line($f); 992 } 993 994 // Generate handler for undefined opcodes 995 switch ($kind) { 996 case ZEND_VM_KIND_CALL: 997 gen_null_handler($f); 998 break; 999 case ZEND_VM_KIND_SWITCH: 1000 out($f,"default:\n"); 1001 out($f,"\tzend_error_noreturn(E_ERROR, \"Invalid opcode %d/%d/%d.\", OPLINE->opcode, OPLINE->op1_type, OPLINE->op2_type);\n"); 1002 out($f,"\tZEND_VM_NEXT_OPCODE(); /* Never reached */\n"); 1003 break; 1004 case ZEND_VM_KIND_GOTO: 1005 out($f,"ZEND_NULL_HANDLER:\n"); 1006 out($f,"\tzend_error_noreturn(E_ERROR, \"Invalid opcode %d/%d/%d.\", OPLINE->opcode, OPLINE->op1_type, OPLINE->op2_type);\n"); 1007 out($f,"\tZEND_VM_NEXT_OPCODE(); /* Never reached */\n"); 1008 break; 1009 } 1010} 1011 1012function skip_blanks($f, $prolog, $epilog) { 1013 if (trim($prolog) != "" || trim($epilog) != "") { 1014 out($f, $prolog.$epilog); 1015 } 1016} 1017 1018// Generates executor from skeleton file and definition (specialized or unspecialized) 1019function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) { 1020 global $params, $skeleton_file, $line_no; 1021 1022 $lineno = 0; 1023 foreach ($skl as $line) { 1024 // Skeleton file contains special markers in form %NAME% those are 1025 // substituted by custom code 1026 if (preg_match("/(.*)[{][%]([A-Z_]*)[%][}](.*)/", $line, $m)) { 1027 switch ($m[2]) { 1028 case "DEFINES": 1029 out($f,"static const void **zend_opcode_handlers;\n"); 1030 out($f,"static const void *zend_vm_get_opcode_handler(zend_uchar opcode, const zend_op* op);\n\n"); 1031 switch ($kind) { 1032 case ZEND_VM_KIND_CALL: 1033 out($f,"\n"); 1034 out($f,"#ifdef ZEND_VM_FP_GLOBAL_REG\n"); 1035 out($f,"#pragma GCC diagnostic ignored \"-Wvolatile-register-var\"\n"); 1036 out($f,"register zend_execute_data* volatile execute_data __asm__(ZEND_VM_FP_GLOBAL_REG);\n"); 1037 out($f,"#pragma GCC diagnostic warning \"-Wvolatile-register-var\"\n"); 1038 out($f,"#endif\n"); 1039 out($f,"\n"); 1040 out($f,"#ifdef ZEND_VM_IP_GLOBAL_REG\n"); 1041 out($f,"#pragma GCC diagnostic ignored \"-Wvolatile-register-var\"\n"); 1042 out($f,"register const zend_op* volatile opline __asm__(ZEND_VM_IP_GLOBAL_REG);\n"); 1043 out($f,"#pragma GCC diagnostic warning \"-Wvolatile-register-var\"\n"); 1044 out($f,"#endif\n"); 1045 out($f,"\n"); 1046 out($f,"#ifdef ZEND_VM_FP_GLOBAL_REG\n"); 1047 out($f,"# define ZEND_OPCODE_HANDLER_ARGS void\n"); 1048 out($f,"# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU\n"); 1049 out($f,"# define ZEND_OPCODE_HANDLER_ARGS_DC\n"); 1050 out($f,"# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC\n"); 1051 out($f,"#else\n"); 1052 out($f,"# define ZEND_OPCODE_HANDLER_ARGS zend_execute_data *execute_data\n"); 1053 out($f,"# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU execute_data\n"); 1054 out($f,"# define ZEND_OPCODE_HANDLER_ARGS_DC , ZEND_OPCODE_HANDLER_ARGS\n"); 1055 out($f,"# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC , ZEND_OPCODE_HANDLER_ARGS_PASSTHRU\n"); 1056 out($f,"#endif\n"); 1057 out($f,"\n"); 1058 out($f,"#if defined(ZEND_VM_FP_GLOBAL_REG) && defined(ZEND_VM_IP_GLOBAL_REG)\n"); 1059 out($f,"# define ZEND_OPCODE_HANDLER_RET void\n"); 1060 out($f,"# define ZEND_VM_TAIL_CALL(call) call; return\n"); 1061 out($f,"# ifdef ZEND_VM_TAIL_CALL_DISPATCH\n"); 1062 out($f,"# define ZEND_VM_CONTINUE() ((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); return\n"); 1063 out($f,"# else\n"); 1064 out($f,"# define ZEND_VM_CONTINUE() return\n"); 1065 out($f,"# endif\n"); 1066 out($f,"# define ZEND_VM_RETURN() opline = NULL; return\n"); 1067 out($f,"#else\n"); 1068 out($f,"# define ZEND_OPCODE_HANDLER_RET int\n"); 1069 out($f,"# define ZEND_VM_TAIL_CALL(call) return call\n"); 1070 out($f,"# define ZEND_VM_CONTINUE() return 0\n"); 1071 out($f,"# define ZEND_VM_RETURN() return -1\n"); 1072 out($f,"#endif\n"); 1073 out($f,"\n"); 1074 out($f,"typedef ZEND_OPCODE_HANDLER_RET (ZEND_FASTCALL *opcode_handler_t) (ZEND_OPCODE_HANDLER_ARGS);\n"); 1075 out($f,"\n"); 1076 out($f,"#undef OPLINE\n"); 1077 out($f,"#undef DCL_OPLINE\n"); 1078 out($f,"#undef USE_OPLINE\n"); 1079 out($f,"#undef LOAD_OPLINE\n"); 1080 out($f,"#undef LOAD_OPLINE_EX\n"); 1081 out($f,"#undef SAVE_OPLINE\n"); 1082 out($f,"#define DCL_OPLINE\n"); 1083 out($f,"#ifdef ZEND_VM_IP_GLOBAL_REG\n"); 1084 out($f,"# define OPLINE opline\n"); 1085 out($f,"# define USE_OPLINE\n"); 1086 out($f,"# define LOAD_OPLINE() opline = EX(opline)\n"); 1087 out($f,"# define LOAD_NEXT_OPLINE() opline = EX(opline) + 1\n"); 1088 out($f,"# define SAVE_OPLINE() EX(opline) = opline\n"); 1089 out($f,"#else\n"); 1090 out($f,"# define OPLINE EX(opline)\n"); 1091 out($f,"# define USE_OPLINE const zend_op *opline = EX(opline);\n"); 1092 out($f,"# define LOAD_OPLINE()\n"); 1093 out($f,"# define LOAD_NEXT_OPLINE() ZEND_VM_INC_OPCODE()\n"); 1094 out($f,"# define SAVE_OPLINE()\n"); 1095 out($f,"#endif\n"); 1096 out($f,"#undef HANDLE_EXCEPTION\n"); 1097 out($f,"#undef HANDLE_EXCEPTION_LEAVE\n"); 1098 out($f,"#define HANDLE_EXCEPTION() LOAD_OPLINE(); ZEND_VM_CONTINUE()\n"); 1099 out($f,"#define HANDLE_EXCEPTION_LEAVE() LOAD_OPLINE(); ZEND_VM_LEAVE()\n"); 1100 out($f,"#if defined(ZEND_VM_FP_GLOBAL_REG)\n"); 1101 out($f,"# define ZEND_VM_ENTER() execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_CONTINUE()\n"); 1102 out($f,"# define ZEND_VM_LEAVE() ZEND_VM_CONTINUE()\n"); 1103 out($f,"#elif defined(ZEND_VM_IP_GLOBAL_REG)\n"); 1104 out($f,"# define ZEND_VM_ENTER() opline = EG(current_execute_data)->opline; return 1\n"); 1105 out($f,"# define ZEND_VM_LEAVE() return 2\n"); 1106 out($f,"#else\n"); 1107 out($f,"# define ZEND_VM_ENTER() return 1\n"); 1108 out($f,"# define ZEND_VM_LEAVE() return 2\n"); 1109 out($f,"#endif\n"); 1110 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"); 1111 out($f,"\n"); 1112 break; 1113 case ZEND_VM_KIND_SWITCH: 1114 out($f,"\n"); 1115 out($f,"#undef OPLINE\n"); 1116 out($f,"#undef DCL_OPLINE\n"); 1117 out($f,"#undef USE_OPLINE\n"); 1118 out($f,"#undef LOAD_OPLINE\n"); 1119 out($f,"#undef LOAD_NEXT_OPLINE\n"); 1120 out($f,"#undef SAVE_OPLINE\n"); 1121 out($f,"#define OPLINE opline\n"); 1122 out($f,"#ifdef ZEND_VM_IP_GLOBAL_REG\n"); 1123 out($f,"# define DCL_OPLINE register const zend_op *opline __asm__(ZEND_VM_IP_GLOBAL_REG);\n"); 1124 out($f,"#else\n"); 1125 out($f,"# define DCL_OPLINE const zend_op *opline;\n"); 1126 out($f,"#endif\n"); 1127 out($f,"#define USE_OPLINE\n"); 1128 out($f,"#define LOAD_OPLINE() opline = EX(opline)\n"); 1129 out($f,"#define LOAD_NEXT_OPLINE() opline = EX(opline) + 1\n"); 1130 out($f,"#define SAVE_OPLINE() EX(opline) = opline\n"); 1131 out($f,"#undef HANDLE_EXCEPTION\n"); 1132 out($f,"#undef HANDLE_EXCEPTION_LEAVE\n"); 1133 out($f,"#define HANDLE_EXCEPTION() LOAD_OPLINE(); ZEND_VM_CONTINUE()\n"); 1134 out($f,"#define HANDLE_EXCEPTION_LEAVE() LOAD_OPLINE(); ZEND_VM_LEAVE()\n"); 1135 out($f,"#define ZEND_VM_CONTINUE() goto zend_vm_continue\n"); 1136 out($f,"#define ZEND_VM_RETURN() return\n"); 1137 out($f,"#define ZEND_VM_ENTER() execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_CONTINUE()\n"); 1138 out($f,"#define ZEND_VM_LEAVE() ZEND_VM_CONTINUE()\n"); 1139 out($f,"#define ZEND_VM_DISPATCH(opcode, opline) dispatch_handler = zend_vm_get_opcode_handler(opcode, opline); goto zend_vm_dispatch;\n"); 1140 out($f,"\n"); 1141 break; 1142 case ZEND_VM_KIND_GOTO: 1143 out($f,"\n"); 1144 out($f,"#undef OPLINE\n"); 1145 out($f,"#undef DCL_OPLINE\n"); 1146 out($f,"#undef USE_OPLINE\n"); 1147 out($f,"#undef LOAD_OPLINE\n"); 1148 out($f,"#undef LOAD_NEXT_OPLINE\n"); 1149 out($f,"#undef SAVE_OPLINE\n"); 1150 out($f,"#define OPLINE opline\n"); 1151 out($f,"#ifdef ZEND_VM_IP_GLOBAL_REG\n"); 1152 out($f,"# define DCL_OPLINE register const zend_op *opline __asm__(ZEND_VM_IP_GLOBAL_REG);\n"); 1153 out($f,"#else\n"); 1154 out($f,"# define DCL_OPLINE const zend_op *opline;\n"); 1155 out($f,"#endif\n"); 1156 out($f,"#define USE_OPLINE\n"); 1157 out($f,"#define LOAD_OPLINE() opline = EX(opline)\n"); 1158 out($f,"#define LOAD_NEXT_OPLINE() opline = EX(opline) + 1\n"); 1159 out($f,"#define SAVE_OPLINE() EX(opline) = opline\n"); 1160 out($f,"#undef HANDLE_EXCEPTION\n"); 1161 out($f,"#undef HANDLE_EXCEPTION_LEAVE\n"); 1162 if (ZEND_VM_SPEC) { 1163 out($f,"#define HANDLE_EXCEPTION() goto ZEND_HANDLE_EXCEPTION_SPEC_HANDLER\n"); 1164 out($f,"#define HANDLE_EXCEPTION_LEAVE() goto ZEND_HANDLE_EXCEPTION_SPEC_HANDLER\n"); 1165 } else { 1166 out($f,"#define HANDLE_EXCEPTION() goto ZEND_HANDLE_EXCEPTION_HANDLER\n"); 1167 out($f,"#define HANDLE_EXCEPTION_LEAVE() goto ZEND_HANDLE_EXCEPTION_HANDLER\n"); 1168 } 1169 out($f,"#define ZEND_VM_CONTINUE() goto *(void**)(OPLINE->handler)\n"); 1170 out($f,"#define ZEND_VM_RETURN() return\n"); 1171 out($f,"#define ZEND_VM_ENTER() execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_CONTINUE()\n"); 1172 out($f,"#define ZEND_VM_LEAVE() ZEND_VM_CONTINUE()\n"); 1173 out($f,"#define ZEND_VM_DISPATCH(opcode, opline) goto *(void**)(zend_vm_get_opcode_handler(opcode, opline));\n"); 1174 out($f,"\n"); 1175 break; 1176 } 1177 break; 1178 case "EXECUTOR_NAME": 1179 out($f, $m[1].$executor_name.$m[3]."\n"); 1180 break; 1181 case "HELPER_VARS": 1182 if ($kind != ZEND_VM_KIND_CALL) { 1183 if ($kind == ZEND_VM_KIND_SWITCH) { 1184 out($f,$m[1]."const void *dispatch_handler;\n"); 1185 } 1186 // Emit local variables those are used for helpers' parameters 1187 foreach ($params as $param => $x) { 1188 out($f,$m[1].$param.";\n"); 1189 } 1190 out($f,"#ifdef ZEND_VM_FP_GLOBAL_REG\n"); 1191 out($f,$m[1]."register zend_execute_data *execute_data __asm__(ZEND_VM_FP_GLOBAL_REG) = ex;\n"); 1192 out($f,"#else\n"); 1193 out($f,$m[1]."zend_execute_data *execute_data = ex;\n"); 1194 out($f,"#endif\n"); 1195 } else { 1196 out($f,"#ifdef ZEND_VM_IP_GLOBAL_REG\n"); 1197 out($f,$m[1]."const zend_op *orig_opline = opline;\n"); 1198 out($f,"#endif\n"); 1199 out($f,"#ifdef ZEND_VM_FP_GLOBAL_REG\n"); 1200 out($f,$m[1]."zend_execute_data *orig_execute_data = execute_data;\n"); 1201 out($f,$m[1]."execute_data = ex;\n"); 1202 out($f,"#else\n"); 1203 out($f,$m[1]."zend_execute_data *execute_data = ex;\n"); 1204 out($f,"#endif\n"); 1205 } 1206 break; 1207 case "INTERNAL_LABELS": 1208 if ($kind == ZEND_VM_KIND_GOTO) { 1209 // Emit array of labels of opcode handlers and code for 1210 // zend_opcode_handlers initialization 1211 $prolog = $m[1]; 1212 out($f,$prolog."if (UNEXPECTED(execute_data == NULL)) {\n"); 1213 out($f,$prolog."\tstatic const void* labels[] = {\n"); 1214 gen_labels($f, $spec, $kind, $prolog."\t\t"); 1215 out($f,$prolog."\t};\n"); 1216 out($f,$prolog."\tzend_opcode_handlers = (const void **)labels;\n"); 1217 out($f,$prolog."\treturn;\n"); 1218 out($f,$prolog."}\n"); 1219 } else { 1220 skip_blanks($f, $m[1], $m[3]); 1221 } 1222 break; 1223 case "ZEND_VM_CONTINUE_LABEL": 1224 if ($kind == ZEND_VM_KIND_CALL) { 1225 // Only SWITCH dispatch method use it 1226 out($f,"#if !defined(ZEND_VM_FP_GLOBAL_REG) || !defined(ZEND_VM_IP_GLOBAL_REG)\n"); 1227 out($f,$m[1]."\tint ret;".$m[3]."\n"); 1228 out($f,"#endif\n"); 1229 } else if ($kind == ZEND_VM_KIND_SWITCH) { 1230 // Only SWITCH dispatch method use it 1231 out($f,"zend_vm_continue:".$m[3]."\n"); 1232 } else { 1233 skip_blanks($f, $m[1], $m[3]); 1234 } 1235 break; 1236 case "ZEND_VM_DISPATCH": 1237 // Emit code that dispatches to opcode handler 1238 switch ($kind) { 1239 case ZEND_VM_KIND_CALL: 1240 out($f,"#if defined(ZEND_VM_FP_GLOBAL_REG) && defined(ZEND_VM_IP_GLOBAL_REG)\n"); 1241 out($f, $m[1]."((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n"); 1242 out($f, $m[1]."if (UNEXPECTED(!OPLINE))".$m[3]."\n"); 1243 out($f,"#else\n"); 1244 out($f, $m[1]."if (UNEXPECTED((ret = ((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)) != 0))".$m[3]."\n"); 1245 out($f,"#endif\n"); 1246 break; 1247 case ZEND_VM_KIND_SWITCH: 1248 out($f, $m[1]."dispatch_handler = OPLINE->handler;\nzend_vm_dispatch:\n".$m[1]."switch ((int)(uintptr_t)dispatch_handler)".$m[3]."\n"); 1249 break; 1250 case ZEND_VM_KIND_GOTO: 1251 out($f, $m[1]."goto *(void**)(OPLINE->handler);".$m[3]."\n"); 1252 break; 1253 } 1254 break; 1255 case "INTERNAL_EXECUTOR": 1256 if ($kind == ZEND_VM_KIND_CALL) { 1257 // Executor is defined as a set of functions 1258 out($f, 1259 "#ifdef ZEND_VM_FP_GLOBAL_REG\n" . 1260 $m[1]."execute_data = orig_execute_data;\n" . 1261 "# ifdef ZEND_VM_IP_GLOBAL_REG\n" . 1262 $m[1]."opline = orig_opline;\n" . 1263 "# endif\n" . 1264 $m[1]."return;\n" . 1265 "#else\n" . 1266 $m[1]."if (EXPECTED(ret > 0)) {\n" . 1267 $m[1]."\texecute_data = EG(current_execute_data);\n". 1268 $m[1]."} else {\n" . 1269 "# ifdef ZEND_VM_IP_GLOBAL_REG\n" . 1270 $m[1]."\topline = orig_opline;\n" . 1271 "# endif\n". 1272 $m[1]."\treturn;\n". 1273 $m[1]."}\n". 1274 "#endif\n"); 1275 } else { 1276 // Emit executor code 1277 gen_executor_code($f, $spec, $kind, $m[1]); 1278 } 1279 break; 1280 case "EXTERNAL_EXECUTOR": 1281 if ($kind == ZEND_VM_KIND_CALL) { 1282 gen_executor_code($f, $spec, $kind, $m[1]); 1283 } 1284 break; 1285 case "INITIALIZER_NAME": 1286 out($f, $m[1].$initializer_name.$m[3]."\n"); 1287 break; 1288 case "EXTERNAL_LABELS": 1289 // Emit code that initializes zend_opcode_handlers array 1290 $prolog = $m[1]; 1291 if ($kind == ZEND_VM_KIND_GOTO) { 1292 // Labels are defined in the executor itself, so we call it 1293 // with execute_data NULL and it sets zend_opcode_handlers array 1294 out($f,$prolog.""); 1295 out($f,$prolog.$executor_name."_ex(NULL);\n"); 1296 } else { 1297 out($f,$prolog."static const void *labels[] = {\n"); 1298 gen_labels($f, $spec, $kind, $prolog."\t"); 1299 out($f,$prolog."};\n"); 1300 out($f,$prolog."zend_opcode_handlers = labels;\n"); 1301 } 1302 break; 1303 default: 1304 die("ERROR: Unknown keyword ".$m[2]." in skeleton file.\n"); 1305 } 1306 } else { 1307 // Copy the line as is 1308 out($f, $line); 1309 } 1310 } 1311} 1312 1313function gen_vm($def, $skel) { 1314 global $definition_file, $skeleton_file, $executor_file, 1315 $op_types, $list, $opcodes, $helpers, $params, $opnames; 1316 1317 // Load definition file 1318 $in = @file($def); 1319 if (!$in) { 1320 die("ERROR: Can not open definition file '$def'\n"); 1321 } 1322 // We need absolute path to definition file to use it in #line directives 1323 $definition_file = realpath($def); 1324 1325 // Load skeleton file 1326 $skl = @file($skel); 1327 if (!$skl) { 1328 die("ERROR: Can not open skeleton file '$skel'\n"); 1329 } 1330 // We need absolute path to skeleton file to use it in #line directives 1331 $skeleton_file = realpath($skel); 1332 1333 // Parse definition file into tree 1334 $lineno = 0; 1335 $handler = null; 1336 $helper = null; 1337 $max_opcode_len = 0; 1338 $max_opcode = 0; 1339 $export = array(); 1340 foreach ($in as $line) { 1341 ++$lineno; 1342 if (strpos($line,"ZEND_VM_HANDLER(") === 0) { 1343 // Parsing opcode handler's definition 1344 if (preg_match( 1345 "/^ZEND_VM_HANDLER\(\s*([0-9]+)\s*,\s*([A-Z_]+)\s*,\s*([A-Z|]+)\s*,\s*([A-Z|]+)\s*\)/", 1346 $line, 1347 $m) == 0) { 1348 die("ERROR ($def:$lineno): Invalid ZEND_VM_HANDLER definition.\n"); 1349 } 1350 $code = (int)$m[1]; 1351 $op = $m[2]; 1352 $len = strlen($op); 1353 $op1 = array_flip(explode("|",$m[3])); 1354 $op2 = array_flip(explode("|",$m[4])); 1355 1356 if ($len > $max_opcode_len) { 1357 $max_opcode_len = $len; 1358 } 1359 if ($code > $max_opcode) { 1360 $max_opcode = $code; 1361 } 1362 if (isset($opcodes[$code])) { 1363 die("ERROR ($def:$lineno): Opcode with code '$code' is already defined.\n"); 1364 } 1365 if (isset($opnames[$op])) { 1366 die("ERROR ($def:$lineno): Opcode with name '$op' is already defined.\n"); 1367 } 1368 $opcodes[$code] = array("op"=>$op,"op1"=>$op1,"op2"=>$op2,"code"=>""); 1369 $opnames[$op] = $code; 1370 $handler = $code; 1371 $helper = null; 1372 $list[$lineno] = array("handler"=>$handler); 1373 } else if (strpos($line,"ZEND_VM_HELPER(") === 0) { 1374 // Parsing helper's definition 1375 if (preg_match( 1376 "/^ZEND_VM_HELPER\(\s*([A-Za-z_]+)\s*,\s*([A-Z|]+)\s*,\s*([A-Z|]+)\s*\)/", 1377 $line, 1378 $m) == 0) { 1379 die("ERROR ($def:$lineno): Invalid ZEND_VM_HELPER definition.\n"); 1380 } 1381 $helper = $m[1]; 1382 $op1 = array_flip(explode("|",$m[2])); 1383 $op2 = array_flip(explode("|",$m[3])); 1384 if (isset($helpers[$helper])) { 1385 die("ERROR ($def:$lineno): Helper with name '$helper' is already defined.\n"); 1386 } 1387 $helpers[$helper] = array("op1"=>$op1,"op2"=>$op2,"param"=>null,"code"=>""); 1388 $handler = null; 1389 $list[$lineno] = array("helper"=>$helper); 1390 } else if (strpos($line,"ZEND_VM_HELPER_EX(") === 0) { 1391 // Parsing helper with parameter definition 1392 if (preg_match( 1393 "/^ZEND_VM_HELPER_EX\(\s*([A-Za-z_]+)\s*,\s*([A-Z|]+)\s*,\s*([A-Z|]+)\s*,\s*(.*)\s*\)/", 1394 $line, 1395 $m) == 0) { 1396 die("ERROR ($def:$lineno): Invalid ZEND_VM_HELPER definition.\n"); 1397 } 1398 $helper = $m[1]; 1399 $op1 = array_flip(explode("|",$m[2])); 1400 $op2 = array_flip(explode("|",$m[3])); 1401 $param = $m[4]; 1402 if (isset($helpers[$helper])) { 1403 die("ERROR ($def:$lineno): Helper with name '$helper' is already defined.\n"); 1404 } 1405 1406 // Store parameter 1407 $params[$param] = 1; 1408 1409 $helpers[$helper] = array("op1"=>$op1,"op2"=>$op2,"param"=>$param,"code"=>""); 1410 $handler = null; 1411 $list[$lineno] = array("helper"=>$helper); 1412 } else if (strpos($line,"ZEND_VM_EXPORT_HANDLER(") === 0) { 1413 if (preg_match( 1414 "/^ZEND_VM_EXPORT_HANDLER\(\s*([A-Za-z_]+)\s*,\s*([A-Z_]+)\s*\)/", 1415 $line, 1416 $m) == 0) { 1417 die("ERROR ($def:$lineno): Invalid ZEND_VM_EXPORT_HANDLER definition.\n"); 1418 } 1419 if (!isset($opnames[$m[2]])) { 1420 die("ERROR ($def:$lineno): opcode '{$m[2]}' is not defined.\n"); 1421 } 1422 $export[] = array("handler",$m[1],$m[2]); 1423 } else if (strpos($line,"ZEND_VM_EXPORT_HELPER(") === 0) { 1424 if (preg_match( 1425 "/^ZEND_VM_EXPORT_HELPER\(\s*([A-Za-z_]+)\s*,\s*([A-Za-z_]+)\s*\)/", 1426 $line, 1427 $m) == 0) { 1428 die("ERROR ($def:$lineno): Invalid ZEND_VM_EXPORT_HELPER definition.\n"); 1429 } 1430 if (!isset($helpers[$m[2]])) { 1431 die("ERROR ($def:$lineno): helper '{$m[2]}' is not defined.\n"); 1432 } 1433 $export[] = array("helper",$m[1],$m[2]); 1434 } else if (strpos($line,"ZEND_VM_DEFINE_OP(") === 0) { 1435 if (preg_match( 1436 "/^ZEND_VM_DEFINE_OP\(\s*([0-9]+)\s*,\s*([A-Z_]+)\s*\);/", 1437 $line, 1438 $m) == 0) { 1439 die("ERROR ($def:$lineno): Invalid ZEND_VM_DEFINE_OP definition.\n"); 1440 } 1441 $code = (int)$m[1]; 1442 $op = $m[2]; 1443 $len = strlen($op); 1444 1445 if ($len > $max_opcode_len) { 1446 $max_opcode_len = $len; 1447 } 1448 if ($code > $max_opcode) { 1449 $max_opcode = $code; 1450 } 1451 if (isset($opcodes[$code])) { 1452 die("ERROR ($def:$lineno): Opcode with code '$code' is already defined.\n"); 1453 } 1454 if (isset($opnames[$op])) { 1455 die("ERROR ($def:$lineno): Opcode with name '$op' is already defined.\n"); 1456 } 1457 $opcodes[$code] = array("op"=>$op,"code"=>""); 1458 $opnames[$op] = $code; 1459 } else if ($handler !== null) { 1460 // Add line of code to current opcode handler 1461 $opcodes[$handler]["code"] .= $line; 1462 } else if ($helper !== null) { 1463 // Add line of code to current helper 1464 $helpers[$helper]["code"] .= $line; 1465 } 1466 } 1467 1468 ksort($opcodes); 1469 1470 // Search for opcode handlers those are used by other opcode handlers 1471 foreach ($opcodes as $dsc) { 1472 if (preg_match("/ZEND_VM_DISPATCH_TO_HANDLER\(\s*([A-Z_]*)\s*\)/m", $dsc["code"], $m)) { 1473 $op = $m[1]; 1474 if (!isset($opnames[$op])) { 1475 die("ERROR ($def:$lineno): Opcode with name '$op' is not defined.\n"); 1476 } 1477 $code = $opnames[$op]; 1478 $opcodes[$code]['use'] = 1; 1479 } 1480 } 1481 1482 // Generate opcode #defines (zend_vm_opcodes.h) 1483 $code_len = strlen((string)$max_opcode); 1484 $f = fopen(__DIR__ . "/zend_vm_opcodes.h", "w+") or die("ERROR: Cannot create zend_vm_opcodes.h\n"); 1485 1486 // Insert header 1487 out($f, $GLOBALS['header_text']); 1488 fputs($f, "#ifndef ZEND_VM_OPCODES_H\n#define ZEND_VM_OPCODES_H\n\n"); 1489 fputs($f, "#define ZEND_VM_SPEC\t\t" . ZEND_VM_SPEC . "\n"); 1490 fputs($f, "#define ZEND_VM_LINES\t\t" . ZEND_VM_LINES . "\n"); 1491 fputs($f, "#define ZEND_VM_KIND_CALL\t" . ZEND_VM_KIND_CALL . "\n"); 1492 fputs($f, "#define ZEND_VM_KIND_SWITCH\t" . ZEND_VM_KIND_SWITCH . "\n"); 1493 fputs($f, "#define ZEND_VM_KIND_GOTO\t" . ZEND_VM_KIND_GOTO . "\n"); 1494 fputs($f, "#define ZEND_VM_KIND\t\t" . $GLOBALS["vm_kind_name"][ZEND_VM_KIND] . "\n"); 1495 fputs($f, "\n"); 1496 fputs($f, "BEGIN_EXTERN_C()\n\n"); 1497 fputs($f, "ZEND_API const char *zend_get_opcode_name(zend_uchar opcode);\n\n"); 1498 fputs($f, "END_EXTERN_C()\n\n"); 1499 1500 foreach ($opcodes as $code => $dsc) { 1501 $code = str_pad((string)$code,$code_len," ",STR_PAD_LEFT); 1502 $op = str_pad($dsc["op"],$max_opcode_len); 1503 fputs($f,"#define $op $code\n"); 1504 } 1505 1506 fputs($f, "\n#endif\n"); 1507 fclose($f); 1508 echo "zend_vm_opcodes.h generated successfully.\n"; 1509 1510 // zend_vm_opcodes.c 1511 $f = fopen(__DIR__ . "/zend_vm_opcodes.c", "w+") or die("ERROR: Cannot create zend_vm_opcodes.c\n"); 1512 1513 // Insert header 1514 out($f, $GLOBALS['header_text']); 1515 fputs($f,"#include <stdio.h>\n"); 1516 fputs($f,"#include <zend.h>\n\n"); 1517 1518 fputs($f,"const char *zend_vm_opcodes_map[".($max_opcode + 1)."] = {\n"); 1519 for ($i = 0; $i <= $max_opcode; $i++) { 1520 fputs($f,"\t".(isset($opcodes[$i]["op"])?'"'.$opcodes[$i]["op"].'"':"NULL").",\n"); 1521 } 1522 fputs($f, "};\n\n"); 1523 1524 fputs($f, "ZEND_API const char* zend_get_opcode_name(zend_uchar opcode) {\n"); 1525 fputs($f, "\treturn zend_vm_opcodes_map[opcode];\n"); 1526 fputs($f, "}\n"); 1527 1528 fclose($f); 1529 echo "zend_vm_opcodes.c generated successfully.\n"; 1530 1531 // Generate zend_vm_execute.h 1532 $f = fopen(__DIR__ . "/zend_vm_execute.h", "w+") or die("ERROR: Cannot create zend_vm_execute.h\n"); 1533 $executor_file = realpath(__DIR__ . "/zend_vm_execute.h"); 1534 1535 // Insert header 1536 out($f, $GLOBALS['header_text']); 1537 1538 out($f, "#ifdef ZEND_WIN32\n"); 1539 // Suppress free_op1 warnings on Windows 1540 out($f, "# pragma warning(once : 4101)\n"); 1541 if (ZEND_VM_SPEC) { 1542 // Suppress (<non-zero constant> || <expression>) warnings on windows 1543 out($f, "# pragma warning(once : 6235)\n"); 1544 // Suppress (<zero> && <expression>) warnings on windows 1545 out($f, "# pragma warning(once : 6237)\n"); 1546 // Suppress (<non-zero constant> && <expression>) warnings on windows 1547 out($f, "# pragma warning(once : 6239)\n"); 1548 // Suppress (<expression> && <non-zero constant>) warnings on windows 1549 out($f, "# pragma warning(once : 6240)\n"); 1550 // Suppress (<non-zero constant> || <non-zero constant>) warnings on windows 1551 out($f, "# pragma warning(once : 6285)\n"); 1552 // Suppress (<non-zero constant> || <expression>) warnings on windows 1553 out($f, "# pragma warning(once : 6286)\n"); 1554 // Suppress constant with constant comparison warnings on windows 1555 out($f, "# pragma warning(once : 6326)\n"); 1556 } 1557 out($f, "#endif\n"); 1558 1559 // Support for ZEND_USER_OPCODE 1560 out($f, "static user_opcode_handler_t zend_user_opcode_handlers[256] = {\n"); 1561 for ($i = 0; $i < 255; ++$i) { 1562 out($f, "\t(user_opcode_handler_t)NULL,\n"); 1563 } 1564 out($f, "\t(user_opcode_handler_t)NULL\n};\n\n"); 1565 1566 out($f, "static zend_uchar zend_user_opcodes[256] = {"); 1567 for ($i = 0; $i < 255; ++$i) { 1568 if ($i % 16 == 1) out($f, "\n\t"); 1569 out($f, "$i,"); 1570 } 1571 out($f, "255\n};\n\n"); 1572 1573 // Generate specialized executor 1574 gen_executor($f, $skl, ZEND_VM_SPEC, ZEND_VM_KIND, "execute", "zend_init_opcodes_handlers"); 1575 1576 // Generate zend_vm_get_opcode_handler() function 1577 out($f, "static const void *zend_vm_get_opcode_handler(zend_uchar opcode, const zend_op* op)\n"); 1578 out($f, "{\n"); 1579 if (!ZEND_VM_SPEC) { 1580 out($f, "\treturn zend_opcode_handlers[opcode];\n"); 1581 } else { 1582 out($f, "\t\tstatic const int zend_vm_decode[] = {\n"); 1583 out($f, "\t\t\t_UNUSED_CODE, /* 0 */\n"); 1584 out($f, "\t\t\t_CONST_CODE, /* 1 = IS_CONST */\n"); 1585 out($f, "\t\t\t_TMP_CODE, /* 2 = IS_TMP_VAR */\n"); 1586 out($f, "\t\t\t_UNUSED_CODE, /* 3 */\n"); 1587 out($f, "\t\t\t_VAR_CODE, /* 4 = IS_VAR */\n"); 1588 out($f, "\t\t\t_UNUSED_CODE, /* 5 */\n"); 1589 out($f, "\t\t\t_UNUSED_CODE, /* 6 */\n"); 1590 out($f, "\t\t\t_UNUSED_CODE, /* 7 */\n"); 1591 out($f, "\t\t\t_UNUSED_CODE, /* 8 = IS_UNUSED */\n"); 1592 out($f, "\t\t\t_UNUSED_CODE, /* 9 */\n"); 1593 out($f, "\t\t\t_UNUSED_CODE, /* 10 */\n"); 1594 out($f, "\t\t\t_UNUSED_CODE, /* 11 */\n"); 1595 out($f, "\t\t\t_UNUSED_CODE, /* 12 */\n"); 1596 out($f, "\t\t\t_UNUSED_CODE, /* 13 */\n"); 1597 out($f, "\t\t\t_UNUSED_CODE, /* 14 */\n"); 1598 out($f, "\t\t\t_UNUSED_CODE, /* 15 */\n"); 1599 out($f, "\t\t\t_CV_CODE /* 16 = IS_CV */\n"); 1600 out($f, "\t\t};\n"); 1601 out($f, "\t\treturn zend_opcode_handlers[opcode * 25 + zend_vm_decode[op->op1_type] * 5 + zend_vm_decode[op->op2_type]];\n"); 1602 } 1603 out($f, "}\n\n"); 1604 1605 // Generate zend_vm_get_opcode_handler() function 1606 out($f, "ZEND_API void zend_vm_set_opcode_handler(zend_op* op)\n"); 1607 out($f, "{\n"); 1608 out($f, "\top->handler = zend_vm_get_opcode_handler(zend_user_opcodes[op->opcode], op);\n"); 1609 out($f, "}\n\n"); 1610 1611 // Generate zend_vm_call_opcode_handler() function 1612 if (ZEND_VM_KIND == ZEND_VM_KIND_CALL) { 1613 out($f, "ZEND_API int zend_vm_call_opcode_handler(zend_execute_data* ex)\n"); 1614 out($f, "{\n"); 1615 out($f, "\tint ret;\n"); 1616 out($f, "#ifdef ZEND_VM_IP_GLOBAL_REG\n"); 1617 out($f, "\tconst zend_op *orig_opline = opline;\n"); 1618 out($f, "#endif\n"); 1619 out($f, "#ifdef ZEND_VM_FP_GLOBAL_REG\n"); 1620 out($f, "\tzend_execute_data *orig_execute_data = execute_data;\n"); 1621 out($f, "\texecute_data = ex;\n"); 1622 out($f, "#else\n"); 1623 out($f, "\tzend_execute_data *execute_data = ex;\n"); 1624 out($f, "#endif\n"); 1625 out($f, "\n"); 1626 out($f, "\tLOAD_OPLINE();\n"); 1627 out($f,"#if defined(ZEND_VM_FP_GLOBAL_REG) && defined(ZEND_VM_IP_GLOBAL_REG)\n"); 1628 out($f, "\t((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n"); 1629 out($f, "\tif (EXPECTED(opline)) {\n"); 1630 out($f, "\t\tret = execute_data != ex ? (int)(execute_data->prev_execute_data != ex) + 1 : 0;\n"); 1631 out($f, "\t\tSAVE_OPLINE();\n"); 1632 out($f, "\t} else {\n"); 1633 out($f, "\t\tret = -1;\n"); 1634 out($f, "\t}\n"); 1635 out($f, "#else\n"); 1636 out($f, "\tret = ((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n"); 1637 out($f, "\tSAVE_OPLINE();\n"); 1638 out($f, "#endif\n"); 1639 out($f, "#ifdef ZEND_VM_FP_GLOBAL_REG\n"); 1640 out($f, "\texecute_data = orig_execute_data;\n"); 1641 out($f, "#endif\n"); 1642 out($f, "#ifdef ZEND_VM_IP_GLOBAL_REG\n"); 1643 out($f, "\topline = orig_opline;\n"); 1644 out($f, "#endif\n"); 1645 out($f, "\treturn ret;\n"); 1646 out($f, "}\n\n"); 1647 } else { 1648 out($f, "ZEND_API int zend_vm_call_opcode_handler(zend_execute_data* ex)\n"); 1649 out($f, "{\n"); 1650 out($f, "\tzend_error_noreturn(E_CORE_ERROR, \"zend_vm_call_opcode_handler() is not supported\");\n"); 1651 out($f, "\treturn 0;\n"); 1652 out($f, "}\n\n"); 1653 } 1654 1655 // Export handlers and helpers 1656 if (count($export) > 0 && 1657 ZEND_VM_KIND != ZEND_VM_KIND_CALL) { 1658 out($f,"#undef OPLINE\n"); 1659 out($f,"#undef DCL_OPLINE\n"); 1660 out($f,"#undef USE_OPLINE\n"); 1661 out($f,"#undef LOAD_OPLINE\n"); 1662 out($f,"#undef LOAD_NEXT_OPLINE\n"); 1663 out($f,"#undef SAVE_OPLINE\n"); 1664 out($f,"#define OPLINE EX(opline)\n"); 1665 out($f,"#define DCL_OPLINE\n"); 1666 out($f,"#define USE_OPLINE const zend_op *opline = EX(opline);\n"); 1667 out($f,"#define LOAD_OPLINE()\n"); 1668 out($f,"#define LOAD_NEXT_OPLINE() ZEND_VM_INC_OPCODE()\n"); 1669 out($f,"#define SAVE_OPLINE()\n"); 1670 out($f,"#undef HANDLE_EXCEPTION\n"); 1671 out($f,"#undef HANDLE_EXCEPTION_LEAVE\n"); 1672 out($f,"#define HANDLE_EXCEPTION() LOAD_OPLINE(); ZEND_VM_CONTINUE()\n"); 1673 out($f,"#define HANDLE_EXCEPTION_LEAVE() LOAD_OPLINE(); ZEND_VM_LEAVE()\n"); 1674 out($f,"#undef ZEND_VM_CONTINUE\n"); 1675 out($f,"#undef ZEND_VM_RETURN\n"); 1676 out($f,"#undef ZEND_VM_ENTER\n"); 1677 out($f,"#undef ZEND_VM_LEAVE\n"); 1678 out($f,"#undef ZEND_VM_DISPATCH\n"); 1679 out($f,"#define ZEND_VM_CONTINUE() return 0\n"); 1680 out($f,"#define ZEND_VM_RETURN() return -1\n"); 1681 out($f,"#define ZEND_VM_ENTER() return 1\n"); 1682 out($f,"#define ZEND_VM_LEAVE() return 2\n"); 1683 out($f,"#define ZEND_VM_DISPATCH(opcode, opline) return zend_vm_get_opcode_handler(opcode, opline)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n\n"); 1684 out($f,"\n"); 1685 } 1686 foreach ($export as $dsk) { 1687 list($kind, $func, $name) = $dsk; 1688 out($f, "ZEND_API int $func("); 1689 if ($kind == "handler") { 1690 out($f, "ZEND_OPCODE_HANDLER_ARGS)\n"); 1691 $code = $opcodes[$opnames[$name]]['code']; 1692 } else { 1693 $h = $helpers[$name]; 1694 if ($h['param'] == null) { 1695 out($f, "ZEND_OPCODE_HANDLER_ARGS)\n"); 1696 } else { 1697 out($f, $h['param']. " ZEND_OPCODE_HANDLER_ARGS_DC)\n"); 1698 } 1699 $code = $h['code']; 1700 } 1701 $done = 0; 1702 if (ZEND_VM_KIND == ZEND_VM_KIND_CALL) { 1703 if ($kind == "handler") { 1704 $op = $opcodes[$opnames[$name]]; 1705 if (isset($op['op1']["ANY"]) && isset($op['op2']["ANY"])) { 1706 out($f, "{\n\treturn ".$name.(ZEND_VM_SPEC?"_SPEC":"")."_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n}\n\n"); 1707 $done = 1; 1708 } 1709 } else if ($helpers[$name]["param"] == null) { 1710 $h = $helpers[$name]; 1711 if (isset($h['op1']["ANY"]) && isset($h['op2']["ANY"])) { 1712 out($f, "{\n\treturn ".$name.(ZEND_VM_SPEC?"_SPEC":"")."(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n}\n\n"); 1713 $done = 1; 1714 } 1715 } 1716 } 1717 if (!$done) { 1718 gen_code($f, 0, ZEND_VM_KIND_CALL, 1, $code, 'ANY', 'ANY', $name); 1719 } 1720 } 1721 1722 fclose($f); 1723 echo "zend_vm_execute.h generated successfully.\n"; 1724} 1725 1726function usage() { 1727 echo("\nUsage: php zend_vm_gen.php [options]\n". 1728 "\nOptions:". 1729 "\n --with-vm-kind=CALL|SWITCH|GOTO - select threading model (default is CALL)". 1730 "\n --without-specializer - disable executor specialization". 1731 "\n --with-lines - enable #line directives". 1732 "\n\n"); 1733} 1734 1735// Parse arguments 1736for ($i = 1; $i < $argc; $i++) { 1737 if (strpos($argv[$i],"--with-vm-kind=") === 0) { 1738 $kind = substr($argv[$i], strlen("--with-vm-kind=")); 1739 switch ($kind) { 1740 case "CALL": 1741 define("ZEND_VM_KIND", ZEND_VM_KIND_CALL); 1742 break; 1743 case "SWITCH": 1744 define("ZEND_VM_KIND", ZEND_VM_KIND_SWITCH); 1745 break; 1746 case "GOTO": 1747 define("ZEND_VM_KIND", ZEND_VM_KIND_GOTO); 1748 break; 1749 default: 1750 echo("ERROR: Invalid vm kind '$kind'\n"); 1751 usage(); 1752 die(); 1753 } 1754 } else if ($argv[$i] == "--without-specializer") { 1755 // Disabling specialization 1756 define("ZEND_VM_SPEC", 0); 1757 } else if ($argv[$i] == "--with-lines") { 1758 // Enabling debugging using original zend_vm_def.h 1759 define("ZEND_VM_LINES", 1); 1760 } else if ($argv[$i] == "--help") { 1761 usage(); 1762 exit(); 1763 } else { 1764 echo("ERROR: Invalid option '".$argv[$i]."'\n"); 1765 usage(); 1766 die(); 1767 } 1768} 1769 1770// Using defaults 1771if (!defined("ZEND_VM_KIND")) { 1772 // Using CALL threading by default 1773 define("ZEND_VM_KIND", ZEND_VM_KIND_CALL); 1774} 1775if (!defined("ZEND_VM_SPEC")) { 1776 // Using specialized executor by default 1777 define("ZEND_VM_SPEC", 1); 1778} 1779if (!defined("ZEND_VM_LINES")) { 1780 // Disabling #line directives 1781 define("ZEND_VM_LINES", 0); 1782} 1783 1784gen_vm(__DIR__ . "/zend_vm_def.h", __DIR__ . "/zend_vm_execute.skl"); 1785 1786?> 1787