You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1302 lines
42 KiB

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