• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "ecmascript/compiler/circuit.h"
17 #include "ecmascript/compiler/debug_info.h"
18 #include "ecmascript/compiler/gate_accessor.h"
19 
20 namespace panda::ecmascript::kungfu {
Circuit(NativeAreaAllocator * allocator,DebugInfo * debugInfo,const char * funcName,bool isArch64,panda::ecmascript::FrameType type)21 Circuit::Circuit(NativeAreaAllocator* allocator, DebugInfo* debugInfo, const char* funcName,
22                  bool isArch64, panda::ecmascript::FrameType type)
23     : circuitSize_(0),
24       gateCount_(0),
25       time_(1),
26       frameType_(type),
27       isArch64_(isArch64),
28       chunk_(allocator),
29       root_(Circuit::NullGate()),
30       metaBuilder_(chunk()),
31       gateToDInfo_(chunk()),
32       debugInfo_(debugInfo)
33 #ifndef NDEBUG
34       , allGates_(chunk())
35 #endif
36 {
37     if (funcName != nullptr && debugInfo_ != nullptr && debugInfo_->IsEnable()) {
38         debugInfo_->AddFuncDebugInfo(funcName);
39     }
40     space_ = panda::ecmascript::PageMap(CIRCUIT_SPACE, PAGE_PROT_READWRITE).GetMem();
41     InitRoot();
42 }
43 
~Circuit()44 Circuit::~Circuit()
45 {
46     panda::ecmascript::PageUnmap(MemMap(space_, CIRCUIT_SPACE));
47     debugInfo_ = nullptr;
48     space_ = nullptr;
49 }
50 
InitRoot()51 void Circuit::InitRoot()
52 {
53     root_ = NewGate(metaBuilder_.CircuitRoot(), MachineType::NOVALUE, {}, GateType::Empty());
54     NewGate(metaBuilder_.StateEntry(), MachineType::NOVALUE, { root_ }, GateType::Empty());
55     NewGate(metaBuilder_.DependEntry(), MachineType::NOVALUE, { root_ }, GateType::Empty());
56     NewGate(metaBuilder_.ReturnList(), MachineType::NOVALUE, { root_ }, GateType::Empty());
57     NewGate(metaBuilder_.ArgList(), MachineType::NOVALUE, { root_ }, GateType::Empty());
58 }
59 
AllocateSpace(size_t gateSize)60 uint8_t *Circuit::AllocateSpace(size_t gateSize)
61 {
62     circuitSize_ += gateSize;
63     if (circuitSize_ > CIRCUIT_SPACE) {
64         return nullptr;  // abort compilation
65     }
66     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
67     return GetDataPtr(circuitSize_ - gateSize);
68 }
69 
AllocateGateSpace(size_t numIns)70 Gate *Circuit::AllocateGateSpace(size_t numIns)
71 {
72     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
73     return reinterpret_cast<Gate *>(AllocateSpace(Gate::GetGateSize(numIns)) + Gate::GetOutListSize(numIns));
74 }
75 
AddComment(GateRef g,std::string && str)76 bool Circuit::AddComment(GateRef g, std::string &&str)
77 {
78     if (debugInfo_ == nullptr) {
79         return false;
80     }
81     if (!debugInfo_->IsEnable()) {
82         return false;
83     }
84     auto it = gateToDInfo_.find(g);
85     if (it == gateToDInfo_.end()) {
86         size_t index = debugInfo_->AddComment(std::move(str));
87         gateToDInfo_[g] = index;
88     } else {
89         debugInfo_->AppendComment(it->second, std::move(str));
90     }
91     return true;
92 }
93 
GetComment(GateRef gate) const94 std::string_view Circuit::GetComment(GateRef gate) const
95 {
96     if (debugInfo_ == nullptr || !debugInfo_->IsEnable()) {
97         return "";
98     }
99     size_t index;
100     if (!GetDebugInfo(gate, index)) {
101         return "";
102     }
103     return debugInfo_->GetComment(index);
104 }
105 
GetDebugInfo(GateRef g,size_t & index) const106 bool Circuit::GetDebugInfo(GateRef g, size_t &index) const
107 {
108     auto it = gateToDInfo_.find(g);
109     if (it != gateToDInfo_.end()) {
110         index = it->second;
111         return true;
112     } else {
113         return false;
114     }
115 }
116 
117 // NOLINTNEXTLINE(modernize-avoid-c-arrays)
NewGate(const GateMetaData * meta,MachineType machineType,size_t numIns,const GateRef inList[],GateType type,const char * comment)118 GateRef Circuit::NewGate(const GateMetaData *meta, MachineType machineType, size_t numIns,
119                          const GateRef inList[], GateType type, const char* comment)
120 {
121 #ifndef NDEBUG
122     if (numIns != meta->GetNumIns()) {
123         LOG_COMPILER(FATAL) << "Invalid input list!"
124                             << " op=" << meta->GetOpCode()
125                             << " expected_num_in=" << meta->GetNumIns() << " actual_num_in=" << numIns;
126         UNREACHABLE();
127     }
128 #endif
129     std::vector<Gate *> inPtrList(numIns);
130     auto gateSpace = AllocateGateSpace(numIns);
131     for (size_t idx = 0; idx < numIns; idx++) {
132         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
133         inPtrList[idx] = (inList[idx] == Circuit::NullGate()) ? nullptr : LoadGatePtr(inList[idx]);
134     }
135     auto newGate = new (gateSpace) Gate(meta, gateCount_++, inPtrList.data(), machineType, type);
136 #ifndef NDEBUG
137     allGates_.push_back(GetGateRef(newGate));
138 #endif
139     GateRef result = GetGateRef(newGate);
140     if (comment != nullptr) {
141         AddComment(result, std::string(comment));
142     }
143 #ifndef NDEBUG
144     if (UNLIKELY(debugInfo_ != nullptr && !currentComment_.empty())) {
145         AddComment(result, std::string(currentComment_));
146     }
147 #endif
148     return result;
149 }
150 
NewGate(const GateMetaData * meta,const std::vector<GateRef> & inList,const char * comment)151 GateRef Circuit::NewGate(const GateMetaData *meta, const std::vector<GateRef> &inList, const char* comment)
152 {
153     return NewGate(meta, MachineType::NOVALUE, inList.size(), inList.data(), GateType::Empty(), comment);
154 }
155 
NewGate(const GateMetaData * meta,MachineType machineType,const std::initializer_list<GateRef> & args,GateType type,const char * comment)156 GateRef Circuit::NewGate(const GateMetaData *meta, MachineType machineType,
157     const std::initializer_list<GateRef>& args, GateType type, const char* comment)
158 {
159     return NewGate(meta, machineType, args.size(), args.begin(), type, comment);
160 }
161 
NewGate(const GateMetaData * meta,MachineType machineType,const std::vector<GateRef> & inList,GateType type,const char * comment)162 GateRef Circuit::NewGate(const GateMetaData *meta, MachineType machineType,
163     const std::vector<GateRef>& inList, GateType type, const char* comment)
164 {
165     return NewGate(meta, machineType, inList.size(), inList.data(), type, comment);
166 }
167 
NewGate(const GateMetaData * meta,MachineType machineType,GateType type,const char * comment)168 GateRef Circuit::NewGate(const GateMetaData *meta, MachineType machineType, GateType type, const char* comment)
169 {
170     return NewGate(meta, machineType, {}, type, comment);
171 }
172 
PrintAllGates() const173 void Circuit::PrintAllGates() const
174 {
175     std::vector<GateRef> gateList;
176     GetAllGates(gateList);
177     for (const auto &gate : gateList) {
178         LoadGatePtrConst(gate)->Print();
179     }
180 }
181 
PrintAllGatesWithBytecode() const182 void Circuit::PrintAllGatesWithBytecode() const
183 {
184     std::vector<GateRef> gateList;
185     GetAllGates(gateList);
186     for (const auto &gate : gateList) {
187         LoadGatePtrConst(gate)->PrintWithBytecode(GetComment(gate));
188     }
189 }
190 
GetAllGates(std::vector<GateRef> & gateList) const191 void Circuit::GetAllGates(std::vector<GateRef>& gateList) const
192 {
193     gateList.clear();
194     for (size_t out = 0; out < circuitSize_;
195         out += Gate::GetGateSize(reinterpret_cast<const Out *>(LoadGatePtrConst(GateRef(out)))->GetIndex() + 1)) {
196         auto gatePtr = reinterpret_cast<const Out *>(LoadGatePtrConst(GateRef(out)))->GetGateConst();
197         if (!gatePtr->GetMetaData()->IsNop()) {
198             gateList.push_back(GetGateRef(gatePtr));
199         }
200     }
201 }
202 
GetGateRef(const Gate * gate) const203 GateRef Circuit::GetGateRef(const Gate *gate) const
204 {
205     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
206     return static_cast<GateRef>(reinterpret_cast<const uint8_t *>(gate) - GetDataPtrConst(0));
207 }
208 
LoadGatePtr(GateRef shift)209 Gate *Circuit::LoadGatePtr(GateRef shift)
210 {
211     ASSERT(shift != Circuit::NullGate());
212     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
213     return reinterpret_cast<Gate *>(GetDataPtr(shift));
214 }
215 
LoadGatePtrConst(GateRef shift) const216 const Gate *Circuit::LoadGatePtrConst(GateRef shift) const
217 {
218     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
219     return reinterpret_cast<const Gate *>(GetDataPtrConst(shift));
220 }
221 
AdvanceTime() const222 void Circuit::AdvanceTime() const
223 {
224     auto &curTime = const_cast<TimeStamp &>(time_);
225     curTime++;
226     if (curTime == 0) {
227         curTime = 1;
228         ResetAllGateTimeStamps();
229     }
230 }
231 
ResetAllGateTimeStamps() const232 void Circuit::ResetAllGateTimeStamps() const
233 {
234     std::vector<GateRef> gateList;
235     GetAllGates(gateList);
236     for (auto &gate : gateList) {
237         const_cast<Gate *>(LoadGatePtrConst(gate))->SetMark(MarkCode::NO_MARK, 0);
238     }
239 }
240 
GetTime() const241 TimeStamp Circuit::GetTime() const
242 {
243     return time_;
244 }
245 
GetMark(GateRef gate) const246 MarkCode Circuit::GetMark(GateRef gate) const
247 {
248     return LoadGatePtrConst(gate)->GetMark(GetTime());
249 }
250 
SetMark(GateRef gate,MarkCode mark) const251 void Circuit::SetMark(GateRef gate, MarkCode mark) const
252 {
253     const_cast<Gate *>(LoadGatePtrConst(gate))->SetMark(mark, GetTime());
254 }
255 
Verify(GateRef gate,const std::string & methodName) const256 void Circuit::Verify(GateRef gate, const std::string& methodName) const
257 {
258     LoadGatePtrConst(gate)->Verify(IsArch64(), methodName);
259 }
260 
NullGate()261 GateRef Circuit::NullGate()
262 {
263     return Gate::InvalidGateRef;
264 }
265 
IsLoopHead(GateRef gate) const266 bool Circuit::IsLoopHead(GateRef gate) const
267 {
268     if (gate != NullGate()) {
269         const Gate *curGate = LoadGatePtrConst(gate);
270         return curGate->GetMetaData()->IsLoopHead();
271     }
272     return false;
273 }
274 
IsControlCase(GateRef gate) const275 bool Circuit::IsControlCase(GateRef gate) const
276 {
277     if (gate != NullGate()) {
278         const Gate *curGate = LoadGatePtrConst(gate);
279         return curGate->GetMetaData()->IsControlCase();
280     }
281     return false;
282 }
283 
IsValueSelector(GateRef gate) const284 bool Circuit::IsValueSelector(GateRef gate) const
285 {
286     if (gate != NullGate()) {
287         const Gate *curGate = LoadGatePtrConst(gate);
288         return curGate->GetOpCode() == OpCode::VALUE_SELECTOR;
289     }
290     return false;
291 }
292 
IsSelector(GateRef gate) const293 bool Circuit::IsSelector(GateRef gate) const
294 {
295     if (gate != NullGate()) {
296         const Gate *curGate = LoadGatePtrConst(gate);
297         OpCode op = curGate->GetOpCode();
298         return (op == OpCode::VALUE_SELECTOR) || (op == OpCode::DEPEND_SELECTOR);
299     }
300     return false;
301 }
302 
GetIn(GateRef gate,size_t idx) const303 GateRef Circuit::GetIn(GateRef gate, size_t idx) const
304 {
305     ASSERT(idx < LoadGatePtrConst(gate)->GetNumIns());
306     if (IsInGateNull(gate, idx)) {
307         return NullGate();
308     }
309     const Gate *curGate = LoadGatePtrConst(gate);
310     return GetGateRef(curGate->GetInGateConst(idx));
311 }
312 
IsInGateNull(GateRef gate,size_t idx) const313 bool Circuit::IsInGateNull(GateRef gate, size_t idx) const
314 {
315     const Gate *curGate = LoadGatePtrConst(gate);
316     return curGate->GetInConst(idx)->IsGateNull();
317 }
318 
IsFirstOutNull(GateRef gate) const319 bool Circuit::IsFirstOutNull(GateRef gate) const
320 {
321     const Gate *curGate = LoadGatePtrConst(gate);
322     return curGate->IsFirstOutNull();
323 }
324 
GetOutVector(GateRef gate) const325 std::vector<GateRef> Circuit::GetOutVector(GateRef gate) const
326 {
327     std::vector<GateRef> result;
328     const Gate *curGate = LoadGatePtrConst(gate);
329     if (!curGate->IsFirstOutNull()) {
330         const Out *curOut = curGate->GetFirstOutConst();
331         result.push_back(GetGateRef(curOut->GetGateConst()));
332         while (!curOut->IsNextOutNull()) {
333             curOut = curOut->GetNextOutConst();
334             result.push_back(GetGateRef(curOut->GetGateConst()));
335         }
336     }
337     return result;
338 }
339 
NewIn(GateRef gate,size_t idx,GateRef in)340 void Circuit::NewIn(GateRef gate, size_t idx, GateRef in)
341 {
342 #ifndef NDEBUG
343     ASSERT(idx < LoadGatePtrConst(gate)->GetNumIns());
344     ASSERT(Circuit::IsInGateNull(gate, idx));
345 #endif
346     LoadGatePtr(gate)->NewIn(idx, LoadGatePtr(in));
347 }
348 
ModifyIn(GateRef gate,size_t idx,GateRef in)349 void Circuit::ModifyIn(GateRef gate, size_t idx, GateRef in)
350 {
351 #ifndef NDEBUG
352     ASSERT(idx < LoadGatePtrConst(gate)->GetNumIns());
353     ASSERT(!Circuit::IsInGateNull(gate, idx) || (GetOpCode(gate) == OpCode::SAVE_REGISTER));
354 #endif
355     LoadGatePtr(gate)->ModifyIn(idx, LoadGatePtr(in));
356 }
357 
DeleteIn(GateRef gate,size_t idx)358 void Circuit::DeleteIn(GateRef gate, size_t idx)
359 {
360     ASSERT(idx < LoadGatePtrConst(gate)->GetNumIns());
361     ASSERT(!Circuit::IsInGateNull(gate, idx));
362     LoadGatePtr(gate)->DeleteIn(idx);
363 }
364 
DeleteGate(GateRef gate)365 void Circuit::DeleteGate(GateRef gate)
366 {
367     // constant in constant cache, dont delete it.
368     if (GetOpCode(gate) != OpCode::CONSTANT) {
369         LoadGatePtr(gate)->DeleteGate();
370         LoadGatePtr(gate)->SetMetaData(Nop());
371     }
372 }
373 
DecreaseIn(GateRef gate,size_t idx)374 void Circuit::DecreaseIn(GateRef gate, size_t idx)
375 {
376     auto numIns = LoadGatePtrConst(gate)->GetNumIns();
377     ASSERT(numIns > 0);
378     for (size_t i = idx; i < numIns - 1; i++) {
379         ModifyIn(gate, i, GetIn(gate, i + 1));
380     }
381     DeleteIn(gate, numIns - 1);
382     GateMetaData *meta = const_cast<GateMetaData *>(
383             LoadGatePtr(gate)->GetMetaData());
384     if (meta->GetKind() == GateMetaData::Kind::MUTABLE_WITH_SIZE) {
385         meta->DecreaseIn(idx);
386     } else {
387         meta = metaBuilder_.NewGateMetaData(meta);
388         meta->DecreaseIn(idx);
389         LoadGatePtr(gate)->SetMetaData(meta);
390     }
391 }
392 
SetGateType(GateRef gate,GateType type)393 void Circuit::SetGateType(GateRef gate, GateType type)
394 {
395     LoadGatePtr(gate)->SetGateType(type);
396 }
397 
SetMachineType(GateRef gate,MachineType machineType)398 void Circuit::SetMachineType(GateRef gate, MachineType machineType)
399 {
400     LoadGatePtr(gate)->SetMachineType(machineType);
401 }
402 
GetGateType(GateRef gate) const403 GateType Circuit::GetGateType(GateRef gate) const
404 {
405     return LoadGatePtrConst(gate)->GetGateType();
406 }
407 
GetMachineType(GateRef gate) const408 MachineType Circuit::GetMachineType(GateRef gate) const
409 {
410     return LoadGatePtrConst(gate)->GetMachineType();
411 }
412 
GetOpCode(GateRef gate) const413 OpCode Circuit::GetOpCode(GateRef gate) const
414 {
415     return LoadGatePtrConst(gate)->GetOpCode();
416 }
417 
GetId(GateRef gate) const418 GateId Circuit::GetId(GateRef gate) const
419 {
420     return LoadGatePtrConst(gate)->GetId();
421 }
422 
423 #ifndef NDEBUG
ScopedComment(std::string && str,std::string_view * comment)424 Circuit::ScopedComment::ScopedComment(std::string &&str, std::string_view *comment)
425     : old_(*comment), comment_(comment)
426 {
427     if (comment->empty()) {
428         str_ = std::move(str);
429     } else {
430         str_ = std::string{*comment} + " " + std::move(str);
431     }
432     *comment_ = {str_};
433 }
434 
VisitGateBegin(GateRef visitedGate)435 Circuit::ScopedComment Circuit::VisitGateBegin(GateRef visitedGate)
436 {
437     return ScopedComment("old " + std::to_string(GetId(visitedGate)), &currentComment_);
438 }
439 
CommentBegin(std::string && str)440 Circuit::ScopedComment Circuit::CommentBegin(std::string &&str)
441 {
442     return ScopedComment(std::move(str), &currentComment_);
443 }
444 #endif
445 
Print(GateRef gate) const446 void Circuit::Print(GateRef gate) const
447 {
448     LoadGatePtrConst(gate)->Print();
449 }
450 
GetCircuitDataSize() const451 size_t Circuit::GetCircuitDataSize() const
452 {
453     return circuitSize_;
454 }
455 
GetSpaceDataStartPtrConst() const456 const void *Circuit::GetSpaceDataStartPtrConst() const
457 {
458     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
459     return GetDataPtrConst(0);
460 }
461 
GetSpaceDataEndPtrConst() const462 const void *Circuit::GetSpaceDataEndPtrConst() const
463 {
464     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
465     return GetDataPtrConst(circuitSize_);
466 }
467 
GetDataPtrConst(size_t offset) const468 const uint8_t *Circuit::GetDataPtrConst(size_t offset) const
469 {
470     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
471     return static_cast<uint8_t *>(space_) + offset;
472 }
473 
GetDataPtr(size_t offset)474 uint8_t *Circuit::GetDataPtr(size_t offset)
475 {
476     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
477     return static_cast<uint8_t *>(space_) + offset;
478 }
479 
GetFrameType() const480 panda::ecmascript::FrameType Circuit::GetFrameType() const
481 {
482     return frameType_;
483 }
484 
SetFrameType(panda::ecmascript::FrameType type)485 void Circuit::SetFrameType(panda::ecmascript::FrameType type)
486 {
487     frameType_ = type;
488 }
489 
GetConstantGate(MachineType machineType,uint64_t value,GateType type)490 GateRef Circuit::GetConstantGate(MachineType machineType, uint64_t value,
491                                  GateType type)
492 {
493     auto search = constantCache_.find({machineType, value, type});
494     if (search != constantCache_.end()) {
495         return search->second;
496     }
497     auto gate = NewGate(metaBuilder_.Constant(value), machineType, type);
498     constantCache_[{machineType, value, type}] = gate;
499     return gate;
500 }
501 
GetConstantGateWithoutCache(MachineType machineType,uint64_t value,GateType type)502 GateRef Circuit::GetConstantGateWithoutCache(MachineType machineType, uint64_t value, GateType type)
503 {
504     auto gate = NewGate(metaBuilder_.Constant(value), machineType, type);
505     return gate;
506 }
507 
ClearConstantCache(MachineType machineType,uint64_t value,GateType type)508 void Circuit::ClearConstantCache(MachineType machineType, uint64_t value, GateType type)
509 {
510     auto search = constantCache_.find({machineType, value, type});
511     if (search != constantCache_.end()) {
512         constantCache_.erase(search);
513     }
514 }
515 
GetConstantStringGate(MachineType machineType,std::string_view str,GateType type)516 GateRef Circuit::GetConstantStringGate(MachineType machineType, std::string_view str,
517                                        GateType type)
518 {
519     auto gate = NewGate(metaBuilder_.ConstString(str), machineType, type);
520     return gate;
521 }
522 
GetInitialEnvGate(GateRef depend,GateRef jsFunc)523 GateRef Circuit::GetInitialEnvGate(GateRef depend, GateRef jsFunc)
524 {
525     auto search = initialEnvCache_.find(jsFunc);
526     if (search != initialEnvCache_.end()) {
527         return initialEnvCache_.at(jsFunc);
528     }
529     auto gate = NewGate(GetEnv(), MachineType::I64, {depend, jsFunc}, GateType::AnyType());
530     initialEnvCache_[jsFunc] = gate;
531     return gate;
532 }
533 
NewArg(MachineType machineType,size_t index,GateType type,GateRef argRoot)534 GateRef Circuit::NewArg(MachineType machineType, size_t index,
535                         GateType type, GateRef argRoot)
536 {
537     return NewGate(metaBuilder_.Arg(index), machineType, { argRoot }, type);
538 }
539 
GetGateCount() const540 size_t Circuit::GetGateCount() const
541 {
542     return gateCount_;
543 }
544 
GetStateRoot() const545 GateRef Circuit::GetStateRoot() const
546 {
547     const GateAccessor acc(const_cast<Circuit*>(this));
548     return acc.GetStateRoot();
549 }
550 
GetDependRoot() const551 GateRef Circuit::GetDependRoot() const
552 {
553     const GateAccessor acc(const_cast<Circuit*>(this));
554     return acc.GetDependRoot();
555 }
556 
GetArgRoot() const557 GateRef Circuit::GetArgRoot() const
558 {
559     const GateAccessor acc(const_cast<Circuit*>(this));
560     return acc.GetArgRoot();
561 }
562 
GetReturnRoot() const563 GateRef Circuit::GetReturnRoot() const
564 {
565     const GateAccessor acc(const_cast<Circuit*>(this));
566     return acc.GetReturnRoot();
567 }
568 }  // namespace panda::ecmascript::kungfu
569