IRViewer.cpp 21 KB

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