SwitchIRBuilder.h 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  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. #pragma once
  6. /**
  7. * The object that handles actions generated by a SwitchIRBuilder, which
  8. * will be either an IRBuilder or an IRBuilderAsmJs
  9. */
  10. struct SwitchAdapter {
  11. virtual void AddBranchInstr(IR::BranchInstr * instr, uint32 offset, uint32 targetOffset, bool clearBackEdge = false) = 0;
  12. virtual void AddInstr(IR::Instr * instr, uint32 offset) = 0;
  13. virtual void CreateRelocRecord(IR::BranchInstr * branchInstr, uint32 offset, uint32 targetOffset, bool clearBackEdge = false) = 0;
  14. virtual void ConvertToBailOut(IR::Instr * instr, IR::BailOutKind kind) = 0;
  15. };
  16. /**
  17. * Handles delegating actions generated by a SwitchIRBuilder to an IRBuilder
  18. */
  19. struct IRBuilderSwitchAdapter : public SwitchAdapter {
  20. private:
  21. IRBuilder * m_builder;
  22. public:
  23. IRBuilderSwitchAdapter(IRBuilder * builder)
  24. : m_builder(builder) {}
  25. virtual void AddBranchInstr(IR::BranchInstr * instr, uint32 offset, uint32 targetOffset, bool clearBackEdge = false);
  26. virtual void AddInstr(IR::Instr * instr, uint32 offset);
  27. virtual void CreateRelocRecord(IR::BranchInstr * branchInstr, uint32 offset, uint32 targetOffset, bool clearBackEdge = false);
  28. virtual void ConvertToBailOut(IR::Instr * instr, IR::BailOutKind kind);
  29. };
  30. /**
  31. * Handles delegating actions generated by a SwitchIRBuilder to an IRBuilderAsmJs
  32. */
  33. #ifdef ASMJS_PLAT
  34. struct IRBuilderAsmJsSwitchAdapter : public SwitchAdapter {
  35. private:
  36. IRBuilderAsmJs * m_builder;
  37. public:
  38. IRBuilderAsmJsSwitchAdapter(IRBuilderAsmJs * builder)
  39. : m_builder(builder) {}
  40. virtual void AddBranchInstr(IR::BranchInstr * instr, uint32 offset, uint32 targetOffset, bool clearBackEdge = false);
  41. virtual void AddInstr(IR::Instr * instr, uint32 offset);
  42. virtual void CreateRelocRecord(IR::BranchInstr * branchInstr, uint32 offset, uint32 targetOffset, bool clearBackEdge = false);
  43. virtual void ConvertToBailOut(IR::Instr * instr, IR::BailOutKind kind);
  44. };
  45. #endif
  46. /**
  47. * Handles construction of switch statements, with appropriate optimizations. Note that some of these
  48. * optimizations occur during IR building (rather than GlobOpt) because the abstraction of a switch/case
  49. * block is not maintained with the resulting IR. Thus, some optimizations must occur during this phase.
  50. */
  51. class SwitchIRBuilder {
  52. private:
  53. typedef JsUtil::List<CaseNode*, JitArenaAllocator> CaseNodeList;
  54. typedef JsUtil::List<JITJavascriptString *, JitArenaAllocator> StrSwitchCaseList;
  55. SwitchAdapter* m_adapter;
  56. Func* m_func;
  57. JitArenaAllocator* m_tempAlloc;
  58. CaseNodeList* m_caseNodes;
  59. bool m_seenOnlySingleCharStrCaseNodes;
  60. IR::Instr * m_profiledSwitchInstr;
  61. bool m_isAsmJs;
  62. bool m_switchOptBuildBail; //bool refers to whether the bail out has to be generated or not
  63. bool m_switchIntDynProfile; // bool refers to whether dynamic profile info says that the switch expression is an integer or not
  64. bool m_switchStrDynProfile; // bool refers to whether dynamic profile info says that the switch expression is a string or not
  65. BVSparse<JitArenaAllocator> * m_intConstSwitchCases;
  66. StrSwitchCaseList * m_strConstSwitchCases;
  67. Js::OpCode m_eqOp;
  68. Js::OpCode m_ltOp;
  69. Js::OpCode m_leOp;
  70. Js::OpCode m_gtOp;
  71. Js::OpCode m_geOp;
  72. Js::OpCode m_subOp;
  73. public:
  74. SwitchIRBuilder(SwitchAdapter * adapter)
  75. : m_adapter(adapter)
  76. , m_profiledSwitchInstr(nullptr)
  77. , m_switchOptBuildBail(false)
  78. , m_switchIntDynProfile(false)
  79. , m_switchStrDynProfile(false)
  80. , m_isAsmJs(false)
  81. , m_seenOnlySingleCharStrCaseNodes(true) {}
  82. void Init(Func * func, JitArenaAllocator * tempAlloc, bool isAsmJs);
  83. void BeginSwitch();
  84. void EndSwitch(uint32 offset, uint32 targetOffset);
  85. void SetProfiledInstruction(IR::Instr * instr, Js::ProfileId profileId);
  86. void OnCase(IR::RegOpnd * src1Opnd, IR::Opnd * src2Opnd, uint32 offset, uint32 targetOffset);
  87. void FlushCases(uint32 targetOffset);
  88. void RefineCaseNodes();
  89. void ResetCaseNodes();
  90. void BuildCaseBrInstr(uint32 targetOffset);
  91. void BuildBinaryTraverseInstr(int start, int end, uint32 defaultLeafBranch);
  92. void BuildLinearTraverseInstr(int start, int end, uint32 defaultLeafBranch);
  93. void BuildEmptyCasesInstr(CaseNode* currCaseNode, uint32 defaultLeafBranch);
  94. void BuildOptimizedIntegerCaseInstrs(uint32 targetOffset);
  95. void BuildMultiBrCaseInstrForStrings(uint32 targetOffset);
  96. void FixUpMultiBrJumpTable(IR::MultiBranchInstr * multiBranchInstr, uint32 targetOffset);
  97. void TryBuildBinaryTreeOrMultiBrForSwitchInts(IR::MultiBranchInstr * &multiBranchInstr, uint32 fallthrOffset,
  98. int startjmpTableIndex, int endjmpTableIndex, int startBinaryTravIndex, uint32 targetOffset);
  99. bool TestAndAddStringCaseConst(JITJavascriptString * str);
  100. void BuildBailOnNotInteger();
  101. void BuildBailOnNotString();
  102. IR::MultiBranchInstr * BuildMultiBrCaseInstrForInts(uint32 start, uint32 end, uint32 targetOffset);
  103. };