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,const char * str)79 bool Circuit::AddComment(GateRef g, const char* str)
80 {
81 ASSERT(debugInfo_ != nullptr);
82 if (!debugInfo_->IsEnable()) {
83 return false;
84 }
85 auto it = gateToDInfo_.find(g);
86 if (it == gateToDInfo_.end()) {
87 ASSERT(debugInfo_ != nullptr);
88 size_t index = debugInfo_->AddComment(str);
89 gateToDInfo_[g] = index;
90 return true;
91 }
92 return false;
93 }
94
GetDebugInfo(GateRef g,size_t & index) const95 bool Circuit::GetDebugInfo(GateRef g, size_t &index) const
96 {
97 auto it = gateToDInfo_.find(g);
98 if (it != gateToDInfo_.end()) {
99 index = it->second;
100 return true;
101 } else {
102 return false;
103 }
104 }
105
106 // NOLINTNEXTLINE(modernize-avoid-c-arrays)
NewGate(const GateMetaData * meta,MachineType machineType,size_t numIns,const GateRef inList[],GateType type,const char * comment)107 GateRef Circuit::NewGate(const GateMetaData *meta, MachineType machineType, size_t numIns,
108 const GateRef inList[], GateType type, const char* comment)
109 {
110 #ifndef NDEBUG
111 if (numIns != meta->GetNumIns()) {
112 LOG_COMPILER(FATAL) << "Invalid input list!"
113 << " op=" << meta->GetOpCode()
114 << " expected_num_in=" << meta->GetNumIns() << " actual_num_in=" << numIns;
115 UNREACHABLE();
116 }
117 #endif
118 std::vector<Gate *> inPtrList(numIns);
119 auto gateSpace = AllocateGateSpace(numIns);
120 for (size_t idx = 0; idx < numIns; idx++) {
121 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
122 inPtrList[idx] = (inList[idx] == Circuit::NullGate()) ? nullptr : LoadGatePtr(inList[idx]);
123 }
124 auto newGate = new (gateSpace) Gate(meta, gateCount_++, inPtrList.data(), machineType, type);
125 #ifndef NDEBUG
126 allGates_.push_back(GetGateRef(newGate));
127 #endif
128 GateRef result = GetGateRef(newGate);
129 if (comment != nullptr) {
130 AddComment(result, comment);
131 }
132 return result;
133 }
134
NewGate(const GateMetaData * meta,const std::vector<GateRef> & inList,const char * comment)135 GateRef Circuit::NewGate(const GateMetaData *meta, const std::vector<GateRef> &inList, const char* comment)
136 {
137 return NewGate(meta, MachineType::NOVALUE, inList.size(), inList.data(), GateType::Empty(), comment);
138 }
139
NewGate(const GateMetaData * meta,MachineType machineType,const std::initializer_list<GateRef> & args,GateType type,const char * comment)140 GateRef Circuit::NewGate(const GateMetaData *meta, MachineType machineType,
141 const std::initializer_list<GateRef>& args, GateType type, const char* comment)
142 {
143 return NewGate(meta, machineType, args.size(), args.begin(), type, comment);
144 }
145
NewGate(const GateMetaData * meta,MachineType machineType,const std::vector<GateRef> & inList,GateType type,const char * comment)146 GateRef Circuit::NewGate(const GateMetaData *meta, MachineType machineType,
147 const std::vector<GateRef>& inList, GateType type, const char* comment)
148 {
149 return NewGate(meta, machineType, inList.size(), inList.data(), type, comment);
150 }
151
NewGate(const GateMetaData * meta,MachineType machineType,GateType type,const char * comment)152 GateRef Circuit::NewGate(const GateMetaData *meta, MachineType machineType, GateType type, const char* comment)
153 {
154 return NewGate(meta, machineType, {}, type, comment);
155 }
156
PrintAllGates() const157 void Circuit::PrintAllGates() const
158 {
159 std::vector<GateRef> gateList;
160 GetAllGates(gateList);
161 for (const auto &gate : gateList) {
162 LoadGatePtrConst(gate)->Print();
163 }
164 }
165
PrintAllGatesWithBytecode() const166 void Circuit::PrintAllGatesWithBytecode() const
167 {
168 std::vector<GateRef> gateList;
169 GetAllGates(gateList);
170 for (const auto &gate : gateList) {
171 LoadGatePtrConst(gate)->PrintWithBytecode();
172 }
173 }
174
GetAllGates(std::vector<GateRef> & gateList) const175 void Circuit::GetAllGates(std::vector<GateRef>& gateList) const
176 {
177 gateList.clear();
178 for (size_t out = 0; out < circuitSize_;
179 out += Gate::GetGateSize(reinterpret_cast<const Out *>(LoadGatePtrConst(GateRef(out)))->GetIndex() + 1)) {
180 auto gatePtr = reinterpret_cast<const Out *>(LoadGatePtrConst(GateRef(out)))->GetGateConst();
181 if (!gatePtr->GetMetaData()->IsNop()) {
182 gateList.push_back(GetGateRef(gatePtr));
183 }
184 }
185 }
186
GetGateRef(const Gate * gate) const187 GateRef Circuit::GetGateRef(const Gate *gate) const
188 {
189 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
190 return static_cast<GateRef>(reinterpret_cast<const uint8_t *>(gate) - GetDataPtrConst(0));
191 }
192
LoadGatePtr(GateRef shift)193 Gate *Circuit::LoadGatePtr(GateRef shift)
194 {
195 ASSERT(shift != Circuit::NullGate());
196 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
197 return reinterpret_cast<Gate *>(GetDataPtr(shift));
198 }
199
LoadGatePtrConst(GateRef shift) const200 const Gate *Circuit::LoadGatePtrConst(GateRef shift) const
201 {
202 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
203 return reinterpret_cast<const Gate *>(GetDataPtrConst(shift));
204 }
205
AdvanceTime() const206 void Circuit::AdvanceTime() const
207 {
208 auto &curTime = const_cast<TimeStamp &>(time_);
209 curTime++;
210 if (curTime == 0) {
211 curTime = 1;
212 ResetAllGateTimeStamps();
213 }
214 }
215
ResetAllGateTimeStamps() const216 void Circuit::ResetAllGateTimeStamps() const
217 {
218 std::vector<GateRef> gateList;
219 GetAllGates(gateList);
220 for (auto &gate : gateList) {
221 const_cast<Gate *>(LoadGatePtrConst(gate))->SetMark(MarkCode::NO_MARK, 0);
222 }
223 }
224
GetTime() const225 TimeStamp Circuit::GetTime() const
226 {
227 return time_;
228 }
229
GetMark(GateRef gate) const230 MarkCode Circuit::GetMark(GateRef gate) const
231 {
232 return LoadGatePtrConst(gate)->GetMark(GetTime());
233 }
234
SetMark(GateRef gate,MarkCode mark) const235 void Circuit::SetMark(GateRef gate, MarkCode mark) const
236 {
237 const_cast<Gate *>(LoadGatePtrConst(gate))->SetMark(mark, GetTime());
238 }
239
Verify(GateRef gate) const240 void Circuit::Verify(GateRef gate) const
241 {
242 LoadGatePtrConst(gate)->Verify(IsArch64());
243 }
244
NullGate()245 GateRef Circuit::NullGate()
246 {
247 return Gate::InvalidGateRef;
248 }
249
IsLoopHead(GateRef gate) const250 bool Circuit::IsLoopHead(GateRef gate) const
251 {
252 if (gate != NullGate()) {
253 const Gate *curGate = LoadGatePtrConst(gate);
254 return curGate->GetMetaData()->IsLoopHead();
255 }
256 return false;
257 }
258
IsControlCase(GateRef gate) const259 bool Circuit::IsControlCase(GateRef gate) const
260 {
261 if (gate != NullGate()) {
262 const Gate *curGate = LoadGatePtrConst(gate);
263 return curGate->GetMetaData()->IsControlCase();
264 }
265 return false;
266 }
267
IsValueSelector(GateRef gate) const268 bool Circuit::IsValueSelector(GateRef gate) const
269 {
270 if (gate != NullGate()) {
271 const Gate *curGate = LoadGatePtrConst(gate);
272 return curGate->GetOpCode() == OpCode::VALUE_SELECTOR;
273 }
274 return false;
275 }
276
IsSelector(GateRef gate) const277 bool Circuit::IsSelector(GateRef gate) const
278 {
279 if (gate != NullGate()) {
280 const Gate *curGate = LoadGatePtrConst(gate);
281 OpCode op = curGate->GetOpCode();
282 return (op == OpCode::VALUE_SELECTOR) || (op == OpCode::DEPEND_SELECTOR);
283 }
284 return false;
285 }
286
GetIn(GateRef gate,size_t idx) const287 GateRef Circuit::GetIn(GateRef gate, size_t idx) const
288 {
289 ASSERT(idx < LoadGatePtrConst(gate)->GetNumIns());
290 if (IsInGateNull(gate, idx)) {
291 return NullGate();
292 }
293 const Gate *curGate = LoadGatePtrConst(gate);
294 return GetGateRef(curGate->GetInGateConst(idx));
295 }
296
IsInGateNull(GateRef gate,size_t idx) const297 bool Circuit::IsInGateNull(GateRef gate, size_t idx) const
298 {
299 const Gate *curGate = LoadGatePtrConst(gate);
300 return curGate->GetInConst(idx)->IsGateNull();
301 }
302
IsFirstOutNull(GateRef gate) const303 bool Circuit::IsFirstOutNull(GateRef gate) const
304 {
305 const Gate *curGate = LoadGatePtrConst(gate);
306 return curGate->IsFirstOutNull();
307 }
308
GetOutVector(GateRef gate) const309 std::vector<GateRef> Circuit::GetOutVector(GateRef gate) const
310 {
311 std::vector<GateRef> result;
312 const Gate *curGate = LoadGatePtrConst(gate);
313 if (!curGate->IsFirstOutNull()) {
314 const Out *curOut = curGate->GetFirstOutConst();
315 result.push_back(GetGateRef(curOut->GetGateConst()));
316 while (!curOut->IsNextOutNull()) {
317 curOut = curOut->GetNextOutConst();
318 result.push_back(GetGateRef(curOut->GetGateConst()));
319 }
320 }
321 return result;
322 }
323
NewIn(GateRef gate,size_t idx,GateRef in)324 void Circuit::NewIn(GateRef gate, size_t idx, GateRef in)
325 {
326 #ifndef NDEBUG
327 ASSERT(idx < LoadGatePtrConst(gate)->GetNumIns());
328 ASSERT(Circuit::IsInGateNull(gate, idx));
329 #endif
330 LoadGatePtr(gate)->NewIn(idx, LoadGatePtr(in));
331 }
332
ModifyIn(GateRef gate,size_t idx,GateRef in)333 void Circuit::ModifyIn(GateRef gate, size_t idx, GateRef in)
334 {
335 #ifndef NDEBUG
336 ASSERT(idx < LoadGatePtrConst(gate)->GetNumIns());
337 ASSERT(!Circuit::IsInGateNull(gate, idx) || (GetOpCode(gate) == OpCode::SAVE_REGISTER));
338 #endif
339 LoadGatePtr(gate)->ModifyIn(idx, LoadGatePtr(in));
340 }
341
DeleteIn(GateRef gate,size_t idx)342 void Circuit::DeleteIn(GateRef gate, size_t idx)
343 {
344 ASSERT(idx < LoadGatePtrConst(gate)->GetNumIns());
345 ASSERT(!Circuit::IsInGateNull(gate, idx));
346 LoadGatePtr(gate)->DeleteIn(idx);
347 }
348
DeleteGate(GateRef gate)349 void Circuit::DeleteGate(GateRef gate)
350 {
351 // constant in constant cache, dont delete it.
352 if (GetOpCode(gate) != OpCode::CONSTANT) {
353 LoadGatePtr(gate)->DeleteGate();
354 LoadGatePtr(gate)->SetMetaData(Nop());
355 }
356 }
357
DecreaseIn(GateRef gate,size_t idx)358 void Circuit::DecreaseIn(GateRef gate, size_t idx)
359 {
360 auto numIns = LoadGatePtrConst(gate)->GetNumIns();
361 for (size_t i = idx; i < numIns - 1; i++) {
362 ModifyIn(gate, i, GetIn(gate, i + 1));
363 }
364 DeleteIn(gate, numIns - 1);
365 GateMetaData *meta = const_cast<GateMetaData *>(
366 LoadGatePtr(gate)->GetMetaData());
367 if (meta->GetKind() == GateMetaData::Kind::MUTABLE_WITH_SIZE) {
368 meta->DecreaseIn(idx);
369 } else {
370 meta = metaBuilder_.NewGateMetaData(meta);
371 meta->DecreaseIn(idx);
372 LoadGatePtr(gate)->SetMetaData(meta);
373 }
374 }
375
SetGateType(GateRef gate,GateType type)376 void Circuit::SetGateType(GateRef gate, GateType type)
377 {
378 LoadGatePtr(gate)->SetGateType(type);
379 }
380
SetMachineType(GateRef gate,MachineType machineType)381 void Circuit::SetMachineType(GateRef gate, MachineType machineType)
382 {
383 LoadGatePtr(gate)->SetMachineType(machineType);
384 }
385
GetGateType(GateRef gate) const386 GateType Circuit::GetGateType(GateRef gate) const
387 {
388 return LoadGatePtrConst(gate)->GetGateType();
389 }
390
GetMachineType(GateRef gate) const391 MachineType Circuit::GetMachineType(GateRef gate) const
392 {
393 return LoadGatePtrConst(gate)->GetMachineType();
394 }
395
GetOpCode(GateRef gate) const396 OpCode Circuit::GetOpCode(GateRef gate) const
397 {
398 return LoadGatePtrConst(gate)->GetOpCode();
399 }
400
GetId(GateRef gate) const401 GateId Circuit::GetId(GateRef gate) const
402 {
403 return LoadGatePtrConst(gate)->GetId();
404 }
405
Print(GateRef gate) const406 void Circuit::Print(GateRef gate) const
407 {
408 LoadGatePtrConst(gate)->Print();
409 }
410
GetCircuitDataSize() const411 size_t Circuit::GetCircuitDataSize() const
412 {
413 return circuitSize_;
414 }
415
GetSpaceDataStartPtrConst() const416 const void *Circuit::GetSpaceDataStartPtrConst() const
417 {
418 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
419 return GetDataPtrConst(0);
420 }
421
GetSpaceDataEndPtrConst() const422 const void *Circuit::GetSpaceDataEndPtrConst() const
423 {
424 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
425 return GetDataPtrConst(circuitSize_);
426 }
427
GetDataPtrConst(size_t offset) const428 const uint8_t *Circuit::GetDataPtrConst(size_t offset) const
429 {
430 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
431 return static_cast<uint8_t *>(space_) + offset;
432 }
433
GetDataPtr(size_t offset)434 uint8_t *Circuit::GetDataPtr(size_t offset)
435 {
436 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
437 return static_cast<uint8_t *>(space_) + offset;
438 }
439
GetFrameType() const440 panda::ecmascript::FrameType Circuit::GetFrameType() const
441 {
442 return frameType_;
443 }
444
SetFrameType(panda::ecmascript::FrameType type)445 void Circuit::SetFrameType(panda::ecmascript::FrameType type)
446 {
447 frameType_ = type;
448 }
449
GetConstantGate(MachineType machineType,uint64_t value,GateType type)450 GateRef Circuit::GetConstantGate(MachineType machineType, uint64_t value,
451 GateType type)
452 {
453 auto search = constantCache_.find({machineType, value, type});
454 if (search != constantCache_.end()) {
455 return search->second;
456 }
457 auto gate = NewGate(metaBuilder_.Constant(value), machineType, type);
458 constantCache_[{machineType, value, type}] = gate;
459 return gate;
460 }
461
ClearConstantCache(MachineType machineType,uint64_t value,GateType type)462 void Circuit::ClearConstantCache(MachineType machineType, uint64_t value, GateType type)
463 {
464 auto search = constantCache_.find({machineType, value, type});
465 if (search != constantCache_.end()) {
466 constantCache_.erase(search);
467 }
468 }
469
GetConstantStringGate(MachineType machineType,std::string_view str,GateType type)470 GateRef Circuit::GetConstantStringGate(MachineType machineType, std::string_view str,
471 GateType type)
472 {
473 auto gate = NewGate(metaBuilder_.ConstString(str), machineType, type);
474 return gate;
475 }
476
GetInitialEnvGate(GateRef jsFunc)477 GateRef Circuit::GetInitialEnvGate(GateRef jsFunc)
478 {
479 auto search = initialEnvCache_.find(jsFunc);
480 if (search != initialEnvCache_.end()) {
481 return initialEnvCache_.at(jsFunc);
482 }
483 auto gate = NewGate(GetEnv(), MachineType::I64, {jsFunc}, GateType::AnyType());
484 initialEnvCache_[jsFunc] = gate;
485 return gate;
486 }
487
NewArg(MachineType machineType,size_t index,GateType type,GateRef argRoot)488 GateRef Circuit::NewArg(MachineType machineType, size_t index,
489 GateType type, GateRef argRoot)
490 {
491 return NewGate(metaBuilder_.Arg(index), machineType, { argRoot }, type);
492 }
493
GetGateCount() const494 size_t Circuit::GetGateCount() const
495 {
496 return gateCount_;
497 }
498
GetStateRoot() const499 GateRef Circuit::GetStateRoot() const
500 {
501 const GateAccessor acc(const_cast<Circuit*>(this));
502 return acc.GetStateRoot();
503 }
504
GetDependRoot() const505 GateRef Circuit::GetDependRoot() const
506 {
507 const GateAccessor acc(const_cast<Circuit*>(this));
508 return acc.GetDependRoot();
509 }
510
GetArgRoot() const511 GateRef Circuit::GetArgRoot() const
512 {
513 const GateAccessor acc(const_cast<Circuit*>(this));
514 return acc.GetArgRoot();
515 }
516
GetReturnRoot() const517 GateRef Circuit::GetReturnRoot() const
518 {
519 const GateAccessor acc(const_cast<Circuit*>(this));
520 return acc.GetReturnRoot();
521 }
522 } // namespace panda::ecmascript::kungfu
523