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