IRViewer.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #include "Backend.h"
  6. #ifdef IR_VIEWER
  7. /* ----- PRIVATE ----- */
  8. Js::DynamicObject * IRtoJSObjectBuilder::CreateIntConstOpnd(Js::ScriptContext *scriptContext, IR::Opnd *opnd)
  9. {
  10. if (!opnd || !opnd->IsIntConstOpnd())
  11. {
  12. return NULL;
  13. }
  14. IR::IntConstOpnd *op = opnd->AsIntConstOpnd();
  15. IntConstType value = op->GetValue();
  16. Js::Var valueVar = Js::JavascriptNumber::ToVar(value, scriptContext);
  17. Js::DynamicObject *opObject = scriptContext->GetLibrary()->CreateObject();
  18. SetProperty(opObject, _u("value"), valueVar);
  19. return opObject;
  20. }
  21. Js::DynamicObject * IRtoJSObjectBuilder::CreateFloatConstOpnd(Js::ScriptContext *scriptContext, IR::Opnd *opnd)
  22. {
  23. if (!opnd || !opnd->IsFloatConstOpnd() || !opnd->IsFloat32ConstOpnd())
  24. {
  25. return NULL;
  26. }
  27. FloatConstType value = (opnd->IsFloatConstOpnd()) ?
  28. opnd->AsFloatConstOpnd()->m_value :
  29. opnd->AsFloat32ConstOpnd()->m_value;
  30. Js::Var valueVar = Js::JavascriptNumber::New(value, scriptContext);
  31. Js::DynamicObject *opObject = scriptContext->GetLibrary()->CreateObject();
  32. SetProperty(opObject, _u("value"), valueVar);
  33. return opObject;
  34. }
  35. Js::DynamicObject * IRtoJSObjectBuilder::CreateHelperCallOpnd(Js::ScriptContext *scriptContext, IR::Opnd *opnd)
  36. {
  37. if (!opnd || !opnd->IsHelperCallOpnd())
  38. {
  39. return NULL;
  40. }
  41. IR::HelperCallOpnd *op = opnd->AsHelperCallOpnd();
  42. const char16 *helperText = IR::GetMethodName(op->m_fnHelper);
  43. Js::JavascriptString *helperString = NULL;
  44. helperString = Js::JavascriptString::NewCopyBuffer(helperText, wcslen(helperText), scriptContext);
  45. Js::DynamicObject *opObject = scriptContext->GetLibrary()->CreateObject();
  46. SetProperty(opObject, _u("methodName"), helperString);
  47. return opObject;
  48. }
  49. Js::DynamicObject * IRtoJSObjectBuilder::CreateSymOpnd(Js::ScriptContext *scriptContext, IR::Opnd *opnd)
  50. {
  51. if (!opnd || !opnd->IsSymOpnd())
  52. {
  53. return NULL;
  54. }
  55. IR::SymOpnd *op = opnd->AsSymOpnd();
  56. SymID id = op->m_sym->m_id;
  57. Js::Var idValue = Js::JavascriptNumber::ToVar(id, scriptContext);
  58. Js::DynamicObject *opObject = scriptContext->GetLibrary()->CreateObject();
  59. SetProperty(opObject, _u("symid"), idValue);
  60. return opObject;
  61. }
  62. Js::DynamicObject * IRtoJSObjectBuilder::CreateRegOpnd(Js::ScriptContext *scriptContext, IR::Opnd *opnd)
  63. {
  64. if (!opnd || !opnd->IsRegOpnd())
  65. {
  66. return NULL;
  67. }
  68. Js::DynamicObject *opObject = scriptContext->GetLibrary()->CreateObject();
  69. IR::RegOpnd *op = opnd->AsRegOpnd();
  70. RegNum regid = op->GetReg();
  71. SymID symid = 0;
  72. if (op->m_sym)
  73. {
  74. symid = op->m_sym->m_id;
  75. }
  76. if (regid != RegNOREG)
  77. {
  78. Js::Var regidValue = Js::JavascriptNumber::ToVar(regid, scriptContext);
  79. SetProperty(opObject, _u("regid"), regidValue);
  80. }
  81. Js::Var symidValue = Js::JavascriptNumber::ToVar(symid, scriptContext);
  82. SetProperty(opObject, _u("symid"), symidValue);
  83. return opObject;
  84. }
  85. Js::DynamicObject * IRtoJSObjectBuilder::CreateAddrOpnd(Js::ScriptContext *scriptContext, IR::Opnd *opnd, Func *func)
  86. {
  87. if (!opnd || !opnd->IsAddrOpnd())
  88. {
  89. return NULL;
  90. }
  91. IR::AddrOpnd *op = opnd->AsAddrOpnd();
  92. Js::Var address = op->m_address; // TODO (doilij) see opnd.cpp:1802 - not always m_address
  93. Js::Var addressVar = Js::JavascriptNumber::ToVar((uint64)address, scriptContext);
  94. Js::DynamicObject *opObject = scriptContext->GetLibrary()->CreateObject();
  95. SetProperty(opObject, _u("addr"), addressVar);
  96. const size_t count = BUFFER_LEN;
  97. char16 detail[count];
  98. op->GetAddrDescription(detail, count, false, false, func);
  99. Js::JavascriptString *detailString = NULL;
  100. detailString = Js::JavascriptString::NewCopyBuffer(detail, wcslen(detail), scriptContext);
  101. SetProperty(opObject, _u("detail"), detailString);
  102. return opObject;
  103. }
  104. Js::DynamicObject * IRtoJSObjectBuilder::CreateIndirOpnd(Js::ScriptContext *scriptContext, IR::Opnd *opnd)
  105. {
  106. if (!opnd || !opnd->IsIndirOpnd())
  107. {
  108. return NULL;
  109. }
  110. IR::IndirOpnd *op = opnd->AsIndirOpnd();
  111. Js::DynamicObject *opObject = scriptContext->GetLibrary()->CreateObject();
  112. IR::RegOpnd *baseOpnd = op->GetBaseOpnd();
  113. Js::Var baseVar = NULL;
  114. if (baseOpnd->m_sym) {
  115. SymID baseid = baseOpnd->m_sym->m_id;
  116. baseVar = Js::JavascriptNumber::ToVar(baseid, scriptContext);
  117. } else {
  118. RegNum regid = baseOpnd->GetReg();
  119. baseVar = Js::JavascriptNumber::ToVar(regid, scriptContext);
  120. }
  121. SetProperty(opObject, _u("base"), baseVar);
  122. IR::RegOpnd *indexOpnd = op->GetIndexOpnd();
  123. if (indexOpnd)
  124. {
  125. SymID indexid = indexOpnd->m_sym->m_id;
  126. Js::Var indexVar = Js::JavascriptNumber::ToVar(indexid, scriptContext);
  127. SetProperty(opObject, _u("index"), indexVar);
  128. }
  129. int32 offset = op->GetOffset();
  130. if (offset)
  131. {
  132. Js::Var offsetVar = Js::JavascriptNumber::ToVar(offset, scriptContext);
  133. SetProperty(opObject, _u("offset"), offsetVar);
  134. }
  135. return opObject;
  136. }
  137. Js::DynamicObject * IRtoJSObjectBuilder::CreateLabelOpnd(Js::ScriptContext *scriptContext, IR::Opnd *opnd)
  138. {
  139. if (!opnd || !opnd->IsLabelOpnd())
  140. {
  141. return NULL;
  142. }
  143. /*
  144. TODO (doilij) unneeded method?
  145. I don't think any code path would reach here.
  146. For Branch and Label, the LabelOpnd's are taken care of by other code paths:
  147. IRtoJSObjectBuilder::CreateLabelInstruction (IRtoJSObject.cpp:281)
  148. IRtoJSObjectBuilder::CreateBranchInstruction (IRtoJSObject.cpp:293)
  149. */
  150. Js::DynamicObject *opObject = scriptContext->GetLibrary()->CreateObject();
  151. return opObject;
  152. }
  153. /* ----- PUBLIC ----- */
  154. Js::DynamicObject * IRtoJSObjectBuilder::CreateOpnd(Js::ScriptContext *scriptContext, IR::Opnd *opnd, Func *func)
  155. {
  156. if (!opnd)
  157. {
  158. return NULL;
  159. }
  160. Js::DynamicObject *opObject = NULL;
  161. IR::OpndKind kind = opnd->GetKind();
  162. switch (kind)
  163. {
  164. case IR::OpndKind::OpndKindInvalid:
  165. // do nothing
  166. break;
  167. case IR::OpndKind::OpndKindIntConst:
  168. opObject = CreateIntConstOpnd(scriptContext, opnd);
  169. break;
  170. case IR::OpndKind::OpndKindFloat32Const:
  171. case IR::OpndKind::OpndKindFloatConst:
  172. opObject = CreateFloatConstOpnd(scriptContext, opnd);
  173. break;
  174. case IR::OpndKind::OpndKindHelperCall:
  175. opObject = CreateHelperCallOpnd(scriptContext, opnd);
  176. break;
  177. case IR::OpndKind::OpndKindSym:
  178. opObject = CreateSymOpnd(scriptContext, opnd);
  179. break;
  180. case IR::OpndKind::OpndKindReg:
  181. opObject = CreateRegOpnd(scriptContext, opnd);
  182. break;
  183. case IR::OpndKind::OpndKindAddr:
  184. opObject = CreateAddrOpnd(scriptContext, opnd, func);
  185. break;
  186. case IR::OpndKind::OpndKindIndir:
  187. opObject = CreateIndirOpnd(scriptContext, opnd);
  188. break;
  189. case IR::OpndKind::OpndKindLabel:
  190. opObject = CreateLabelOpnd(scriptContext, opnd);
  191. break;
  192. case IR::OpndKind::OpndKindMemRef:
  193. // TODO (doilij) implement
  194. break;
  195. case IR::OpndKind::OpndKindRegBV:
  196. // TODO (doilij) implement
  197. break;
  198. default:
  199. break;
  200. }
  201. // fallback create an object that can be used for identifying what info is missing
  202. if (!opObject)
  203. {
  204. opObject = scriptContext->GetLibrary()->CreateObject();
  205. }
  206. // include the kind of symbol so the UI knows how to display the information
  207. Js::Var kindVar = Js::JavascriptNumber::ToVar(kind, scriptContext);
  208. Js::PropertyId id_kind = CreateProperty(scriptContext, _u("kind"));
  209. SetProperty(opObject, id_kind, kindVar);
  210. return opObject;
  211. }
  212. Js::PropertyId IRtoJSObjectBuilder::CreateProperty(Js::ScriptContext *scriptContext, const char16 *propertyName)
  213. {
  214. Js::PropertyRecord const *propertyRecord;
  215. scriptContext->GetOrAddPropertyRecord(propertyName, (int) wcslen(propertyName), &propertyRecord);
  216. Js::PropertyId propertyId = propertyRecord->GetPropertyId();
  217. return propertyId;
  218. }
  219. void IRtoJSObjectBuilder::SetProperty(Js::DynamicObject *obj, const char16 *propertyName, Js::Var value)
  220. {
  221. const size_t len = wcslen(propertyName);
  222. if (!(len > 0))
  223. {
  224. return;
  225. }
  226. Js::PropertyId id = CreateProperty(obj->GetScriptContext(), propertyName);
  227. SetProperty(obj, id, value);
  228. }
  229. void IRtoJSObjectBuilder::SetProperty(Js::DynamicObject *obj, Js::PropertyId id, Js::Var value)
  230. {
  231. if (value == NULL)
  232. {
  233. return;
  234. }
  235. Js::JavascriptOperators::SetProperty(obj, obj, id, value, obj->GetScriptContext());
  236. }
  237. enum STATEMENT_PARSE_T {
  238. STATEMENT_PARSE_NORMAL,
  239. STATEMENT_PARSE_QUOT,
  240. STATEMENT_PARSE_QQUOT,
  241. STATEMENT_PARSE_ESC_QUOT,
  242. STATEMENT_PARSE_ESC_QQUOT,
  243. STATEMENT_PARSE_SEARCH_COMMENT,
  244. STATEMENT_PARSE_LINE_COMMENT,
  245. STATEMENT_PARSE_BLOCK_COMMENT,
  246. STATEMENT_PARSE_SEARCH_BLOCK_COMMENT_END,
  247. STATEMENT_PARSE_SEMICOLON,
  248. STATEMENT_PARSE_END,
  249. STATEMENT_PARSE_MAX
  250. };
  251. /**
  252. Get the statement's source string, cutting the source string short by detecting the first semicolon
  253. which is not contained within a comment or string.
  254. Uses a regular FSM to scan char-by-char for the end of the statement.
  255. NOTE: This does not account for the possibility of semicolons within RegEx. In order to properly
  256. detect where a RegEx begins and ends, a more sophisticated parser is probably needed.
  257. @param buffer A buffer to write the source line into.
  258. @param sourceBegin A pointer to the beginning of the source string.
  259. @param sourceEnd A pointer to the farthest point at which the end of statement could exist.
  260. @param len The size of the buffer (maximum number of characters to copy).
  261. */
  262. void IRtoJSObjectBuilder::GetStatementSourceString(__out_ecount(len) char16 *buffer, LPCUTF8 sourceBegin, LPCUTF8 sourceEnd, const size_t len)
  263. {
  264. enum STATEMENT_PARSE_T state;
  265. size_t i;
  266. // copy characters until end of statement is reached (semicolon or newline)
  267. for (i = 0, state = STATEMENT_PARSE_NORMAL;
  268. (i < len-1) && ((sourceBegin+i) < sourceEnd) && state != STATEMENT_PARSE_END;
  269. i++)
  270. {
  271. utf8char_t ch = sourceBegin[i];
  272. buffer[i] = ch;
  273. switch (state)
  274. {
  275. case STATEMENT_PARSE_NORMAL:
  276. switch (ch)
  277. {
  278. case '\'':
  279. state = STATEMENT_PARSE_QUOT;
  280. break;
  281. case '\"':
  282. state = STATEMENT_PARSE_QQUOT;
  283. break;
  284. case '/':
  285. state = STATEMENT_PARSE_SEARCH_COMMENT;
  286. break;
  287. case ';':
  288. state = STATEMENT_PARSE_END;
  289. break;
  290. default:
  291. // continue in this state
  292. break;
  293. }
  294. break;
  295. case STATEMENT_PARSE_QUOT: // single quoted string
  296. switch (ch)
  297. {
  298. case '\\':
  299. state = STATEMENT_PARSE_ESC_QUOT;
  300. break;
  301. case '\'':
  302. state = STATEMENT_PARSE_NORMAL; // end of single-quoted string
  303. break;
  304. default:
  305. // continue in this state
  306. break;
  307. }
  308. break;
  309. case STATEMENT_PARSE_QQUOT: // double quoted string
  310. switch (ch)
  311. {
  312. case '\\':
  313. state = STATEMENT_PARSE_ESC_QQUOT;
  314. break;
  315. case '\"':
  316. state = STATEMENT_PARSE_NORMAL; // end of double-quoted string
  317. break;
  318. default:
  319. // continue in this state
  320. break;
  321. }
  322. break;
  323. case STATEMENT_PARSE_ESC_QUOT:
  324. state = STATEMENT_PARSE_QUOT; // unconditionally ignore this character and return to string parsing
  325. break;
  326. case STATEMENT_PARSE_ESC_QQUOT:
  327. state = STATEMENT_PARSE_QQUOT; // unconditionally ignore this character and return to string parsing
  328. break;
  329. case STATEMENT_PARSE_SEARCH_COMMENT:
  330. switch (ch)
  331. {
  332. case '/':
  333. state = STATEMENT_PARSE_LINE_COMMENT;
  334. break;
  335. case '*':
  336. state = STATEMENT_PARSE_BLOCK_COMMENT;
  337. break;
  338. default:
  339. state = STATEMENT_PARSE_NORMAL;
  340. break;
  341. }
  342. break;
  343. case STATEMENT_PARSE_LINE_COMMENT:
  344. // do nothing till end of line
  345. break;
  346. case STATEMENT_PARSE_BLOCK_COMMENT:
  347. switch (ch)
  348. {
  349. case '*':
  350. state = STATEMENT_PARSE_SEARCH_BLOCK_COMMENT_END;
  351. break;
  352. default:
  353. // continue in this state
  354. break;
  355. }
  356. break;
  357. case STATEMENT_PARSE_SEARCH_BLOCK_COMMENT_END:
  358. switch (ch)
  359. {
  360. case '/':
  361. state = STATEMENT_PARSE_NORMAL;
  362. break;
  363. default:
  364. // continue in this state
  365. break;
  366. }
  367. break;
  368. }
  369. }
  370. Assert(i < len);
  371. buffer[i] = 0; // NULL terminate
  372. }
  373. void IRtoJSObjectBuilder::CreateLabelInstruction(Js::ScriptContext *scriptContext,
  374. IR::LabelInstr *inst, Js::DynamicObject *currObject)
  375. {
  376. Js::Var labelVar = Js::JavascriptNumber::ToVar(inst->m_id, scriptContext);
  377. SetProperty(currObject, _u("label"), labelVar);
  378. }
  379. void IRtoJSObjectBuilder::CreateBranchInstruction(Js::ScriptContext *scriptContext,
  380. IR::BranchInstr *inst, Js::DynamicObject *currObject)
  381. {
  382. if (!inst->GetTarget())
  383. {
  384. return;
  385. }
  386. Js::Var labelVar = Js::JavascriptNumber::ToVar(inst->GetTarget()->m_id, scriptContext);
  387. SetProperty(currObject, _u("branch"), labelVar);
  388. }
  389. void IRtoJSObjectBuilder::CreatePragmaInstruction(Js::ScriptContext *scriptContext,
  390. IR::PragmaInstr *inst, Js::DynamicObject *currObject,
  391. Func *func)
  392. {
  393. int32 statementIndex = (int32)inst->m_statementIndex;
  394. LPCUTF8 sourceBegin = NULL;
  395. LPCUTF8 sourceEnd = NULL;
  396. ULONG line = 0;
  397. LONG col = 0;
  398. Js::FunctionBody *fnBody = func->GetJnFunction()->GetFunctionBody();
  399. fnBody->GetStatementSourceInfo(statementIndex, &sourceBegin, &sourceEnd, &line, &col);
  400. // move line and column into a sane range
  401. line += 2; // start at line 1 (up from -1)
  402. col += 1; // start at col 1 (up from 0)
  403. //
  404. // extract source string
  405. //
  406. char16 buffer[BUFFER_LEN];
  407. GetStatementSourceString(buffer, sourceBegin, sourceEnd, BUFFER_LEN);
  408. //
  409. // assign source info
  410. //
  411. Js::JavascriptString *sourceString = NULL;
  412. sourceString = Js::JavascriptString::NewCopyBuffer(buffer, wcslen(buffer), scriptContext);
  413. SetProperty(currObject, _u("source"), sourceString);
  414. Js::Var lineVar = Js::JavascriptNumber::ToVar((uint32)line, scriptContext);
  415. SetProperty(currObject, _u("line"), lineVar);
  416. Js::Var colVar = Js::JavascriptNumber::ToVar((uint32)col, scriptContext);
  417. SetProperty(currObject, _u("col"), colVar);
  418. if (statementIndex != -1)
  419. {
  420. Js::Var indexVar = Js::JavascriptNumber::ToVar(statementIndex, scriptContext);
  421. SetProperty(currObject, _u("statementIndex"), indexVar);
  422. }
  423. }
  424. void IRtoJSObjectBuilder::CreateDefaultInstruction(Js::ScriptContext *scriptContext,
  425. IR::Instr *currInst, Js::DynamicObject *currObject,
  426. Func *func)
  427. {
  428. Js::DynamicObject *src1 = IRtoJSObjectBuilder::CreateOpnd(scriptContext, currInst->GetSrc1(), func);
  429. Js::DynamicObject *src2 = IRtoJSObjectBuilder::CreateOpnd(scriptContext, currInst->GetSrc2(), func);
  430. Js::DynamicObject *dst = IRtoJSObjectBuilder::CreateOpnd(scriptContext, currInst->GetDst(), func);
  431. SetProperty(currObject, _u("src1"), src1);
  432. SetProperty(currObject, _u("src2"), src2);
  433. SetProperty(currObject, _u("dst"), dst);
  434. }
  435. /**
  436. Retrieve metadata about the IR dump.
  437. Includes the following information:
  438. * The names of registers (for each regid) for the current architecture.
  439. */
  440. Js::DynamicObject * IRtoJSObjectBuilder::GetMetadata(Js::ScriptContext *scriptContext)
  441. {
  442. Js::JavascriptArray *regNameArray = scriptContext->GetLibrary()->CreateArray(RegNumCount);
  443. for (int i = 0; i < RegNumCount; ++i)
  444. {
  445. const char16 *regName = RegNamesW[i];
  446. Js::Var detailString;
  447. detailString = Js::JavascriptString::NewCopyBuffer(regName, wcslen(regName), scriptContext);
  448. // regNameArray->SetArrayLiteralItem(i, detailString);
  449. regNameArray->SetItem(i, detailString, Js::PropertyOperationFlags::PropertyOperation_None);
  450. }
  451. Js::DynamicObject *metadata = scriptContext->GetLibrary()->CreateObject();
  452. SetProperty(metadata, _u("regNames"), regNameArray);
  453. return metadata;
  454. }
  455. Js::DynamicObject * IRtoJSObjectBuilder::DumpIRtoJSObject(Func *func, Js::Phase phase)
  456. {
  457. if (!CONFIG_FLAG(IRViewer) || !func)
  458. {
  459. // if we actually return null and this value is used, we end up with a failed assertion
  460. return NULL; // TODO (doilij) is this okay or does the return value need to be explicitly undefined?
  461. }
  462. #ifdef ENABLE_IR_VIEWER_DBG_DUMP
  463. if (Js::Configuration::Global.flags.Verbose)
  464. {
  465. Output::Print(_u("\n>>> Begin Dump IR to JS Object (phase: %s) <<<\n"), Js::PhaseNames[phase]);
  466. Output::Flush();
  467. }
  468. #endif
  469. // FIXME (doilij) why only printing the last function? because linking pointer to first IR stmt for a function
  470. // TODO (doilij) make a linked list of functions instead which contain a linked list of IR statements
  471. CodeGenWorkItem *workItem = func->m_workItem;
  472. Js::ScriptContext *scriptContext = workItem->irViewerRequestContext;
  473. if (!scriptContext)
  474. {
  475. // TODO (doilij) should set the requestContext on parseIR code path
  476. scriptContext = func->GetScriptContext();
  477. }
  478. Js::DynamicObject *dumpir = scriptContext->GetLibrary()->CreateObject();
  479. Js::DynamicObject *prevObject = NULL;
  480. Js::DynamicObject *currObject = dumpir;
  481. IR::Instr *currInst = func->m_headInstr;
  482. // property ids for loop
  483. Js::PropertyId id_opcode = CreateProperty(scriptContext, _u("opcode"));
  484. Js::PropertyId id_next = CreateProperty(scriptContext, _u("next"));
  485. while (currInst)
  486. {
  487. //
  488. // "currObject.opcode = Js::OpCodeNamesW[opcode]"
  489. //
  490. Js::OpCode opcode = currInst->m_opcode;
  491. char16 const *const opcodeName = Js::OpCodeUtil::GetOpCodeName(opcode);
  492. Js::JavascriptString *opcodeString = NULL;
  493. opcodeString = Js::JavascriptString::NewCopyBuffer(opcodeName, wcslen(opcodeName), scriptContext);
  494. SetProperty(currObject, id_opcode, opcodeString);
  495. //
  496. // operands
  497. //
  498. if (currInst->IsLabelInstr())
  499. {
  500. IR::LabelInstr *inst = currInst->AsLabelInstr();
  501. CreateLabelInstruction(scriptContext, inst, currObject);
  502. }
  503. else if (currInst->IsBranchInstr())
  504. {
  505. IR::BranchInstr *inst = currInst->AsBranchInstr();
  506. CreateBranchInstruction(scriptContext, inst, currObject);
  507. }
  508. else if (currInst->IsPragmaInstr())
  509. {
  510. IR::PragmaInstr *inst = currInst->AsPragmaInstr();
  511. CreatePragmaInstruction(scriptContext, inst, currObject, currInst->m_func);
  512. }
  513. else
  514. {
  515. CreateDefaultInstruction(scriptContext, currInst, currObject, func);
  516. }
  517. //
  518. // "prevObject.next = currObject"
  519. //
  520. if (prevObject)
  521. {
  522. SetProperty(prevObject, id_next, currObject);
  523. // Note: setting a prev pointer may cause an infinite loop when converting to JSON
  524. }
  525. //
  526. // epilogue
  527. //
  528. prevObject = currObject;
  529. currObject = scriptContext->GetLibrary()->CreateObject();
  530. currInst = currInst->m_next;
  531. }
  532. Js::DynamicObject *baseObject = func->GetJnFunction()->GetFunctionBody()->GetIRDumpBaseObject();
  533. // attach output for given phase
  534. SetProperty(baseObject, Js::PhaseNames[phase], dumpir);
  535. // attach IR metadata
  536. Js::PropertyId id_metadata = CreateProperty(scriptContext, _u("metadata"));
  537. if (!baseObject->HasProperty(id_metadata))
  538. {
  539. Js::DynamicObject *metadata = GetMetadata(scriptContext);
  540. SetProperty(baseObject, id_metadata, metadata);
  541. }
  542. return baseObject;
  543. }
  544. // TODO (doilij) update the name of this function
  545. // TODO (doilij) write documentation for this function
  546. void IRtoJSObjectBuilder::DumpIRtoGlobalObject(Func *func, Js::Phase phase)
  547. {
  548. // FIXME (doilij) this cast has got to be unnecessary
  549. CodeGenWorkItem *workItem =func->m_workItem;
  550. bool rejit = workItem->isRejitIRViewerFunction;
  551. bool irDumpEnabled = func->GetJnFunction()->GetFunctionBody()->IsIRDumpEnabled();
  552. if (!(irDumpEnabled || rejit))
  553. {
  554. return;
  555. }
  556. Js::DynamicObject *baseObject = DumpIRtoJSObject(func, phase);
  557. workItem->SetIRViewerOutput(baseObject);
  558. }
  559. #endif /* IR_VIEWER */