Advertisement
Guest User

Untitled

a guest
Sep 30th, 2014
218
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 54.02 KB | None | 0 0
  1. <?php
  2. /*
  3.    +----------------------------------------------------------------------+
  4.    | Zend Engine                                                          |
  5.    +----------------------------------------------------------------------+
  6.    | Copyright (c) 1998-2014 Zend Technologies Ltd. (http://www.zend.com) |
  7.    +----------------------------------------------------------------------+
  8.    | This source file is subject to version 2.00 of the Zend license,     |
  9.    | that is bundled with this package in the file LICENSE, and is        |
  10.    | available through the world-wide-web at the following url:           |
  11.    | http://www.zend.com/license/2_00.txt.                                |
  12.    | If you did not receive a copy of the Zend license and are unable to  |
  13.    | obtain it through the world-wide-web, please send a note to          |
  14.    | license@zend.com so we can mail you a copy immediately.              |
  15.    +----------------------------------------------------------------------+
  16.    | Authors: Dmitry Stogov <dmitry@zend.com>                             |
  17.    +----------------------------------------------------------------------+
  18.  
  19.      $Id$
  20. */
  21.  
  22. $header_text = <<< DATA
  23. /*
  24.    +----------------------------------------------------------------------+
  25.    | Zend Engine                                                          |
  26.    +----------------------------------------------------------------------+
  27.    | Copyright (c) 1998-2014 Zend Technologies Ltd. (http://www.zend.com) |
  28.    +----------------------------------------------------------------------+
  29.    | This source file is subject to version 2.00 of the Zend license,     |
  30.    | that is bundled with this package in the file LICENSE, and is        |
  31.    | available through the world-wide-web at the following url:           |
  32.    | http://www.zend.com/license/2_00.txt.                                |
  33.    | If you did not receive a copy of the Zend license and are unable to  |
  34.    | obtain it through the world-wide-web, please send a note to          |
  35.    | license@zend.com so we can mail you a copy immediately.              |
  36.    +----------------------------------------------------------------------+
  37.    | Authors: Andi Gutmans <andi@zend.com>                                |
  38.    |          Zeev Suraski <zeev@zend.com>                                |
  39.    |          Dmitry Stogov <dmitry@zend.com>                             |
  40.    +----------------------------------------------------------------------+
  41. */
  42.  
  43.  
  44. DATA;
  45.  
  46. /*
  47.     This script creates zend_vm_execute.h and zend_vm_opcodes.h
  48.     from existing zend_vm_def.h and zend_vm_execute.skl
  49. */
  50.  
  51. error_reporting(E_ALL);
  52.  
  53. define("ZEND_VM_KIND_CALL",   1);
  54. define("ZEND_VM_KIND_SWITCH", 2);
  55. define("ZEND_VM_KIND_GOTO",   3);
  56.  
  57. $op_types = array(
  58.     "ANY",
  59.     "CONST",
  60.     "TMP",
  61.     "VAR",
  62.     "UNUSED",
  63.     "CV"
  64. );
  65.  
  66. $prefix = array(
  67.     "ANY"    => "",
  68.     "TMP"    => "_TMP",
  69.     "VAR"    => "_VAR",
  70.     "CONST"  => "_CONST",
  71.     "UNUSED" => "_UNUSED",
  72.     "CV"     => "_CV",
  73. );
  74.  
  75. $typecode = array(
  76.     "ANY"    => 0,
  77.     "TMP"    => 1,
  78.     "VAR"    => 2,
  79.     "CONST"  => 0,
  80.     "UNUSED" => 3,
  81.     "CV"     => 4,
  82. );
  83.  
  84. $op1_type = array(
  85.     "ANY"    => "opline->op1_type",
  86.     "TMP"    => "IS_TMP_VAR",
  87.     "VAR"    => "IS_VAR",
  88.     "CONST"  => "IS_CONST",
  89.     "UNUSED" => "IS_UNUSED",
  90.     "CV"     => "IS_CV",
  91. );
  92.  
  93. $op2_type = array(
  94.     "ANY"    => "opline->op2_type",
  95.     "TMP"    => "IS_TMP_VAR",
  96.     "VAR"    => "IS_VAR",
  97.     "CONST"  => "IS_CONST",
  98.     "UNUSED" => "IS_UNUSED",
  99.     "CV"     => "IS_CV",
  100. );
  101.  
  102. $op1_free = array(
  103.     "ANY"    => "(free_op1.var != NULL)",
  104.     "TMP"    => "1",
  105.     "VAR"    => "(free_op1.var != NULL)",
  106.     "CONST"  => "0",
  107.     "UNUSED" => "0",
  108.     "CV"     => "0",
  109. );
  110.  
  111. $op2_free = array(
  112.     "ANY"    => "(free_op2.var != NULL)",
  113.     "TMP"    => "1",
  114.     "VAR"    => "(free_op2.var != NULL)",
  115.     "CONST"  => "0",
  116.     "UNUSED" => "0",
  117.     "CV"     => "0",
  118. );
  119.  
  120. $op1_get_zval_ptr = array(
  121.     "ANY"    => "get_zval_ptr(opline->op1_type, &opline->op1, execute_data, &free_op1, \\1)",
  122.     "TMP"    => "_get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC)",
  123.     "VAR"    => "_get_zval_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC)",
  124.     "CONST"  => "opline->op1.zv",
  125.     "UNUSED" => "NULL",
  126.     "CV"     => "_get_zval_ptr_cv_\\1(execute_data, opline->op1.var TSRMLS_CC)",
  127. );
  128.  
  129. $op2_get_zval_ptr = array(
  130.     "ANY"    => "get_zval_ptr(opline->op2_type, &opline->op2, execute_data, &free_op2, \\1)",
  131.     "TMP"    => "_get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC)",
  132.     "VAR"    => "_get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC)",
  133.     "CONST"  => "opline->op2.zv",
  134.     "UNUSED" => "NULL",
  135.     "CV"     => "_get_zval_ptr_cv_\\1(execute_data, opline->op2.var TSRMLS_CC)",
  136. );
  137.  
  138. $op1_get_zval_ptr_ptr = array(
  139.     "ANY"    => "get_zval_ptr_ptr(opline->op1_type, &opline->op1, execute_data, &free_op1, \\1)",
  140.     "TMP"    => "NULL",
  141.     "VAR"    => "_get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC)",
  142.     "CONST"  => "NULL",
  143.     "UNUSED" => "NULL",
  144.     "CV"     => "_get_zval_ptr_ptr_cv_\\1(execute_data, opline->op1.var TSRMLS_CC)",
  145. );
  146. $op1_get_zval_ptr_ptr_fast = $op1_get_zval_ptr_ptr;
  147. $op1_get_zval_ptr_ptr_fast["VAR"] = "_get_zval_ptr_ptr_var_fast(opline->op1.var, execute_data, &free_op1 TSRMLS_CC)";
  148.  
  149. $op2_get_zval_ptr_ptr = array(
  150.     "ANY"    => "get_zval_ptr_ptr(opline->op2_type, &opline->op2, execute_data, &free_op2, \\1)",
  151.     "TMP"    => "NULL",
  152.     "VAR"    => "_get_zval_ptr_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC)",
  153.     "CONST"  => "NULL",
  154.     "UNUSED" => "NULL",
  155.     "CV"     => "_get_zval_ptr_ptr_cv_\\1(execute_data, opline->op2.var TSRMLS_CC)",
  156. );
  157. $op2_get_zval_ptr_ptr_fast = $op2_get_zval_ptr_ptr;
  158. $op2_get_zval_ptr_ptr_fast["VAR"] = "_get_zval_ptr_ptr_var_fast(opline->op2.var, execute_data, &free_op2 TSRMLS_CC)";
  159.  
  160. $op1_get_obj_zval_ptr = array(
  161.     "ANY"    => "get_obj_zval_ptr(opline->op1_type, &opline->op1, execute_data, &free_op1, \\1)",
  162.     "TMP"    => "_get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC)",
  163.     "VAR"    => "_get_zval_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC)",
  164.     "CONST"  => "opline->op1.zv",
  165.     "UNUSED" => "_get_obj_zval_ptr_unused(TSRMLS_C)",
  166.     "CV"     => "_get_zval_ptr_cv_\\1(execute_data, opline->op1.var TSRMLS_CC)",
  167. );
  168.  
  169. $op2_get_obj_zval_ptr = array(
  170.     "ANY"    => "get_obj_zval_ptr(opline->op2_type, &opline->op2, execute_data, &free_op2, \\1)",
  171.     "TMP"    => "_get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC)",
  172.     "VAR"    => "_get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC)",
  173.     "CONST"  => "opline->op2.zv",
  174.     "UNUSED" => "_get_obj_zval_ptr_unused(TSRMLS_C)",
  175.     "CV"     => "_get_zval_ptr_cv_\\1(execute_data, opline->op2.var TSRMLS_CC)",
  176. );
  177.  
  178. $op1_get_obj_zval_ptr_ptr = array(
  179.     "ANY"    => "get_obj_zval_ptr_ptr(opline->op1_type, &opline->op1, execute_data, &free_op1, \\1)",
  180.     "TMP"    => "NULL",
  181.     "VAR"    => "_get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC)",
  182.     "CONST"  => "NULL",
  183.     "UNUSED" => "_get_obj_zval_ptr_ptr_unused(TSRMLS_C)",
  184.     "CV"     => "_get_zval_ptr_ptr_cv_\\1(execute_data, opline->op1.var TSRMLS_CC)",
  185. );
  186. $op1_get_obj_zval_ptr_ptr_fast = $op1_get_obj_zval_ptr_ptr;
  187. $op1_get_obj_zval_ptr_ptr_fast["VAR"] = "_get_zval_ptr_ptr_var_fast(opline->op1.var, execute_data, &free_op1 TSRMLS_CC)";
  188.  
  189. $op2_get_obj_zval_ptr_ptr = array(
  190.     "ANY"    => "get_obj_zval_ptr_ptr(opline->op2_type, &opline->op2, execute_data, &free_op2, \\1)",
  191.     "TMP"    => "NULL",
  192.     "VAR"    => "_get_zval_ptr_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC)",
  193.     "CONST"  => "NULL",
  194.     "UNUSED" => "_get_obj_zval_ptr_ptr_unused(TSRMLS_C)",
  195.     "CV"     => "_get_zval_ptr_ptr_cv_\\1(execute_data, opline->op2.var TSRMLS_CC)",
  196. );
  197. $op2_get_obj_zval_ptr_ptr_fast = $op2_get_obj_zval_ptr_ptr;
  198. $op2_get_obj_zval_ptr_ptr_fast["VAR"] = "_get_zval_ptr_ptr_var_fast(opline->op2.var, execute_data, &free_op2 TSRMLS_CC)";
  199.  
  200. $op1_is_tmp_free = array(
  201.     "ANY"    => "IS_TMP_FREE(free_op1)",
  202.     "TMP"    => "1",
  203.     "VAR"    => "0",
  204.     "CONST"  => "0",
  205.     "UNUSED" => "0",
  206.     "CV"     => "0",
  207. );
  208.  
  209. $op2_is_tmp_free = array(
  210.     "ANY"    => "IS_TMP_FREE(free_op2)",
  211.     "TMP"    => "1",
  212.     "VAR"    => "0",
  213.     "CONST"  => "0",
  214.     "UNUSED" => "0",
  215.     "CV"     => "0",
  216. );
  217.  
  218. $op1_free_op = array(
  219.     "ANY"    => "FREE_OP(free_op1)",
  220.     "TMP"    => "zval_dtor(free_op1.var)",
  221.     "VAR"    => "zval_ptr_dtor_nogc(&free_op1.var)",
  222.     "CONST"  => "",
  223.     "UNUSED" => "",
  224.     "CV"     => "",
  225. );
  226.  
  227. $op2_free_op = array(
  228.     "ANY"    => "FREE_OP(free_op2)",
  229.     "TMP"    => "zval_dtor(free_op2.var)",
  230.     "VAR"    => "zval_ptr_dtor_nogc(&free_op2.var)",
  231.     "CONST"  => "",
  232.     "UNUSED" => "",
  233.     "CV"     => "",
  234. );
  235.  
  236. $op1_free_op_if_var = array(
  237.     "ANY"    => "FREE_OP_IF_VAR(free_op1)",
  238.     "TMP"    => "",
  239.     "VAR"    => "zval_ptr_dtor_nogc(&free_op1.var)",
  240.     "CONST"  => "",
  241.     "UNUSED" => "",
  242.     "CV"     => "",
  243. );
  244.  
  245. $op2_free_op_if_var = array(
  246.     "ANY"    => "FREE_OP_IF_VAR(free_op2)",
  247.     "TMP"    => "",
  248.     "VAR"    => "zval_ptr_dtor_nogc(&free_op2.var)",
  249.     "CONST"  => "",
  250.     "UNUSED" => "",
  251.     "CV"     => "",
  252. );
  253.  
  254. $op1_free_op_var_ptr = array(
  255.     "ANY"    => "if (free_op1.var) {zval_ptr_dtor_nogc(&free_op1.var);}",
  256.     "TMP"    => "",
  257.     "VAR"    => "if (free_op1.var) {zval_ptr_dtor_nogc(&free_op1.var);}",
  258.     "CONST"  => "",
  259.     "UNUSED" => "",
  260.     "CV"     => "",
  261. );
  262. $op1_free_op_var_ptr_fast = $op1_free_op_var_ptr;
  263. $op1_free_op_var_ptr_fast["VAR"] = "zval_ptr_dtor_nogc(&free_op1.var)";
  264.  
  265. $op2_free_op_var_ptr = array(
  266.     "ANY"    => "if (free_op2.var) {zval_ptr_dtor_nogc(&free_op2.var);}",
  267.     "TMP"    => "",
  268.     "VAR"    => "if (free_op2.var) {zval_ptr_dtor_nogc(&free_op2.var);}",
  269.     "CONST"  => "",
  270.     "UNUSED" => "",
  271.     "CV"     => "",
  272. );
  273. $op2_free_op_var_ptr_fast = $op2_free_op_var_ptr;
  274. $op2_free_op_var_ptr_fast["VAR"] = "zval_ptr_dtor_nogc(&free_op2.var)";
  275.  
  276. $list    = array(); // list of opcode handlers and helpers in original order
  277. $opcodes = array(); // opcode handlers by code
  278. $helpers = array(); // opcode helpers by name
  279. $params  = array(); // parameters of helpers
  280. $opnames = array(); // opcode name to code mapping
  281. $line_no = 1;
  282.  
  283. // Writes $s into resulting executor
  284. function out($f, $s) {
  285.     global $line_no;
  286.  
  287.     fputs($f,$s);
  288.     $line_no += substr_count($s, "\n");
  289. }
  290.  
  291. // Resets #line directives in resulting executor
  292. function out_line($f) {
  293.     global $line_no, $executor_file;
  294.  
  295.     fputs($f,"#line ".($line_no+1)." \"".$executor_file."\"\n");
  296.     ++$line_no;
  297. }
  298.  
  299. // Returns name of specialized helper
  300. function helper_name($name, $spec, $op1, $op2) {
  301.     global $prefix, $helpers;
  302.  
  303.     if (isset($helpers[$name])) {
  304.         // If we haven't helper with specified spicialized operands then
  305.         // using unspecialized helper
  306.         if (!isset($helpers[$name]["op1"][$op1]) &&
  307.             isset($helpers[$name]["op1"]["ANY"])) {
  308.             $op1 = "ANY";
  309.         }
  310.         if (!isset($helpers[$name]["op2"][$op2]) &&
  311.             isset($helpers[$name]["op2"]["ANY"])) {
  312.             $op2 = "ANY";
  313.         }
  314.     }
  315.     return $name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2];
  316. }
  317.  
  318. // Generates code for opcode handler or helper
  319. function gen_code($f, $spec, $kind, $export, $code, $op1, $op2, $name) {
  320.     global $op1_type, $op2_type, $op1_get_zval_ptr, $op2_get_zval_ptr,
  321.         $op1_get_zval_ptr_ptr, $op2_get_zval_ptr_ptr,
  322.         $op1_get_obj_zval_ptr, $op2_get_obj_zval_ptr,
  323.         $op1_get_obj_zval_ptr_ptr, $op2_get_obj_zval_ptr_ptr,
  324.         $op1_is_tmp_free, $op2_is_tmp_free, $op1_free, $op2_free,
  325.         $op1_free_op, $op2_free_op, $op1_free_op_if_var, $op2_free_op_if_var,
  326.         $op1_free_op_var_ptr, $op2_free_op_var_ptr, $prefix,
  327.         $op1_get_zval_ptr_ptr_fast, $op2_get_zval_ptr_ptr_fast,
  328.         $op1_get_obj_zval_ptr_ptr_fast, $op2_get_obj_zval_ptr_ptr_fast,
  329.         $op1_free_op_var_ptr_fast, $op2_free_op_var_ptr_fast;
  330.  
  331.     // Specializing
  332.     $code = preg_replace(
  333.         array(
  334.             "/OP1_TYPE/",
  335.             "/OP2_TYPE/",
  336.             "/OP1_FREE/",
  337.             "/OP2_FREE/",
  338.             "/GET_OP1_ZVAL_PTR\(([^)]*)\)/",
  339.             "/GET_OP2_ZVAL_PTR\(([^)]*)\)/",
  340.             "/GET_OP1_ZVAL_PTR_PTR\(([^)]*)\)/",
  341.             "/GET_OP2_ZVAL_PTR_PTR\(([^)]*)\)/",
  342.             "/GET_OP1_OBJ_ZVAL_PTR\(([^)]*)\)/",
  343.             "/GET_OP2_OBJ_ZVAL_PTR\(([^)]*)\)/",
  344.             "/GET_OP1_OBJ_ZVAL_PTR_PTR\(([^)]*)\)/",
  345.             "/GET_OP2_OBJ_ZVAL_PTR_PTR\(([^)]*)\)/",
  346.             "/IS_OP1_TMP_FREE\(\)/",
  347.             "/IS_OP2_TMP_FREE\(\)/",
  348.             "/FREE_OP1\(\)/",
  349.             "/FREE_OP2\(\)/",
  350.             "/FREE_OP1_IF_VAR\(\)/",
  351.             "/FREE_OP2_IF_VAR\(\)/",
  352.             "/FREE_OP1_VAR_PTR\(\)/",
  353.             "/FREE_OP2_VAR_PTR\(\)/",
  354.             "/GET_OP1_ZVAL_PTR_PTR_FAST\(([^)]*)\)/",
  355.             "/GET_OP2_ZVAL_PTR_PTR_FAST\(([^)]*)\)/",
  356.             "/GET_OP1_OBJ_ZVAL_PTR_PTR_FAST\(([^)]*)\)/",
  357.             "/GET_OP2_OBJ_ZVAL_PTR_PTR_FAST\(([^)]*)\)/",
  358.             "/FREE_OP1_VAR_PTR_FAST\(\)/",
  359.             "/FREE_OP2_VAR_PTR_FAST\(\)/",
  360.             "/^#ifdef\s+ZEND_VM_SPEC\s*\n/m",
  361.             "/^#ifndef\s+ZEND_VM_SPEC\s*\n/m",
  362.             "/\!defined\(ZEND_VM_SPEC\)/m",
  363.             "/defined\(ZEND_VM_SPEC\)/m",
  364.             "/ZEND_VM_C_LABEL\(\s*([A-Za-z_]*)\s*\)/m",
  365.             "/ZEND_VM_C_GOTO\(\s*([A-Za-z_]*)\s*\)/m",
  366.             "/^#if\s+1\s*\\|\\|.*[^\\\\]$/m",
  367.             "/^#if\s+0\s*&&.*[^\\\\]$/m",
  368.             "/^#ifdef\s+ZEND_VM_EXPORT\s*\n/m",
  369.             "/^#ifndef\s+ZEND_VM_EXPORT\s*\n/m"
  370.         ),
  371.         array(
  372.             $op1_type[$op1],
  373.             $op2_type[$op2],
  374.             $op1_free[$op1],
  375.             $op2_free[$op2],
  376.             $op1_get_zval_ptr[$op1],
  377.             $op2_get_zval_ptr[$op2],
  378.             $op1_get_zval_ptr_ptr[$op1],
  379.             $op2_get_zval_ptr_ptr[$op2],
  380.             $op1_get_obj_zval_ptr[$op1],
  381.             $op2_get_obj_zval_ptr[$op2],
  382.             $op1_get_obj_zval_ptr_ptr[$op1],
  383.             $op2_get_obj_zval_ptr_ptr[$op2],
  384.             $op1_is_tmp_free[$op1],
  385.             $op2_is_tmp_free[$op2],
  386.             $op1_free_op[$op1],
  387.             $op2_free_op[$op2],
  388.             $op1_free_op_if_var[$op1],
  389.             $op2_free_op_if_var[$op2],
  390.             $op1_free_op_var_ptr[$op1],
  391.             $op2_free_op_var_ptr[$op2],
  392.             $op1_get_zval_ptr_ptr_fast[$op1],
  393.             $op2_get_zval_ptr_ptr_fast[$op2],
  394.             $op1_get_obj_zval_ptr_ptr_fast[$op1],
  395.             $op2_get_obj_zval_ptr_ptr_fast[$op2],
  396.             $op1_free_op_var_ptr_fast[$op1],
  397.             $op2_free_op_var_ptr_fast[$op2],
  398.             ($op1!="ANY"||$op2!="ANY")?"#if 1\n":"#if 0\n",
  399.             ($op1!="ANY"||$op2!="ANY")?"#if 0\n":"#if 1\n",
  400.             ($op1!="ANY"||$op2!="ANY")?"0":"1",
  401.             ($op1!="ANY"||$op2!="ANY")?"1":"0",
  402.             "\\1".(($spec && $kind != ZEND_VM_KIND_CALL)?("_SPEC".$prefix[$op1].$prefix[$op2]):""),
  403.             "goto \\1".(($spec && $kind != ZEND_VM_KIND_CALL)?("_SPEC".$prefix[$op1].$prefix[$op2]):""),
  404.             "#if 1",
  405.             "#if 0",
  406.             $export?"#if 1\n":"#if 0\n",
  407.             $export?"#if 0\n":"#if 1\n"
  408.         ),
  409.         $code);
  410.  
  411.     if (0 && strpos($code, '{') === 0) {
  412.         $code = "{\n\tfprintf(stderr, \"$name\\n\");\n" . substr($code, 1);
  413.     }
  414.     // Updating code according to selected threading model
  415.     switch($kind) {
  416.         case ZEND_VM_KIND_CALL:
  417.             $code = preg_replace_callback(
  418.                 array(
  419.                     "/EXECUTE_DATA/m",
  420.                     "/ZEND_VM_DISPATCH_TO_HANDLER\(\s*([A-Z_]*)\s*\)/m",
  421.                     "/ZEND_VM_DISPATCH_TO_HELPER\(\s*([A-Za-z_]*)\s*\)/m",
  422.                     "/ZEND_VM_DISPATCH_TO_HELPER_EX\(\s*([A-Za-z_]*)\s*,\s*[A-Za-z_]*\s*,\s*(.*)\s*\);/m",
  423.                 ),
  424.                 function($matches) use ($spec, $prefix, $op1, $op2) {
  425.                     if (strncasecmp($matches[0], "EXECUTE_DATA", strlen("EXECUTE_DATA")) == 0) {
  426.                         return "execute_data";
  427.                     } else if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HANDLER", strlen("ZEND_VM_DISPATCH_TO_HANDLER")) == 0) {
  428.                         return "return " . $matches[1] . ($spec?"_SPEC":"") . $prefix[$op1] . $prefix[$op2] . "_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)";
  429.                     } else if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HELPER_EX", strlen("ZEND_VM_DISPATCH_TO_HELPER_EX")) == 0) {
  430.                         return "return " . helper_name($matches[1], $spec, $op1, $op2) . "(" . $matches[2]. ", ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);";
  431.                     } else {
  432.                         return "return " . helper_name($matches[1], $spec, $op1, $op2) . "(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)";
  433.                     }
  434.                 },
  435.                 $code);
  436.             break;
  437.         case ZEND_VM_KIND_SWITCH:
  438.             $code = preg_replace_callback(
  439.                 array(
  440.                     "/EXECUTE_DATA/m",
  441.                     "/ZEND_VM_DISPATCH_TO_HANDLER\(\s*([A-Z_]*)\s*\)/m",
  442.                     "/ZEND_VM_DISPATCH_TO_HELPER\(\s*([A-Za-z_]*)\s*\)/m",
  443.                     "/ZEND_VM_DISPATCH_TO_HELPER_EX\(\s*([A-Za-z_]*)\s*,\s*([A-Za-z_]*)\s*,\s*(.*)\s*\);/m",
  444.                 ),
  445.                 function($matches) use ($spec, $prefix, $op1, $op2) {
  446.                     if (strncasecmp($matches[0], "EXECUTE_DATA", strlen("EXECUTE_DATA")) == 0) {
  447.                         return "execute_data";
  448.                     } else if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HANDLER", strlen("ZEND_VM_DISPATCH_TO_HANDLER")) == 0) {
  449.                         return "goto " . $matches[1] . ($spec?"_SPEC":"") . $prefix[$op1] . $prefix[$op2] . "_LABEL";
  450.                     } else if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HELPER_EX", strlen("ZEND_VM_DISPATCH_TO_HELPER_EX")) == 0) {
  451.                         return $matches[2] . " = " . $matches[3] .  "; goto " . helper_name($matches[1], $spec, $op1, $op2) . ";";
  452.                     } else {
  453.                         return "goto " . helper_name($matches[1], $spec, $op1, $op2);
  454.                     }
  455.                 },
  456.                     $code);
  457.             break;
  458.         case ZEND_VM_KIND_GOTO:
  459.             $code = preg_replace_callback(
  460.                 array(
  461.                     "/EXECUTE_DATA/m",
  462.                     "/ZEND_VM_DISPATCH_TO_HANDLER\(\s*([A-Z_]*)\s*\)/m",
  463.                     "/ZEND_VM_DISPATCH_TO_HELPER\(\s*([A-Za-z_]*)\s*\)/m",
  464.                     "/ZEND_VM_DISPATCH_TO_HELPER_EX\(\s*([A-Za-z_]*)\s*,\s*([A-Za-z_]*)\s*,\s*(.*)\s*\);/m",
  465.                 ),
  466.                 function($matches) use ($spec, $prefix, $op1, $op2) {
  467.                     if (strncasecmp($matches[0], "EXECUTE_DATA", strlen("EXECUTE_DATA")) == 0) {
  468.                         return "execute_data";
  469.                     } else if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HANDLER", strlen("ZEND_VM_DISPATCH_TO_HANDLER")) == 0) {
  470.                         return "goto " . $matches[1] . ($spec?"_SPEC":"") . $prefix[$op1] . $prefix[$op2] . "_HANDLER";
  471.                     } else if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HELPER_EX", strlen("ZEND_VM_DISPATCH_TO_HELPER_EX")) == 0) {
  472.                         return $matches[2] . " = " . $matches[3] .  "; goto " . helper_name($matches[1], $spec, $op1, $op2) . ";";
  473.                     } else {
  474.                         return "goto " . helper_name($matches[1], $spec, $op1, $op2);
  475.                     }
  476.                 },
  477.                     $code);
  478.             break;
  479.     }
  480.  
  481.     /* Remove unused free_op1 and free_op2 declarations */
  482.     if ($spec && preg_match_all('/^\s*zend_free_op\s+[^;]+;\s*$/me', $code, $matches, PREG_SET_ORDER)) {
  483.         $n = 0;
  484.         foreach ($matches as $match) {
  485.           $code = preg_replace('/'.preg_quote($match[0],'/').'/', "\$D$n", $code);
  486.           ++$n;
  487.         }
  488.         $del_free_op1 = (strpos($code, "free_op1") === false);
  489.         $del_free_op2 = (strpos($code, "free_op2") === false);
  490.         $n = 0;
  491.         foreach ($matches as $match) {
  492.             $dcl = $match[0];
  493.             $changed = 0;
  494.             if ($del_free_op1 && strpos($dcl, "free_op1") !== false) {
  495.                 $dcl = preg_replace("/free_op1\s*,\s*/", "", $dcl);
  496.                 $dcl = preg_replace("/free_op1\s*;/", ";", $dcl);
  497.                 $changed = 1;
  498.             }
  499.             if ($del_free_op2 && strpos($dcl, "free_op2") !== false) {
  500.                 $dcl = preg_replace("/free_op2\s*,\s*/", "", $dcl);
  501.                 $dcl = preg_replace("/free_op2\s*;/", ";", $dcl);
  502.                 $changed = 1;
  503.             }
  504.             if ($changed) {
  505.                 $dcl = preg_replace("/,\s*;/", ";", $dcl);
  506.                 $dcl = preg_replace("/zend_free_op\s*;/", "", $dcl);
  507.             }
  508.           $code = preg_replace("/\\\$D$n/", $dcl, $code);
  509.           ++$n;
  510.         }
  511.     }
  512.  
  513.     /* Remove unnecessary ';' */
  514.     $code = preg_replace('/^\s*;\s*$/m', '', $code);
  515.  
  516.     /* Remove WS */
  517.     $code = preg_replace('/[ \t]+\n/m', "\n", $code);
  518.  
  519.     out($f, $code);
  520. }
  521.  
  522. // Generates opcode handler
  523. function gen_handler($f, $spec, $kind, $name, $op1, $op2, $use, $code, $lineno) {
  524.     global $definition_file, $prefix, $typecode, $opnames;
  525.  
  526.     if (ZEND_VM_LINES) {
  527.         out($f, "#line $lineno \"$definition_file\"\n");
  528.     }
  529.  
  530.     // Generate opcode handler's entry point according to selected threading model
  531.     switch($kind) {
  532.         case ZEND_VM_KIND_CALL:
  533.             out($f,"static int ZEND_FASTCALL  ".$name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2]."_HANDLER(ZEND_OPCODE_HANDLER_ARGS)\n");
  534.             break;
  535.         case ZEND_VM_KIND_SWITCH:
  536.             if ($spec) {
  537.                 out($f,"case ".((string)($opnames[$name]*25+($typecode[$op1]*5)+$typecode[$op2])).": /*".$name."_SPEC".$prefix[$op1].$prefix[$op2]."_HANDLER*/");
  538.             } else {
  539.                 out($f,"case ".$name.":");
  540.             }
  541.             if ($use) {
  542.                 // This handler is used by other handlers. We will add label to call it.
  543.                 out($f," ".$name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2]."_LABEL:\n");
  544.             } else {
  545.                 out($f,"\n");
  546.             }
  547.             break;
  548.         case ZEND_VM_KIND_GOTO:
  549.             out($f,$name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2]."_HANDLER: ZEND_VM_GUARD(".$name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2].");\n");
  550.             break;
  551.     }
  552.  
  553.     // Generate opcode handler's code
  554.     gen_code($f, $spec, $kind, 0, $code, $op1, $op2, $name);
  555. }
  556.  
  557. // Generates helper
  558. function gen_helper($f, $spec, $kind, $name, $op1, $op2, $param, $code, $lineno) {
  559.     global $definition_file, $prefix;
  560.  
  561.     if (ZEND_VM_LINES) {
  562.         out($f, "#line $lineno \"$definition_file\"\n");
  563.     }
  564.  
  565.     // Generate helper's entry point according to selected threading model
  566.     switch($kind) {
  567.         case ZEND_VM_KIND_CALL:
  568.             if ($param == null) {
  569.               // Helper without parameters
  570.                 out($f, "static int ZEND_FASTCALL ".$name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2]."(ZEND_OPCODE_HANDLER_ARGS)\n");
  571.             } else {
  572.               // Helper with parameter
  573.                 out($f, "static int ZEND_FASTCALL ".$name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2]."(".$param.", ZEND_OPCODE_HANDLER_ARGS)\n");
  574.             }
  575.             break;
  576.         case ZEND_VM_KIND_SWITCH:
  577.             out($f, $name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2].":\n");
  578.             break;
  579.         case ZEND_VM_KIND_GOTO:
  580.             out($f, $name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2].":\n");
  581.             break;
  582.     }
  583.  
  584.     // Generate helper's code
  585.     gen_code($f, $spec, $kind, 0, $code, $op1, $op2, $name);
  586. }
  587.  
  588. // Generates array of opcode handlers (specialized or unspecialized)
  589. function gen_labels($f, $spec, $kind, $prolog) {
  590.     global $opcodes, $op_types, $prefix, $typecode;
  591.  
  592.     $next = 0;
  593.     if ($spec) {
  594.       // Emit labels for specialized executor
  595.  
  596.       // For each opcode in opcode number order
  597.         foreach($opcodes as $num => $dsc) {
  598.             while ($next != $num) {
  599.               // If some opcode numbers are not used then fill hole with pointers
  600.               // to handler of undefined opcode
  601.                 $op1t = $op_types;
  602.                 // For each op1.op_type except ANY
  603.                 foreach($op1t as $op1) {
  604.                     if ($op1 != "ANY") {
  605.                         $op2t = $op_types;
  606.                         // For each op2.op_type except ANY
  607.                         foreach($op2t as $op2) {
  608.                             if ($op2 != "ANY") {
  609.                               // Emit pointer to handler of undefined opcode
  610.                                 switch ($kind) {
  611.                                     case ZEND_VM_KIND_CALL:
  612.                                         out($f,$prolog."ZEND_NULL_HANDLER,\n");
  613.                                         break;
  614.                                     case ZEND_VM_KIND_SWITCH:
  615.                                         out($f,$prolog."(opcode_handler_t)-1,\n");
  616.                                         break;
  617.                                     case ZEND_VM_KIND_GOTO:
  618.                                         out($f,$prolog."(opcode_handler_t)&&ZEND_NULL_HANDLER,\n");
  619.                                         break;
  620.                                 }
  621.                             }
  622.                         }
  623.                     }
  624.                 }
  625.                 $next++;
  626.             }
  627.             $next = $num + 1;
  628.             $op1t = $op_types;
  629.             // For each op1.op_type except ANY
  630.             foreach($op1t as $op1) {
  631.                 if ($op1 != "ANY") {
  632.                     if (!isset($dsc["op1"][$op1])) {
  633.                         // Try to use unspecialized handler
  634.                         $op1 = "ANY";
  635.                     }
  636.                     $op2t = $op_types;
  637.                     // For each op2.op_type except ANY
  638.                     foreach($op2t as $op2) {
  639.                         if ($op2 != "ANY") {
  640.                             if (!isset($dsc["op2"][$op2])) {
  641.                                 // Try to use unspecialized handler
  642.                                 $op2 = "ANY";
  643.                             }
  644.                             // Check if specialized handler is defined
  645.                             if (isset($dsc["op1"][$op1]) &&
  646.                                 isset($dsc["op2"][$op2])) {
  647.                               // Emit pointer to specialized handler
  648.                                 switch ($kind) {
  649.                                     case ZEND_VM_KIND_CALL:
  650.                                         out($f,$prolog.$dsc["op"]."_SPEC".$prefix[$op1].$prefix[$op2]."_HANDLER,\n");
  651.                                         break;
  652.                                     case ZEND_VM_KIND_SWITCH:
  653.                                         out($f,$prolog."(opcode_handler_t)".((string)($num*25+$typecode[$op1]*5+$typecode[$op2])).",\n");
  654.                                         break;
  655.                                     case ZEND_VM_KIND_GOTO:
  656.                                         out($f,$prolog."(opcode_handler_t)&&".$dsc["op"]."_SPEC".$prefix[$op1].$prefix[$op2]."_HANDLER,\n");
  657.                                         break;
  658.                                 }
  659.                             } else {
  660.                               // Emit pinter to handler of undefined opcode
  661.                                 switch ($kind) {
  662.                                     case ZEND_VM_KIND_CALL:
  663.                                         out($f,$prolog."ZEND_NULL_HANDLER,\n");
  664.                                         break;
  665.                                     case ZEND_VM_KIND_SWITCH:
  666.                                         out($f,$prolog."(opcode_handler_t)-1,\n");
  667.                                         break;
  668.                                     case ZEND_VM_KIND_GOTO:
  669.                                         out($f,$prolog."(opcode_handler_t)&&ZEND_NULL_HANDLER,\n");
  670.                                         break;
  671.                                 }
  672.                             }
  673.                         }
  674.                     }
  675.                 }
  676.             }
  677.         }
  678.     } else {
  679.       // Emit labels for unspecialized executor
  680.  
  681.       // For each opcode in opcode number order
  682.         foreach($opcodes as $num => $dsc) {
  683.             while ($next != $num) {
  684.               // If some opcode numbers are not used then fill hole with pointers
  685.               // to handler of undefined opcode
  686.                 switch ($kind) {
  687.                     case ZEND_VM_KIND_CALL:
  688.                         out($f,$prolog."ZEND_NULL_HANDLER,\n");
  689.                         break;
  690.                     case ZEND_VM_KIND_SWITCH:
  691.                         out($f,$prolog."(opcode_handler_t)-1,\n");
  692.                         break;
  693.                     case ZEND_VM_KIND_GOTO:
  694.                         out($f,$prolog."(opcode_handler_t)&&ZEND_NULL_HANDLER,\n");
  695.                         break;
  696.                 }
  697.                 $next++;
  698.             }
  699.             $next = $num+1;
  700.           // Emit pointer to unspecialized handler
  701.             switch ($kind) {
  702.                 case ZEND_VM_KIND_CALL:
  703.                     out($f,$prolog.$dsc["op"]."_HANDLER,\n");
  704.                     break;
  705.                 case ZEND_VM_KIND_SWITCH:
  706.                     out($f,$prolog."(opcode_handler_t)".((string)$num).",\n");
  707.                     break;
  708.                 case ZEND_VM_KIND_GOTO:
  709.                     out($f,$prolog."(opcode_handler_t)&&".$dsc["op"]."_HANDLER,\n");
  710.                     break;
  711.             }
  712.         }
  713.     }
  714.  
  715.     // Emit last handler's label (undefined opcode)
  716.     switch ($kind) {
  717.         case ZEND_VM_KIND_CALL:
  718.             out($f,$prolog."ZEND_NULL_HANDLER\n");
  719.             break;
  720.         case ZEND_VM_KIND_SWITCH:
  721.             out($f,$prolog."(opcode_handler_t)-1\n");
  722.             break;
  723.         case ZEND_VM_KIND_GOTO:
  724.             out($f,$prolog."(opcode_handler_t)&&ZEND_NULL_HANDLER\n");
  725.             break;
  726.     }
  727. }
  728.  
  729. // Generates handler for undefined opcodes (CALL threading model)
  730. function gen_null_handler($f) {
  731.     static $done = 0;
  732.  
  733.     // New and all executors with CALL threading model can use the same handler
  734.     // for undefined opcodes, do we emit code for it only once
  735.     if (!$done) {
  736.         $done = 1;
  737.         out($f,"static int ZEND_FASTCALL ZEND_NULL_HANDLER(ZEND_OPCODE_HANDLER_ARGS)\n");
  738.         out($f,"{\n");
  739.         out($f,"\tzend_error_noreturn(E_ERROR, \"Invalid opcode %d/%d/%d.\", OPLINE->opcode, OPLINE->op1_type, OPLINE->op2_type);\n");
  740.         out($f,"\tZEND_VM_NEXT_OPCODE(); /* Never reached */\n");
  741.         out($f,"}\n\n");
  742.     }
  743. }
  744.  
  745. // Generates all opcode handlers and helpers (specialized or unspecilaized)
  746. function gen_executor_code($f, $spec, $kind, $prolog) {
  747.     global $list, $opcodes, $helpers, $op_types;
  748.  
  749.     if ($spec) {
  750.         // Produce specialized executor
  751.         $op1t = $op_types;
  752.         // for each op1.op_type
  753.         foreach($op1t as $op1) {
  754.             $op2t = $op_types;
  755.             // for each op2.op_type
  756.             foreach($op2t as $op2) {
  757.                 // for each handlers in helpers in original order
  758.                 foreach ($list as $lineno => $dsc) {
  759.                     if (isset($dsc["handler"])) {
  760.                         $num = $dsc["handler"];
  761.                         // Check if handler accepts such types of operands (op1 and op2)
  762.                         if (isset($opcodes[$num]["op1"][$op1]) &&
  763.                             isset($opcodes[$num]["op2"][$op2])) {
  764.                           // Generate handler code
  765.                             gen_handler($f, 1, $kind, $opcodes[$num]["op"], $op1, $op2, isset($opcodes[$num]["use"]), $opcodes[$num]["code"], $lineno);
  766.                         }
  767.                     } else if (isset($dsc["helper"])) {
  768.                         $num = $dsc["helper"];
  769.                         // Check if handler accepts such types of operands (op1 and op2)
  770.                         if (isset($helpers[$num]["op1"][$op1]) &&
  771.                             isset($helpers[$num]["op2"][$op2])) {
  772.                           // Generate helper code
  773.                             gen_helper($f, 1, $kind, $num, $op1, $op2, $helpers[$num]["param"], $helpers[$num]["code"], $lineno);
  774.                         }
  775.                     } else {
  776.                         var_dump($dsc);
  777.                         die("??? $kind:$num\n");
  778.                     }
  779.                 }
  780.             }
  781.         }
  782.     } else {
  783.         // Produce unspecialized executor
  784.  
  785.         // for each handlers in helpers in original order
  786.         foreach ($list as $lineno => $dsc) {
  787.             if (isset($dsc["handler"])) {
  788.                 $num = $dsc["handler"];
  789.               // Generate handler code
  790.                 gen_handler($f, 0, $kind, $opcodes[$num]["op"], "ANY", "ANY", isset($opcodes[$num]["use"]), $opcodes[$num]["code"], $lineno);
  791.             } else if (isset($dsc["helper"])) {
  792.                 $num = $dsc["helper"];
  793.               // Generate helper code
  794.                 gen_helper($f, 0, $kind, $num, "ANY", "ANY", $helpers[$num]["param"], $helpers[$num]["code"], $lineno);
  795.             } else {
  796.                 var_dump($dsc);
  797.                 die("??? $kind:$num\n");
  798.             }
  799.         }
  800.     }
  801.  
  802.     if (ZEND_VM_LINES) {
  803.         // Reset #line directives
  804.         out_line($f);
  805.     }
  806.  
  807.     // Generate handler for undefined opcodes
  808.     switch ($kind) {
  809.         case ZEND_VM_KIND_CALL:
  810.             gen_null_handler($f);
  811.             break;
  812.         case ZEND_VM_KIND_SWITCH:
  813.             out($f,"default:\n");
  814.             out($f,"\tzend_error_noreturn(E_ERROR, \"Invalid opcode %d/%d/%d.\", OPLINE->opcode, OPLINE->op1_type, OPLINE->op2_type);\n");
  815.             out($f,"\tZEND_VM_NEXT_OPCODE(); /* Never reached */\n");
  816.             break;
  817.         case ZEND_VM_KIND_GOTO:
  818.             out($f,"ZEND_NULL_HANDLER:\n");
  819.             out($f,"\tzend_error_noreturn(E_ERROR, \"Invalid opcode %d/%d/%d.\", OPLINE->opcode, OPLINE->op1_type, OPLINE->op2_type);\n");
  820.             out($f,"\tZEND_VM_NEXT_OPCODE(); /* Never reached */\n");
  821.             break;
  822.     }
  823. }
  824.  
  825. function skip_blanks($f, $prolog, $epilog) {
  826.     if (trim($prolog) != "" || trim($epilog) != "") {
  827.         out($f, $prolog.$epilog);
  828.     }
  829. }
  830.  
  831. // Generates executor from skeleton file and definition (specialized or unspecialized)
  832. function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name, $old) {
  833.     global $params, $skeleton_file, $line_no;
  834.  
  835.     $lineno      = 0;
  836.     foreach ($skl as $line) {
  837.       // Skeleton file contains special markers in form %NAME% those are
  838.       // substituted by custom code
  839.         if (preg_match("/(.*)[{][%]([A-Z_]*)[%][}](.*)/", $line, $m)) {
  840.             switch ($m[2]) {
  841.                 case "DEFINES":
  842.                     if (ZEND_VM_OLD_EXECUTOR && $spec) {
  843.                         out($f,"static int zend_vm_old_executor = 0;\n\n");
  844.                     }
  845.                     out($f,"static opcode_handler_t zend_vm_get_opcode_handler(zend_uchar opcode, zend_op* op);\n\n");
  846.                     switch ($kind) {
  847.                         case ZEND_VM_KIND_CALL:
  848.                             out($f,"\n");                              
  849.                             out($f,"#undef OPLINE\n");
  850.                             out($f,"#undef DCL_OPLINE\n");
  851.                             out($f,"#undef USE_OPLINE\n");
  852.                             out($f,"#undef LOAD_OPLINE\n");
  853.                             out($f,"#undef SAVE_OPLINE\n");
  854.                             out($f,"#define OPLINE EX(opline)\n");
  855.                             out($f,"#define DCL_OPLINE\n");
  856.                             out($f,"#define USE_OPLINE zend_op *opline = EX(opline);\n");
  857.                             out($f,"#define LOAD_OPLINE()\n");
  858.                             out($f,"#define SAVE_OPLINE()\n");
  859.                             out($f,"#undef CHECK_EXCEPTION\n");
  860.                             out($f,"#undef HANDLE_EXCEPTION\n");
  861.                             out($f,"#undef HANDLE_EXCEPTION_LEAVE\n");
  862.                             out($f,"#define CHECK_EXCEPTION() LOAD_OPLINE()\n");
  863.                             out($f,"#define HANDLE_EXCEPTION() LOAD_OPLINE(); ZEND_VM_CONTINUE()\n");
  864.                             out($f,"#define HANDLE_EXCEPTION_LEAVE() LOAD_OPLINE(); ZEND_VM_LEAVE()\n");
  865.                             out($f,"#define LOAD_REGS()\n");
  866.                             out($f,"#define ZEND_VM_CONTINUE()         return 0\n");
  867.                             out($f,"#define ZEND_VM_RETURN()           return 1\n");
  868.                             out($f,"#define ZEND_VM_ENTER()            return 2\n");
  869.                             out($f,"#define ZEND_VM_LEAVE()            return 3\n");
  870.                             out($f,"#define ZEND_VM_DISPATCH(opcode, opline) return zend_vm_get_opcode_handler(opcode, opline)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n\n");
  871.                             out($f,"#define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL execute_data TSRMLS_CC\n");
  872.                             break;
  873.                         case ZEND_VM_KIND_SWITCH:
  874.                             out($f,"\n");
  875.                             out($f,"#undef OPLINE\n");
  876.                             out($f,"#undef DCL_OPLINE\n");
  877.                             out($f,"#undef USE_OPLINE\n");
  878.                             out($f,"#undef LOAD_OPLINE\n");
  879.                             out($f,"#undef SAVE_OPLINE\n");
  880.                             out($f,"#define OPLINE opline\n");
  881.                             out($f,"#define DCL_OPLINE zend_op *opline;\n");
  882.                             out($f,"#define USE_OPLINE\n");
  883.                             out($f,"#define LOAD_OPLINE() opline = EX(opline)\n");
  884.                             out($f,"#define SAVE_OPLINE() EX(opline) = opline\n");
  885.                             out($f,"#undef CHECK_EXCEPTION\n");
  886.                             out($f,"#undef HANDLE_EXCEPTION\n");
  887.                             out($f,"#undef HANDLE_EXCEPTION_LEAVE\n");
  888.                             out($f,"#define CHECK_EXCEPTION() LOAD_OPLINE()\n");
  889.                             out($f,"#define HANDLE_EXCEPTION() LOAD_OPLINE(); ZEND_VM_CONTINUE()\n");
  890.                             out($f,"#define HANDLE_EXCEPTION_LEAVE() LOAD_OPLINE(); ZEND_VM_LEAVE()\n");
  891.                             out($f,"#define LOAD_REGS()\n");
  892.                             out($f,"#define ZEND_VM_CONTINUE() goto zend_vm_continue\n");
  893.                             out($f,"#define ZEND_VM_RETURN()   EG(in_execution) = original_in_execution; return\n");
  894.                             out($f,"#define ZEND_VM_ENTER()    goto zend_vm_enter\n");
  895.                             out($f,"#define ZEND_VM_LEAVE()    ZEND_VM_CONTINUE()\n");
  896.                             out($f,"#define ZEND_VM_DISPATCH(opcode, opline) dispatch_handler = zend_vm_get_opcode_handler(opcode, opline); goto zend_vm_dispatch;\n\n");
  897.                             out($f,"#define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL execute_data TSRMLS_CC\n");
  898.                             break;
  899.                         case ZEND_VM_KIND_GOTO:
  900.                             out($f,"\n");
  901.                             out($f,"#undef OPLINE\n");
  902.                             out($f,"#undef DCL_OPLINE\n");
  903.                             out($f,"#undef USE_OPLINE\n");
  904.                             out($f,"#undef LOAD_OPLINE\n");
  905.                             out($f,"#undef SAVE_OPLINE\n");
  906.                             out($f,"#define OPLINE opline\n");
  907.                             out($f,"#define DCL_OPLINE zend_op *opline;\n");
  908.                             out($f,"#define USE_OPLINE\n");
  909.                             out($f,"#define LOAD_OPLINE() opline = EX(opline)\n");
  910.                             out($f,"#define SAVE_OPLINE() EX(opline) = opline\n");
  911.                             out($f,"#undef CHECK_EXCEPTION\n");
  912.                             out($f,"#undef HANDLE_EXCEPTION\n");
  913.                             out($f,"#undef HANDLE_EXCEPTION_LEAVE\n");
  914.                             if (ZEND_VM_SPEC) {
  915.                                 out($f,"#define CHECK_EXCEPTION() if (UNEXPECTED(EG(exception) != NULL)) goto ZEND_HANDLE_EXCEPTION_SPEC_HANDLER\n");
  916.                                 out($f,"#define HANDLE_EXCEPTION() goto ZEND_HANDLE_EXCEPTION_SPEC_HANDLER\n");
  917.                                 out($f,"#define HANDLE_EXCEPTION_LEAVE() goto ZEND_HANDLE_EXCEPTION_SPEC_HANDLER\n");
  918.                             } else {
  919.                                 out($f,"#define CHECK_EXCEPTION() if (UNEXPECTED(EG(exception) != NULL)) goto ZEND_HANDLE_EXCEPTION_HANDLER\n");
  920.                                 out($f,"#define HANDLE_EXCEPTION() goto ZEND_HANDLE_EXCEPTION_HANDLER\n");
  921.                                 out($f,"#define HANDLE_EXCEPTION_LEAVE() goto ZEND_HANDLE_EXCEPTION_HANDLER\n");
  922.                             }
  923.                             out($f,"#define LOAD_REGS()\n");
  924.                             out($f,"#define ZEND_VM_CONTINUE() goto *(void**)(OPLINE->handler)\n");
  925.                             out($f,"#define ZEND_VM_RETURN()   EG(in_execution) = original_in_execution; return\n");
  926.                             out($f,"#define ZEND_VM_ENTER()    goto zend_vm_enter\n");
  927.                             out($f,"#define ZEND_VM_LEAVE()    ZEND_VM_CONTINUE()\n");
  928.                             out($f,"#define ZEND_VM_DISPATCH(opcode, opline) goto *(void**)(zend_vm_get_opcode_handler(opcode, opline));\n\n");
  929.                             out($f,"#define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL execute_data TSRMLS_CC\n");
  930.                             break;
  931.                     }
  932.                     break;
  933.                 case "EXECUTOR_NAME":
  934.                     out($f, $m[1].$executor_name.$m[3]."\n");
  935.                     break;
  936.                 case "HELPER_VARS":
  937.                     if ($kind != ZEND_VM_KIND_CALL) {
  938.                         if ($kind == ZEND_VM_KIND_SWITCH) {
  939.                             out($f,$m[1]."opcode_handler_t dispatch_handler;\n");
  940.                         }
  941.                       // Emit local variables those are used for helpers' parameters
  942.                         foreach ($params as $param => $x) {
  943.                             out($f,$m[1].$param.";\n");
  944.                         }
  945.                     } else {
  946.                         skip_blanks($f, $m[1], $m[3]."\n");
  947.                     }
  948.                     break;
  949.                 case "INTERNAL_LABELS":
  950.                     if ($kind == ZEND_VM_KIND_GOTO) {
  951.                       // Emit array of labels of opcode handlers and code for
  952.                       // zend_opcode_handlers initialization
  953.                         $prolog = $m[1];
  954.                         out($f,$prolog."if (execute_data == NULL) {\n");
  955.                         out($f,$prolog."\tstatic const opcode_handler_t labels[] = {\n");
  956.                         gen_labels($f, $spec, $kind, $prolog."\t\t");
  957.                         out($f,$prolog."\t};\n");
  958.                         out($f,$prolog."\tzend_opcode_handlers = (opcode_handler_t*)labels;\n");
  959.                         out($f,$prolog."\treturn;\n");
  960.                         out($f,$prolog."}\n");
  961.                     } else {
  962.                         skip_blanks($f, $m[1], $m[3]);
  963.                     }
  964.                     break;
  965.                 case "ZEND_VM_CONTINUE_LABEL":
  966.                     if ($kind == ZEND_VM_KIND_CALL) {
  967.                       // Only SWITCH dispatch method use it
  968.                         out($f,$m[1]."\tint ret;".$m[3]."\n");
  969.                     } else if ($kind == ZEND_VM_KIND_SWITCH) {
  970.                       // Only SWITCH dispatch method use it
  971.                         out($f,"zend_vm_continue:".$m[3]."\n");
  972.                     } else {
  973.                         skip_blanks($f, $m[1], $m[3]);
  974.                     }
  975.                     break;
  976.                 case "ZEND_VM_DISPATCH":
  977.                   // Emit code that dispatches to opcode handler
  978.                     switch ($kind) {
  979.                         case ZEND_VM_KIND_CALL:
  980.                             out($f, $m[1]."if ((ret = OPLINE->handler(execute_data TSRMLS_CC)) > 0)".$m[3]."\n");
  981.                             break;
  982.                         case ZEND_VM_KIND_SWITCH:
  983.                             out($f, $m[1]."dispatch_handler = OPLINE->handler;\nzend_vm_dispatch:\n".$m[1]."switch ((int)dispatch_handler)".$m[3]."\n");
  984.                             break;
  985.                         case ZEND_VM_KIND_GOTO:
  986.                             out($f, $m[1]."goto *(void**)(OPLINE->handler);".$m[3]."\n");
  987.                             break;
  988.                     }
  989.                     break;
  990.                 case "INTERNAL_EXECUTOR":
  991.                     if ($kind == ZEND_VM_KIND_CALL) {
  992.                       // Executor is defined as a set of functions
  993.                         out($f, $m[1]."switch (ret) {\n" .
  994.                                 $m[1]."\tcase 1:\n" .
  995.                                 $m[1]."\t\tEG(in_execution) = original_in_execution;\n".
  996.                                 $m[1]."\t\treturn;\n".
  997.                                 $m[1]."\tcase 2:\n" .
  998.                                 $m[1]."\t\tgoto zend_vm_enter;\n".
  999.                                 $m[1]."\t\tbreak;\n" .
  1000.                                 $m[1]."\tcase 3:\n" .
  1001.                                 $m[1]."\t\texecute_data = EG(current_execute_data);\n".
  1002.                                 $m[1]."\t\tbreak;\n" .
  1003.                                 $m[1]."\tdefault:\n".
  1004.                                 $m[1]."\t\tbreak;\n".
  1005.                                 $m[1]."}".$m[3]."\n");
  1006.                     } else {
  1007.                       // Emit executor code
  1008.                         gen_executor_code($f, $spec, $kind, $m[1]);
  1009.                     }
  1010.                     break;
  1011.                 case "EXTERNAL_EXECUTOR":
  1012.                     if ($kind == ZEND_VM_KIND_CALL) {
  1013.                       // Unspecialized executor with CALL threading is the same as the
  1014.                       // old one, so we don't need to produce code twitch
  1015.                         if (!$old || ZEND_VM_SPEC || (ZEND_VM_KIND != ZEND_VM_KIND_CALL)) {
  1016.                             // Emit executor code
  1017.                             gen_executor_code($f, $spec, $kind, $m[1]);
  1018.                         }
  1019.                     }
  1020.                     break;
  1021.                 case "INITIALIZER_NAME":
  1022.                     out($f, $m[1].$initializer_name.$m[3]."\n");
  1023.                     break;
  1024.                 case "EXTERNAL_LABELS":
  1025.                   // Emit code that initializes zend_opcode_handlers array
  1026.                     $prolog = $m[1];
  1027.                     if ($kind == ZEND_VM_KIND_GOTO) {
  1028.                       // Labels are defined in the executor itself, so we call it
  1029.                       // with execute_data NULL and it sets zend_opcode_handlers array
  1030.                         out($f,$prolog."TSRMLS_FETCH();\n");
  1031.                         out($f,$prolog.$executor_name."_ex(NULL TSRMLS_CC);\n");
  1032.                     } else {
  1033.                         if ($old) {
  1034.                           // Reserving space for user-defined opcodes
  1035.                             out($f,$prolog."static opcode_handler_t labels[512] = {\n");
  1036.                         } else {
  1037.                             out($f,$prolog."static const opcode_handler_t labels[] = {\n");
  1038.                         }
  1039.                         gen_labels($f, $spec, $kind, $prolog."\t");
  1040.                         out($f,$prolog."};\n");
  1041.                         out($f,$prolog."zend_opcode_handlers = (opcode_handler_t*)labels;\n");
  1042.                         if ($old) {
  1043.                           // Setup old executor
  1044.                             out($f,$prolog."zend_vm_old_executor = 1;\n");
  1045.                             out($f,$prolog."zend_execute = old_execute;\n");
  1046.                         }
  1047.                     }
  1048.                     break;
  1049.                 default:
  1050.                     die("ERROR: Unknown keyword ".$m[2]." in skeleton file.\n");
  1051.             }
  1052.         } else {
  1053.           // Copy the line as is
  1054.             out($f, $line);
  1055.         }
  1056.     }
  1057. }
  1058.  
  1059. function gen_vm($def, $skel) {
  1060.     global $definition_file, $skeleton_file, $executor_file,
  1061.         $op_types, $list, $opcodes, $helpers, $params, $opnames;
  1062.  
  1063.     // Load definition file
  1064.     $in = @file($def);
  1065.     if (!$in) {
  1066.         die("ERROR: Can not open definition file '$def'\n");
  1067.     }
  1068.     // We need absolute path to definition file to use it in #line directives
  1069.     $definition_file = realpath($def);
  1070.  
  1071.     // Load skeleton file
  1072.     $skl = @file($skel);
  1073.     if (!$skl) {
  1074.         die("ERROR: Can not open skeleton file '$skel'\n");
  1075.     }
  1076.     // We need absolute path to skeleton file to use it in #line directives
  1077.     $skeleton_file = realpath($skel);
  1078.  
  1079.     // Parse definition file into tree
  1080.     $lineno         = 0;
  1081.     $handler        = null;
  1082.     $helper         = null;
  1083.     $max_opcode_len = 0;
  1084.     $max_opcode     = 0;
  1085.     $export         = array();
  1086.     foreach ($in as $line) {
  1087.         ++$lineno;
  1088.         if (strpos($line,"ZEND_VM_HANDLER(") === 0) {
  1089.           // Parsing opcode handler's definition
  1090.             if (preg_match(
  1091.                     "/^ZEND_VM_HANDLER\(\s*([0-9]+)\s*,\s*([A-Z_]+)\s*,\s*([A-Z|]+)\s*,\s*([A-Z|]+)\s*\)/",
  1092.                     $line,
  1093.                     $m) == 0) {
  1094.                 die("ERROR ($def:$lineno): Invalid ZEND_VM_HANDLER definition.\n");
  1095.             }
  1096.             $code = (int)$m[1];
  1097.             $op   = $m[2];
  1098.             $len  = strlen($op);
  1099.             $op1  = array_flip(explode("|",$m[3]));
  1100.             $op2  = array_flip(explode("|",$m[4]));
  1101.  
  1102.             if ($len > $max_opcode_len) {
  1103.                 $max_opcode_len = $len;
  1104.             }
  1105.             if ($code > $max_opcode) {
  1106.                 $max_opcode = $code;
  1107.             }
  1108.             if (isset($opcodes[$code])) {
  1109.                 die("ERROR ($def:$lineno): Opcode with code '$code' is already defined.\n");
  1110.             }
  1111.             if (isset($opnames[$op])) {
  1112.                 die("ERROR ($def:$lineno): Opcode with name '$op' is already defined.\n");
  1113.             }
  1114.             $opcodes[$code] = array("op"=>$op,"op1"=>$op1,"op2"=>$op2,"code"=>"");
  1115.             $opnames[$op] = $code;
  1116.             $handler = $code;
  1117.             $helper = null;
  1118.             $list[$lineno] = array("handler"=>$handler);
  1119.         } else if (strpos($line,"ZEND_VM_HELPER(") === 0) {
  1120.           // Parsing helper's definition
  1121.             if (preg_match(
  1122.                     "/^ZEND_VM_HELPER\(\s*([A-Za-z_]+)\s*,\s*([A-Z|]+)\s*,\s*([A-Z|]+)\s*\)/",
  1123.                     $line,
  1124.                     $m) == 0) {
  1125.                 die("ERROR ($def:$lineno): Invalid ZEND_VM_HELPER definition.\n");
  1126.             }
  1127.             $helper = $m[1];
  1128.             $op1    = array_flip(explode("|",$m[2]));
  1129.             $op2    = array_flip(explode("|",$m[3]));
  1130.             if (isset($helpers[$helper])) {
  1131.                 die("ERROR ($def:$lineno): Helper with name '$helper' is already defined.\n");
  1132.             }
  1133.             $helpers[$helper] = array("op1"=>$op1,"op2"=>$op2,"param"=>null,"code"=>"");
  1134.             $handler = null;
  1135.             $list[$lineno] = array("helper"=>$helper);
  1136.         } else if (strpos($line,"ZEND_VM_HELPER_EX(") === 0) {
  1137.           // Parsing helper with parameter definition
  1138.             if (preg_match(
  1139.                     "/^ZEND_VM_HELPER_EX\(\s*([A-Za-z_]+)\s*,\s*([A-Z|]+)\s*,\s*([A-Z|]+)\s*,\s*(.*)\s*\)/",
  1140.                     $line,
  1141.                     $m) == 0) {
  1142.                 die("ERROR ($def:$lineno): Invalid ZEND_VM_HELPER definition.\n");
  1143.             }
  1144.             $helper = $m[1];
  1145.             $op1    = array_flip(explode("|",$m[2]));
  1146.             $op2    = array_flip(explode("|",$m[3]));
  1147.             $param  = $m[4];
  1148.             if (isset($helpers[$helper])) {
  1149.                 die("ERROR ($def:$lineno): Helper with name '$helper' is already defined.\n");
  1150.             }
  1151.  
  1152.             // Store parameter
  1153.             $params[$param] = 1;
  1154.  
  1155.             $helpers[$helper] = array("op1"=>$op1,"op2"=>$op2,"param"=>$param,"code"=>"");
  1156.             $handler = null;
  1157.             $list[$lineno] = array("helper"=>$helper);
  1158.         } else if (strpos($line,"ZEND_VM_EXPORT_HANDLER(") === 0) {
  1159.             if (preg_match(
  1160.                     "/^ZEND_VM_EXPORT_HANDLER\(\s*([A-Za-z_]+)\s*,\s*([A-Z_]+)\s*\)/",
  1161.                     $line,
  1162.                     $m) == 0) {
  1163.                 die("ERROR ($def:$lineno): Invalid ZEND_VM_EXPORT_HANDLER definition.\n");
  1164.             }
  1165.             if (!isset($opnames[$m[2]])) {
  1166.                 die("ERROR ($def:$lineno): opcode '{$m[2]}' is not defined.\n");
  1167.             }
  1168.             $export[] = array("handler",$m[1],$m[2]);
  1169.         } else if (strpos($line,"ZEND_VM_EXPORT_HELPER(") === 0) {
  1170.             if (preg_match(
  1171.                     "/^ZEND_VM_EXPORT_HELPER\(\s*([A-Za-z_]+)\s*,\s*([A-Za-z_]+)\s*\)/",
  1172.                     $line,
  1173.                     $m) == 0) {
  1174.                 die("ERROR ($def:$lineno): Invalid ZEND_VM_EXPORT_HELPER definition.\n");
  1175.             }
  1176.             if (!isset($helpers[$m[2]])) {
  1177.                 die("ERROR ($def:$lineno): helper '{$m[2]}' is not defined.\n");
  1178.             }
  1179.             $export[] = array("helper",$m[1],$m[2]);
  1180.         } else if ($handler !== null) {
  1181.           // Add line of code to current opcode handler
  1182.             $opcodes[$handler]["code"] .= $line;
  1183.         } else if ($helper !== null) {
  1184.           // Add line of code to current helper
  1185.             $helpers[$helper]["code"] .= $line;
  1186.         }
  1187.     }
  1188.  
  1189.     ksort($opcodes);
  1190.  
  1191.     // Search for opcode handlers those are used by other opcode handlers
  1192.     foreach ($opcodes as $dsc) {
  1193.         if (preg_match("/ZEND_VM_DISPATCH_TO_HANDLER\(\s*([A-Z_]*)\s*\)/m", $dsc["code"], $m)) {
  1194.             $op = $m[1];
  1195.             if (!isset($opnames[$op])) {
  1196.                 die("ERROR ($def:$lineno): Opcode with name '$op' is not defined.\n");
  1197.             }
  1198.             $code = $opnames[$op];
  1199.             $opcodes[$code]['use'] = 1;
  1200.         }
  1201.     }
  1202.  
  1203.     // Generate opcode #defines (zend_vm_opcodes.h)
  1204.     $code_len = strlen((string)$max_opcode);
  1205.     $f = fopen(__DIR__ . "/zend_vm_opcodes.h", "w+") or die("ERROR: Cannot create zend_vm_opcodes.h\n");
  1206.  
  1207.     // Insert header
  1208.     out($f, $GLOBALS['header_text']);
  1209.  
  1210.     fputs($f, "#ifndef ZEND_VM_OPCODES_H\n#define ZEND_VM_OPCODES_H\n\n");
  1211.     fputs($f, "ZEND_API const char *zend_get_opcode_name(zend_uchar opcode);\n\n");
  1212.    
  1213.     foreach ($opcodes as $code => $dsc) {
  1214.         $code = str_pad((string)$code,$code_len," ",STR_PAD_LEFT);
  1215.         $op = str_pad($dsc["op"],$max_opcode_len);
  1216.         fputs($f,"#define $op $code\n");
  1217.     }
  1218.  
  1219.     fputs($f, "\n#endif\n");
  1220.     fclose($f);
  1221.     echo "zend_vm_opcodes.h generated successfully.\n";
  1222.  
  1223.     // zend_vm_opcodes.c
  1224.     $f = fopen(__DIR__ . "/zend_vm_opcodes.c", "w+") or die("ERROR: Cannot create zend_vm_opcodes.c\n");
  1225.  
  1226.     // Insert header
  1227.     out($f, $GLOBALS['header_text']);
  1228.     fputs($f,"#include <stdio.h>\n");
  1229.     fputs($f,"#include <zend.h>\n\n");
  1230.    
  1231.     fputs($f,"const char *zend_vm_opcodes_map[".($max_opcode + 1)."] = {\n");
  1232.     for ($i = 0; $i <= $max_opcode; $i++) {
  1233.         fputs($f,"\t".(isset($opcodes[$i]["op"])?'"'.$opcodes[$i]["op"].'"':"NULL").",\n");
  1234.     }
  1235.     fputs($f, "};\n\n");
  1236.    
  1237.     fputs($f, "ZEND_API const char* zend_get_opcode_name(zend_uchar opcode) {\n");
  1238.     fputs($f, "\treturn zend_vm_opcodes_map[opcode];\n");
  1239.     fputs($f, "}\n");
  1240.    
  1241.     fclose($f);
  1242.     echo "zend_vm_opcodes.c generated successfully.\n";
  1243.  
  1244.     // Generate zend_vm_execute.h
  1245.     $f = fopen(__DIR__ . "/zend_vm_execute.h", "w+") or die("ERROR: Cannot create zend_vm_execute.h\n");
  1246.     $executor_file = realpath(__DIR__ . "/zend_vm_execute.h");
  1247.  
  1248.     // Insert header
  1249.     out($f, $GLOBALS['header_text']);
  1250.  
  1251.     out($f, "#ifdef ZEND_WIN32\n");
  1252.     // Suppress free_op1 warnings on Windows
  1253.     out($f, "# pragma warning(once : 4101)\n");
  1254.     if (ZEND_VM_SPEC) {
  1255.         // Suppress (<non-zero constant> || <expression>) warnings on windows
  1256.         out($f, "# pragma warning(once : 6235)\n");
  1257.         // Suppress (<zero> && <expression>) warnings on windows
  1258.         out($f, "# pragma warning(once : 6237)\n");
  1259.         // Suppress (<non-zero constant> && <expression>) warnings on windows
  1260.         out($f, "# pragma warning(once : 6239)\n");
  1261.         // Suppress (<expression> && <non-zero constant>) warnings on windows
  1262.         out($f, "# pragma warning(once : 6240)\n");
  1263.         // Suppress (<non-zero constant> || <non-zero constant>) warnings on windows
  1264.         out($f, "# pragma warning(once : 6285)\n");
  1265.         // Suppress (<non-zero constant> || <expression>) warnings on windows
  1266.         out($f, "# pragma warning(once : 6286)\n");
  1267.         // Suppress constant with constant comparison warnings on windows
  1268.         out($f, "# pragma warning(once : 6326)\n");
  1269.     }
  1270.     out($f, "#endif\n");
  1271.    
  1272.     // Support for ZEND_USER_OPCODE
  1273.     out($f, "static user_opcode_handler_t zend_user_opcode_handlers[256] = {\n");
  1274.     for ($i = 0; $i < 255; ++$i) {
  1275.         out($f, "\t(user_opcode_handler_t)NULL,\n");
  1276.     }
  1277.     out($f, "\t(user_opcode_handler_t)NULL\n};\n\n");
  1278.  
  1279.     out($f, "static zend_uchar zend_user_opcodes[256] = {");
  1280.     for ($i = 0; $i < 255; ++$i) {
  1281.         if ($i % 16 == 1) out($f, "\n\t");
  1282.         out($f, "$i,");
  1283.     }
  1284.     out($f, "255\n};\n\n");
  1285.  
  1286.     // Generate specialized executor
  1287.     gen_executor($f, $skl, ZEND_VM_SPEC, ZEND_VM_KIND, "execute", "zend_init_opcodes_handlers", 0);
  1288.  
  1289.     // Generate un-specialized executor
  1290.     if (ZEND_VM_OLD_EXECUTOR) {
  1291.         out($f,"\n/* Old executor */\n\n");
  1292.         out($f,"#undef ZEND_VM_CONTINUE\n\n");
  1293.         out($f,"#undef ZEND_VM_RETURN\n\n");
  1294.         out($f,"#undef ZEND_VM_ENTER\n\n");
  1295.         out($f,"#undef ZEND_VM_LEAVE\n\n");
  1296.         out($f,"#undef ZEND_VM_DISPATCH\n\n");
  1297.         out($f,"#undef ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL\n\n");
  1298.         gen_executor($f, $skl, 0, ZEND_VM_KIND_CALL, "old_execute", "zend_vm_use_old_executor", 1);
  1299.     }
  1300.  
  1301.     // Generate zend_vm_get_opcode_handler() function
  1302.     out($f, "static opcode_handler_t zend_vm_get_opcode_handler(zend_uchar opcode, zend_op* op)\n");
  1303.     out($f, "{\n");
  1304.     if (!ZEND_VM_SPEC) {
  1305.         out($f, "\treturn zend_opcode_handlers[opcode];\n");
  1306.     } else {
  1307.         if (ZEND_VM_OLD_EXECUTOR) {
  1308.             out($f, "\tif (zend_vm_old_executor) {\n");
  1309.             out($f, "\t\treturn zend_opcode_handlers[opcode];\n");
  1310.             out($f, "\t} else {\n");
  1311.         }
  1312.         out($f, "\t\tstatic const int zend_vm_decode[] = {\n");
  1313.         out($f, "\t\t\t_UNUSED_CODE, /* 0              */\n");
  1314.         out($f, "\t\t\t_CONST_CODE,  /* 1 = IS_CONST   */\n");
  1315.         out($f, "\t\t\t_TMP_CODE,    /* 2 = IS_TMP_VAR */\n");
  1316.         out($f, "\t\t\t_UNUSED_CODE, /* 3              */\n");
  1317.         out($f, "\t\t\t_VAR_CODE,    /* 4 = IS_VAR     */\n");
  1318.         out($f, "\t\t\t_UNUSED_CODE, /* 5              */\n");
  1319.         out($f, "\t\t\t_UNUSED_CODE, /* 6              */\n");
  1320.         out($f, "\t\t\t_UNUSED_CODE, /* 7              */\n");
  1321.         out($f, "\t\t\t_UNUSED_CODE, /* 8 = IS_UNUSED  */\n");
  1322.         out($f, "\t\t\t_UNUSED_CODE, /* 9              */\n");
  1323.         out($f, "\t\t\t_UNUSED_CODE, /* 10             */\n");
  1324.         out($f, "\t\t\t_UNUSED_CODE, /* 11             */\n");
  1325.         out($f, "\t\t\t_UNUSED_CODE, /* 12             */\n");
  1326.         out($f, "\t\t\t_UNUSED_CODE, /* 13             */\n");
  1327.         out($f, "\t\t\t_UNUSED_CODE, /* 14             */\n");
  1328.         out($f, "\t\t\t_UNUSED_CODE, /* 15             */\n");
  1329.         out($f, "\t\t\t_CV_CODE      /* 16 = IS_CV     */\n");
  1330.         out($f, "\t\t};\n");
  1331.         out($f, "\t\treturn zend_opcode_handlers[opcode * 25 + zend_vm_decode[op->op1_type] * 5 + zend_vm_decode[op->op2_type]];\n");
  1332.         if (ZEND_VM_OLD_EXECUTOR) {
  1333.             out($f, "\t}\n");
  1334.         }
  1335.     }
  1336.     out($f, "}\n\n");
  1337.  
  1338.     // Generate zend_vm_get_opcode_handler() function
  1339.     out($f, "ZEND_API void zend_vm_set_opcode_handler(zend_op* op)\n");
  1340.     out($f, "{\n");
  1341.     out($f, "\top->handler = zend_vm_get_opcode_handler(zend_user_opcodes[op->opcode], op);\n");
  1342.     out($f, "}\n\n");
  1343.  
  1344.     // Export handlers and helpers
  1345.     if (count($export) > 0 &&
  1346.         !ZEND_VM_OLD_EXECUTOR &&
  1347.         ZEND_VM_KIND != ZEND_VM_KIND_CALL) {
  1348.         out($f,"#undef OPLINE\n");
  1349.         out($f,"#undef DCL_OPLINE\n");
  1350.         out($f,"#undef USE_OPLINE\n");
  1351.         out($f,"#undef LOAD_OPLINE\n");
  1352.         out($f,"#undef SAVE_OPLINE\n");
  1353.         out($f,"#define OPLINE EX(opline)\n");
  1354.         out($f,"#define DCL_OPLINE\n");
  1355.         out($f,"#define USE_OPLINE zend_op *opline = EX(opline);\n");
  1356.         out($f,"#define LOAD_OPLINE()\n");
  1357.         out($f,"#define SAVE_OPLINE()\n");
  1358.         out($f,"#undef CHECK_EXCEPTION\n");
  1359.         out($f,"#undef HANDLE_EXCEPTION\n");
  1360.         out($f,"#undef HANDLE_EXCEPTION_LEAVE\n");
  1361.         out($f,"#define CHECK_EXCEPTION() LOAD_OPLINE()\n");
  1362.         out($f,"#define HANDLE_EXCEPTION() LOAD_OPLINE(); ZEND_VM_CONTINUE()\n");
  1363.         out($f,"#define HANDLE_EXCEPTION_LEAVE() LOAD_OPLINE(); ZEND_VM_LEAVE()\n");
  1364.         out($f,"#undef ZEND_VM_CONTINUE\n");
  1365.         out($f,"#undef ZEND_VM_RETURN\n");
  1366.         out($f,"#undef ZEND_VM_ENTER\n");
  1367.         out($f,"#undef ZEND_VM_LEAVE\n");
  1368.         out($f,"#undef ZEND_VM_DISPATCH\n");
  1369.         out($f,"#undef ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL\n\n");
  1370.         out($f,"#define ZEND_VM_CONTINUE()   return 0\n");
  1371.         out($f,"#define ZEND_VM_RETURN()     return 1\n");
  1372.         out($f,"#define ZEND_VM_ENTER()      return 2\n");
  1373.         out($f,"#define ZEND_VM_LEAVE()      return 3\n");
  1374.         out($f,"#define ZEND_VM_DISPATCH(opcode, opline) return zend_vm_get_opcode_handler(opcode, opline)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n\n");
  1375.         out($f,"#define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL execute_data TSRMLS_CC\n\n");
  1376.     }
  1377.     foreach ($export as $dsk) {
  1378.         list($kind, $func, $name) = $dsk;
  1379.         out($f, "ZEND_API int $func(");
  1380.         if ($kind == "handler") {
  1381.             out($f, "ZEND_OPCODE_HANDLER_ARGS)\n");
  1382.             $code = $opcodes[$opnames[$name]]['code'];
  1383.         } else {
  1384.             $h = $helpers[$name];
  1385.             if ($h['param'] == null) {
  1386.                 out($f, "ZEND_OPCODE_HANDLER_ARGS)\n");
  1387.             } else {
  1388.                 out($f, $h['param']. ", ZEND_OPCODE_HANDLER_ARGS)\n");
  1389.             }
  1390.             $code = $h['code'];
  1391.         }
  1392.         $done = 0;
  1393.         if (ZEND_VM_OLD_EXECUTOR) {
  1394.             if ($kind == "handler") {
  1395.                 out($f, "{\n\treturn ".$name."_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n}\n\n");
  1396.                 $done = 1;
  1397.             } else if ($helpers[$name]["param"] == null) {
  1398.                 out($f, "{\n\treturn ".$name."(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n}\n\n");
  1399.                 $done = 1;
  1400.             }
  1401.         } else if (ZEND_VM_KIND == ZEND_VM_KIND_CALL) {
  1402.             if ($kind == "handler") {
  1403.                 $op = $opcodes[$opnames[$name]];
  1404.                 if (isset($op['op1']["ANY"]) && isset($op['op2']["ANY"])) {
  1405.                     out($f, "{\n\treturn ".$name.(ZEND_VM_SPEC?"_SPEC":"")."_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n}\n\n");
  1406.                     $done = 1;
  1407.                 }
  1408.             } else if ($helpers[$name]["param"] == null) {
  1409.                 $h = $helpers[$name];
  1410.                 if (isset($h['op1']["ANY"]) && isset($h['op2']["ANY"])) {
  1411.                     out($f, "{\n\treturn ".$name.(ZEND_VM_SPEC?"_SPEC":"")."(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n}\n\n");
  1412.                     $done = 1;
  1413.                 }
  1414.             }
  1415.         }
  1416.         if (!$done) {
  1417.             gen_code($f, 0, ZEND_VM_KIND_CALL, 1, $code, 'ANY', 'ANY', $name);
  1418.         }
  1419.     }
  1420.  
  1421.     fclose($f);
  1422.     echo "zend_vm_execute.h generated successfully.\n";
  1423. }
  1424.  
  1425. function usage() {
  1426.     echo("\nUsage: php zend_vm_gen.php [options]\n".
  1427.          "\nOptions:".
  1428.          "\n  --with-vm-kind=CALL|SWITCH|GOTO - select threading model (default is CALL)".
  1429.          "\n  --without-specializer           - disable executor specialization".
  1430.          "\n  --with-old-executor             - enable old executor".
  1431.          "\n  --with-lines                    - enable #line directives".
  1432.          "\n\n");
  1433. }
  1434.  
  1435. // Parse arguments
  1436. for ($i = 1;  $i < $argc; $i++) {
  1437.     if (strpos($argv[$i],"--with-vm-kind=") === 0) {
  1438.         $kind = substr($argv[$i], strlen("--with-vm-kind="));
  1439.         switch ($kind) {
  1440.             case "CALL":
  1441.                 define("ZEND_VM_KIND", ZEND_VM_KIND_CALL);
  1442.                 break;
  1443.             case "SWITCH":
  1444.                 define("ZEND_VM_KIND", ZEND_VM_KIND_SWITCH);
  1445.                 break;
  1446.             case "GOTO":
  1447.                 define("ZEND_VM_KIND", ZEND_VM_KIND_GOTO);
  1448.                 break;
  1449.             default:
  1450.                 echo("ERROR: Invalid vm kind '$kind'\n");
  1451.                 usage();
  1452.                 die();
  1453.         }
  1454.     } else if ($argv[$i] == "--without-specializer") {
  1455.       // Disabling specialization
  1456.         define("ZEND_VM_SPEC", 0);
  1457.     } else if ($argv[$i] == "--with-old-executor") {
  1458.       // Disabling code for old-style executor
  1459.         define("ZEND_VM_OLD_EXECUTOR", 1);
  1460.     } else if ($argv[$i] == "--with-lines") {
  1461.         // Enabling debugging using original zend_vm_def.h
  1462.         define("ZEND_VM_LINES", 1);
  1463.     } else if ($argv[$i] == "--help") {
  1464.         usage();
  1465.         exit();
  1466.     } else {
  1467.         echo("ERROR: Invalid option '".$argv[$i]."'\n");
  1468.         usage();
  1469.         die();
  1470.     }
  1471. }
  1472.  
  1473. // Using defaults
  1474. if (!defined("ZEND_VM_KIND")) {
  1475.   // Using CALL threading by default
  1476.     define("ZEND_VM_KIND", ZEND_VM_KIND_CALL);
  1477. }
  1478. if (!defined("ZEND_VM_SPEC")) {
  1479.   // Using specialized executor by default
  1480.     define("ZEND_VM_SPEC", 1);
  1481. }
  1482. if (!defined("ZEND_VM_OLD_EXECUTOR")) {
  1483.   // Include old-style executor by default
  1484.     define("ZEND_VM_OLD_EXECUTOR", 0);
  1485. }
  1486. if (!defined("ZEND_VM_LINES")) {
  1487.   // Disabling #line directives
  1488.     define("ZEND_VM_LINES", 0);
  1489. }
  1490.  
  1491. gen_vm(__DIR__ . "/zend_vm_def.h", __DIR__ . "/zend_vm_execute.skl");
  1492.  
  1493. ?>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement