BackendOpCodeAttr.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  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 "RuntimeByteCodePch.h"
  6. #include "BackendOpCodeAttr.h"
  7. namespace OpCodeAttr
  8. {
  9. // OpSideEffect:
  10. // Opcode has side effect not just to the dst/src on the instruction.
  11. // The opcode cannot be deadstored. (e.g. StFld, LdFld from DOM, call valueOf/toString/getter/setter)
  12. // Doesn't include all "exit" script (e.g. LdThis doesn't have side effect for HostDispatch for exiting script to getting the name space parent)
  13. // OpHasImplicitCall:
  14. // Include all possible exit scripts, call valueOf/toString/getter/setter
  15. enum OpCodeAttrEnum
  16. {
  17. None = 0x00000000,
  18. OpSideEffect = 0x00000001, // If dst is unused and src can't call implicitcalls, it still can not be dead-stored (Could throw an exception, etc)
  19. OpUseAllFields = 0x00000002,
  20. OpTempNumberSources = 0x00000004, // OpCode does support temp values as source
  21. OpTempNumberProducing = 0x00000008, // OpCode can produce a temp value
  22. OpTempNumberTransfer = 0x00000010 | OpTempNumberSources, // OpCode transfers a temp value
  23. OpTempObjectSources = 0x00000020, // OpCode does support temp values as source
  24. OpTempObjectProducing = 0x00000040, // OpCode can produce a temp value
  25. OpTempObjectTransfer = 0x00000080 | OpTempObjectSources, // OpCode transfers a temp value
  26. OpTempObjectCanStoreTemp = 0x00000100 | OpTempObjectProducing, // OpCode can produce a temp value, and once marked, it will always produce a temp value so we can store other temp value in the object
  27. OpInlineCallInstr = 0x00000200,
  28. OpOpndHasImplicitCall = 0x00000400, // Evaluation/read/write of opnd may cause implicit call
  29. OpCallInstr = 0x00000800,
  30. OpDoNotTransfer = 0x00001000,
  31. OpHasImplicitCall = 0x00002000, // Operation may cause implicit call not related to opnd evaluation
  32. OpFastFldInstr = 0x00004000,
  33. OpBailOutRec = 0x00008000,
  34. OpInlinableBuiltIn = 0x00010000, // OpCode is an inlinable built-in, such as InlineMathSin, etc.
  35. OpNonIntTransfer = 0x00020000, // OpCode may transfer a non-integer value from the non-constant source to the destination
  36. OpIsInt32 = 0x00040000, // OpCode converts its srcs to int32 or a narrower int type, and produces an int32
  37. OpProducesNumber = 0x00080000, // OpCode always produces a number
  38. OpCanLoadFixedFields = 0x00100000, // OpCode can use fixed fields
  39. OpCanCSE = 0x00200000, // Opcode has no side-effect and always produces the same value for a given input (InlineMathAbs is OK, InlineMathRandom is not)
  40. OpNoFallThrough = 0x00400000, // Opcode doesn't fallthrough in flow and it always jumps to the return from this opcode
  41. OpPostOpDbgBailOut = 0x00800000, // Generate bail out after this opcode. This must be a helper call and needs bailout on return from it. Used for Fast F12.
  42. OpHasMultiSizeLayout = 0x01000000,
  43. OpHasProfiled = 0x02000000,
  44. OpHasProfiledWithICIndex = 0x04000000,
  45. OpDeadFallThrough = 0x08000000,
  46. OpProfiled = 0x10000000, // OpCode is a profiled variant
  47. OpProfiledWithICIndex = 0x20000000, // OpCode is a profiled with IC index variant
  48. OpByteCodeOnly = 0x40000000,
  49. };
  50. static const int OpcodeAttributes[] =
  51. {
  52. #define DEF_OP(name, jnLayout, attrib, ...) attrib,
  53. #include "ByteCode/OpCodeList.h"
  54. #undef DEF_OP
  55. };
  56. static const int ExtendedOpcodeAttributes[] =
  57. {
  58. #define DEF_OP(name, jnLayout, attrib, ...) attrib,
  59. #include "ByteCode/ExtendedOpCodeList.h"
  60. #undef DEF_OP
  61. };
  62. static const int BackendOpCodeAttributes[] =
  63. {
  64. #define DEF_OP(name, jnLayout, attrib, ...) attrib,
  65. #include "BackendOpCodeList.h"
  66. #undef DEF_OP
  67. };
  68. static const int GetOpCodeAttributes(Js::OpCode op)
  69. {
  70. if (op <= Js::OpCode::MaxByteSizedOpcodes)
  71. {
  72. AnalysisAssert(op < _countof(OpcodeAttributes));
  73. return OpcodeAttributes[(int)op];
  74. }
  75. else if (op < Js::OpCode::ByteCodeLast)
  76. {
  77. uint opIndex = op - (Js::OpCode::MaxByteSizedOpcodes + 1);
  78. AnalysisAssert(opIndex < _countof(ExtendedOpcodeAttributes));
  79. return ExtendedOpcodeAttributes[opIndex];
  80. }
  81. uint opIndex = op - (Js::OpCode::ByteCodeLast + 1);
  82. AnalysisAssert(opIndex < _countof(BackendOpCodeAttributes));
  83. return BackendOpCodeAttributes[opIndex];
  84. }
  85. bool HasSideEffects(Js::OpCode opcode)
  86. {
  87. return ((GetOpCodeAttributes(opcode) & OpSideEffect) != 0);
  88. };
  89. bool CanCSE(Js::OpCode opcode)
  90. {
  91. Assert(((GetOpCodeAttributes(opcode) & OpCanCSE) == 0) || ((GetOpCodeAttributes(opcode) & OpSideEffect) == 0));
  92. return ((GetOpCodeAttributes(opcode) & OpCanCSE) != 0);
  93. };
  94. bool UseAllFields(Js::OpCode opcode)
  95. {
  96. return ((GetOpCodeAttributes(opcode) & OpUseAllFields) != 0);
  97. }
  98. bool NonTempNumberSources(Js::OpCode opcode)
  99. {
  100. return ((GetOpCodeAttributes(opcode) & OpTempNumberSources) == 0);
  101. }
  102. bool TempNumberSources(Js::OpCode opcode)
  103. {
  104. return ((GetOpCodeAttributes(opcode) & OpTempNumberSources) != 0);
  105. }
  106. bool TempNumberProducing(Js::OpCode opcode)
  107. {
  108. return ((GetOpCodeAttributes(opcode) & OpTempNumberProducing) != 0);
  109. }
  110. bool TempNumberTransfer(Js::OpCode opcode)
  111. {
  112. return ((GetOpCodeAttributes(opcode) & OpTempNumberTransfer) == OpTempNumberTransfer);
  113. }
  114. bool TempObjectSources(Js::OpCode opcode)
  115. {
  116. return ((GetOpCodeAttributes(opcode) & OpTempObjectSources) != 0);
  117. }
  118. bool TempObjectProducing(Js::OpCode opcode)
  119. {
  120. return ((GetOpCodeAttributes(opcode) & OpTempObjectProducing) != 0);
  121. }
  122. bool TempObjectTransfer(Js::OpCode opcode)
  123. {
  124. return ((GetOpCodeAttributes(opcode) & OpTempObjectTransfer) == OpTempObjectTransfer);
  125. }
  126. bool TempObjectCanStoreTemp(Js::OpCode opcode)
  127. {
  128. return ((GetOpCodeAttributes(opcode) & OpTempObjectCanStoreTemp) == OpTempObjectCanStoreTemp);
  129. }
  130. bool CallInstr(Js::OpCode opcode)
  131. {
  132. return ((GetOpCodeAttributes(opcode) & OpCallInstr) != 0);
  133. }
  134. bool InlineCallInstr(Js::OpCode opcode)
  135. {
  136. return ((GetOpCodeAttributes(opcode) & OpInlineCallInstr) != 0);
  137. }
  138. bool OpndHasImplicitCall(Js::OpCode opcode)
  139. {
  140. return ((GetOpCodeAttributes(opcode) & OpOpndHasImplicitCall) != 0);
  141. }
  142. bool FastFldInstr(Js::OpCode opcode)
  143. {
  144. return ((GetOpCodeAttributes(opcode) & OpFastFldInstr) != 0);
  145. }
  146. bool BailOutRec(Js::OpCode opcode)
  147. {
  148. return ((GetOpCodeAttributes(opcode) & OpBailOutRec) != 0);
  149. }
  150. bool ByteCodeOnly(Js::OpCode opcode)
  151. {
  152. return ((GetOpCodeAttributes(opcode) & OpByteCodeOnly) != 0);
  153. }
  154. bool DoNotTransfer(Js::OpCode opcode)
  155. {
  156. return ((GetOpCodeAttributes(opcode) & OpDoNotTransfer) != 0);
  157. }
  158. bool HasImplicitCall(Js::OpCode opcode)
  159. {
  160. return ((GetOpCodeAttributes(opcode) & OpHasImplicitCall) != 0);
  161. }
  162. bool IsProfiledOp(Js::OpCode opcode)
  163. {
  164. return ((GetOpCodeAttributes(opcode) & OpProfiled) != 0);
  165. }
  166. bool IsProfiledOpWithICIndex(Js::OpCode opcode)
  167. {
  168. return ((GetOpCodeAttributes(opcode) & OpProfiledWithICIndex) != 0);
  169. }
  170. bool IsInlineBuiltIn(Js::OpCode opcode)
  171. {
  172. return ((GetOpCodeAttributes(opcode) & OpInlinableBuiltIn) != 0);
  173. }
  174. bool NonIntTransfer(Js::OpCode opcode)
  175. {
  176. return ((GetOpCodeAttributes(opcode) & OpNonIntTransfer) != 0);
  177. }
  178. bool IsInt32(Js::OpCode opcode)
  179. {
  180. return ((GetOpCodeAttributes(opcode) & OpIsInt32) != 0);
  181. }
  182. bool ProducesNumber(Js::OpCode opcode)
  183. {
  184. return ((GetOpCodeAttributes(opcode) & OpProducesNumber) != 0);
  185. }
  186. bool HasFallThrough(Js::OpCode opcode)
  187. {
  188. return ((GetOpCodeAttributes(opcode) & OpNoFallThrough) == 0);
  189. }
  190. bool NeedsPostOpDbgBailOut(Js::OpCode opcode)
  191. {
  192. return ((GetOpCodeAttributes(opcode) & OpPostOpDbgBailOut) != 0);
  193. }
  194. bool HasMultiSizeLayout(Js::OpCode opcode)
  195. {
  196. return ((GetOpCodeAttributes(opcode) & OpHasMultiSizeLayout) != 0);
  197. }
  198. bool HasProfiledOp(Js::OpCode opcode)
  199. {
  200. return ((GetOpCodeAttributes(opcode) & OpHasProfiled) != 0);
  201. }
  202. bool HasProfiledOpWithICIndex(Js::OpCode opcode)
  203. {
  204. return ((GetOpCodeAttributes(opcode) & OpHasProfiledWithICIndex) != 0);
  205. }
  206. bool HasDeadFallThrough(Js::OpCode opcode)
  207. {
  208. return ((GetOpCodeAttributes(opcode) & OpDeadFallThrough) != 0);
  209. }
  210. bool CanLoadFixedFields(Js::OpCode opcode)
  211. {
  212. return ((GetOpCodeAttributes(opcode) & OpCanLoadFixedFields) != 0);
  213. }
  214. #if DBG
  215. enum OpCodeDebugAttrEnum
  216. {
  217. OpDbgAttr_None,
  218. OpDbgAttr_BackEndOnly = 0x00000001,
  219. OpDbgAttr_LoadRoot = 0x00000002, // opcode uses root object
  220. };
  221. static const int OpcodeDebugAttributes[] =
  222. {
  223. #define DEF_OP(name, jnLayout, attrib, dbgAttrib) dbgAttrib,
  224. #include "ByteCode/OpCodeList.h"
  225. #undef DEF_OP
  226. };
  227. static const int ExtendedOpcodeDebugAttributes[] =
  228. {
  229. #define DEF_OP(name, jnLayout, attrib, dbgAttrib) dbgAttrib,
  230. #include "ByteCode/ExtendedOpCodeList.h"
  231. #undef DEF_OP
  232. };
  233. static const int BackendOpCodeDebugAttributes[] =
  234. {
  235. #define DEF_OP(name, jnLayout, attrib, dbgAttrib) dbgAttrib,
  236. #include "BackendOpCodeList.h"
  237. #undef DEF_OP
  238. };
  239. static const int GetOpCodeDebugAttributes(Js::OpCode op)
  240. {
  241. if (op <= Js::OpCode::MaxByteSizedOpcodes)
  242. {
  243. AnalysisAssert(op < _countof(OpcodeDebugAttributes));
  244. return OpcodeDebugAttributes[(int)op];
  245. }
  246. else if (op < Js::OpCode::ByteCodeLast)
  247. {
  248. uint opIndex = op - (Js::OpCode::MaxByteSizedOpcodes + 1);
  249. AnalysisAssert(opIndex < _countof(ExtendedOpcodeDebugAttributes));
  250. return ExtendedOpcodeDebugAttributes[opIndex];
  251. }
  252. uint opIndex = op - (Js::OpCode::ByteCodeLast + 1);
  253. AnalysisAssert(opIndex < _countof(BackendOpCodeDebugAttributes));
  254. return BackendOpCodeDebugAttributes[opIndex];
  255. }
  256. bool BackEndOnly(Js::OpCode opcode)
  257. {
  258. return ((GetOpCodeDebugAttributes(opcode) & OpDbgAttr_BackEndOnly) != 0);
  259. }
  260. bool LoadRoot(Js::OpCode opcode)
  261. {
  262. return ((GetOpCodeDebugAttributes(opcode) & OpDbgAttr_LoadRoot) != 0);
  263. }
  264. #endif // DBG
  265. }; // OpCodeAttr