/usr/include/falcon/vm.h is in falconpl-dev 0.9.6.9-git20120606-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 | /*
FALCON - The Falcon Programming Language.
FILE: vm.h
Falcon virtual machine.
-------------------------------------------------------------------
Author: Giancarlo Niccolai
Begin: Dom, 08 Aug 2004 01:22:55 +0100
-------------------------------------------------------------------
(C) Copyright 2004: the FALCON developers (see list in AUTHORS file)
See LICENSE file for licensing details.
*/
#ifndef FLC_VM_H
#define FLC_VM_H
#include <falcon/symtab.h>
#include <falcon/symlist.h>
#include <falcon/item.h>
#include <falcon/stackframe.h>
#include <falcon/module.h>
#include <falcon/common.h>
#include <falcon/error.h>
#include <falcon/runtime.h>
#include <falcon/vmmaps.h>
#include <falcon/genericlist.h>
#include <falcon/carray.h>
#include <falcon/string.h>
#include <falcon/coreobject.h>
#include <falcon/coredict.h>
#include <falcon/cclass.h>
#include <falcon/genericmap.h>
#include <falcon/genericlist.h>
#include <falcon/fassert.h>
#include <falcon/vm_sys.h>
#include <falcon/coreslot.h>
#include <falcon/baton.h>
#include <falcon/livemodule.h>
#include <falcon/vmcontext.h>
#include <falcon/mersennetwister.h>
#define FALCON_VM_DFAULT_CHECK_LOOPS 5000
namespace Falcon {
class Runtime;
class VMachine;
class PropertyTable;
class AttribHandler;
class MemPool;
class VMMessage;
class GarbageLock;
typedef void (*tOpcodeHandler)( register VMachine *);
void ContextList_deletor( void * );
class FALCON_DYN_CLASS ContextList: public List
{
friend void ContextList_deletor( void * );
public:
ContextList()
{}
};
void opcodeHandler_END ( register VMachine *vm );
void opcodeHandler_NOP ( register VMachine *vm );
void opcodeHandler_PSHN( register VMachine *vm );
void opcodeHandler_RET ( register VMachine *vm );
void opcodeHandler_RETA( register VMachine *vm );
void opcodeHandler_PTRY( register VMachine *vm );
// Range 2: one parameter ops;
void opcodeHandler_LNIL( register VMachine *vm );
void opcodeHandler_RETV( register VMachine *vm );
void opcodeHandler_FORK( register VMachine *vm );
void opcodeHandler_BOOL( register VMachine *vm );
void opcodeHandler_GENA( register VMachine *vm );
void opcodeHandler_GEND( register VMachine *vm );
void opcodeHandler_PUSH( register VMachine *vm );
void opcodeHandler_PSHR( register VMachine *vm );
void opcodeHandler_POP ( register VMachine *vm );
void opcodeHandler_JMP ( register VMachine *vm );
void opcodeHandler_INC ( register VMachine *vm );
void opcodeHandler_DEC ( register VMachine *vm );
void opcodeHandler_NEG ( register VMachine *vm );
void opcodeHandler_NOT ( register VMachine *vm );
void opcodeHandler_TRAL( register VMachine *vm );
void opcodeHandler_IPOP( register VMachine *vm );
void opcodeHandler_XPOP( register VMachine *vm );
void opcodeHandler_GEOR( register VMachine *vm );
void opcodeHandler_TRY ( register VMachine *vm );
void opcodeHandler_JTRY( register VMachine *vm );
void opcodeHandler_RIS ( register VMachine *vm );
void opcodeHandler_BNOT( register VMachine *vm );
void opcodeHandler_NOTS( register VMachine *vm );
void opcodeHandler_PEEK( register VMachine *vm );
// Range3: Double parameter ops;
void opcodeHandler_LD ( register VMachine *vm );
void opcodeHandler_LDRF( register VMachine *vm );
void opcodeHandler_ADD ( register VMachine *vm );
void opcodeHandler_SUB ( register VMachine *vm );
void opcodeHandler_MUL ( register VMachine *vm );
void opcodeHandler_DIV ( register VMachine *vm );
void opcodeHandler_MOD ( register VMachine *vm );
void opcodeHandler_POW ( register VMachine *vm );
void opcodeHandler_ADDS( register VMachine *vm );
void opcodeHandler_SUBS( register VMachine *vm );
void opcodeHandler_MULS( register VMachine *vm );
void opcodeHandler_DIVS( register VMachine *vm );
void opcodeHandler_MODS( register VMachine *vm );
void opcodeHandler_BAND( register VMachine *vm );
void opcodeHandler_BOR ( register VMachine *vm );
void opcodeHandler_BXOR( register VMachine *vm );
void opcodeHandler_ANDS( register VMachine *vm );
void opcodeHandler_ORS ( register VMachine *vm );
void opcodeHandler_XORS( register VMachine *vm );
void opcodeHandler_GENR( register VMachine *vm );
void opcodeHandler_EQ ( register VMachine *vm );
void opcodeHandler_NEQ ( register VMachine *vm );
void opcodeHandler_GT ( register VMachine *vm );
void opcodeHandler_GE ( register VMachine *vm );
void opcodeHandler_LT ( register VMachine *vm );
void opcodeHandler_LE ( register VMachine *vm );
void opcodeHandler_IFT ( register VMachine *vm );
void opcodeHandler_IFF ( register VMachine *vm );
void opcodeHandler_CALL( register VMachine *vm );
void opcodeHandler_INST( register VMachine *vm );
void opcodeHandler_ONCE( register VMachine *vm );
void opcodeHandler_LDV ( register VMachine *vm );
void opcodeHandler_LDP ( register VMachine *vm );
void opcodeHandler_TRAN( register VMachine *vm );
void opcodeHandler_LDAS( register VMachine *vm );
void opcodeHandler_SWCH( register VMachine *vm );
void opcodeHandler_IN ( register VMachine *vm );
void opcodeHandler_NOIN( register VMachine *vm );
void opcodeHandler_PROV( register VMachine *vm );
void opcodeHandler_SSTA( register VMachine *vm );
void opcodeHandler_SVAL( register VMachine *vm );
void opcodeHandler_STPS( register VMachine *vm );
void opcodeHandler_STVS( register VMachine *vm );
void opcodeHandler_LSTA( register VMachine *vm );
void opcodeHandler_LVAL( register VMachine *vm );
void opcodeHandler_AND ( register VMachine *vm );
void opcodeHandler_OR ( register VMachine *vm );
void opcodeHandler_PASS( register VMachine *vm );
void opcodeHandler_PSIN( register VMachine *vm );
// Range 4: ternary opcodes;
void opcodeHandler_STP ( register VMachine *vm );
void opcodeHandler_STV ( register VMachine *vm );
void opcodeHandler_LDVT( register VMachine *vm );
void opcodeHandler_LDPT( register VMachine *vm );
void opcodeHandler_STPR( register VMachine *vm );
void opcodeHandler_STVR( register VMachine *vm );
void opcodeHandler_TRAV( register VMachine *vm );
void opcodeHandler_SJMP( register VMachine *vm );
void opcodeHandler_INCP( register VMachine *vm );
void opcodeHandler_DECP( register VMachine *vm );
void opcodeHandler_SHL( register VMachine *vm );
void opcodeHandler_SHR( register VMachine *vm );
void opcodeHandler_SHLS( register VMachine *vm );
void opcodeHandler_SHRS( register VMachine *vm );
void opcodeHandler_CLOS( register VMachine *vm );
void opcodeHandler_PSHL( register VMachine *vm );
void opcodeHandler_POWS( register VMachine *vm );
void opcodeHandler_LSB( register VMachine *vm );
void opcodeHandler_SELE( register VMachine *vm );
void opcodeHandler_INDI( register VMachine *vm );
void opcodeHandler_STEX( register VMachine *vm );
void opcodeHandler_TRAC( register VMachine *vm );
void opcodeHandler_WRT( register VMachine *vm );
void opcodeHandler_STO( register VMachine *vm );
void opcodeHandler_FORB( register VMachine *vm );
void opcodeHandler_EVAL( register VMachine *vm );
void opcodeHandler_OOB( register VMachine *vm );
void opcodeHandler_TRDN( register VMachine *vm );
void opcodeHandler_EXEQ( register VMachine *vm );
class VMachine;
class FALCON_DYN_CLASS VMBaton: public Baton
{
VMachine *m_owner;
public:
VMBaton( VMachine* owner ):
Baton( true ),
m_owner( owner )
{}
virtual ~VMBaton() {}
virtual void release();
virtual void onBlockedAcquire();
void releaseNotIdle();
};
/** The Falcon virtual machine.
Virtual machine is in charge to execute Falcon bytecode.
The virtual machine execution model is quite flexible, and allow infinite execution,
step-by-step execution, limited runs and interrupts (event rising and debug requests)
from external code while running.
To run, the Virtual Machine needs to be properly setup. However, this "setup steps" are
thought as customization steps so that the VM user is able to configure it
on its needs, and they are both simple and effective.
Minimal configuration needed requires to add a Runtime object, which holds the lists of
all non-main modules. It is then possible to execute a routine exported by any of the
modules in the runtime, or to provide a "running module", or "main module" with the
setup() method. Once the startup symbol, or running module (or both) are set, the
it is possible to call run().
\note It is possible that this interface will be simplified in the future so that only one
method is used to set up the runtime and the start symbol or main module.
\note This class implements the error handler interface because it may act as an
error handler for the embedding components: compiler, assembler, module loader
and runtime may all be embedded in a VM that may act as a referee for the
script to be i.e. evaluating correctly a piece of falcon source code.
*/
class FALCON_DYN_CLASS VMachine: public BaseAlloc
{
friend class MemPool;
public:
/** This valuess indicates that the VM is in external execution mode.
With this value in m_pc, the VM will execute the symbol found
in m_symbol.
*/
enum {
i_pc_call_request = 0xFFFFFFFF-sizeof(int32)*4,
i_pc_redo_request =0xFFFFFFFF-sizeof(int32)*4,
i_pc_call_external_ctor = 0xFFFFFFFF-sizeof(int32)*3,
i_pc_call_external_ctor_return = 0xFFFFFFFF-sizeof(int32)*2,
i_pc_call_external = 0xFFFFFFFF-sizeof(int32),
i_pc_call_external_return = 0xFFFFFFFF
};
protected:
/** Structure used to save the vardefs during class link */
class VarDefMod: public BaseAlloc
{
public:
VarDef *vd;
LiveModule *lmod;
};
mutable Mutex m_mtx;
/** Mutex guarding the slot structure. */
mutable Mutex m_slot_mtx;
/** Main module.
This is the last linked module, that should also be the module where to search
for start symbols; by default, launch() searches symbol here,
and if not found, they search start symbols in globally exported symbol tables.
*/
LiveModule *m_mainModule;
/** Space for immediate operands. */
Item m_imm[4];
Stream *m_stdIn;
Stream *m_stdOut;
Stream *m_stdErr;
bool m_bhasStandardStreams;
/** Number of opcodes that the current coroutine has performed. */
uint32 m_opCount;
/** Maximum operations that can be performed */
uint32 m_opLimit;
/** Timeout for GC collection */
uint32 m_loopsGC;
/** Timeout for Context checks */
uint32 m_loopsContext;
/** Timeout for Callbacks */
uint32 m_loopsCallback;
/** True for single stepping */
bool m_bSingleStep;
uint32 m_opNextGC;
uint32 m_opNextContext;
uint32 m_opNextCallback;
/** Smaller check in op loops. */
uint32 m_opNextCheck;
/** Generation at which the garbage data in this VM is marked. */
uint32 m_generation;
/** Map of live modules.
Todo: better docs.
*/
LiveModuleMap m_liveModules;
/** This value indicate that there isn't any active try handler in the stack */
enum {
i_noTryFrame = 0xFFFFFFFF
};
/** Context currently being executed. */
VMContext *m_currentContext;
/** Ready to run contexts. */
ContextList m_contexts;
/** Contexts willing to sleep for a while */
ContextList m_sleepingContexts;
/** Wether or not to allow a VM hostile takeover of the current context. */
bool m_allowYield;
/** Execute at link time? */
bool m_launchAtLink;
/** Opcode handler function calls. */
tOpcodeHandler *m_opHandlers;
/** Map of global symbols (and the item they are connected to).
Each item of the map contains a Symbol * and an ID that allows to
*/
SymModuleMap m_globalSyms;
/** Map of well knwon symbols (and the item they are connected to).
Each item of the map contains a Symbol * and an ID that allows to
*/
SymModuleMap m_wellKnownSyms;
/** Puts the given context at sleep.
This function inserts the given context in the sleep queue, inserting it in
schedule order.
Contexts waiting forever are put at bottom; contexts not wishing to sleep
are put at top.
*/
void putAtSleep( VMContext *ctx );
/** Resort this context changing its position in the sleep list.
Actually, this function works as putAtSleep(), but it
continues to scan the sleeping context sleep till it finds
the previous position of the context to remove it.
*/
void reschedule( VMContext *ctx );
/** Service recursive function called by LinkClass to create a class. */
bool linkSubClass( LiveModule *mod , const Symbol *clssym, Map &props, Map &states, ObjectFactory *factory );
friend class VMContext;
friend class VMSemaphore;
/** Subscribed services map.
Services are allocated in the respective module.
Currently, there's no way to remove a module from a VM once it's linked,
so there's no need for a special de-subscription mechanism.
Of course, if/when an unlink method is added, the module should also de-subscribe
its services.
*/
Map m_services;
/** User available pointer.
\see userData( void * );
*/
void *m_userData;
/** System specific data.
\see systemData();
*/
Sys::SystemData m_systemData;
CoreClass **m_metaClasses;
Map m_slots;
VMachine *m_nextVM;
VMachine *m_prevVM;
VMachine *m_idleNext;
VMachine *m_idlePrev;
/** If true, the VM allows to be blocked periodically by the GC in case of need.
If false, the VM is left alone, and in case it becomes the VM having taken a GC
scan for the last, its GC data gets promoted only if the GC enters the active
state.
*/
bool m_bGcEnabled;
/** Main synchronization baton. */
VMBaton m_baton;
Mutex m_mtx_mesasges;
VMMessage* m_msg_head;
VMMessage* m_msg_tail;
/** Event set by the VM to ask for priority GC.
This is used by the performGC() function to inform the GC loop about the priority
of this VM.
*/
bool m_bPirorityGC;
/** Event set by the GC to confirm the forced GC loop is over. */
Event m_eGCPerformed;
/** True when we want to wait for collection before being notified in priority scans. */
bool m_bWaitForCollect;
/** Mutex for locked items ring.
* -- unused; kept for binary compatibilty
* */
Mutex m_mtx_lockitem;
/** Locked and unreclaimable items are stored in this ring.
* -- unused; kept for binary compatibilty
* */
GarbageLock *m_lockRoot;
/** Reference count.
Usually, shouldn't be very high: the caller program, the GC and possibly
some extra method in embedding applications.
*/
volatile int m_refcount;
/** True if current frame should break */
bool m_break;
/** Finalization hook for MT system. */
void (*m_onFinalize)(VMachine *vm);
/** filtered load path */
String m_appSearchPath;
/** random number generator */
MTRand _mtrand;
//=============================================================
// Private functions
//
/** Utility for switch opcode.
Just pretend it's not here.
*/
bool seekInteger( int64 num, byte *base, uint16 size, uint32 &landing ) const;
/** Utility for switch opcode.
Just pretend it's not here.
*/
bool seekInRange( int64 num, byte *base, uint16 size, uint32 &landing ) const;
/** Utility for switch opcode.
Just pretend it's not here.
*/
bool seekString( const String *str, byte *base, uint16 size, uint32 &landing ) const;
/** Utility for switch opcode.
Just pretend it's not here.
*/
bool seekItem( const Item *item, byte *base, uint16 size, uint32 &landing );
/** Utility for select opcode.
Just pretend it's not here.
*/
bool seekItemClass( const Item *obj, byte *base, uint16 size, uint32 &landing ) const;
void internal_construct();
Item *parseSquareAccessor( const Item &accessed, String &accessor ) const;
/** Returns the next NTD32 parameter, advancing the pointer to the next instruction */
int32 getNextNTD32()
{
register int32 ret = *reinterpret_cast<int32 *>(
m_currentContext->code() + m_currentContext->pc_next() );
m_currentContext->pc_next() += sizeof( int32 );
return ret;
}
/** Returns the next NTD64 parameter, advancing the pointer to the next instruction */
int64 getNextNTD64()
{
register int64 ret = loadInt64(
m_currentContext->code() + m_currentContext->pc_next() );
m_currentContext->pc_next() += sizeof( int64 );
return ret;
}
/** Gets the nth parameter of an opcode. */
Item *getOpcodeParam( register uint32 bc_pos );
/** Perform an item raise.
This implements the "raise" keyword or "RIS" opcode, that is,
takes an item and sends it to the relevant catch in the call
hierarcy.
If the item can't be caught by the current context, then it is
eventually encapsulated in an error and thrown to the applicaiton
with a C++ throw new Error*. If the item contains an instance of
a Falcon Error class, the inner core Error* is taken and that is
raised instead.
After this call, if the item or error could be caught by the script,
the context is prepared to run the error handler at the very next
VM loop.
@param value The item to be raised, possibly but not necessarily
derived from a Falcon level Error class.
*/
void handleRaisedItem( Item& value );
/** Decides what to do with an error incoming in the main loop.
Usually, this get either rethrown to the application or
handled as an item down to the script.
Stack is eventually unrolled till the item handler is found.
*/
void handleRaisedError( Error* err );
/** Performs periodic checks on the virtual machine. */
void periodicChecks();
/** Creates a new stack frame in the current context
\param paramCount number of parameters in the stack
\param frameEndFunc Callback function to be executed at frame end
*/
void createFrame( uint32 paramCount, ext_func_frame_t frameEndFunc = 0 )
{
m_currentContext->prepareFrame( paramCount, frameEndFunc );
}
/** Sets the currently running VM.
The Currently running VM is the VM currently in control
of garbage collecting and item creation.
There can be only one current VM per thread; the value is
stored in a thread specific variable.
Accessing it can be relatively heavy, so it is highly advised
not tu use it except when absolutely necessary to know
the current vm and the value is currently unknown.
\note Embedding applications are advised not to "corss VM", that is,
not to nest call into different VMs in the same thread
*/
void setCurrent() const;
/** Process all the pending messages.
* Pending mesasges are sent to the processMessage() method, which
* creates a coroutine context ready to be fired as soon as the VM
* gets back in action.
*
* The processing order is not granted.
*/
void processPendingMessages();
/** Processes an incoming message.
This searches for the slot requierd by the message;
if it is found, the message is broadcast to the slot in a newly created coroutine,
otherwise the onMessageComplete is immedately called.
void terminateCurrentContext();
The message will be immediately destroyed if it can't be broadcast.
\param msg The message to be processed.
*/
void processMessage( VMMessage* msg );
virtual bool linkDefinedSymbol( const Symbol *sym, LiveModule *lmod );
virtual bool linkUndefinedSymbol( const Symbol *sym, LiveModule *lmod );
virtual bool completeModLink( LiveModule *lmod );
virtual LiveModule *prelink( Module *mod, bool bIsMain, bool bPrivate );
void raiseHardError( int code, const String &expl, int32 line );
/** Gets the next item in a trav loop */
Item* getNextTravVar();
/** Prepare a coroutine context.
The context is immediately swapped, so any operation performed by
the caller is done on the new context. This allow to call an item
right after coroutine creation.
\param paramCount Number of parameters to be passed in the coroutine stack.
*/
VMContext* coPrepare( int32 paramCount );
/** Destroys the virtual machine.
Protected as it can't be called directly.
*/
virtual ~VMachine();
public:
/** Returns the currently running VM.
The Currently running VM is the VM currently in control
of garbage collecting and item creation.
There can be only one current VM per thread; the value is
stored in a thread specific variable.
Accessing it can be relatively heavy, so it is highly advised
not tu use it except when absolutely necessary to know
the current vm and the value is currently unknown.
\note Embedding applications are advised not to "corss VM", that is,
not to nest call into different VMs in the same thread
*/
static VMachine *getCurrent();
/** Initialize VM from subclasses.
Subclasses willing to provide their own initialization routine,
or code wishing to configure the machine, may use this constructor
to prevent the call of the init() routine of this class, which fills
some configurable component of the machine.
\param initItems false to prevent creation of base items
\see init()
*/
VMachine( bool initItems );
/** Creates the virtual machine.
The default constructor calss the virtual method init().
Subclasses may overload it to setup personalized VMs. \see init().
*/
VMachine();
/** Initialize the virutal machine.
Setups some configurable items that are used by the machine.
They are namely:
- m_stdIn: standard input. The default is to use an instance returned by
stdInputStream(), which interfaces a localized text version of
process stdin.
- m_stdOut: standard output. The default is to use an instance returned by
stdOutputStream(), which interfaces a localized text version of
process stdout.
- m_stdErr: standard error. The default is to use an instance returned by
stdErrorStream(), which interfaces a localized text version of
process stderr. void terminateCurrentContext();
The subclass should set up its own items, if the default ones are not
suitable, and then call the base class init(). The base init will
not overwrite those items if they are valorized, but it may configure
them to set up them properly, so it should always be called even if
all the items are set by the subclass.
\see VMachine( bool )
*/
void init();
/** Links a set of modules stored in a runtime.
The modules that have been loaded and pre-linked by the runtime
are correctly inserted in the VM. The topmost module in the
Runtime is set as main module.
After the link step, the runtime is not needed anymore and can
be destroyed; the modules are safely referenced in the VM.
In case of link error, the error handler of the VM is signaled and the
function returns false, otherwise it returns true. If the VM hasn't an
error handler set, nothing is signaled, but the error is still available
after return through exitError() method.
\note The main module is the module that is preferentially searched
for start symbol(s) by prepare() function.
\param rt the runtime to be linked
\return The topmost module in the runtime turned into a livemoude, or zero on failure.
*/
virtual LiveModule* link( Runtime *rt );
/** Links a single module.
The last-linked module is usually set as the main module, but it is possible
to link a non-main module.
After linking, the caller may release the reference if the module is needed
only in this VM; the VM keeps a reference to the module.
The VM holds a reference to the module also in case of errors: the module
may be still needed for error reports or debug. To destroy definitely the
module, the VM must be destroyed or the module must be unlinked.
In case of link error, the error handler of the VM is signaled and the
function returns false, otherwise it returns true. If the VM hasn't an
error handler set, nothing is signaled, but the error is still available
after return through exitError() method.
\note The main module is the module that is preferentially searched
for start symbol(s) by prepare() function.
\param rt the runtime to be linked
\param isMainModule false to prevent this module to be chosen as startup module.
\param bPrivate false to allow this module to export the exported symbols, true
to make the module private (and prevent exports).
\return 0 time error, the internally built LiveModule instance on success.
*/
virtual LiveModule *link( Module *module, bool isMainModule=true, bool bPrivate = false );
/** Links a single symbol on an already existing live module.
This won't actually link instances and classes which must be post-processed.
\param sym The symbol to be linked.
\param lmod The live module where the symbol must go.
\return false if the link fails, true on success.
*/
virtual bool linkSymbol( const Symbol *sym, LiveModule *lmod );
/** Try to link a dynamic symbol.
This method asks the modules that can provide dynamic symbols if they
are interested to serve us with a symbol for the given name. If so,
the symbol is linked, and a complete reference to its position (SymModule) is
returned.
The symbol needs not to be global to be exported this way. The providers may
return private symbols that will be used just in this occasion and won't enter
the global symbol map.
The method may raise any error that linkSymbolComplete may raise. The same
cares used for LinkSymbolComplete void terminateCurrentContext(); should be used.
The method is virtual, so subclasses are able to create symbols dynamically
by providing them directly. However, subclasses creating directly symbols
must still create them inside a FlexyModule and use linkCompleteSymbol
to bless the symbol in the VM.
It is advisable to call the base class version of the method on subclass
default.
\param name The symbol to be searched for.
\param symdata Coordinates of the linked symbol, on success.
\return true on success, false if the symbol is not found or if it was found
but couldn't be linked.
*/
virtual bool linkSymbolDynamic( const String &name, SymModule &symdata );
/** Links a class symbol.
Class symbols must be specially post-processed after all the other symbols
(including themselves) are pre-linked, so that cross references can be resolved.
This method preforms the creation of a CoreClass that will reside in the live
module passed as parameter.
In debug, an assert checks that the incoming symbol is a class. If dynamically
called, the caller should check that \b sym is a real class symbol.
\param sym The class symbol to be linked.
\param lmod The live module where the symbol must go.
\return false if the link fails, true on success.
*/
virtual bool linkClassSymbol( const Symbol *sym, LiveModule *livemod );
/** Links a class instance.
Class instances are what is commonly called "Singleton objects", declared through
the "object" Falcon keyword.
Class instances must be specially post-processed after all the other symbols
and class declarations are pre-linked, so that cross references can be resolved.
This method preforms the creation of a CoreClass that will reside in the live
module passed as parameter.
In debug, an assert checks that the incoming symbol is a class. If dynamically
called, the caller should check that \b sym is a real class symbol.
\param sym The instance symbol to be linked.
\param lmod The live module where the symbol must go.
\return false if the link fails, true on success.
*/
virtual bool linkInstanceSymbol( const Symbol *sym, LiveModule *livemod );
/** Constructs an instance calling its _init method if necessary.
Instance construction must be performed after all the items are pre-linked,
all the classes are formed and all the instances are set-up; in this way,
it is possible for object _init method to refer to other objects, even if
not yet initialized, as their structure is complete and coherent in the VM.
The VM may call either its own VM bytecode or external functions; calls are
performed in non-atomic mode. This means that this method should not be called
from functions executed by the VM, normally. If this is necessary, then
the call of this method must be surrounded by setting and resetting the
atomic mode.
\note Running in atomic mode doesn't mean "locking the VM"; the atomic mode is just a mode
in which the VM runs without switching coroutines, accepting sleep requests or
fulfilling suspension requests. Trying to suspend or prehempt the VM in atomic
mode raises an unblockable exception, terminating the current script (and leaving it
in a non-resumable status).
\note This method won't apply the init state, if existing.
\param sym The class instance to be initialized.
\param lmod The live module where the symbol must go.
\throw Error if the instance cannot be created.
*/
virtual void initializeInstance( const Symbol *sym, LiveModule *livemod );
/** Links a symbol eventually performing class and instances initializations.
This method should be called when incrementally adding symbol once is knonw
that the classes and objects they refer to are (or should) be already linked
in the VM, in already existing live modules.
This is the case of dynamic symbol creation in flexy modules, where
the running scripts can create new symbols or invoke module actions that will
create symbols; this is perfectly legal, but in that case the created instance
will need to have everything prepared; cross references won't be resolved.
This also means that the caller willing to link completely a new instance symbol
must first link it's referenced class.
This method should run in atomic mode (see initializeInstance() ).
*/
virtual bool linkCompleteSymbol( const Symbol *sym, LiveModule *livemod );
/** Links a symbol eventually performing class and instances initializations.
This method resoves the module name into its liveMod before performing
complete linking. This allows external elements (i.e. FALCON_FUNC methods)
to create new symbols on the fly, declaring just into which module they
should be created.
If the target module is not found the method returns false, otherwise it calls directly
linkCompleteSymbol( Symbol *, LiveModule * ) with the appropriate instance
of the LiveModule.
This method should run in atomic mode (see initializeInstance() ).
\param sym Symbol created dynamically.
\param moduleName name of the module that has created it and wants it to be
inserted in the VM.
*/
virtual bool linkCompleteSymbol( Symbol *sym, const String &moduleName );
/** Returns the main module, if it exists.
Returns an instance of the LiveModule class, that is the local representation
of a module linked in the VM, that holds informations about the "main" module
in this virtual machine.
*/
LiveModule *mainModule() const { return m_mainModule; }
/** Unlinks all the modules in the runtime.
The unlinked module(s) become unavailable, and all the callable items referencing
symbols in the module become uncallable. Exported global variables survive unlinking,
and their value can still be inspected, modified and discarded after they
have been unlinked.
It is not possible to unlink a module which is currently being run (that is,
which is the module holding the currently executed symbol).
It is possible to unlink the main module, but a new main module won't be
automatically elected; unless the start symbol is exported by other modules,
prepare() will fail if a new main module is not linked in the VM.
The function may return false either if one of the module in the runtime
is not present in the VM or if one of them is the "current module". However,
some of the modules may have got unlinked int he meanwhile, and unlinking
also dereferences them.
\param rt the runtime with all the modules to be unlinked
\return true on success, false on error.
*/
virtual bool unlink( const Runtime *rt );
/** Unlinks a module.
The unlinked module become unavailable, and all the callable items referencing
symbols in the module become uncallable. Exported global variables survive unlinking,
and their value can still be inspected, modified and discarded after they
have been unlinked.
It is not possible to unlink a module which is currently being run (that is,
which is the module holding the currently executed symbol).
It is possible to unlink the main module, but a new main module won't be
automatically elected; unless the start symbol is exported by other modules,
prepare() will fail if a new main module is not linked in the VM.
The function may return false either if the module
is not present in the VM or if it is the "current module".
\param module the module to be unlinked.
\return true on success, false on error.
*/
virtual bool unlink( const Module *module );
/** Creates a new class live item.
This function recursively resolves inheritences and constructor of
classes to generate a "CoreClass", which is a template ready
to create new instances.
\param lmod the live module (module + live data) where this class is generated
\param clsym the symbol where the class is defined.
*/
virtual CoreClass *linkClass( LiveModule *lmod, const Symbol *clsym );
/** Launches the "__main__" symbol.
This is a proxy call to launch( "__main__" );
*/
void launch() { launch( "__main__" ); }
/** Launches a routine.
This methods prepares the execution environment of the script by allocating the items that
represents the global variables in the various modules.
This step is called "realization" of the Runtime, as it provides a set of "real"
(in the sense of effective) values for the items that are drawn in the library. This may be a
relatively long step.
If the VM had been already used to launch a routine, the status and memory are cleaned and
everything is returned to the startup state.
Then the routine whose name is given is searched in the top module (the one that has been added last
to the runtime). If not found there, it is searched in the exported symbols of the whole runtime.
If not given, the __main__ symbol of the top module is executed. If the required symbol cannot be
found an error is raised and false is returned.
The routine returns true if execution is successful; the VM may return because the routine terminates,
because of an explicit END opcode and because execution limit (single step or limited step count) is
matched. Also, uncaught exceptions or explicit requests for termination may cause the VM to return.
It is possible to know if the execution is complete by looking at the last VM event with the
lastEvent() method: if none or quit, then the execution is just terminated, else an event is set
(i.e. tSuspend).
\param startSym the name of a routine to be executed.
\param paramCount Number of parameters that have been pushed in the stack as parameters.
\throw CodeError* if the symbol to be launched couldn't be found.
*/
void launch( const String &startSym, uint32 paramCount = 0 );
/** Virtual machine main loop.
This is the method that is responsible for the main virtual
machine loop. The VM can be configured to run a limited number
of steps (or even one); there are also several other settings
that may affect the run behavior.
Usually, the user program won't call this; the launch() method sets up the
execution environment and then calls run(). Calling this method is useful
to continue a pending execution (including single step execution).
If a symbol name is provided, then the symbol is executed retaining all the current
status. The symbol is searched in the locals of the top module, and then in the
global of the runtime eaxtly as for launch(). This is useful, for example, to provide
callback entry points in scripts that must maintain their execution status between
calls. In this way, each run maintain the previous status but grants execution of
different entry points; also this is quite faster than having to enter the realization
phase.
An error will be risen if launch has not been previously called and the routine name
is not provided.
*/
virtual void run();
/** Become target of OS signals. */
bool becomeSignalTarget()
{
return m_systemData.becomeSignalTarget();
}
/** Fills an error traceback with the current VM traceback. */
void fillErrorTraceback( Error &error ) { currentContext()->fillErrorTraceback( error ); }
/** Returns a single step traceback in the current context. */
bool getTraceStep( uint32 level, const Symbol* &sym, uint32& line, uint32 &pc )
{
return m_currentContext->getTraceStep( level, sym, line, pc );
}
/** Get the caller of the current symbol.
If the caller cannot be found (i.e. because the current symbol is
called directly by the embedding program) the method returns false.
\param sym on success, will hold a pointer to the symbol that called the current symbol.
\param module on success, will hold a pointer to the module where the caller symbol resides.
\return true on success, false on failure.
*/
bool getCaller( const Symbol *&sym, const Module *&module);
/** Get the item that called the current symbol.
If the caller cannot be found (i.e. because the current symbol is
called directly by the embedding program) the method returns false.
\param item on success, will hold the item (eventually the method) that originated the call.
\param level previous callers desired (0 is the first caller).
\return true on success, false on failure.
*/
bool getCallerItem( Item &caller, uint32 level=0 );
/** Fills an error with current VM execution context and traceback.
*/
void fillErrorContext( Error *err, bool filltb = true );
/** Returns the current stack as a reference. */
ItemArray &stack() { return m_currentContext->stack(); }
/** Returns the current stack as a reference (const version). */
const ItemArray &stack() const { return m_currentContext->stack(); }
/** Returns a reference to the nth item in the current stack. */
Item &stackItem( uint32 pos ) { return stack()[ pos ]; }
/** Returns a reference to the nth item in the current stack (const version). */
const Item &stackItem( uint32 pos ) const { return stack()[pos]; }
/** Returns the current module global variables vector. */
ItemArray ¤tGlobals() { return m_currentContext->globals(); }
/** Returns the current module global variables vector (const version). */
const ItemArray ¤tGlobals() const { return m_currentContext->globals(); }
/** Returns a reference to the nth item in the current module global variables vector. */
Item &moduleItem( uint32 pos ) { return currentGlobals()[ pos ]; }
/** Returns a reference to the nth item in the current module global variables vector (const version). */
const Item &moduleItem( uint32 pos ) const { return currentGlobals()[ pos ]; }
/** Returns the module in which the execution is currently taking place. */
const Module *currentModule() const { return m_currentContext->lmodule()->module(); }
/** Returns the module in which the execution is currently taking place. */
LiveModule *currentLiveModule() const { return m_currentContext->lmodule(); }
/** Find a linked module with a given name.
Returns a pointer to the linked live module if the name exists, or 0 if the named module
doesn't exist.
*/
LiveModule *findModule( const String &name );
/** Return the map of live modules ordered by name.
\return the list of live (linked) modules.
*/
LiveModuleMap &liveModules() { return m_liveModules; }
/** Return the map of live modules ordered by name (const version).
\return the list of live (linked) modules.
*/
const LiveModuleMap &liveModules() const { return m_liveModules; }
/** Returns the parameter count for the current function.
\note Calling this when the VM is not engaged in executing a function will crash.
\return parameter count for the current function.
*/
int32 paramCount() const {
return currentContext()->paramCount();
}
/** Returns the nth paramter passed to the VM.
Const version of param(uint32).
*/
const Item *param( uint32 itemId ) const
{
return currentContext()->param( itemId );
}
/** Returns the nth paramter passed to the VM.
This is just the noncost version.
The count is 0 based (0 is the first parameter).
If the parameter exists, a pointer to the Item holding the
parameter will be returned. If the item is a reference,
the referenced item is returned instead (i.e. the parameter
is dereferenced before the return).
The pointer may be modified by the caller, but this will usually
have no effect in the calling program unless the parameter has been
passed by reference.
\note Fetched item pointers are valid while the stack doesn't change.
Pushes, addLocal(), item calls and VM operations may alter the
stack. Using this method again after such operations allows to
get a valid pointer to the desired item. Items extracted with
this method can be also saved locally in an Item instance, at
the cost of a a flat item copy (a few bytes).
\param itemId the number of the parameter accessed, 0 based.
\return a valid pointer to the (dereferenced) parameter or 0 if itemId is invalid.
\see isParamByRef
*/
Item *param( uint32 itemId )
{
return currentContext()->param( itemId );
}
/** Returns the nth pre-paramter passed to the VM.
Pre-parameters can be used to pass items to external functions.
They are numbered 0...n in reverse push order, and start at the first
push before the first real parameter.
For example;
\code
Item *p0, *p1, *callable;
...
vm->pushParameter( (int64) 0 ); // pre-parameter 1
vm->pushParameter( vm->self() ); // pre-parameter 0
vm->pushParameter( *p0 );
vm->pushParameter( *p1 );
vm->callFrame( *callable, 2 ); // 2 parameters
\endcode
*/
Item *preParam( uint32 itemId )
{
return currentContext()->preParam( itemId );
}
/** Const version of preParam */
const Item *preParam( uint32 itemId ) const
{
return currentContext()->preParam( itemId );
}
/** Returns true if the nth element of the current function has been passed by reference.
\param itemId the number of the parameter accessed, 0 based.
\return true if the parameter exists and has been passed by reference, false otherwise
*/
bool isParamByRef( uint32 itemId ) const
{
return currentContext()->isParamByRef( itemId );
}
/** Returns the nth local item.
The first variable in the local context is numbered 0.
\note Fetched item pointers are valid while the stack doesn't change.
Pushes, addLocal(), item calls and VM operations may alter the
stack. Using this method again after such operations allows to
get a valid pointer to the desired item again. Items extracted with
this method can be also saved locally in an Item instance, at
the cost of a a flat item copy (a few bytes).
\param itemId the number of the local item accessed.
\return a valid pointer to the (dereferenced) local variable or 0 if itemId is invalid.
*/
const Item *local( uint32 itemId ) const
{
return m_currentContext->local( itemId );
}
/** Returns the nth local item.
This is just the non-const version.
The first variable in the local context is numbered 0.
\param itemId the number of the local item accessed.
\return a valid pointer to the (dereferenced) local variable or 0 if itemId is invalid.
*/
Item *local( uint32 itemId )
{
return m_currentContext->local( itemId );
}
const Item ®A() const { return m_currentContext->regA(); }
Item ®A() { return m_currentContext->regA(); }
const Item ®B() const { return m_currentContext->regB(); }
Item ®B() { return m_currentContext->regB(); }
const Item ®Bind() const { return m_currentContext->regBind(); }
Item ®Bind() { return m_currentContext->regBind(); }
const Item ®BindP() const { return m_currentContext->regBindP(); }
Item ®BindP() { return m_currentContext->regBindP(); }
const Item &self() const { return m_currentContext->self(); }
Item &self() { return m_currentContext->self(); }
const Item &felf() const { return m_currentContext->fself(); }
Item &fself() { return m_currentContext->fself(); }
/** Latch item.
Generated on load property/vector instructions, it stores the accessed object.
*/
const Item &latch() const { return m_currentContext->latch(); }
/** Latch item.
Generated on load property/vector instructions, it stores the accessed object.
*/
Item &latch() { return m_currentContext->latch(); }
/** Latcher item.
Generated on load property/vector instructions, it stores the accessor item.
*/
const Item &latcher() const { return m_currentContext->latcher(); }
/** Latcher item.
Generated on load property/vector instructions, it stores the accessor item.
*/
Item &latcher() { return m_currentContext->latcher(); }
void retval( bool val ) {
m_currentContext->regA().setBoolean( val );
}
void retval( int32 val ) {
m_currentContext->regA().setInteger( (int64) val );
}
void retval( int64 val ) {
m_currentContext->regA().setInteger( val );
}
void retval( numeric val ) {
m_currentContext->regA().setNumeric( val );
}
void retval( const Item &val ) {
m_currentContext->regA() = val;
}
/** Returns a non garbageable string. */
void retval( String *cs )
{
m_currentContext->regA().setString(cs);
}
/** Returns a garbageable string.
\note to put a nongarbage string in the VM use regA() accessor, but you must know what you're doing.
*/
void retval( CoreString *cs )
{
m_currentContext->regA().setString(cs);
}
void retval( CoreArray *ca ) {
m_currentContext->regA().setArray(ca);
}
void retval( MemBuf* mb ) {
m_currentContext->regA().setMemBuf(mb);
}
void retval( CoreDict *cd ) {
m_currentContext->regA().setDict( cd );
}
void retval( CoreObject *co ) {
m_currentContext->regA().setObject(co);
}
void retval( CoreClass *cc ) {
m_currentContext->regA().setClass(cc);
}
void retval( const String &cs ) {
CoreString *cs1 = new CoreString( cs );
cs1->bufferize();
m_currentContext->regA().setString( cs1 );
}
void retnil() { m_currentContext->regA().setNil();}
const Symbol *currentSymbol() const { return m_currentContext->symbol(); }
uint32 programCounter() const { return m_currentContext->pc(); }
const SymModule *findGlobalSymbol( const String &str ) const;
/** Make this context to sleep and elect a new one.
If no other context can be elected, the VM may issue an
onIdleTime() and eventually sleep a bit.
*/
void yield( numeric seconds );
void rotateContext();
void terminateCurrentContext();
/** Returns a well known item.
A well known item is an item that does not phiscally resides in any module, and is
at complete disposal of VM.
Usually, System relevant classes as Error, TimeStamp, Stream and so on are
considered WKI.
Modules can declare their own WKIs so that they can safely retreive their own original
live data that cannot be possibly transformed by scripts.
Modules just need to declare a symbol adding the Symbol::setWKI clause, and the VM will create
a proper entry on link step. WKI items are created for the module, but a safe copy is also
saved in another location.
WKI items have not to be exported, although they can.
\note the data is not deep-copied. WKI are prevented to be chaged in their nature,
but their content can still be changed. Please, notice that both flat items
and classes are read-only from a script standpoint, while strings, arrays, objects
and dictionaries can have their contents changed.
\note The returned Well Known item is never to be de/referenced.
\param name the WKI to be found
\return 0 if a WKI with that name can't be found, a valid item pointer on success.
*/
Item *findWKI( const String &name ) const;
/** Returns a live global given the name of its symbol.
Items exported by moduels becomes associated with an item that can be
accessed (and then changed) by both scripts and modules extensions.
This method returns a pointer to the item that stores the current value
of the given global symbol, and it is exactly the item that the scripts
using that symbol are seeing.
The returned item is already dereferenced. Changing it will change all
items referred by this symbol in all the modules.
\note To create failsafe new instances of classes or to access critical
functions exported by modules, use findWKI().
\param name the symbol to be searched.
\return the global item associated with the symbol if found, or 0 if the item does not exist.
*/
Item *findGlobalItem( const String &name ) const;
/** Returns the value of a local variable.
This function searces for a variable in the local context, and eventually in the
global context if not locally found.
The function also parses accessors as the "." dot operator or the [] array access
operator, but it doesn't support range accessors or function calls.
As the value of object accessor may be synthezized on the fly, the method cannot
return a physical pointer; the value of the variable is flat-copied in the data
parameter.
\param name the variable to be found.
\param data where to store the value if found.
\return true if the value can be found, false otherwise.
*/
bool findLocalVariable( const String &name, Item &data ) const;
/** Returns the value of a local variable.
Similar to findLocalVariable(), but will return only the item coresponding to the
named symbol. The symName parameter must be already trimmed and corespond exactly
to the name of a variable in the local context.
If the symbol is not found in the local symbol table, accessible global tables
are searched in order of visibility.
If the variable cannot be found, 0 is returned.
\param symName the symbol name to be found
\return the physical pointer to the variable storage, or 0 on failure.
*/
Item *findLocalSymbolItem( const String &symName ) const;
/** Calls an item.
The item may contain any valid callable object:
- An external (C/C++) function.
- A falcon function.
- A method
- A class
External functions are immediately called, the flow of the VM being
interrupted.
Falcon function and method calls prepare this vm to execute the first
instruction of the item, pushing a stack frame that allows RET and similar
pcodes to return to the VM instruction after the one that was currently
being executed. Control may or may not return immediately to the caller;
if e_callNormal, e_callInst or e_callPassIn modes are used, the function
returns only after the called item returns, else the function returns
immediately and the vm is readied to continue execution from the new
position.
Class calls actually searches for the class constructor, and call that one.
If the called class has no constructor, the function returns true but actually
does nothing.
Before calling this function, enough parameters must be pushed in the stack
using pushParam() method.
The paramCount parameter must be smaller or equal to the size of the stack,
or an unblockable error will be raised.
\param callable the item to be called.
\param paramCount the number of elements in the stack to be considered parameters.
\param mode the item call mode.
*/
void callItem( const Item &callable, int32 paramCount )
{
callFrame( callable, paramCount );
execFrame();
}
/** Shortcut for to call an item from a VM frame.
Extension functions and VM/core functions meant to be called from the
run() loop should use this function instead the callItem.
The function prepares the VM to execute the desired item at the next run loop,
as soon as the calling function returns.
The caller should return immediately, or after a short cleanup, in case the
call is succesful (and the function returns true).
If the function needs to continue or do some post-processing after calling
the callable item, it must install a return frame handler using returnHandler()
*/
void callFrame( const Item &callable, int32 paramCount )
{
callable.readyFrame( this, paramCount );
}
/** Prepares a VM call frame with a return handler.
When the code flow will return to the calling run(), or when it will enter
run() for the first time, the code in callable will be executed.
At termination, the vm will immediately call callbackFunc that may create new
frames and return true, to ask the VM to continue the evaluation, or return
false and terminate this frame, effectively "returning" from the callable.
*/
void callFrame( const Item &callable, int32 paramCount, ext_func_frame_t callbackFunc )
{
callable.readyFrame( this, paramCount );
m_currentContext->returnHandler( callbackFunc );
}
/** Prepare a frame for a function call */
void prepareFrame( CoreFunc* cf, uint32 paramCount );
/** Prepare a frame for an array call.
The function oesn't check for the array to be callable because
it's supposed that the check is on the caller.
However, a debug assert is performed.
*/
void prepareFrame( CoreArray* ca, uint32 paramCount );
/** Executes an executable item in a coroutine.
\param callable The callable routine.
\param paramCount Number of parameters to be passed in the coroutine stack.
*/
bool callCoroFrame( const Item &callable, int32 paramCount );
/** Executes currently prepared frame. */
void execFrame()
{
currentFrame()->m_break = true; // force to exit when meeting this limit
m_currentContext->pc() = m_currentContext->pc_next();
run();
}
StackFrame* currentFrame() const
{
return m_currentContext->currentFrame();
}
VMContext* currentContext() const
{
return m_currentContext;
}
/** Resets the return handler and prepares to call given external handler.
This function prepares the VM to execute a return handler immediately
after the calling function returns.
The net effect is that, when called from inside an extension function,
the given callback will be called by the VM as the very next operation,
after checks on events, timings and context switches.
The difference with callFrame is that the stack is unaffected, and
the called function will have the same call frame as the caller.
The difference with returnHandler is that the VM is instructed
to execute the retun procedure (that will call the given call back
function) immediately, while returnHandler just sets an handler
for a future time when the readied call frame will be unrolled.
This function can be safely called from inside the same callback
function, so to create loops in which each call goes through
VM checks for operation counts and events.
The callbackFunc should behave as specified for returnHandler(),
returning true if creating another frame with callFrame() or calling
another return handler (or even itself) using callFrameNow().
\note recallFrame() is a (more) efficient shortcut for
using callFrameNow on the same calling function.
\see returnHandler()
\param callbackFunc the function to be called ASAP.
*/
void callFrameNow( ext_func_frame_t callbackFunc );
/** Prepare the VM to recall current return frame.
Calling this method and returning true, an handler set with
returnFrame() can instruct the VM to call itself again after
having performed a loop check.
\note This method must be called only inside extension functions,
better if they are also return frame handlers.
\see callFrameNow()
*/
void recallFrame() { m_currentContext->pc_next() = m_currentContext->pc(); } // reset pc advancement
/** Call an item in atomic mode.
This method is meant to call the vm run loop from inside another vm
run loop. When this is necessary, the inner call must end as soon as
possible. The VM becomes unprehemptible; contexts are never switched,
operation count limits (except for hard limits) are not accounted and
any explicit try to ask for the VM to suspend, wait, yield or sleep
raises an unblockable error.
Things to be called in atomic mode are i.e. small VM operations
overload methods, as the toString or the compare. All the rest should
be performed using the callFrame mechanism.
\throw CodeError if the item is not callable.
*/
void callItemAtomic(const Item &callable, int32 paramCount );
/** Installs a post-processing return frame handler.
The function passed as a parmeter will receive a pointer to this VM.
The function <b>MUST</b> return true if it performs another frame item call. This will
tell the VM that the stack cannot be freed now, as a new call stack has been
prepared for immediate execution. When done, the function will be called again.
A frame handler willing to call another frame and not willing to be called anymore
must first unininstall itself by calling this method with parameters set at 0,
and then it <b>MUST return true</b>.
A frame handler not installing a new call frame <b>MUST return false</b>. This will
terminate the current stack frame and cause the VM to complete the return stack.
\param callbackFunct the return frame handler, or 0 to disinstall a previously set handler.
*/
void returnHandler( ext_func_frame_t callbackFunc ) {
m_currentContext->returnHandler( callbackFunc );
}
ext_func_frame_t returnHandler() const
{
return m_currentContext->returnHandler();
}
/** Returns currently installed return handler, or zero if none.
\return currently installed return handler, or zero if none.
*/
ext_func_frame_t returnHandler();
/** Alias for void pushParameter() */
void pushParam( const Item &item ) { m_currentContext->pushParam(item); }
void pushParameter( const Item &item ) { m_currentContext->pushParam(item); }
/** Adds some local space in the current context.
\param amount how many local variables must be created
*/
void addLocals( uint32 space )
{
m_currentContext->addLocals( space );
}
byte operandType( byte opNum ) const {
return m_currentContext->code()[m_currentContext->pc() + 1 + opNum];
}
/** True if the VM is allowed to execute a context switch. */
bool allowYield() { return m_allowYield; }
/** Change turnover mode. */
void allowYield( bool mode ) { m_allowYield = mode; }
const ContextList *getCtxList() const { return &m_contexts; }
const ContextList *getSleepingList() const { return &m_sleepingContexts; }
/** Return from the last called subroutine.
Usually used internally by the opcodes of the VM.
*/
void callReturn()
{
// if the stack frame requires an end handler...
// ... but only if not unrolling a stack because of error...
if ( currentFrame()->m_endFrameFunc != 0 )
{
currentContext()->pc_next() = currentContext()->pc();
// if the frame requires to stay here, return immediately
if ( currentFrame()->m_endFrameFunc( this ) )
{
return;
}
}
m_break = currentContext()->callReturn();
// if we have nowhere to return...
if( currentContext()->currentFrame() == 0 && ! m_break )
{
terminateCurrentContext();
}
}
/** Converts an item into a string.
The string is NOT added to the garbage collecting system,
so it may be disposed freely by the caller.
This translates into a direct call to Item::toString(), unless the
item is an object.
In that case, if the item provides a toString() method, then that method is called
passing the "format" parameter (only if it's not empty).
\param itm a pointer to the item that must be represented as a string,
\param format a format that will be eventually sent to the "toString" method of the object.
\param target the output representation of the string
*/
void itemToString( String &target, const Item *itm, const String &format );
void itemToString( String &target, const Item *itm )
{
itemToString( target, itm, "" );
}
/** Creates the template for a core class.
\param lmod the module id for which this class is being created.
\param pt a ClassDef wise property table containing properties definition.
\return a newly created property table ready to be added to a core class.
*/
PropertyTable *createClassTemplate( LiveModule *lmod, const Map &pt );
/** Publish a service.
Will raise an error and return false if the service is already published.
\param svr the service to be published on this VM.
\throws CodeError on dupilcated names.
*/
void publishService( Service *svr );
/** Queries the VM for a published service.
If a service with the given name has been published, the VM will return it;
otherwise returns 0.
\param name the service to be published on this VM.
\return the required service or 0.
*/
Service *getService( const String &name );
/** Gets the standard input stream associated with this VM.
VM may offer this stream to RTL and module functions wishing to
get some input (as, i.e., input() ).
By default, it is pointing
to a correctly internationalized verisons of text-oriented Stream
Transcoders. The transcoder is selected depending on the system
environmental conditions, but there is no particular reason
to use a transcoder instead of a direct stream, if this vm and
functions using the standard streams abstractions held in the VM
are willingt to operate on binary streams or on streams with
different encodings.
\return current incarnation of standard input stream.
*/
Stream *stdIn() const { return m_stdIn; }
/** Gets the standard input stream associated with this VM.
VM may offer this stream to RTL and module functions wishing to
write generic output, as print, printl and inspect.
By default, it is pointing
to a correctly internationalized verisons of text-oriented Stream
Transcoders. The transcoder is selected depending on the system
environmental conditions, but there is no particular reason
to use a transcoder instead of a direct stream, if this vm and
functions using the standard streams abstractions held in the VM
are willingt to operate on binary streams or on streams with
different encodings.
\return current incarnation of standard output stream.
*/
Stream *stdOut() const { return m_stdOut; }
/** Gets the standard input stream associated with this VM.
VM may offer this stream to RTL and module functions wishing to print
error messages.
By default, it is pointing
to a correctly internationalized verisons of text-oriented Stream
Transcoders. The transcoder is selected depending on the system
environmental conditions, but there is no particular reason
to use a transcoder instead of a direct stream, if this vm and
functions using the standard streams abstractions held in the VM
are willingt to operate on binary streams or on streams with
different encodings.
\note the VM uses the default std error stream to feed the
standard Default Error Handler at its creation. That handler
has its own copy of a StdErrorStream implementation, and changing
this object won't affect the default error handler. If the
error handler output has to be redirected as well, the new
stream must be directly set. Also, be sure not to give ownership
of the stream to the default handler, as giving ownership
would cause the handler AND the VM to try to destroy the
same pointer.
\return current incarnation of standard error stream.
*/
Stream *stdErr() const { return m_stdErr; }
/** Set stdandard input stream.
Old standard input stream abstraction is destroyed (vm owns it).
\see stdIn()
\param nstream the new stream
*/
void stdIn( Stream *nstream );
/** Set stdandard output stream.
Old standard output stream abstraction is destroyed (vm owns it).
\see stdOut()
\param nstream the new stream
*/
void stdOut( Stream *nstream );
/** Set stdandard error stream.
Old standard error stream abstraction is destroyed (vm owns it).
\note This doesn't changes the stream used by the standard error handler, which,
by default, is set to a owned copy of this stream.
\see stdOut()
\param nstream the new stream
*/
void stdErr( Stream *nstream ) ;
bool hasProcessStreams() const { return m_bhasStandardStreams; }
/** Indicastes if this VM has been given standard streams control or not.
VM in embedding applications hold generally streams that are not pointing to the
process streams. Only direct itepreters (e.g. falcon command line) generally
provides the VM with the process standard streams; normally, the process doesn't
want the VM to use its standard stream, and even when it does, it doesn't want the
VM (and the scripts) to be able to close the streams on its behalf.
This is however desirable when scripts are running in a standalone environment,
so that they can interact with other piped processes. In that case, both embedding
applications, but more generally script interpreters as falcon command line, will
give full stream ownership to the VM, and let them to possibly close the streams
directly.
\param b set to true to allow the scripts on this VM to close standard streams.
*/
void hasProcessStreams( bool b ) { m_bhasStandardStreams = b; }
/** Return current module string at given ID.
Retreives the module string which has been given the passed ID,
and returns it to the caller. If the string is not found, a
statically allocated empty string is returned instead.
\param stringId the id for the string in the current module
*/
const String &moduleString( uint32 stringId ) const;
/** Reset machine for a clean execution.
This resets the VM to execute cleanly a ascript, removing all
the dirty variables, execution context and the rest.
*/
virtual void reset();
void limitLoops( uint32 l ) { m_opLimit = l; }
uint32 limitLoops() const { return m_opLimit; }
bool limitLoopsHit() const { return m_opLimit >= m_opCount; }
void resetCounters();
/** Performs a single VM step and return. */
void step() {
m_currentContext->pc() = m_currentContext->pc_next();
m_bSingleStep = true;
// stop next loop
m_opNextCheck = m_opCount + 1;
run();
}
void singleStep( bool ss ) { m_bSingleStep = ss; }
bool singleStep() const { return m_bSingleStep; }
/** Periodic callback.
This is the periodic callback routine. Subclasses may use this function to get
called every now and then to i.e. stop the VM asynchronously, or to perform
debugging.
*/
virtual void periodicCallback();
void callbackLoops( uint32 cl ) { m_loopsCallback = cl; }
uint32 callbackLoops() const { return m_loopsCallback; }
void gcCheckLoops( uint32 cl ) { m_loopsGC = cl; }
uint32 gcCheckLoops() const { return m_loopsGC; }
void contextCheckLoops( uint32 cl ) { m_loopsContext = cl; }
uint32 contextCheckLoops() const { return m_loopsContext; }
/** Return the loops that this VM has performed.
There is no guarantee that the loops performed by the virtual
machine hadn't overflown the uint32 size, nuless there is a
physical loop limit set with loopLimit().
However, this counter can be useful to check different algorithm
performances.
*/
uint32 elapsedLoops() const { return m_opCount; }
/** Push current try position */
void pushTry( uint32 landingPC ) { currentContext()->pushTry( landingPC ); }
/** Pop a try position, eventually changing the frame to the handler. */
void popTry( bool moveTo ) { currentContext()->popTry( moveTo ); }
/** Elects a new context ready for execution.
This method should be called by embedding applications that have performed
a sleep operations right after the elapsed sleep time. The VM will elect
the most suitable context for execution.
On output, the VM will be ready to run (call the run() function); if no context
is willing to run yet, there this method will set the eventSleep (hadSleepRequest()
will return true), and the sleep request time will be propery set.
*/
void electContext();
/** Types of return values.
When a function may return more than simply syccess or failure, this code
specifies what went wrong in a VM function.
*/
typedef enum {
return_ok,
return_error_string,
return_error_parse,
return_error_internal,
return_error_parse_fmt
}
returnCode;
/** Performs a string expansion.
\return a returnCode enumeration explaining possible errors in string expansion
*/
returnCode expandString( const String &src, String &target );
/** Creates a reference to an item.
The source item is turned into a reference which is passed in the
target item. If the source is already a reference, the reference
is just passed in the target.
\param target the item that will accept reference to source
\param source the source item to be referenced
*/
void referenceItem( Item &target, Item &source );
/** Set user data.
VM is passed to every extension function, and is also quite used by the
embedding application. To provide application specific per-vm data to
the scripts, the best solution for embedding applications is usually
to extend the VM into a subclass. Contrarily, middleware extensions,
as, for example, script plugins for applications, may prefer to use the
standard Falcon VM and use this pointer to store application specific data.
The VM makes no assumption on the kind of user data. The data is not destroyed
at VM destruction. If there is the need to destroy the data at VM destruction,
then VM derivation seems a more sensible choice.
\param ud the application specific user data.
*/
void userData( void *ud ) { m_userData = ud; }
/** Get the user data associated with this VM.
\see userData( void * )
\return the previously set user data or 0 if user data is not set.
*/
void *userData() const { return m_userData; }
/** Evaluate the item in a functional context.
The function return either true or false, evaluating the item
as a funcional token.
# If the item is an array, it is recursively scanned.
# If the item is a callable item (including callable arrayas),
it is called and then the return value is evaluated in a
non-functional context (plain evaluation).
# In all the other cases, the item is evaluated in a non-functional
context.
More simply, if the item is callable is called, and is result
is checked for Falcon truth value. If not, it's simply checked.
The return value will be in regA(), and it's the "reduced" list
of items.
The function returns true if it has to stop for frame evaluation,
false if the caller can loop. When the function returns true, the
caller must immediately return to the calling frame; in case it
needs to continue processing, it must install a frame return handler
to be called back when the frame created by functionalEval is done.
\param itm the item to be functionally evaluated.
\param pcount the number of parameters in the VM to be treated as evaluation parameters.
\param retArray true to force return of an evaluated array in case the input is not a Sigma sequence.
\return false if the caller can proceed, true if it must return.
*/
bool functionalEval( const Item &itm, uint32 pcount=0, bool retArray = true );
/** Interrupts pending I/O on this machine from a separate thread.
Interrupts compliant streams I/O and wait operations. The next I/O or
the next wait, or the next compliant system blocking operation
will cause an Interrupted exception to be raised.
This method does not generate an "interrupt request" on the VM, that will
keep on running until a blocking operation is encountered.
This method can be safely called from other threads in the same application
where the is currently executed, as well as from inside the same thread.
*/
void interrupt() { m_systemData.interrupt(); }
/** Returns true if the VM has been interrupted.
If an asynchronous interrupt has been generated, this method will return true.
This is meant to be called from those compliant operations that require polling,
or just before starting waiting on interruptable code to avoid useless calculations,
or right after to know if the VM has been interrupted during the computation.
\param raise if true, prepare an Interrupted exception in the VM context if the VM has been
interrupted.
\param reset if true, reset interrupted status now.
\param dontCheck suppse interruption test is already done, and just raise the error and reset.
\return true if the machine has been interrupted through interrupt() request.
*/
bool interrupted( bool raise = false, bool reset = false, bool dontCheck = false );
/** Get System Specific data.
\returns system specific data bound with this machine.
*/
virtual const Sys::SystemData &systemData() const { return m_systemData; }
/** Get System Specific data (non const).
\returns system specific data bound with this machine.
*/
Sys::SystemData &systemData() { return m_systemData; }
/** Exports a single symbol.
This publishes a symbol on the global symbol map,
and/or eventually to the WKS map.
The function checks for the symbol to be exported and/or Well Known before
actually performing the final export.
*/
virtual bool exportSymbol( const Symbol *sym, LiveModule *mod );
/** Exports all symbols in a module.
To be called when changing the module publicity policy.
*/
virtual bool exportAllSymbols( LiveModule *mod );
/** Changes the status of launch-at-link mode */
void launchAtLink( bool mode ) { m_launchAtLink = mode; }
/** Returns the launch-at-link mode.
This method returns true if the VM will launch the __main__ symbol of modules
as soon as they are linked in the vm, or false otherwise.
*/
bool launchAtLink() const { return m_launchAtLink; }
/** Set current binding context.
The current binding context is a dictionary containing
a set of bound symbols and their value (referenced).
Binding context is NOT GC masked, so it must exist
elsewhere (i.e. in a live dictionary).
The binding context is automatically removed at
frame return.
*/
void setBindingContext( CoreDict *ctx ) { m_currentContext->regBind() = ctx; }
/** Return the value associated with a binding symbol.
This function searches the given binding symbol name
in the current binding context and in all the
visible contexts (?).
If the function returns 0, the symbol is unbound.
\param bind The binding symbol name.
\return A valid non-dereferenced binding value or 0 if the symbol is unbound.
*/
Item *getBinding( const String &bind ) const;
/** Return the value associated with a binding symbol, or creates one if not found.
This function searches the given binding symbol name
in the current binding context and in all the
visible contexts (?). If the symbol is not found,
it is created in the innermost visible context.
If the function returns 0, then there is no visible context.
\param bind The binding symbol name.
\return A valid non-dereferenced binding value or 0 if there is no visible context.
*/
Item *getSafeBinding( const String &bind );
/** Set a binding value.
This function sets a binding value in the current context.
If a binding context has not been set, the function returns false.
\param bind The binding symbol name.
\param value The value to associate to this binding.
*/
bool setBinding( const String &bind, const Item &value );
typedef enum {
lm_complete,
lm_prelink,
lm_postlink
} t_linkMode;
/** Request a constructor call after a call frame.
If the preceding callFrame() was directed to an external function, requests the VM to treat
the return value as an init() return, placing self() in regA() when all is done.
*/
void requestConstruct() {
if( m_currentContext->pc_next() == i_pc_call_external )
m_currentContext->pc_next() = i_pc_call_external_ctor;
}
void setMetaClass( int itemID, CoreClass *metaClass )
{
fassert( itemID >= 0 && itemID < FLC_ITEM_COUNT );
m_metaClasses[ itemID ] = metaClass;
}
CoreClass *getMetaClass( int itemID )
{
fassert( itemID >= 0 && itemID < FLC_ITEM_COUNT );
return m_metaClasses[ itemID ];
}
/** Gets a slot for a given message.
If the slot doesn't exist, 0 is returned, unless create is set to true.
In that case, the slot is created anew and returned.
*/
virtual CoreSlot* getSlot( const String& slotName, bool create = true );
/** Removes and dereference a message slot in the VM.
*/
virtual void removeSlot( const String& slotName );
/** Used by the garbage collector to accunt for items stored as slot callbacks. */
virtual void markSlots( uint32 mark );
/** Comsume the currently broadcast signal.
This blocks the processing of signals to further listener of the currently broadcasting slot.
\return true if the signal is consumed, false if there was no signal to consume.
*/
virtual bool consumeSignal();
/** Declares an IDLE section.
In code sections where the VM is idle, it is granted not to change its internal
structure. This allow inspection from outer code, as i.e. the garbage collector.
\note Calls VM baton release (just candy grammar).
\see baton()
*/
virtual void idle() { m_baton.release(); }
/** Declares the end of an idle code section.
\note Calls VM baton acquire (just candy grammar).
\see baton()
*/
virtual void unidle() { m_baton.acquire(); }
/** Enable the Garbage Collector requests on this VM.
If \b mode is false, the VM never checks for garbage collector requests to
block operations for detailed inspections.
If \b mode is true, the VM periodically tells the GC that it is ready for inspection,
and it is forced to honor block requests when memory gets critically high.
However, if the GC is disabled, the VM may be inspected if it volountarily enters
the idle state (sleep or I/O calls).
\param mode True to allow forced periodic inspections in case of need.
*/
void gcEnable( bool mode );
bool isGcEnabled() const;
/** Setup the main script standard parameters and variables.
This is an utility function filling the follwing global variables,
provided they have been linked and are globally exported from some
module in the VM:
- script_name: the logical module name of the main module.
- script_path: physical path of the main module.
- args: filled with argc and argv.
*/
virtual void setupScript( int argc, char** argv );
/** Class automating idle-unidle fragments.
This purely inlined class automathises the task of calling
unidle() as a function putting the VM in idle (i.e. I/O function)
returns.
*/
class Pauser
{
VMachine *m_vm;
public:
inline Pauser( VMachine *vm ):
m_vm( vm ) { m_vm->idle(); }
inline ~Pauser() { m_vm->unidle(); }
};
/** Accessor to the VM baton.
Used to serialize concurrent access to this VM.
*/
const VMBaton& baton() const { return m_baton; }
/** Accessor to the VM baton.
Used to serialize concurrent access to this VM.
*/
VMBaton& baton() { return m_baton; }
/** Send a message to the VMachine.
If the virtual machine is currently idle, the message is immediately processed.
Otherwise, it is posted to the main VM loop, and it is executed as soon as
possible.
The ownership of the message passes to the virtual machine, which will destroy
it as the message is complete.
The message is processed by broadcasting on the coresponding VM slot.
*/
void postMessage( VMMessage *vm );
/** Return current generation. */
uint32 generation() const;
/** Force a GC collection loop on the virtual machine.
Waits for the GC loop to be completed. The virtual machine must
be in non-idle mode when calling this function, as the idle ownership
is directly transferred to the GC and then back to the calling VM
without interruption.
Normallym the GC will notify the VM back as soon as the mark loop is over;
If the VM wants to wait for the free memory to be collected, set
the parameter to true.
*/
void performGC( bool bWaitForCollection = false );
/** Increments the reference count for this VMachine. */
void incref();
/** Decrements the reference count for this virtual machine.
If the count hits zero, the virtual machine is immediately destroyed.
*/
void decref();
/** Terminates this VM activity.
The thread creating the VM or the VM owner shall call this to inform the system
that the VM will not be actvive anymore.
The VM will be destroyed immediately or as soon as all the other references
are released.
This fucntion also dereference the VM once (in the behalf of the VM original
owner).
*/
void finalize();
/** Finalization callback function (used by MT) */
void setFinalizeCallback( void (*finfunc)( VMachine* vm ) )
{
m_onFinalize = finfunc;
}
/** Executes the return frame as soon as the control reaches the VM main loop.
Can be used in conjunction with a fake call frame where the real work
is done by the return frame function.
\code
static bool real_handler( VMachine *vm )
{
//do real work
return false; // remove frame?
}
void extension_func( VMachine *vm )
{
vm->invokeReturnFrame( real_handler ); // prevent executing unexisting code in this frame.
vm->addLocals( 5 );
// configure local variables...
// return, and let the VM call the real_handler
}
\endcode.
*/
void invokeReturnFrame( ext_func_frame_t func ) {
createFrame( 0, func );
m_currentContext->pc_next() = i_pc_call_external_return;
}
/** Get the default application load path. */
const String& appSearchPath() const { return m_appSearchPath; }
/** Sets the default application load path (as seen by this vm). */
void appSearchPath( const String &p ) { m_appSearchPath = p; }
/** Call back on sleep requests.
This method is called back when the virtual machine detects the
need to perform a pause.
The default VMachine version calls the system "sleep" routine,
but the application may find something more interesting to
do.
@note The application should eventually call idle() and
unidle() respectively at enter and exit of this callback if
it doesn't use the VM while in this routine.
@param seconds Number of seconds (and fractions) that the VM is
idle.
@throws InterruptedError if the wait was interrupted.
@throws CodeError if the wait is < 0 (infinite) and there are
no active contexts able to wake up this one.
*/
virtual void onIdleTime( numeric seconds );
//TODO: change signature next version
bool replaceMe_onIdleTime( numeric seconds );
/** Binds a late binding in the current context.
As late bindings are known by name, only the name is necessary
for the binding to complete.
\param name the symbolic name of the binding.
\param value the value to be associated with the late binding.
*/
void bindItem( const String& name, const Item& value );
/** Unbinds a late binding on the given target.
If the lbind item is not a late binding, tgt is copied from this item.
If lbind is a literal late binding, returns a non-literal late binding.
If lbind is a non-literal late binding tries to resolve the late binding;
in success placese the bound item (by value) in tgt.
*/
void unbindItem( const String& name, Item &tgt ) const;
/** Change the position of the next executed instruction. */
void jump( uint32 pos )
{
m_currentContext->pc_next() = pos;
}
/** Expand a number of variables from the current value of an iterator.
Uses the current VM pc_next position to decode \b count variables
stored in NOP opcodes, storing the current value of the iterator
into them.
* */
void expandTRAV( uint32 count, Iterator& iter );
void breakRequest( bool mode ) { m_break = mode; }
bool breakRequest() const { return m_break; }
/** Returns the Random Number Generator */
MTRand& getRNG(void) { return _mtrand; }
//==========================================================================
//==========================================================================
//==========================================================================
// Range 1: Parameterless ops
/** End opcode handler.
END opcode terminates current coroutine or current virtual machine execution.
*/
friend void opcodeHandler_END ( register VMachine *vm );
friend void opcodeHandler_NOP ( register VMachine *vm );
friend void opcodeHandler_PSHN( register VMachine *vm );
friend void opcodeHandler_RET ( register VMachine *vm );
friend void opcodeHandler_RETA( register VMachine *vm );
friend void opcodeHandler_PTRY( register VMachine *vm );
// Range 2: one parameter ops;
friend void opcodeHandler_LNIL( register VMachine *vm );
friend void opcodeHandler_RETV( register VMachine *vm );
friend void opcodeHandler_FORK( register VMachine *vm );
friend void opcodeHandler_BOOL( register VMachine *vm );
friend void opcodeHandler_GENA( register VMachine *vm );
friend void opcodeHandler_GEND( register VMachine *vm );
friend void opcodeHandler_PUSH( register VMachine *vm );
friend void opcodeHandler_PSHR( register VMachine *vm );
friend void opcodeHandler_POP ( register VMachine *vm );
friend void opcodeHandler_JMP ( register VMachine *vm );
friend void opcodeHandler_INC ( register VMachine *vm );
friend void opcodeHandler_DEC ( register VMachine *vm );
friend void opcodeHandler_NEG ( register VMachine *vm );
friend void opcodeHandler_NOT ( register VMachine *vm );
friend void opcodeHandler_TRAL( register VMachine *vm );
friend void opcodeHandler_IPOP( register VMachine *vm );
friend void opcodeHandler_XPOP( register VMachine *vm );
friend void opcodeHandler_GEOR( register VMachine *vm );
friend void opcodeHandler_TRY ( register VMachine *vm );
friend void opcodeHandler_JTRY( register VMachine *vm );
friend void opcodeHandler_RIS ( register VMachine *vm );
friend void opcodeHandler_BNOT( register VMachine *vm );
friend void opcodeHandler_NOTS( register VMachine *vm );
friend void opcodeHandler_PEEK( register VMachine *vm );
// Range3: Double parameter ops;
friend void opcodeHandler_LD ( register VMachine *vm );
friend void opcodeHandler_LDRF( register VMachine *vm );
friend void opcodeHandler_ADD ( register VMachine *vm );
friend void opcodeHandler_SUB ( register VMachine *vm );
friend void opcodeHandler_MUL ( register VMachine *vm );
friend void opcodeHandler_DIV ( register VMachine *vm );
friend void opcodeHandler_MOD ( register VMachine *vm );
friend void opcodeHandler_POW ( register VMachine *vm );
friend void opcodeHandler_ADDS( register VMachine *vm );
friend void opcodeHandler_SUBS( register VMachine *vm );
friend void opcodeHandler_MULS( register VMachine *vm );
friend void opcodeHandler_DIVS( register VMachine *vm );
friend void opcodeHandler_MODS( register VMachine *vm );
friend void opcodeHandler_BAND( register VMachine *vm );
friend void opcodeHandler_BOR ( register VMachine *vm );
friend void opcodeHandler_BXOR( register VMachine *vm );
friend void opcodeHandler_ANDS( register VMachine *vm );
friend void opcodeHandler_ORS ( register VMachine *vm );
friend void opcodeHandler_XORS( register VMachine *vm );
friend void opcodeHandler_GENR( register VMachine *vm );
friend void opcodeHandler_EQ ( register VMachine *vm );
friend void opcodeHandler_NEQ ( register VMachine *vm );
friend void opcodeHandler_GT ( register VMachine *vm );
friend void opcodeHandler_GE ( register VMachine *vm );
friend void opcodeHandler_LT ( register VMachine *vm );
friend void opcodeHandler_LE ( register VMachine *vm );
friend void opcodeHandler_IFT ( register VMachine *vm );
friend void opcodeHandler_IFF ( register VMachine *vm );
friend void opcodeHandler_CALL( register VMachine *vm );
friend void opcodeHandler_INST( register VMachine *vm );
friend void opcodeHandler_ONCE( register VMachine *vm );
friend void opcodeHandler_LDV ( register VMachine *vm );
friend void opcodeHandler_LDP ( register VMachine *vm );
friend void opcodeHandler_TRAN( register VMachine *vm );
friend void opcodeHandler_LDAS( register VMachine *vm );
friend void opcodeHandler_SWCH( register VMachine *vm );
friend void opcodeHandler_IN ( register VMachine *vm );
friend void opcodeHandler_NOIN( register VMachine *vm );
friend void opcodeHandler_PROV( register VMachine *vm );
friend void opcodeHandler_SSTA( register VMachine *vm );
friend void opcodeHandler_SVAL( register VMachine *vm );
friend void opcodeHandler_STPS( register VMachine *vm );
friend void opcodeHandler_STVS( register VMachine *vm );
friend void opcodeHandler_LSTA( register VMachine *vm );
friend void opcodeHandler_LVAL( register VMachine *vm );
friend void opcodeHandler_AND ( register VMachine *vm );
friend void opcodeHandler_OR ( register VMachine *vm );
friend void opcodeHandler_PASS( register VMachine *vm );
friend void opcodeHandler_PSIN( register VMachine *vm );
// Range 4: ternary opcodes;
friend void opcodeHandler_STP ( register VMachine *vm );
friend void opcodeHandler_STV ( register VMachine *vm );
friend void opcodeHandler_LDVT( register VMachine *vm );
friend void opcodeHandler_LDPT( register VMachine *vm );
friend void opcodeHandler_STPR( register VMachine *vm );
friend void opcodeHandler_STVR( register VMachine *vm );
friend void opcodeHandler_TRAV( register VMachine *vm );
friend void opcodeHandler_INCP( register VMachine *vm );
friend void opcodeHandler_DECP( register VMachine *vm );
friend void opcodeHandler_SHL( register VMachine *vm );
friend void opcodeHandler_SHR( register VMachine *vm );
friend void opcodeHandler_SHLS( register VMachine *vm );
friend void opcodeHandler_SHRS( register VMachine *vm );
friend void opcodeHandler_CLOS( register VMachine *vm );
friend void opcodeHandler_PSHL( register VMachine *vm );
friend void opcodeHandler_POWS( register VMachine *vm );
friend void opcodeHandler_LSB( register VMachine *vm );
friend void opcodeHandler_SELE( register VMachine *vm );
friend void opcodeHandler_INDI( register VMachine *vm );
friend void opcodeHandler_STEX( register VMachine *vm );
friend void opcodeHandler_TRAC( register VMachine *vm );
friend void opcodeHandler_WRT( register VMachine *vm );
friend void opcodeHandler_STO( register VMachine *vm );
friend void opcodeHandler_FORB( register VMachine *vm );
friend void opcodeHandler_EVAL( register VMachine *vm );
friend void opcodeHandler_OOB( register VMachine *vm );
friend void opcodeHandler_TRDN( register VMachine *vm );
friend void opcodeHandler_EXEQ( register VMachine *vm );
};
class FALCON_DYN_SYM VMachineWrapper
{
private:
VMachine *m_vm;
public:
VMachineWrapper():
m_vm( new VMachine )
{
}
VMachineWrapper( VMachine *host ):
m_vm(host)
{}
~VMachineWrapper()
{
m_vm->finalize();
}
VMachine *operator->() const
{
return m_vm;
}
VMachine *vm() const
{
return m_vm;
}
};
}
#endif
/* end of vm.h */
|