SwitchIRBuilder.h 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  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. struct IRBuilderAsmJsSwitchAdapter : public SwitchAdapter {
  34. private:
  35. IRBuilderAsmJs * m_builder;
  36. public:
  37. IRBuilderAsmJsSwitchAdapter(IRBuilderAsmJs * builder)
  38. : m_builder(builder) {}
  39. virtual void AddBranchInstr(IR::BranchInstr * instr, uint32 offset, uint32 targetOffset, bool clearBackEdge = false);
  40. virtual void AddInstr(IR::Instr * instr, uint32 offset);
  41. virtual void CreateRelocRecord(IR::BranchInstr * branchInstr, uint32 offset, uint32 targetOffset, bool clearBackEdge = false);
  42. virtual void ConvertToBailOut(IR::Instr * instr, IR::BailOutKind kind);
  43. };
  44. /**
  45. * Handles construction of switch statements, with appropriate optimizations
  46. */
  47. class SwitchIRBuilder {
  48. private:
  49. typedef JsUtil::List<CaseNode*, JitArenaAllocator> CaseNodeList;
  50. typedef JsUtil::List<Js::JavascriptString *, JitArenaAllocator> StrSwitchCaseList;
  51. SwitchAdapter* m_adapter;
  52. Func* m_func;
  53. JitArenaAllocator* m_tempAlloc;
  54. CaseNodeList* m_caseNodes;
  55. bool m_seenOnlySingleCharStrCaseNodes;
  56. IR::Instr * m_profiledSwitchInstr;
  57. bool m_isAsmJs;
  58. bool m_switchOptBuildBail; //bool refers to whether the bail out has to be generated or not
  59. bool m_switchIntDynProfile; // bool refers to whether dynamic profile info says that the switch expression is an integer or not
  60. bool m_switchStrDynProfile; // bool refers to whether dynamic profile info says that the switch expression is an string or not
  61. BVSparse<JitArenaAllocator> * m_intConstSwitchCases;
  62. StrSwitchCaseList * m_strConstSwitchCases;
  63. Js::OpCode m_eqOp;
  64. Js::OpCode m_ltOp;
  65. Js::OpCode m_leOp;
  66. Js::OpCode m_gtOp;
  67. Js::OpCode m_geOp;
  68. Js::OpCode m_subOp;
  69. public:
  70. SwitchIRBuilder(SwitchAdapter * adapter)
  71. : m_adapter(adapter)
  72. , m_profiledSwitchInstr(nullptr)
  73. , m_switchOptBuildBail(false)
  74. , m_switchIntDynProfile(false)
  75. , m_switchStrDynProfile(false)
  76. , m_isAsmJs(false)
  77. , m_seenOnlySingleCharStrCaseNodes(true) {}
  78. void Init(Func * func, JitArenaAllocator * tempAlloc, bool isAsmJs);
  79. void BeginSwitch();
  80. void EndSwitch(uint32 offset, uint32 targetOffset);
  81. void SetProfiledInstruction(IR::Instr * instr, Js::ProfileId profileId);
  82. void OnCase(IR::RegOpnd * src1Opnd, IR::RegOpnd * src2Opnd, uint32 offset, uint32 targetOffset);
  83. void FlushCases(uint32 targetOffset);
  84. void RefineCaseNodes();
  85. void ResetCaseNodes();
  86. void BuildCaseBrInstr(uint32 targetOffset);
  87. void BuildBinaryTraverseInstr(int start, int end, uint32 defaultLeafBranch);
  88. void BuildLinearTraverseInstr(int start, int end, uint32 defaultLeafBranch);
  89. void BuildEmptyCasesInstr(CaseNode* currCaseNode, uint32 defaultLeafBranch);
  90. void BuildOptimizedIntegerCaseInstrs(uint32 targetOffset);
  91. void BuildMultiBrCaseInstrForStrings(uint32 targetOffset);
  92. void FixUpMultiBrJumpTable(IR::MultiBranchInstr * multiBranchInstr, uint32 targetOffset);
  93. void TryBuildBinaryTreeOrMultiBrForSwitchInts(IR::MultiBranchInstr * &multiBranchInstr, uint32 fallthrOffset,
  94. int startjmpTableIndex, int endjmpTableIndex, int startBinaryTravIndex, uint32 targetOffset);
  95. bool TestAndAddStringCaseConst(Js::JavascriptString * str);
  96. void BuildBailOnNotInteger();
  97. void BuildBailOnNotString();
  98. IR::MultiBranchInstr * BuildMultiBrCaseInstrForInts(uint32 start, uint32 end, uint32 targetOffset);
  99. };