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