codeBlock.cpp 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "console/console.h"
  23. #include "console/compiler.h"
  24. #include "console/codeBlock.h"
  25. #include "console/telnetDebugger.h"
  26. #include "console/ast.h"
  27. #include "core/strings/unicode.h"
  28. #include "core/strings/stringFunctions.h"
  29. #include "core/stringTable.h"
  30. #include "core/stream/fileStream.h"
  31. using namespace Compiler;
  32. bool CodeBlock::smInFunction = false;
  33. CodeBlock * CodeBlock::smCodeBlockList = NULL;
  34. CodeBlock * CodeBlock::smCurrentCodeBlock = NULL;
  35. ConsoleParser *CodeBlock::smCurrentParser = NULL;
  36. extern FuncVars gEvalFuncVars;
  37. extern FuncVars gGlobalScopeFuncVars;
  38. extern FuncVars* gFuncVars;
  39. //-------------------------------------------------------------------------
  40. CodeBlock::CodeBlock()
  41. {
  42. globalStrings = NULL;
  43. functionStrings = NULL;
  44. functionStringsMaxLen = 0;
  45. globalStringsMaxLen = 0;
  46. globalFloats = NULL;
  47. functionFloats = NULL;
  48. lineBreakPairs = NULL;
  49. breakList = NULL;
  50. breakListSize = 0;
  51. refCount = 0;
  52. code = NULL;
  53. name = NULL;
  54. fullPath = NULL;
  55. modPath = NULL;
  56. codeSize = 0;
  57. lineBreakPairCount = 0;
  58. nextFile = NULL;
  59. }
  60. CodeBlock::~CodeBlock()
  61. {
  62. // Make sure we aren't lingering in the current code block...
  63. AssertFatal(smCurrentCodeBlock != this, "CodeBlock::~CodeBlock - Caught lingering in smCurrentCodeBlock!");
  64. if (name)
  65. removeFromCodeList();
  66. delete[] const_cast<char*>(globalStrings);
  67. delete[] const_cast<char*>(functionStrings);
  68. functionStringsMaxLen = 0;
  69. globalStringsMaxLen = 0;
  70. delete[] globalFloats;
  71. delete[] functionFloats;
  72. delete[] code;
  73. delete[] breakList;
  74. }
  75. //-------------------------------------------------------------------------
  76. StringTableEntry CodeBlock::getCurrentCodeBlockName()
  77. {
  78. if (CodeBlock::getCurrentBlock())
  79. return CodeBlock::getCurrentBlock()->name;
  80. else
  81. return NULL;
  82. }
  83. StringTableEntry CodeBlock::getCurrentCodeBlockFullPath()
  84. {
  85. if (CodeBlock::getCurrentBlock())
  86. return CodeBlock::getCurrentBlock()->fullPath;
  87. else
  88. return NULL;
  89. }
  90. StringTableEntry CodeBlock::getCurrentCodeBlockModName()
  91. {
  92. if (CodeBlock::getCurrentBlock())
  93. return CodeBlock::getCurrentBlock()->modPath;
  94. else
  95. return NULL;
  96. }
  97. CodeBlock *CodeBlock::find(StringTableEntry name)
  98. {
  99. for (CodeBlock *walk = CodeBlock::getCodeBlockList(); walk; walk = walk->nextFile)
  100. if (walk->name == name)
  101. return walk;
  102. return NULL;
  103. }
  104. //-------------------------------------------------------------------------
  105. void CodeBlock::addToCodeList()
  106. {
  107. // remove any code blocks with my name
  108. for (CodeBlock **walk = &smCodeBlockList; *walk; walk = &((*walk)->nextFile))
  109. {
  110. if ((*walk)->name == name)
  111. {
  112. *walk = (*walk)->nextFile;
  113. break;
  114. }
  115. }
  116. nextFile = smCodeBlockList;
  117. smCodeBlockList = this;
  118. }
  119. void CodeBlock::clearAllBreaks()
  120. {
  121. if (!lineBreakPairs)
  122. return;
  123. for (U32 i = 0; i < lineBreakPairCount; i++)
  124. {
  125. U32 *p = lineBreakPairs + i * 2;
  126. code[p[1]] = p[0] & 0xFF;
  127. }
  128. }
  129. void CodeBlock::clearBreakpoint(U32 lineNumber)
  130. {
  131. if (!lineBreakPairs)
  132. return;
  133. for (U32 i = 0; i < lineBreakPairCount; i++)
  134. {
  135. U32 *p = lineBreakPairs + i * 2;
  136. if ((p[0] >> 8) == lineNumber)
  137. {
  138. code[p[1]] = p[0] & 0xFF;
  139. return;
  140. }
  141. }
  142. }
  143. void CodeBlock::setAllBreaks()
  144. {
  145. if (!lineBreakPairs)
  146. return;
  147. for (U32 i = 0; i < lineBreakPairCount; i++)
  148. {
  149. U32 *p = lineBreakPairs + i * 2;
  150. code[p[1]] = OP_BREAK;
  151. }
  152. }
  153. bool CodeBlock::setBreakpoint(U32 lineNumber)
  154. {
  155. if (!lineBreakPairs)
  156. return false;
  157. for (U32 i = 0; i < lineBreakPairCount; i++)
  158. {
  159. U32 *p = lineBreakPairs + i * 2;
  160. if ((p[0] >> 8) == lineNumber)
  161. {
  162. code[p[1]] = OP_BREAK;
  163. return true;
  164. }
  165. }
  166. return false;
  167. }
  168. U32 CodeBlock::findFirstBreakLine(U32 lineNumber)
  169. {
  170. if (!lineBreakPairs)
  171. return 0;
  172. for (U32 i = 0; i < lineBreakPairCount; i++)
  173. {
  174. U32 *p = lineBreakPairs + i * 2;
  175. U32 line = (p[0] >> 8);
  176. if (lineNumber <= line)
  177. return line;
  178. }
  179. return 0;
  180. }
  181. struct LinePair
  182. {
  183. U32 instLine;
  184. U32 ip;
  185. };
  186. void CodeBlock::findBreakLine(U32 ip, U32 &line, U32 &instruction)
  187. {
  188. U32 min = 0;
  189. U32 max = lineBreakPairCount - 1;
  190. LinePair *p = (LinePair *)lineBreakPairs;
  191. U32 found;
  192. if (!lineBreakPairCount || p[min].ip > ip || p[max].ip < ip)
  193. {
  194. line = 0;
  195. instruction = OP_INVALID;
  196. return;
  197. }
  198. else if (p[min].ip == ip)
  199. found = min;
  200. else if (p[max].ip == ip)
  201. found = max;
  202. else
  203. {
  204. for (;;)
  205. {
  206. if (min == max - 1)
  207. {
  208. found = min;
  209. break;
  210. }
  211. U32 mid = (min + max) >> 1;
  212. if (p[mid].ip == ip)
  213. {
  214. found = mid;
  215. break;
  216. }
  217. else if (p[mid].ip > ip)
  218. max = mid;
  219. else
  220. min = mid;
  221. }
  222. }
  223. instruction = p[found].instLine & 0xFF;
  224. line = p[found].instLine >> 8;
  225. }
  226. const char *CodeBlock::getFileLine(U32 ip)
  227. {
  228. static char nameBuffer[256];
  229. U32 line, inst;
  230. findBreakLine(ip, line, inst);
  231. dSprintf(nameBuffer, sizeof(nameBuffer), "%s (%d)", name ? name : "<input>", line);
  232. return nameBuffer;
  233. }
  234. void CodeBlock::removeFromCodeList()
  235. {
  236. for (CodeBlock **walk = &smCodeBlockList; *walk; walk = &((*walk)->nextFile))
  237. {
  238. if (*walk == this)
  239. {
  240. *walk = nextFile;
  241. // clear out all breakpoints
  242. clearAllBreaks();
  243. break;
  244. }
  245. }
  246. // Let the telnet debugger know that this code
  247. // block has been unloaded and that it needs to
  248. // remove references to it.
  249. if (TelDebugger)
  250. TelDebugger->clearCodeBlockPointers(this);
  251. }
  252. void CodeBlock::calcBreakList()
  253. {
  254. U32 size = 0;
  255. S32 line = -1;
  256. U32 seqCount = 0;
  257. U32 i;
  258. for (i = 0; i < lineBreakPairCount; i++)
  259. {
  260. U32 lineNumber = lineBreakPairs[i * 2];
  261. if (lineNumber == U32(line + 1))
  262. seqCount++;
  263. else
  264. {
  265. if (seqCount)
  266. size++;
  267. size++;
  268. seqCount = 1;
  269. }
  270. line = lineNumber;
  271. }
  272. if (seqCount)
  273. size++;
  274. breakList = new U32[size+3]; //lineBreakPairs plus pad
  275. breakListSize = size;
  276. line = -1;
  277. seqCount = 0;
  278. size = 0;
  279. for (i = 0; i < lineBreakPairCount; i++)
  280. {
  281. U32 lineNumber = lineBreakPairs[i * 2];
  282. if (lineNumber == U32(line + 1))
  283. seqCount++;
  284. else
  285. {
  286. if (seqCount)
  287. breakList[size++] = seqCount;
  288. breakList[size++] = lineNumber - getMax(0, line) - 1;
  289. seqCount = 1;
  290. }
  291. line = lineNumber;
  292. }
  293. if (seqCount)
  294. breakList[size++] = seqCount;
  295. for (i = 0; i < lineBreakPairCount; i++)
  296. {
  297. U32 *p = lineBreakPairs + i * 2;
  298. p[0] = (p[0] << 8) | code[p[1]];
  299. }
  300. // Let the telnet debugger know that this code
  301. // block has been loaded and that it can add break
  302. // points it has for it.
  303. if (TelDebugger)
  304. TelDebugger->addAllBreakpoints(this);
  305. }
  306. bool CodeBlock::read(StringTableEntry fileName, Stream &st)
  307. {
  308. const StringTableEntry exePath = Platform::getMainDotCsDir();
  309. const StringTableEntry cwd = Platform::getCurrentDirectory();
  310. name = fileName;
  311. if (fileName)
  312. {
  313. fullPath = NULL;
  314. if (Platform::isFullPath(fileName))
  315. fullPath = fileName;
  316. if (dStrnicmp(exePath, fileName, dStrlen(exePath)) == 0)
  317. name = StringTable->insert(fileName + dStrlen(exePath) + 1, true);
  318. else if (dStrnicmp(cwd, fileName, dStrlen(cwd)) == 0)
  319. name = StringTable->insert(fileName + dStrlen(cwd) + 1, true);
  320. if (fullPath == NULL)
  321. {
  322. char buf[1024];
  323. fullPath = StringTable->insert(Platform::makeFullPathName(fileName, buf, sizeof(buf)), true);
  324. }
  325. modPath = Con::getModNameFromPath(fileName);
  326. }
  327. //
  328. addToCodeList();
  329. U32 globalSize, size, i;
  330. st.read(&size);
  331. if (size)
  332. {
  333. globalStrings = new char[size];
  334. globalStringsMaxLen = size;
  335. st.read(size, globalStrings);
  336. }
  337. globalSize = size;
  338. st.read(&size);
  339. if (size)
  340. {
  341. functionStrings = new char[size];
  342. functionStringsMaxLen = size;
  343. st.read(size, functionStrings);
  344. }
  345. st.read(&size);
  346. if (size)
  347. {
  348. globalFloats = new F64[size];
  349. for (i = 0; i < size; i++)
  350. st.read(&globalFloats[i]);
  351. }
  352. st.read(&size);
  353. if (size)
  354. {
  355. functionFloats = new F64[size];
  356. for (i = 0; i < size; i++)
  357. st.read(&functionFloats[i]);
  358. }
  359. // Variable register mapping table
  360. st.read(&size);
  361. if (size)
  362. {
  363. for (i = 0; i < size; i++)
  364. {
  365. StringTableEntry fnName = st.readSTString();
  366. U32 count;
  367. st.read(&count);
  368. for (U32 j = 0; j < count; j++)
  369. {
  370. StringTableEntry varName = st.readSTString();
  371. variableRegisterTable.localVarToRegister[fnName].varList.push_back(varName);
  372. }
  373. }
  374. }
  375. U32 codeLength;
  376. st.read(&codeLength);
  377. st.read(&lineBreakPairCount);
  378. U32 totSize = codeLength + lineBreakPairCount * 2;
  379. code = new U32[totSize+1];
  380. // 0xFF is used as a flag to help compress the bytecode.
  381. // If detected, the bytecode is only a U8.
  382. for (i = 0; i < codeLength; i++)
  383. {
  384. U8 b;
  385. st.read(&b);
  386. if (b == 0xFF)
  387. st.read(&code[i]);
  388. else
  389. code[i] = b;
  390. }
  391. for (i = codeLength; i < totSize; i++)
  392. st.read(&code[i]);
  393. lineBreakPairs = code + codeLength;
  394. // StringTable-ize our identifiers.
  395. U32 identCount;
  396. st.read(&identCount);
  397. while (identCount--)
  398. {
  399. U32 offset;
  400. st.read(&offset);
  401. StringTableEntry ste;
  402. if (offset < globalSize)
  403. ste = StringTable->insert(globalStrings + offset);
  404. else
  405. ste = StringTable->EmptyString();
  406. U32 count;
  407. st.read(&count);
  408. while (count--)
  409. {
  410. U32 ip;
  411. st.read(&ip);
  412. #if defined(TORQUE_CPU_X64) || defined(TORQUE_CPU_ARM64)
  413. *(U64*)(code + ip) = (U64)ste;
  414. #else
  415. code[ip] = *((U32 *)&ste);
  416. #endif
  417. }
  418. }
  419. if (lineBreakPairCount)
  420. calcBreakList();
  421. return true;
  422. }
  423. bool CodeBlock::compile(const char *codeFileName, StringTableEntry fileName, const char *inScript, bool overrideNoDso)
  424. {
  425. AssertFatal(Con::isMainThread(), "Compiling code on a secondary thread");
  426. // This will return true, but return value is ignored
  427. char *script;
  428. chompUTF8BOM(inScript, &script);
  429. gSyntaxError = false;
  430. gIsEvalCompile = false;
  431. gFuncVars = NULL;
  432. consoleAllocReset();
  433. STEtoCode = compileSTEtoCode;
  434. gStatementList = NULL;
  435. // Set up the parser.
  436. smCurrentParser = getParserForFile(fileName);
  437. AssertISV(smCurrentParser, avar("CodeBlock::compile - no parser available for '%s'!", fileName));
  438. // Now do some parsing.
  439. smCurrentParser->setScanBuffer(script, fileName);
  440. smCurrentParser->restart(NULL);
  441. smCurrentParser->parse();
  442. if (gSyntaxError)
  443. {
  444. consoleAllocReset();
  445. return false;
  446. }
  447. #ifdef TORQUE_NO_DSO_GENERATION
  448. if (!overrideNoDso)
  449. return false;
  450. #endif // !TORQUE_NO_DSO_GENERATION
  451. FileStream st;
  452. if (!st.open(codeFileName, Torque::FS::File::Write))
  453. return false;
  454. st.write(U32(Con::DSOVersion));
  455. // Reset all our value tables...
  456. resetTables();
  457. smInFunction = false;
  458. CodeStream codeStream;
  459. U32 lastIp;
  460. if (gStatementList)
  461. {
  462. lastIp = compileBlock(gStatementList, codeStream, 0) + 1;
  463. }
  464. else
  465. {
  466. codeSize = 1;
  467. lastIp = 0;
  468. }
  469. codeStream.emit(OP_RETURN_VOID);
  470. codeStream.emitCodeStream(&codeSize, &code, &lineBreakPairs);
  471. lineBreakPairCount = codeStream.getNumLineBreaks();
  472. // Write string table data...
  473. getGlobalStringTable().write(st);
  474. getFunctionStringTable().write(st);
  475. // Write float table data...
  476. getGlobalFloatTable().write(st);
  477. getFunctionFloatTable().write(st);
  478. // write variable mapping table
  479. getFunctionVariableMappingTable().write(st);
  480. if (lastIp != codeSize)
  481. Con::errorf(ConsoleLogEntry::General, "CodeBlock::compile - precompile size mismatch, a precompile/compile function pair is probably mismatched.");
  482. U32 totSize = codeSize + codeStream.getNumLineBreaks() * 2;
  483. st.write(codeSize);
  484. st.write(lineBreakPairCount);
  485. // Write out our bytecode, doing a bit of compression for low numbers.
  486. U32 i;
  487. for (i = 0; i < codeSize; i++)
  488. {
  489. if (code[i] < 0xFF)
  490. st.write(U8(code[i]));
  491. else
  492. {
  493. st.write(U8(0xFF));
  494. st.write(code[i]);
  495. }
  496. }
  497. // Write the break info...
  498. for (i = codeSize; i < totSize; i++)
  499. st.write(code[i]);
  500. getIdentTable().write(st);
  501. consoleAllocReset();
  502. st.close();
  503. return true;
  504. }
  505. ConsoleValue CodeBlock::compileExec(StringTableEntry fileName, const char *inString, bool noCalls, S32 setFrame)
  506. {
  507. AssertFatal(Con::isMainThread(), "Compiling code on a secondary thread");
  508. // Check for a UTF8 script file
  509. char *string;
  510. chompUTF8BOM(inString, &string);
  511. STEtoCode = evalSTEtoCode;
  512. consoleAllocReset();
  513. name = fileName;
  514. if (fileName)
  515. {
  516. const StringTableEntry exePath = Platform::getMainDotCsDir();
  517. const StringTableEntry cwd = Platform::getCurrentDirectory();
  518. fullPath = NULL;
  519. if (Platform::isFullPath(fileName))
  520. fullPath = fileName;
  521. if (dStrnicmp(exePath, fileName, dStrlen(exePath)) == 0)
  522. name = StringTable->insert(fileName + dStrlen(exePath) + 1, true);
  523. else if (dStrnicmp(cwd, fileName, dStrlen(cwd)) == 0)
  524. name = StringTable->insert(fileName + dStrlen(cwd) + 1, true);
  525. if (fullPath == NULL)
  526. {
  527. char buf[1024];
  528. fullPath = StringTable->insert(Platform::makeFullPathName(fileName, buf, sizeof(buf)), true);
  529. }
  530. modPath = Con::getModNameFromPath(fileName);
  531. }
  532. if (name)
  533. addToCodeList();
  534. gStatementList = NULL;
  535. // we are an eval compile if we don't have a file name associated (no exec)
  536. gIsEvalCompile = fileName == NULL;
  537. gFuncVars = gIsEvalCompile ? &gEvalFuncVars : &gGlobalScopeFuncVars;
  538. // Set up the parser.
  539. smCurrentParser = getParserForFile(fileName);
  540. AssertISV(smCurrentParser, avar("CodeBlock::compile - no parser available for '%s'!", fileName));
  541. // Now do some parsing.
  542. smCurrentParser->setScanBuffer(string, fileName);
  543. smCurrentParser->restart(NULL);
  544. smCurrentParser->parse();
  545. if (!gStatementList)
  546. {
  547. delete this;
  548. return std::move(ConsoleValue());
  549. }
  550. resetTables();
  551. smInFunction = false;
  552. CodeStream codeStream;
  553. U32 lastIp = compileBlock(gStatementList, codeStream, 0);
  554. lineBreakPairCount = codeStream.getNumLineBreaks();
  555. globalStrings = getGlobalStringTable().build();
  556. globalStringsMaxLen = getGlobalStringTable().totalLen;
  557. functionStrings = getFunctionStringTable().build();
  558. functionStringsMaxLen = getFunctionStringTable().totalLen;
  559. globalFloats = getGlobalFloatTable().build();
  560. functionFloats = getFunctionFloatTable().build();
  561. variableRegisterTable = getFunctionVariableMappingTable().copy();
  562. codeStream.emit(OP_RETURN_VOID);
  563. codeStream.emitCodeStream(&codeSize, &code, &lineBreakPairs);
  564. S32 localRegisterCount = gIsEvalCompile ? gEvalFuncVars.count() : gGlobalScopeFuncVars.count();
  565. consoleAllocReset();
  566. #ifndef TORQUE_SHIPPING
  567. if (Con::getBoolVariable("$Debug::DumpByteCode"))
  568. {
  569. dumpInstructions();
  570. }
  571. #endif
  572. if (lineBreakPairCount && fileName)
  573. calcBreakList();
  574. if (lastIp + 1 != codeSize)
  575. Con::warnf(ConsoleLogEntry::General, "precompile size mismatch, precompile: %d compile: %d", codeSize, lastIp);
  576. // repurpose argc as local register counter for global state
  577. return std::move(exec(0, fileName, NULL, localRegisterCount, 0, noCalls, NULL, setFrame));
  578. }
  579. //-------------------------------------------------------------------------
  580. void CodeBlock::incRefCount()
  581. {
  582. refCount++;
  583. }
  584. void CodeBlock::decRefCount()
  585. {
  586. refCount--;
  587. if (!refCount)
  588. delete this;
  589. }
  590. //-------------------------------------------------------------------------
  591. String CodeBlock::getFunctionArgs(U32 ip)
  592. {
  593. StringBuilder str;
  594. StringTableEntry fnName = CodeToSTE(code, ip);
  595. StringTableEntry fnNamespace = CodeToSTE(code, ip + 2);
  596. StringTableEntry fnNsName = StringTable->insert(avar("%s::%s", fnNamespace, fnName));
  597. U32 fnArgc = code[ip + 8];
  598. for (U32 i = 0; i < fnArgc; ++i)
  599. {
  600. StringTableEntry var = variableRegisterTable.localVarToRegister[fnNsName].varList[i];
  601. if (i != 0)
  602. str.append(", ");
  603. str.append("string ");
  604. // Try to capture junked parameters
  605. if (var[0])
  606. str.append(var + 1);
  607. else
  608. str.append("JUNK");
  609. }
  610. return str.end();
  611. }
  612. //-------------------------------------------------------------------------
  613. void CodeBlock::dumpInstructions(U32 startIp, bool upToReturn)
  614. {
  615. U32 ip = startIp;
  616. smInFunction = false;
  617. U32 endFuncIp = 0;
  618. while (ip < codeSize)
  619. {
  620. if (ip > endFuncIp)
  621. {
  622. smInFunction = false;
  623. }
  624. switch (code[ip++])
  625. {
  626. case OP_FUNC_DECL:
  627. {
  628. StringTableEntry fnName = CodeToSTE(code, ip);
  629. StringTableEntry fnNamespace = CodeToSTE(code, ip + 2);
  630. StringTableEntry fnPackage = CodeToSTE(code, ip + 4);
  631. bool hasBody = bool(code[ip + 6]);
  632. U32 newIp = code[ip + 7];
  633. U32 argc = code[ip + 8];
  634. U32 regCount = code[ip + 9];
  635. endFuncIp = newIp;
  636. Con::printf("%i: OP_FUNC_DECL stk=+0 name=%s nspace=%s package=%s hasbody=%i newip=%i argc=%i regCount=%i",
  637. ip - 1, fnName, fnNamespace, fnPackage, hasBody, newIp, argc, regCount);
  638. // Skip args.
  639. ip += 10 + argc;
  640. smInFunction = true;
  641. break;
  642. }
  643. case OP_CREATE_OBJECT:
  644. {
  645. StringTableEntry objParent = CodeToSTE(code, ip);
  646. bool isDataBlock = code[ip + 2];
  647. bool isInternal = code[ip + 3];
  648. bool isSingleton = code[ip + 4];
  649. U32 lineNumber = code[ip + 5];
  650. U32 failJump = code[ip + 6];
  651. Con::printf("%i: OP_CREATE_OBJECT stk=+0 objParent=%s isDataBlock=%i isInternal=%i isSingleton=%i lineNumber=%i failJump=%i",
  652. ip - 1, objParent, isDataBlock, isInternal, isSingleton, lineNumber, failJump);
  653. ip += 7;
  654. break;
  655. }
  656. case OP_ADD_OBJECT:
  657. {
  658. bool placeAtRoot = code[ip++];
  659. const char* stk = placeAtRoot ? "+1" : "0";
  660. Con::printf("%i: OP_ADD_OBJECT stk=%s placeAtRoot=%i", ip - 1, stk, placeAtRoot);
  661. break;
  662. }
  663. case OP_END_OBJECT:
  664. {
  665. bool placeAtRoot = code[ip++];
  666. const char* stk = placeAtRoot ? "-1" : "0";
  667. Con::printf("%i: OP_END_OBJECT stk=%s placeAtRoot=%i", ip - 1, stk, placeAtRoot);
  668. break;
  669. }
  670. case OP_FINISH_OBJECT:
  671. {
  672. Con::printf("%i: OP_FINISH_OBJECT", ip - 1);
  673. break;
  674. }
  675. case OP_JMPIFFNOT:
  676. {
  677. Con::printf("%i: OP_JMPIFFNOT stk=-1 ip=%i", ip - 1, code[ip]);
  678. ++ip;
  679. break;
  680. }
  681. case OP_JMPIFNOT:
  682. {
  683. Con::printf("%i: OP_JMPIFNOT stk=-1 ip=%i", ip - 1, code[ip]);
  684. ++ip;
  685. break;
  686. }
  687. case OP_JMPIFF:
  688. {
  689. Con::printf("%i: OP_JMPIFF stk=-1 ip=%i", ip - 1, code[ip]);
  690. ++ip;
  691. break;
  692. }
  693. case OP_JMPIF:
  694. {
  695. Con::printf("%i: OP_JMPIF stk=-1 ip=%i", ip - 1, code[ip]);
  696. ++ip;
  697. break;
  698. }
  699. case OP_JMPIFNOT_NP:
  700. {
  701. Con::printf("%i: OP_JMPIFNOT_NP stk=-1 or 0 ip=%i", ip - 1, code[ip]);
  702. ++ip;
  703. break;
  704. }
  705. case OP_JMPIF_NP:
  706. {
  707. Con::printf("%i: OP_JMPIF_NP stk=-1 or 0 ip=%i", ip - 1, code[ip]);
  708. ++ip;
  709. break;
  710. }
  711. case OP_JMP:
  712. {
  713. Con::printf("%i: OP_JMP stk=0 ip=%i", ip - 1, code[ip]);
  714. ++ip;
  715. break;
  716. }
  717. case OP_RETURN_VOID:
  718. {
  719. Con::printf("%i: OP_RETURN_VOID stk=0", ip - 1);
  720. if (upToReturn)
  721. return;
  722. break;
  723. }
  724. case OP_RETURN:
  725. {
  726. Con::printf("%i: OP_RETURN stk=-1", ip - 1);
  727. if (upToReturn)
  728. return;
  729. break;
  730. }
  731. case OP_RETURN_UINT:
  732. {
  733. Con::printf("%i: OP_RETURNUINT stk=-1", ip - 1);
  734. if (upToReturn)
  735. return;
  736. break;
  737. }
  738. case OP_RETURN_FLT:
  739. {
  740. Con::printf("%i: OP_RETURNFLT stk=-1", ip - 1);
  741. if (upToReturn)
  742. return;
  743. break;
  744. }
  745. case OP_CMPEQ:
  746. {
  747. Con::printf("%i: OP_CMPEQ stk=-1", ip - 1);
  748. break;
  749. }
  750. case OP_CMPGR:
  751. {
  752. Con::printf("%i: OP_CMPGR stk=-1", ip - 1);
  753. break;
  754. }
  755. case OP_CMPGE:
  756. {
  757. Con::printf("%i: OP_CMPGE stk=-1", ip - 1);
  758. break;
  759. }
  760. case OP_CMPLT:
  761. {
  762. Con::printf("%i: OP_CMPLT stk=-1", ip - 1);
  763. break;
  764. }
  765. case OP_CMPLE:
  766. {
  767. Con::printf("%i: OP_CMPLE stk=-1", ip - 1);
  768. break;
  769. }
  770. case OP_CMPNE:
  771. {
  772. Con::printf("%i: OP_CMPNE stk=-1", ip - 1);
  773. break;
  774. }
  775. case OP_XOR:
  776. {
  777. Con::printf("%i: OP_XOR stk=-1", ip - 1);
  778. break;
  779. }
  780. case OP_MOD:
  781. {
  782. Con::printf("%i: OP_MOD stk=-1", ip - 1);
  783. break;
  784. }
  785. case OP_BITAND:
  786. {
  787. Con::printf("%i: OP_BITAND stk=-1", ip - 1);
  788. break;
  789. }
  790. case OP_BITOR:
  791. {
  792. Con::printf("%i: OP_BITOR stk=-1", ip - 1);
  793. break;
  794. }
  795. case OP_NOT:
  796. {
  797. Con::printf("%i: OP_NOT stk=0", ip - 1);
  798. break;
  799. }
  800. case OP_NOTF:
  801. {
  802. Con::printf("%i: OP_NOTF stk=0", ip - 1);
  803. break;
  804. }
  805. case OP_ONESCOMPLEMENT:
  806. {
  807. Con::printf("%i: OP_ONESCOMPLEMENT stk=0", ip - 1);
  808. break;
  809. }
  810. case OP_SHR:
  811. {
  812. Con::printf("%i: OP_SHR stk=-1", ip - 1);
  813. break;
  814. }
  815. case OP_SHL:
  816. {
  817. Con::printf("%i: OP_SHL stk=-1", ip - 1);
  818. break;
  819. }
  820. case OP_AND:
  821. {
  822. Con::printf("%i: OP_AND stk=-1", ip - 1);
  823. break;
  824. }
  825. case OP_OR:
  826. {
  827. Con::printf("%i: OP_OR stk=-1", ip - 1);
  828. break;
  829. }
  830. case OP_ADD:
  831. {
  832. Con::printf("%i: OP_ADD stk=-1", ip - 1);
  833. break;
  834. }
  835. case OP_SUB:
  836. {
  837. Con::printf("%i: OP_SUB stk=-1", ip - 1);
  838. break;
  839. }
  840. case OP_MUL:
  841. {
  842. Con::printf("%i: OP_MUL stk=-1", ip - 1);
  843. break;
  844. }
  845. case OP_DIV:
  846. {
  847. Con::printf("%i: OP_DIV stk=-1", ip - 1);
  848. break;
  849. }
  850. case OP_NEG:
  851. {
  852. Con::printf("%i: OP_NEG stk=0", ip - 1);
  853. break;
  854. }
  855. case OP_INC:
  856. {
  857. Con::printf("%i: OP_INC stk=0 reg=%i", ip - 1, code[ip]);
  858. ++ip;
  859. break;
  860. }
  861. case OP_SETCURVAR:
  862. {
  863. StringTableEntry var = CodeToSTE(code, ip);
  864. Con::printf("%i: OP_SETCURVAR stk=0 var=%s", ip - 1, var);
  865. ip += 2;
  866. break;
  867. }
  868. case OP_SETCURVAR_CREATE:
  869. {
  870. StringTableEntry var = CodeToSTE(code, ip);
  871. Con::printf("%i: OP_SETCURVAR_CREATE stk=0 var=%s", ip - 1, var);
  872. ip += 2;
  873. break;
  874. }
  875. case OP_SETCURVAR_ARRAY:
  876. {
  877. Con::printf("%i: OP_SETCURVAR_ARRAY stk=0", ip - 1);
  878. break;
  879. }
  880. case OP_SETCURVAR_ARRAY_CREATE:
  881. {
  882. Con::printf("%i: OP_SETCURVAR_ARRAY_CREATE stk=0", ip - 1);
  883. break;
  884. }
  885. case OP_LOADVAR_UINT:
  886. {
  887. Con::printf("%i: OP_LOADVAR_UINT stk=+1", ip - 1);
  888. break;
  889. }
  890. case OP_LOADVAR_FLT:
  891. {
  892. Con::printf("%i: OP_LOADVAR_FLT stk=+1", ip - 1);
  893. break;
  894. }
  895. case OP_LOADVAR_STR:
  896. {
  897. Con::printf("%i: OP_LOADVAR_STR stk=+1", ip - 1);
  898. break;
  899. }
  900. case OP_SAVEVAR_UINT:
  901. {
  902. Con::printf("%i: OP_SAVEVAR_UINT stk=0", ip - 1);
  903. break;
  904. }
  905. case OP_SAVEVAR_FLT:
  906. {
  907. Con::printf("%i: OP_SAVEVAR_FLT stk=0", ip - 1);
  908. break;
  909. }
  910. case OP_SAVEVAR_STR:
  911. {
  912. Con::printf("%i: OP_SAVEVAR_STR stk=0", ip - 1);
  913. break;
  914. }
  915. case OP_LOAD_LOCAL_VAR_UINT:
  916. {
  917. Con::printf("%i: OP_LOAD_LOCAL_VAR_UINT stk=+1 reg=%i", ip - 1, code[ip]);
  918. ++ip;
  919. break;
  920. }
  921. case OP_LOAD_LOCAL_VAR_FLT:
  922. {
  923. Con::printf("%i: OP_LOAD_LOCAL_VAR_FLT stk=+1 reg=%i", ip - 1, code[ip]);
  924. ++ip;
  925. break;
  926. }
  927. case OP_LOAD_LOCAL_VAR_STR:
  928. {
  929. Con::printf("%i: OP_LOAD_LOCAL_VAR_STR stk=+1 reg=%i", ip - 1, code[ip]);
  930. ++ip;
  931. break;
  932. }
  933. case OP_SAVE_LOCAL_VAR_UINT:
  934. {
  935. Con::printf("%i: OP_SAVE_LOCAL_VAR_UINT stk=0 reg=%i", ip - 1, code[ip]);
  936. ++ip;
  937. break;
  938. }
  939. case OP_SAVE_LOCAL_VAR_FLT:
  940. {
  941. Con::printf("%i: OP_SAVE_LOCAL_VAR_FLT stk=0 reg=%i", ip - 1, code[ip]);
  942. ++ip;
  943. break;
  944. }
  945. case OP_SAVE_LOCAL_VAR_STR:
  946. {
  947. Con::printf("%i: OP_SAVE_LOCAL_VAR_STR stk=0 reg=%i", ip - 1, code[ip]);
  948. ++ip;
  949. break;
  950. }
  951. case OP_SETCUROBJECT:
  952. {
  953. Con::printf("%i: OP_SETCUROBJECT stk=0", ip - 1);
  954. break;
  955. }
  956. case OP_SETCUROBJECT_NEW:
  957. {
  958. Con::printf("%i: OP_SETCUROBJECT_NEW stk=0", ip - 1);
  959. break;
  960. }
  961. case OP_SETCUROBJECT_INTERNAL:
  962. {
  963. Con::printf("%i: OP_SETCUROBJECT_INTERNAL stk=0", ip - 1);
  964. ++ip;
  965. break;
  966. }
  967. case OP_SETCURFIELD:
  968. {
  969. StringTableEntry curField = CodeToSTE(code, ip);
  970. Con::printf("%i: OP_SETCURFIELD stk=0 field=%s", ip - 1, curField);
  971. ip += 2;
  972. break;
  973. }
  974. case OP_SETCURFIELD_ARRAY:
  975. {
  976. Con::printf("%i: OP_SETCURFIELD_ARRAY stk=0", ip - 1);
  977. break;
  978. }
  979. case OP_SETCURFIELD_TYPE:
  980. {
  981. U32 type = code[ip];
  982. Con::printf("%i: OP_SETCURFIELD_TYPE stk=0 type=%i", ip - 1, type);
  983. ++ip;
  984. break;
  985. }
  986. case OP_LOADFIELD_UINT:
  987. {
  988. Con::printf("%i: OP_LOADFIELD_UINT stk=+1", ip - 1);
  989. break;
  990. }
  991. case OP_LOADFIELD_FLT:
  992. {
  993. Con::printf("%i: OP_LOADFIELD_FLT stk=+1", ip - 1);
  994. break;
  995. }
  996. case OP_LOADFIELD_STR:
  997. {
  998. Con::printf("%i: OP_LOADFIELD_STR stk=+1", ip - 1);
  999. break;
  1000. }
  1001. case OP_SAVEFIELD_UINT:
  1002. {
  1003. Con::printf("%i: OP_SAVEFIELD_UINT stk=0", ip - 1);
  1004. break;
  1005. }
  1006. case OP_SAVEFIELD_FLT:
  1007. {
  1008. Con::printf("%i: OP_SAVEFIELD_FLT stk=0", ip - 1);
  1009. break;
  1010. }
  1011. case OP_SAVEFIELD_STR:
  1012. {
  1013. Con::printf("%i: OP_SAVEFIELD_STR stk=0", ip - 1);
  1014. break;
  1015. }
  1016. case OP_POP_STK:
  1017. {
  1018. Con::printf("%i: OP_POP_STK stk=-1", ip - 1);
  1019. break;
  1020. }
  1021. case OP_LOADIMMED_UINT:
  1022. {
  1023. U32 val = code[ip];
  1024. Con::printf("%i: OP_LOADIMMED_UINT stk=+1 val=%i", ip - 1, val);
  1025. ++ip;
  1026. break;
  1027. }
  1028. case OP_LOADIMMED_FLT:
  1029. {
  1030. F64 val = (smInFunction ? functionFloats : globalFloats)[code[ip]];
  1031. Con::printf("%i: OP_LOADIMMED_FLT stk=+1 val=%f", ip - 1, val);
  1032. ++ip;
  1033. break;
  1034. }
  1035. case OP_TAG_TO_STR:
  1036. {
  1037. const char* str = (smInFunction ? functionStrings : globalStrings) + code[ip];
  1038. Con::printf("%i: OP_TAG_TO_STR stk=0 str=%s", ip - 1, str);
  1039. Con::printf(" OP_LOADIMMED_STR stk=+1 (fallthrough)");
  1040. ++ip;
  1041. break;
  1042. }
  1043. case OP_LOADIMMED_STR:
  1044. {
  1045. const char* str = (smInFunction ? functionStrings : globalStrings) + code[ip];
  1046. Con::printf("%i: OP_LOADIMMED_STR stk=+1 str=%s", ip - 1, str);
  1047. ++ip;
  1048. break;
  1049. }
  1050. case OP_DOCBLOCK_STR:
  1051. {
  1052. const char* str = (smInFunction ? functionStrings : globalStrings) + code[ip];
  1053. Con::printf("%i: OP_DOCBLOCK_STR stk=0 str=%s", ip - 1, str);
  1054. ++ip;
  1055. break;
  1056. }
  1057. case OP_LOADIMMED_IDENT:
  1058. {
  1059. StringTableEntry str = CodeToSTE(code, ip);
  1060. Con::printf("%i: OP_LOADIMMED_IDENT stk=+1 str=%s", ip - 1, str);
  1061. ip += 2;
  1062. break;
  1063. }
  1064. case OP_CALLFUNC:
  1065. {
  1066. StringTableEntry fnNamespace = CodeToSTE(code, ip + 2);
  1067. StringTableEntry fnName = CodeToSTE(code, ip);
  1068. U32 callType = code[ip + 4];
  1069. StringTableEntry callTypeName;
  1070. switch (callType)
  1071. {
  1072. case FuncCallExprNode::FunctionCall: callTypeName = "FunctionCall"; break;
  1073. case FuncCallExprNode::MethodCall: callTypeName = "MethodCall"; break;
  1074. case FuncCallExprNode::ParentCall: callTypeName = "ParentCall"; break;
  1075. case FuncCallExprNode::StaticCall: callTypeName = "StaticCall"; break;
  1076. default: callTypeName = "INVALID"; break;
  1077. }
  1078. Con::printf("%i: OP_CALLFUNC stk=+1 name=%s nspace=%s callType=%s", ip - 1, fnName, fnNamespace, callTypeName);
  1079. ip += 5;
  1080. break;
  1081. }
  1082. case OP_ADVANCE_STR_APPENDCHAR:
  1083. {
  1084. char ch = code[ip];
  1085. Con::printf("%i: OP_ADVANCE_STR_APPENDCHAR stk=0 char=%c", ip - 1, ch);
  1086. ++ip;
  1087. break;
  1088. }
  1089. case OP_REWIND_STR:
  1090. {
  1091. Con::printf("%i: OP_REWIND_STR stk=0", ip - 1);
  1092. Con::printf(" OP_TERMINATE_REWIND_STR stk=-1 (fallthrough)");
  1093. break;
  1094. }
  1095. case OP_TERMINATE_REWIND_STR:
  1096. {
  1097. Con::printf("%i: OP_TERMINATE_REWIND_STR stk=-1", ip - 1);
  1098. break;
  1099. }
  1100. case OP_COMPARE_STR:
  1101. {
  1102. Con::printf("%i: OP_COMPARE_STR stk=-1", ip - 1);
  1103. break;
  1104. }
  1105. case OP_PUSH:
  1106. {
  1107. Con::printf("%i: OP_PUSH stk=-1", ip - 1);
  1108. break;
  1109. }
  1110. case OP_PUSH_FRAME:
  1111. {
  1112. Con::printf("%i: OP_PUSH_FRAME stk=0 count=%i", ip - 1, code[ip]);
  1113. ++ip;
  1114. break;
  1115. }
  1116. case OP_ASSERT:
  1117. {
  1118. const char* message = (smInFunction ? functionStrings : globalStrings) + code[ip];
  1119. Con::printf("%i: OP_ASSERT stk=-1 message=%s", ip - 1, message);
  1120. ++ip;
  1121. break;
  1122. }
  1123. case OP_BREAK:
  1124. {
  1125. Con::printf("%i: OP_BREAK stk=0", ip - 1);
  1126. break;
  1127. }
  1128. case OP_ITER_BEGIN:
  1129. {
  1130. bool isGlobal = code[ip];
  1131. if (isGlobal)
  1132. {
  1133. StringTableEntry varName = CodeToSTE(code, ip + 1);
  1134. U32 failIp = code[ip + 3];
  1135. Con::printf("%i: OP_ITER_BEGIN stk=0 varName=%s failIp=%i isGlobal=%s", ip - 1, varName, failIp, "true");
  1136. ip += 4;
  1137. }
  1138. else
  1139. {
  1140. S32 reg = code[ip + 1];
  1141. U32 failIp = code[ip + 2];
  1142. Con::printf("%i: OP_ITER_BEGIN stk=0 varRegister=%d failIp=%i isGlobal=%s", ip - 1, reg, failIp, "false");
  1143. ip += 3;
  1144. }
  1145. break;
  1146. }
  1147. case OP_ITER_BEGIN_STR:
  1148. {
  1149. bool isGlobal = code[ip];
  1150. if (isGlobal)
  1151. {
  1152. StringTableEntry varName = CodeToSTE(code, ip + 1);
  1153. U32 failIp = code[ip + 3];
  1154. Con::printf("%i: OP_ITER_BEGIN_STR stk=0 varName=%s failIp=%i isGlobal=%s", ip - 1, varName, failIp, "true");
  1155. Con::printf(" OP_ITER_BEGIN stk=0 (fallthrough)");
  1156. ip += 4;
  1157. }
  1158. else
  1159. {
  1160. S32 reg = code[ip + 1];
  1161. U32 failIp = code[ip + 2];
  1162. Con::printf("%i: OP_ITER_BEGIN_STR stk=0 varRegister=%d failIp=%i isGlobal=%s", ip - 1, reg, failIp, "false");
  1163. Con::printf(" OP_ITER_BEGIN stk=0 (fallthrough)");
  1164. ip += 3;
  1165. }
  1166. break;
  1167. }
  1168. case OP_ITER:
  1169. {
  1170. U32 breakIp = code[ip];
  1171. Con::printf("%i: OP_ITER stk=0 breakIp=%i", ip - 1, breakIp);
  1172. ++ip;
  1173. break;
  1174. }
  1175. case OP_ITER_END:
  1176. {
  1177. Con::printf("%i: OP_ITER_END stk=-1", ip - 1);
  1178. break;
  1179. }
  1180. default:
  1181. Con::printf("%i: !!INVALID!!", ip - 1);
  1182. break;
  1183. }
  1184. }
  1185. smInFunction = false;
  1186. }