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