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