/* * Copyright (c) 2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ECMASCRIPT_CLASS_LINKER_BYTECODE_CIRCUIT_IR_BUILDER_H #define ECMASCRIPT_CLASS_LINKER_BYTECODE_CIRCUIT_IR_BUILDER_H #include #include #include #include #include "circuit.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/interpreter/interpreter-inl.h" #include "ecmascript/js_method.h" namespace panda::ecmascript::kungfu { using VRegIDType = uint16_t; enum class SplitKind : uint8_t { DEFAULT, START, END }; struct CfgInfo { uint8_t *pc {nullptr}; SplitKind splitKind {SplitKind::DEFAULT}; std::vector succs {}; CfgInfo(uint8_t *startOrEndPc, SplitKind kind, std::vector successors) : pc(startOrEndPc), splitKind(kind), succs(successors) {}; bool operator<(const CfgInfo &rhs) const { if (this->pc != rhs.pc) { return this->pc < rhs.pc; } else { return this->splitKind < rhs.splitKind; } } bool operator==(const CfgInfo &rhs) const { return this->pc == rhs.pc && this->splitKind == rhs.splitKind; } }; struct BytecodeRegion { int32_t id {-1}; uint8_t *start {nullptr}; uint8_t *end {nullptr}; std::vector preds {}; // List of predessesor blocks std::vector succs {}; // List of successors blocks std::vector trys {}; // List of trys blocks std::vector catchs {}; // List of catches blocks std::vector immDomBlocks {}; // List of dominated blocks BytecodeRegion *iDominator {nullptr}; // Block that dominates the current block std::vector domFrontiers {}; // List of dominace frontiers bool isDead {false}; std::set phi {}; // phi node bool phiAcc {false}; int32_t numOfStatePreds {0}; int32_t statePredIndex {0}; std::vector> expandedPreds {}; kungfu::GateRef stateStart {kungfu::Circuit::NullGate()}; kungfu::GateRef dependStart {kungfu::Circuit::NullGate()}; std::map vregToValSelectorGate {}; // corresponding ValueSelector gates of vregs kungfu::GateRef valueSelectorAccGate {kungfu::Circuit::NullGate()}; bool operator <(const BytecodeRegion &target) const { return id < target.id; } }; struct BytecodeInfo { std::vector vregIn {}; // read register std::vector vregOut {}; // write register bool accIn {false}; // read acc bool accOut {false}; // write acc uint64_t imm {0}; uint8_t opcode {0}; uint16_t offset {0}; }; struct BytecodeGraph { std::vector graph {}; const JSMethod *method; }; enum BytecodeOffset { ONE = 1, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN }; enum CommonArgIdx : uint8_t { GLUE = 0, FUNC, NEW_TARGET, THIS, NUM_OF_ARGS, }; class BytecodeCircuitBuilder { public: explicit BytecodeCircuitBuilder() = default; ~BytecodeCircuitBuilder() = default; NO_COPY_SEMANTIC(BytecodeCircuitBuilder); NO_MOVE_SEMANTIC(BytecodeCircuitBuilder); void PUBLIC_API BytecodeToCircuit(const std::vector &pcArray, const panda_file::File &pf, const JSMethod *method); [[nodiscard]] kungfu::Circuit* GetCircuit() { return &circuit_; } [[nodiscard]] const std::map>& GetGateToBytecode() const { return jsgateToBytecode_; } [[nodiscard]] const std::map& GetBytecodeToGate() const { return byteCodeToJSGate_; } [[nodiscard]] std::string GetBytecodeStr(kungfu::GateRef gate) const { auto pc = jsgateToBytecode_.at(gate).second; return GetEcmaOpcodeStr(static_cast(*pc)); } [[nodiscard]] uint8_t* GetJSBytecode(GateRef gate) const { return jsgateToBytecode_.at(gate).second; } [[nodiscard]] GateRef GetCommonArgByIndex(CommonArgIdx idx) { return commonArgs_[idx]; } private: void PUBLIC_API CollectBytecodeBlockInfo(uint8_t* pc, std::vector &bytecodeBlockInfos); std::map, std::vector> CollectTryCatchBlockInfo( const panda_file::File &file, const JSMethod *method, std::map &byteCodeCurPrePc, std::vector &bytecodeBlockInfos); void CompleteBytecodeBlockInfo(std::map &byteCodeCurPrePc, std::vector &bytecodeBlockInfos); void BuildBasicBlocks(const JSMethod *method, std::map, std::vector> &exception, std::vector &bytecodeBlockInfo, std::map &byteCodeCurPrePc); void ComputeDominatorTree(BytecodeGraph &byteCodeGraph); void BuildImmediateDominator(std::vector &immDom, BytecodeGraph &byteCodeGraph); void ComputeDomFrontiers(std::vector &immDom, BytecodeGraph &byteCodeGraph); BytecodeInfo GetBytecodeInfo(uint8_t *pc); void RemoveDeadRegions(const std::map &dfsTimestamp, BytecodeGraph &byteCodeGraph); void InsertPhi(BytecodeGraph &byteCodeGraph); void UpdateCFG(BytecodeGraph &byteCodeGraph); void BuildCircuit(BytecodeGraph &byteCodeGraph); void PrintCollectBlockInfo(std::vector &bytecodeBlockInfos); void PrintGraph(std::vector &graph); void PrintBytecodeInfo(std::vector &graph); void PrintBBInfo(std::vector &graph); static bool IsJump(EcmaOpcode opcode); static bool IsCondJump(EcmaOpcode opcode); static bool IsMov(EcmaOpcode opcode); static bool IsReturn(EcmaOpcode opcode); static bool IsThrow(EcmaOpcode opcode); static bool IsGeneral(EcmaOpcode opcode); static bool IsSetConstant(EcmaOpcode opcode); size_t GetActualNumArgs(size_t numArgs) { return numArgs + CommonArgIdx::NUM_OF_ARGS; } kungfu::Circuit circuit_; std::map> jsgateToBytecode_; std::map byteCodeToJSGate_; std::map bbIdToBasicBlock_; std::array commonArgs_ {}; }; } // namespace panda::ecmascript::kungfu #endif // ECMASCRIPT_CLASS_LINKER_BYTECODE_CIRCUIT_IR_BUILDER_H