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* gFuncVars;
  38. //-------------------------------------------------------------------------
  39. CodeBlock::CodeBlock()
  40. {
  41. globalStrings = NULL;
  42. functionStrings = NULL;
  43. functionStringsMaxLen = 0;
  44. globalStringsMaxLen = 0;
  45. globalFloats = NULL;
  46. functionFloats = NULL;
  47. lineBreakPairs = NULL;
  48. breakList = NULL;
  49. breakListSize = 0;
  50. refCount = 0;
  51. code = NULL;
  52. name = NULL;
  53. fullPath = NULL;
  54. modPath = NULL;
  55. codeSize = 0;
  56. lineBreakPairCount = 0;
  57. nextFile = NULL;
  58. }
  59. CodeBlock::~CodeBlock()
  60. {
  61. // Make sure we aren't lingering in the current code block...
  62. AssertFatal(smCurrentCodeBlock != this, "CodeBlock::~CodeBlock - Caught lingering in smCurrentCodeBlock!");
  63. if (name)
  64. removeFromCodeList();
  65. delete[] const_cast<char*>(globalStrings);
  66. delete[] const_cast<char*>(functionStrings);
  67. functionStringsMaxLen = 0;
  68. globalStringsMaxLen = 0;
  69. delete[] globalFloats;
  70. delete[] functionFloats;
  71. delete[] code;
  72. delete[] breakList;
  73. }
  74. //-------------------------------------------------------------------------
  75. StringTableEntry CodeBlock::getCurrentCodeBlockName()
  76. {
  77. if (CodeBlock::getCurrentBlock())
  78. return CodeBlock::getCurrentBlock()->name;
  79. else
  80. return NULL;
  81. }
  82. StringTableEntry CodeBlock::getCurrentCodeBlockFullPath()
  83. {
  84. if (CodeBlock::getCurrentBlock())
  85. return CodeBlock::getCurrentBlock()->fullPath;
  86. else
  87. return NULL;
  88. }
  89. StringTableEntry CodeBlock::getCurrentCodeBlockModName()
  90. {
  91. if (CodeBlock::getCurrentBlock())
  92. return CodeBlock::getCurrentBlock()->modPath;
  93. else
  94. return NULL;
  95. }
  96. CodeBlock *CodeBlock::find(StringTableEntry name)
  97. {
  98. for (CodeBlock *walk = CodeBlock::getCodeBlockList(); walk; walk = walk->nextFile)
  99. if (walk->name == name)
  100. return walk;
  101. return NULL;
  102. }
  103. //-------------------------------------------------------------------------
  104. void CodeBlock::addToCodeList()
  105. {
  106. // remove any code blocks with my name
  107. for (CodeBlock **walk = &smCodeBlockList; *walk; walk = &((*walk)->nextFile))
  108. {
  109. if ((*walk)->name == name)
  110. {
  111. *walk = (*walk)->nextFile;
  112. break;
  113. }
  114. }
  115. nextFile = smCodeBlockList;
  116. smCodeBlockList = this;
  117. }
  118. void CodeBlock::clearAllBreaks()
  119. {
  120. if (!lineBreakPairs)
  121. return;
  122. for (U32 i = 0; i < lineBreakPairCount; i++)
  123. {
  124. U32 *p = lineBreakPairs + i * 2;
  125. code[p[1]] = p[0] & 0xFF;
  126. }
  127. }
  128. void CodeBlock::clearBreakpoint(U32 lineNumber)
  129. {
  130. if (!lineBreakPairs)
  131. return;
  132. for (U32 i = 0; i < lineBreakPairCount; i++)
  133. {
  134. U32 *p = lineBreakPairs + i * 2;
  135. if ((p[0] >> 8) == lineNumber)
  136. {
  137. code[p[1]] = p[0] & 0xFF;
  138. return;
  139. }
  140. }
  141. }
  142. void CodeBlock::setAllBreaks()
  143. {
  144. if (!lineBreakPairs)
  145. return;
  146. for (U32 i = 0; i < lineBreakPairCount; i++)
  147. {
  148. U32 *p = lineBreakPairs + i * 2;
  149. code[p[1]] = OP_BREAK;
  150. }
  151. }
  152. bool CodeBlock::setBreakpoint(U32 lineNumber)
  153. {
  154. if (!lineBreakPairs)
  155. return false;
  156. for (U32 i = 0; i < lineBreakPairCount; i++)
  157. {
  158. U32 *p = lineBreakPairs + i * 2;
  159. if ((p[0] >> 8) == lineNumber)
  160. {
  161. code[p[1]] = OP_BREAK;
  162. return true;
  163. }
  164. }
  165. return false;
  166. }
  167. U32 CodeBlock::findFirstBreakLine(U32 lineNumber)
  168. {
  169. if (!lineBreakPairs)
  170. return 0;
  171. for (U32 i = 0; i < lineBreakPairCount; i++)
  172. {
  173. U32 *p = lineBreakPairs + i * 2;
  174. U32 line = (p[0] >> 8);
  175. if (lineNumber <= line)
  176. return line;
  177. }
  178. return 0;
  179. }
  180. struct LinePair
  181. {
  182. U32 instLine;
  183. U32 ip;
  184. };
  185. void CodeBlock::findBreakLine(U32 ip, U32 &line, U32 &instruction)
  186. {
  187. U32 min = 0;
  188. U32 max = lineBreakPairCount - 1;
  189. LinePair *p = (LinePair *)lineBreakPairs;
  190. U32 found;
  191. if (!lineBreakPairCount || p[min].ip > ip || p[max].ip < ip)
  192. {
  193. line = 0;
  194. instruction = OP_INVALID;
  195. return;
  196. }
  197. else if (p[min].ip == ip)
  198. found = min;
  199. else if (p[max].ip == ip)
  200. found = max;
  201. else
  202. {
  203. for (;;)
  204. {
  205. if (min == max - 1)
  206. {
  207. found = min;
  208. break;
  209. }
  210. U32 mid = (min + max) >> 1;
  211. if (p[mid].ip == ip)
  212. {
  213. found = mid;
  214. break;
  215. }
  216. else if (p[mid].ip > ip)
  217. max = mid;
  218. else
  219. min = mid;
  220. }
  221. }
  222. instruction = p[found].instLine & 0xFF;
  223. line = p[found].instLine >> 8;
  224. }
  225. const char *CodeBlock::getFileLine(U32 ip)
  226. {
  227. static char nameBuffer[256];
  228. U32 line, inst;
  229. findBreakLine(ip, line, inst);
  230. dSprintf(nameBuffer, sizeof(nameBuffer), "%s (%d)", name ? name : "<input>", line);
  231. return nameBuffer;
  232. }
  233. void CodeBlock::removeFromCodeList()
  234. {
  235. for (CodeBlock **walk = &smCodeBlockList; *walk; walk = &((*walk)->nextFile))
  236. {
  237. if (*walk == this)
  238. {
  239. *walk = nextFile;
  240. // clear out all breakpoints
  241. clearAllBreaks();
  242. break;
  243. }
  244. }
  245. // Let the telnet debugger know that this code
  246. // block has been unloaded and that it needs to
  247. // remove references to it.
  248. if (TelDebugger)
  249. TelDebugger->clearCodeBlockPointers(this);
  250. }
  251. void CodeBlock::calcBreakList()
  252. {
  253. U32 size = 0;
  254. S32 line = -1;
  255. U32 seqCount = 0;
  256. U32 i;
  257. for (i = 0; i < lineBreakPairCount; i++)
  258. {
  259. U32 lineNumber = lineBreakPairs[i * 2];
  260. if (lineNumber == U32(line + 1))
  261. seqCount++;
  262. else
  263. {
  264. if (seqCount)
  265. size++;
  266. size++;
  267. seqCount = 1;
  268. }
  269. line = lineNumber;
  270. }
  271. if (seqCount)
  272. size++;
  273. breakList = new U32[size];
  274. breakListSize = size;
  275. line = -1;
  276. seqCount = 0;
  277. size = 0;
  278. for (i = 0; i < lineBreakPairCount; i++)
  279. {
  280. U32 lineNumber = lineBreakPairs[i * 2];
  281. if (lineNumber == U32(line + 1))
  282. seqCount++;
  283. else
  284. {
  285. if (seqCount)
  286. breakList[size++] = seqCount;
  287. breakList[size++] = lineNumber - getMax(0, line) - 1;
  288. seqCount = 1;
  289. }
  290. line = lineNumber;
  291. }
  292. if (seqCount)
  293. breakList[size++] = seqCount;
  294. for (i = 0; i < lineBreakPairCount; i++)
  295. {
  296. U32 *p = lineBreakPairs + i * 2;
  297. p[0] = (p[0] << 8) | code[p[1]];
  298. }
  299. // Let the telnet debugger know that this code
  300. // block has been loaded and that it can add break
  301. // points it has for it.
  302. if (TelDebugger)
  303. TelDebugger->addAllBreakpoints(this);
  304. }
  305. bool CodeBlock::read(StringTableEntry fileName, Stream &st)
  306. {
  307. const StringTableEntry exePath = Platform::getMainDotCsDir();
  308. const StringTableEntry cwd = Platform::getCurrentDirectory();
  309. name = fileName;
  310. if (fileName)
  311. {
  312. fullPath = NULL;
  313. if (Platform::isFullPath(fileName))
  314. fullPath = fileName;
  315. if (dStrnicmp(exePath, fileName, dStrlen(exePath)) == 0)
  316. name = StringTable->insert(fileName + dStrlen(exePath) + 1, true);
  317. else if (dStrnicmp(cwd, fileName, dStrlen(cwd)) == 0)
  318. name = StringTable->insert(fileName + dStrlen(cwd) + 1, true);
  319. if (fullPath == NULL)
  320. {
  321. char buf[1024];
  322. fullPath = StringTable->insert(Platform::makeFullPathName(fileName, buf, sizeof(buf)), true);
  323. }
  324. modPath = Con::getModNameFromPath(fileName);
  325. }
  326. //
  327. addToCodeList();
  328. U32 globalSize, size, i;
  329. st.read(&size);
  330. if (size)
  331. {
  332. globalStrings = new char[size];
  333. globalStringsMaxLen = size;
  334. st.read(size, globalStrings);
  335. }
  336. globalSize = size;
  337. st.read(&size);
  338. if (size)
  339. {
  340. functionStrings = new char[size];
  341. functionStringsMaxLen = size;
  342. st.read(size, functionStrings);
  343. }
  344. st.read(&size);
  345. if (size)
  346. {
  347. globalFloats = new F64[size];
  348. for (i = 0; i < size; i++)
  349. st.read(&globalFloats[i]);
  350. }
  351. st.read(&size);
  352. if (size)
  353. {
  354. functionFloats = new F64[size];
  355. for (i = 0; i < size; i++)
  356. st.read(&functionFloats[i]);
  357. }
  358. // Variable register mapping table
  359. st.read(&size);
  360. if (size)
  361. {
  362. for (i = 0; i < size; i++)
  363. {
  364. StringTableEntry fnName = st.readSTString();
  365. U32 count;
  366. st.read(&count);
  367. for (U32 j = 0; j < count; j++)
  368. {
  369. StringTableEntry varName = st.readSTString();
  370. variableRegisterTable.localVarToRegister[fnName].varList.push_back(varName);
  371. }
  372. }
  373. }
  374. U32 codeLength;
  375. st.read(&codeLength);
  376. st.read(&lineBreakPairCount);
  377. U32 totSize = codeLength + lineBreakPairCount * 2;
  378. code = new U32[totSize];
  379. // 0xFF is used as a flag to help compress the bytecode.
  380. // If detected, the bytecode is only a U8.
  381. for (i = 0; i < codeLength; i++)
  382. {
  383. U8 b;
  384. st.read(&b);
  385. if (b == 0xFF)
  386. st.read(&code[i]);
  387. else
  388. code[i] = b;
  389. }
  390. for (i = codeLength; i < totSize; i++)
  391. st.read(&code[i]);
  392. lineBreakPairs = code + codeLength;
  393. // StringTable-ize our identifiers.
  394. U32 identCount;
  395. st.read(&identCount);
  396. while (identCount--)
  397. {
  398. U32 offset;
  399. st.read(&offset);
  400. StringTableEntry ste;
  401. if (offset < globalSize)
  402. ste = StringTable->insert(globalStrings + offset);
  403. else
  404. ste = StringTable->EmptyString();
  405. U32 count;
  406. st.read(&count);
  407. while (count--)
  408. {
  409. U32 ip;
  410. st.read(&ip);
  411. #if defined(TORQUE_CPU_X64) || defined(TORQUE_CPU_ARM64)
  412. *(U64*)(code + ip) = (U64)ste;
  413. #else
  414. code[ip] = *((U32 *)&ste);
  415. #endif
  416. }
  417. }
  418. if (lineBreakPairCount)
  419. calcBreakList();
  420. return true;
  421. }
  422. bool CodeBlock::compile(const char *codeFileName, StringTableEntry fileName, const char *inScript, bool overrideNoDso)
  423. {
  424. AssertFatal(Con::isMainThread(), "Compiling code on a secondary thread");
  425. // This will return true, but return value is ignored
  426. char *script;
  427. chompUTF8BOM(inScript, &script);
  428. gSyntaxError = false;
  429. gIsEvalCompile = false;
  430. gFuncVars = NULL;
  431. consoleAllocReset();
  432. STEtoCode = compileSTEtoCode;
  433. gStatementList = NULL;
  434. // Set up the parser.
  435. smCurrentParser = getParserForFile(fileName);
  436. AssertISV(smCurrentParser, avar("CodeBlock::compile - no parser available for '%s'!", fileName));
  437. // Now do some parsing.
  438. smCurrentParser->setScanBuffer(script, fileName);
  439. smCurrentParser->restart(NULL);
  440. smCurrentParser->parse();
  441. if (gSyntaxError)
  442. {
  443. consoleAllocReset();
  444. return false;
  445. }
  446. #ifdef TORQUE_NO_DSO_GENERATION
  447. if (!overrideNoDso)
  448. return false;
  449. #endif // !TORQUE_NO_DSO_GENERATION
  450. FileStream st;
  451. if (!st.open(codeFileName, Torque::FS::File::Write))
  452. return false;
  453. st.write(U32(Con::DSOVersion));
  454. // Reset all our value tables...
  455. resetTables();
  456. smInFunction = false;
  457. CodeStream codeStream;
  458. U32 lastIp;
  459. if (gStatementList)
  460. {
  461. lastIp = compileBlock(gStatementList, codeStream, 0) + 1;
  462. }
  463. else
  464. {
  465. codeSize = 1;
  466. lastIp = 0;
  467. }
  468. codeStream.emit(OP_RETURN_VOID);
  469. codeStream.emitCodeStream(&codeSize, &code, &lineBreakPairs);
  470. lineBreakPairCount = codeStream.getNumLineBreaks();
  471. // Write string table data...
  472. getGlobalStringTable().write(st);
  473. getFunctionStringTable().write(st);
  474. // Write float table data...
  475. getGlobalFloatTable().write(st);
  476. getFunctionFloatTable().write(st);
  477. // write variable mapping table
  478. getFunctionVariableMappingTable().write(st);
  479. if (lastIp != codeSize)
  480. Con::errorf(ConsoleLogEntry::General, "CodeBlock::compile - precompile size mismatch, a precompile/compile function pair is probably mismatched.");
  481. U32 totSize = codeSize + codeStream.getNumLineBreaks() * 2;
  482. st.write(codeSize);
  483. st.write(lineBreakPairCount);
  484. // Write out our bytecode, doing a bit of compression for low numbers.
  485. U32 i;
  486. for (i = 0; i < codeSize; i++)
  487. {
  488. if (code[i] < 0xFF)
  489. st.write(U8(code[i]));
  490. else
  491. {
  492. st.write(U8(0xFF));
  493. st.write(code[i]);
  494. }
  495. }
  496. // Write the break info...
  497. for (i = codeSize; i < totSize; i++)
  498. st.write(code[i]);
  499. getIdentTable().write(st);
  500. consoleAllocReset();
  501. st.close();
  502. return true;
  503. }
  504. ConsoleValue CodeBlock::compileExec(StringTableEntry fileName, const char *inString, bool noCalls, S32 setFrame)
  505. {
  506. AssertFatal(Con::isMainThread(), "Compiling code on a secondary thread");
  507. // Check for a UTF8 script file
  508. char *string;
  509. chompUTF8BOM(inString, &string);
  510. STEtoCode = evalSTEtoCode;
  511. consoleAllocReset();
  512. name = fileName;
  513. if (fileName)
  514. {
  515. const StringTableEntry exePath = Platform::getMainDotCsDir();
  516. const StringTableEntry cwd = Platform::getCurrentDirectory();
  517. fullPath = NULL;
  518. if (Platform::isFullPath(fileName))
  519. fullPath = fileName;
  520. if (dStrnicmp(exePath, fileName, dStrlen(exePath)) == 0)
  521. name = StringTable->insert(fileName + dStrlen(exePath) + 1, true);
  522. else if (dStrnicmp(cwd, fileName, dStrlen(cwd)) == 0)
  523. name = StringTable->insert(fileName + dStrlen(cwd) + 1, true);
  524. if (fullPath == NULL)
  525. {
  526. char buf[1024];
  527. fullPath = StringTable->insert(Platform::makeFullPathName(fileName, buf, sizeof(buf)), true);
  528. }
  529. modPath = Con::getModNameFromPath(fileName);
  530. }
  531. if (name)
  532. addToCodeList();
  533. gStatementList = NULL;
  534. // we are an eval compile if we don't have a file name associated (no exec)
  535. gIsEvalCompile = fileName == NULL;
  536. // In eval mode, global func vars are allowed.
  537. gFuncVars = gIsEvalCompile ? &gEvalFuncVars : NULL;
  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() : 0;
  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. }