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)), ¤tComment_);
438 }
439
CommentBegin(std::string && str)440 Circuit::ScopedComment Circuit::CommentBegin(std::string &&str)
441 {
442 return ScopedComment(std::move(str), ¤tComment_);
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