codeBlock.cpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440
  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];
  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];
  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. }
  1077. Con::printf("%i: OP_CALLFUNC stk=+1 name=%s nspace=%s callType=%s", ip - 1, fnName, fnNamespace, callTypeName);
  1078. ip += 5;
  1079. break;
  1080. }
  1081. case OP_ADVANCE_STR_APPENDCHAR:
  1082. {
  1083. char ch = code[ip];
  1084. Con::printf("%i: OP_ADVANCE_STR_APPENDCHAR stk=0 char=%c", ip - 1, ch);
  1085. ++ip;
  1086. break;
  1087. }
  1088. case OP_REWIND_STR:
  1089. {
  1090. Con::printf("%i: OP_REWIND_STR stk=0", ip - 1);
  1091. Con::printf(" OP_TERMINATE_REWIND_STR stk=-1 (fallthrough)");
  1092. break;
  1093. }
  1094. case OP_TERMINATE_REWIND_STR:
  1095. {
  1096. Con::printf("%i: OP_TERMINATE_REWIND_STR stk=-1", ip - 1);
  1097. break;
  1098. }
  1099. case OP_COMPARE_STR:
  1100. {
  1101. Con::printf("%i: OP_COMPARE_STR stk=-1", ip - 1);
  1102. break;
  1103. }
  1104. case OP_PUSH:
  1105. {
  1106. Con::printf("%i: OP_PUSH stk=-1", ip - 1);
  1107. break;
  1108. }
  1109. case OP_PUSH_FRAME:
  1110. {
  1111. Con::printf("%i: OP_PUSH_FRAME stk=0 count=%i", ip - 1, code[ip]);
  1112. ++ip;
  1113. break;
  1114. }
  1115. case OP_ASSERT:
  1116. {
  1117. const char* message = (smInFunction ? functionStrings : globalStrings) + code[ip];
  1118. Con::printf("%i: OP_ASSERT stk=-1 message=%s", ip - 1, message);
  1119. ++ip;
  1120. break;
  1121. }
  1122. case OP_BREAK:
  1123. {
  1124. Con::printf("%i: OP_BREAK stk=0", ip - 1);
  1125. break;
  1126. }
  1127. case OP_ITER_BEGIN:
  1128. {
  1129. bool isGlobal = code[ip];
  1130. if (isGlobal)
  1131. {
  1132. StringTableEntry varName = CodeToSTE(code, ip + 1);
  1133. U32 failIp = code[ip + 3];
  1134. Con::printf("%i: OP_ITER_BEGIN stk=0 varName=%s failIp=%i isGlobal=%s", ip - 1, varName, failIp, "true");
  1135. ip += 4;
  1136. }
  1137. else
  1138. {
  1139. S32 reg = code[ip + 1];
  1140. U32 failIp = code[ip + 2];
  1141. Con::printf("%i: OP_ITER_BEGIN stk=0 varRegister=%d failIp=%i isGlobal=%s", ip - 1, reg, failIp, "false");
  1142. ip += 3;
  1143. }
  1144. break;
  1145. }
  1146. case OP_ITER_BEGIN_STR:
  1147. {
  1148. bool isGlobal = code[ip];
  1149. if (isGlobal)
  1150. {
  1151. StringTableEntry varName = CodeToSTE(code, ip + 1);
  1152. U32 failIp = code[ip + 3];
  1153. Con::printf("%i: OP_ITER_BEGIN_STR stk=0 varName=%s failIp=%i isGlobal=%s", ip - 1, varName, failIp, "true");
  1154. Con::printf(" OP_ITER_BEGIN stk=0 (fallthrough)");
  1155. ip += 4;
  1156. }
  1157. else
  1158. {
  1159. S32 reg = code[ip + 1];
  1160. U32 failIp = code[ip + 2];
  1161. Con::printf("%i: OP_ITER_BEGIN_STR stk=0 varRegister=%d failIp=%i isGlobal=%s", ip - 1, reg, failIp, "false");
  1162. Con::printf(" OP_ITER_BEGIN stk=0 (fallthrough)");
  1163. ip += 3;
  1164. }
  1165. break;
  1166. }
  1167. case OP_ITER:
  1168. {
  1169. U32 breakIp = code[ip];
  1170. Con::printf("%i: OP_ITER stk=0 breakIp=%i", ip - 1, breakIp);
  1171. ++ip;
  1172. break;
  1173. }
  1174. case OP_ITER_END:
  1175. {
  1176. Con::printf("%i: OP_ITER_END stk=-1", ip - 1);
  1177. break;
  1178. }
  1179. default:
  1180. Con::printf("%i: !!INVALID!!", ip - 1);
  1181. break;
  1182. }
  1183. }
  1184. smInFunction = false;
  1185. }