• 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/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