1 /* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef ECMASCRIPT_COMPILER_CIRCUIT_H 17 #define ECMASCRIPT_COMPILER_CIRCUIT_H 18 19 #include <algorithm> 20 #include <iostream> 21 #include <map> 22 #include <unordered_map> 23 #include <vector> 24 25 #include "ecmascript/compiler/gate.h" 26 #include "ecmascript/compiler/share_gate_meta_data.h" 27 #include "ecmascript/compiler/lcr_gate_meta_data.h" 28 #include "ecmascript/compiler/mcr_gate_meta_data.h" 29 #include "ecmascript/compiler/hcr_gate_meta_data.h" 30 #include "ecmascript/compiler/gate_meta_data_builder.h" 31 #include "ecmascript/frames.h" 32 33 #include "libpandabase/macros.h" 34 #include "securec.h" 35 36 namespace panda::ecmascript::kungfu { 37 class DebugInfo; 38 class ArgumentAccessor; 39 enum class VisitState : uint8_t { 40 UNVISITED, 41 PENDING, 42 VISITED, 43 }; 44 45 class Circuit { // note: calling NewGate could make all saved Gate* invalid 46 public: 47 explicit Circuit(NativeAreaAllocator* allocator, DebugInfo* dInfo = nullptr, const char* funcName = nullptr, 48 bool isArch64 = true, FrameType type = FrameType::OPTIMIZED_FRAME); 49 ~Circuit(); 50 NO_COPY_SEMANTIC(Circuit); 51 NO_MOVE_SEMANTIC(Circuit); 52 53 ArgumentAccessor *GetArgumentAccessor(); 54 GateRef NewGate(const GateMetaData *meta, const std::vector<GateRef> &inList, const char* comment = nullptr); 55 GateRef NewGate(const GateMetaData *meta, MachineType machineType, GateType type, const char* comment = nullptr); 56 GateRef NewGate(const GateMetaData *meta, MachineType machineType, 57 const std::initializer_list<GateRef>& args, GateType type, const char* comment = nullptr); 58 GateRef NewGate(const GateMetaData *meta, MachineType machineType, size_t numIns, 59 const GateRef inList[], GateType type, const char* comment = nullptr); 60 GateRef NewGate(const GateMetaData *meta, MachineType machineType, 61 const std::vector<GateRef>& inList, GateType type, const char* comment = nullptr); 62 void PrintAllGates() const; 63 void PrintAllGatesWithBytecode() const; 64 void GetAllGates(std::vector<GateRef>& gates) const; 65 static GateRef NullGate(); 66 void Verify(GateRef gate, const std::string& methodName = "") const; 67 panda::ecmascript::FrameType GetFrameType() const; 68 void SetFrameType(panda::ecmascript::FrameType type); 69 GateRef GetConstantGate(MachineType machineType, uint64_t value, GateType type); 70 GateRef GetHeapConstantGate(uint32_t heapConstantIndex); 71 GateRef GetConstantGateWithoutCache(MachineType machineType, uint64_t value, GateType type); 72 void ClearConstantCache(MachineType machineType, uint64_t value, GateType type); 73 GateRef GetConstantStringGate(MachineType machineType, std::string_view str, GateType type); 74 GateRef NewArg(MachineType machineType, size_t index, GateType type, GateRef argRoot); 75 GateRef GetInitialEnvGate(GateRef depend, GateRef jsFunc); 76 size_t GetGateCount() const; 77 TimeStamp GetTime() const; 78 void AdvanceTime() const; SetArch(bool isArch64)79 void SetArch(bool isArch64) 80 { 81 isArch64_ = isArch64; 82 } IsArch64()83 bool IsArch64() const 84 { 85 return isArch64_; 86 } 87 void InitRoot(); GetRoot()88 GateRef GetRoot() const 89 { 90 return root_; 91 } SetRoot(GateRef root)92 void SetRoot(GateRef root) 93 { 94 root_ = root; 95 } 96 GetGlobalEnvCache()97 GateRef GetGlobalEnvCache() const 98 { 99 return globalEnv_; 100 } SetGlobalEnvCache(GateRef globalEnv)101 void SetGlobalEnvCache(GateRef globalEnv) 102 { 103 globalEnv_ = globalEnv; 104 } 105 chunk()106 Chunk* chunk() 107 { 108 return &chunk_; 109 } 110 GetMetaBuilder()111 GateMetaBuilder *GetMetaBuilder() 112 { 113 return &metaBuilder_; 114 } 115 116 GateRef GetStateRoot() const; 117 GateRef GetDependRoot() const; 118 GateRef GetArgRoot() const; 119 GateRef GetReturnRoot() const; 120 enum class ArgAccCond: uint8_t { 121 UNSTART, // argAcc_ not initialized 122 START, // argAcc_ initialized 123 CHANGED, // circuit changed after argAcc_ initialized 124 }; 125 // Check circuit is not changed while using argAcc_ 126 ArgAccCond checkArgAcc_ = ArgAccCond::UNSTART; 127 128 #define DECLARE_GATE_META(NAME, OP, R, S, D, V) \ 129 const GateMetaData* NAME() \ 130 { \ 131 return metaBuilder_.NAME(); \ 132 } 133 IMMUTABLE_META_DATA_CACHE_LIST(DECLARE_GATE_META) 134 #undef DECLARE_GATE_META 135 136 #define DECLARE_GATE_META(NAME, OP, R, S, D, V) \ 137 const GateMetaData* NAME(size_t value) \ 138 { \ 139 return metaBuilder_.NAME(value); \ 140 } GATE_META_DATA_LIST_WITH_SIZE(DECLARE_GATE_META)141 GATE_META_DATA_LIST_WITH_SIZE(DECLARE_GATE_META) 142 #undef DECLARE_GATE_META 143 144 #define DECLARE_GATE_META(NAME, OP, R, S, D, V) \ 145 const GateMetaData* NAME(uint64_t value) \ 146 { \ 147 return metaBuilder_.NAME(value); \ 148 } 149 GATE_META_DATA_LIST_WITH_ONE_PARAMETER(DECLARE_GATE_META) 150 #undef DECLARE_GATE_META 151 152 #define DECLARE_GATE_META(NAME, OP, R, S, D, V) \ 153 const GateMetaData* NAME(bool value) \ 154 { \ 155 return metaBuilder_.NAME(value); \ 156 } 157 GATE_META_DATA_LIST_WITH_BOOL(DECLARE_GATE_META) 158 #undef DECLARE_GATE_META 159 160 #define DECLARE_GATE_META_WITH_BOOL_VALUE_IN(NAME, OP, R, S, D, V) \ 161 const GateMetaData* NAME(size_t value, bool flag) \ 162 { \ 163 return metaBuilder_.NAME(value, flag); \ 164 } 165 GATE_META_DATA_LIST_WITH_BOOL_VALUE_IN(DECLARE_GATE_META_WITH_BOOL_VALUE_IN) 166 #undef DECLARE_GATE_META_WITH_BOOL_VALUE_IN 167 168 #define DECLARE_GATE_META(NAME, OP, R, S, D, V) \ 169 const GateMetaData* NAME(uint64_t value, uint64_t pcOffset) \ 170 { \ 171 return metaBuilder_.NAME(value, pcOffset); \ 172 } 173 GATE_META_DATA_LIST_WITH_PC_OFFSET(DECLARE_GATE_META) 174 #undef DECLARE_GATE_META 175 176 #define DECLARE_GATE_META_FOR_CALL(NAME, OP, R, S, D, V) \ 177 const GateMetaData* NAME(uint64_t value, uint64_t pcOffset, bool noGC) \ 178 { \ 179 return metaBuilder_.NAME(value, pcOffset, noGC); \ 180 } 181 GATE_META_DATA_LIST_FOR_CALL(DECLARE_GATE_META_FOR_CALL) 182 #undef DECLARE_GATE_META_FOR_CALL 183 184 #define DECLARE_GATE_META_FOR_NEW(NAME, OP, R, S, D, V) \ 185 const GateMetaData* NAME(uint64_t value, uint64_t pcOffset, \ 186 bool needPushArgv, bool isFastCall) \ 187 { \ 188 return metaBuilder_.NAME(value, pcOffset, needPushArgv, isFastCall); \ 189 } 190 GATE_META_DATA_LIST_FOR_NEW(DECLARE_GATE_META_FOR_NEW) 191 #undef DECLARE_GATE_META_FOR_NEW 192 193 #define DECLARE_GATE_META(NAME, OP, R, S, D, V) \ 194 const GateMetaData* NAME(uint64_t pcOffset) const \ 195 { \ 196 return metaBuilder_.NAME(pcOffset); \ 197 } 198 GATE_META_DATA_LIST_WITH_PC_OFFSET_FIXED_VALUE(DECLARE_GATE_META) 199 #undef DECLARE_GATE_META 200 201 const GateMetaData* Nop() 202 { 203 return metaBuilder_.Nop(); 204 } 205 JSBytecode(size_t valuesIn,uint32_t methodId,EcmaOpcode opcode,uint32_t pcOffset,uint32_t bcIndex,bool writable,bool hasFrameState)206 const GateMetaData* JSBytecode(size_t valuesIn, uint32_t methodId, EcmaOpcode opcode, 207 uint32_t pcOffset, uint32_t bcIndex, bool writable, bool hasFrameState) 208 { 209 GateFlags writableFlags = writable ? GateFlags::NONE_FLAG : GateFlags::NO_WRITE; 210 GateFlags frameStateFlags = hasFrameState ? GateFlags::HAS_FRAME_STATE : GateFlags::NONE_FLAG; 211 GateFlags flags = static_cast<GateFlags>(writableFlags | frameStateFlags); 212 return metaBuilder_.JSBytecode(valuesIn, methodId, opcode, pcOffset, bcIndex, flags); 213 } 214 DeadGate()215 GateRef DeadGate() 216 { 217 if (dead_ == NullGate()) { 218 dead_ = NewGate(Dead(), MachineType::NOVALUE, GateType::Empty()); 219 } 220 return dead_; 221 } 222 GetMaxGateId()223 size_t GetMaxGateId() const 224 { 225 ASSERT(gateCount_ != 0); 226 return static_cast<size_t>(gateCount_ - 1); 227 } 228 IsOptimizedOrFastJit()229 bool IsOptimizedOrFastJit() const 230 { 231 return IsOptimizedJSFunctionFrame() || IsFastJitFunctionFrame(); 232 } 233 IsOptimizedJSFunctionFrame()234 bool IsOptimizedJSFunctionFrame() const 235 { 236 return frameType_ == FrameType::OPTIMIZED_JS_FUNCTION_FRAME 237 || frameType_ == FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME; 238 } 239 IsFastJitFunctionFrame()240 bool IsFastJitFunctionFrame() const 241 { 242 return frameType_ == FrameType::FASTJIT_FUNCTION_FRAME 243 || frameType_ == FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME; 244 } 245 246 bool GetDebugInfo(GateRef g, size_t &index) const; 247 IsOsr()248 bool IsOsr() const 249 { 250 return isOsr_; 251 } 252 SetIsOsr()253 void SetIsOsr() 254 { 255 isOsr_ = true; 256 } 257 258 #ifndef NDEBUG 259 class ScopedComment { 260 public: 261 explicit ScopedComment(std::string &&str, std::string_view *comment); 262 ~ScopedComment()263 ~ScopedComment() 264 { 265 *comment_ = old_; 266 } 267 private: 268 std::string_view old_; 269 std::string str_; 270 std::string_view *comment_; 271 }; 272 273 ScopedComment VisitGateBegin(GateRef visitedGate); 274 ScopedComment CommentBegin(std::string &&str); 275 #else VisitGateBegin(GateRef visitedGate)276 size_t VisitGateBegin([[maybe_unused]] GateRef visitedGate) 277 { 278 return 0; 279 } CommentBegin(GateRef visitedGate)280 size_t CommentBegin([[maybe_unused]] GateRef visitedGate) 281 { 282 return 0; 283 } 284 #endif 285 286 private: 287 static const size_t CIRCUIT_SPACE = 1U << 30U; // 1GB 288 public: 289 void Print(GateRef gate) const; 290 bool AddComment(GateRef g, std::string &&str); 291 std::string_view GetComment(GateRef gate) const; 292 293 private: 294 GateType GetGateType(GateRef gate) const; 295 GateRef GetGateRef(const Gate *gate) const; 296 MachineType GetMachineType(GateRef gate) const; 297 void SetMark(GateRef gate, MarkCode mark) const; 298 OpCode GetOpCode(GateRef gate) const; 299 void SetMachineType(GateRef gate, MachineType machineType); 300 void SetGateType(GateRef gate, GateType type); 301 GateId GetId(GateRef gate) const; 302 void DeleteGate(GateRef gate); 303 void DecreaseIn(GateRef gate, size_t idx); 304 305 MarkCode GetMark(GateRef gate) const; 306 void DeleteIn(GateRef gate, size_t idx); 307 void ModifyIn(GateRef gate, size_t idx, GateRef in); 308 void NewIn(GateRef gate, size_t idx, GateRef in); 309 std::vector<GateRef> GetOutVector(GateRef gate) const; 310 bool IsFirstOutNull(GateRef gate) const; 311 bool IsInGateNull(GateRef gate, size_t idx) const; 312 GateRef GetIn(GateRef gate, size_t idx) const; 313 bool IsValueSelector(GateRef gate) const; 314 bool IsSelector(GateRef gate) const; 315 bool IsControlCase(GateRef gate) const; 316 bool IsLoopHead(GateRef gate) const; 317 void ResetAllGateTimeStamps() const; 318 uint8_t *AllocateSpace(size_t gateSize); 319 Gate *AllocateGateSpace(size_t numIns); 320 size_t GetCircuitDataSize() const; 321 const void *GetSpaceDataStartPtrConst() const; 322 const void *GetSpaceDataEndPtrConst() const; 323 const uint8_t *GetDataPtrConst(size_t offset) const; 324 uint8_t *GetDataPtr(size_t offset); 325 Gate *LoadGatePtr(GateRef shift); 326 const Gate *LoadGatePtrConst(GateRef shift) const; GetMetaData(GateRef gate)327 const GateMetaData *GetMetaData(GateRef gate) const 328 { 329 return LoadGatePtrConst(gate)->GetMetaData(); 330 } 331 #ifndef NDEBUG GetGateRefById(size_t id)332 GateRef GetGateRefById(size_t id) const 333 { 334 if (id > allGates_.size()) { 335 return NullGate(); 336 } 337 return allGates_[id]; 338 } 339 #endif 340 341 private: 342 void* space_ {nullptr}; 343 size_t circuitSize_ {0}; 344 size_t gateCount_ {0}; 345 TimeStamp time_; 346 std::map<std::tuple<MachineType, BitField, GateType>, GateRef> constantCache_ {}; 347 std::unordered_map<std::uint32_t, GateRef> heapConstantCache_; 348 std::map<std::pair<BitField, GateRef>, GateRef> constantDataCache_ {}; 349 std::map<GateRef, GateRef> initialEnvCache_ {}; 350 panda::ecmascript::FrameType frameType_ {FrameType::OPTIMIZED_FRAME}; 351 bool isArch64_ { false }; 352 bool isOsr_ { false }; 353 354 Chunk chunk_; 355 GateRef root_ { NullGate() }; 356 GateRef dead_ { NullGate() }; 357 GateRef globalEnv_ {NullGate()}; 358 GateRef replaceable_ {NullGate()}; 359 GateMetaBuilder metaBuilder_; 360 ChunkMap<GateRef, size_t> gateToDInfo_; 361 DebugInfo* debugInfo_ {nullptr}; 362 std::unique_ptr<ArgumentAccessor> argAcc_; 363 #ifndef NDEBUG 364 ChunkVector<GateRef> allGates_; 365 std::string_view currentComment_ {}; 366 #endif 367 368 friend class GateAccessor; 369 friend class ConstGateAccessor; 370 friend class Verifier; 371 }; 372 } // namespace panda::ecmascript::kungfu 373 374 #endif // ECMASCRIPT_COMPILER_CIRCUIT_H 375