• 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)24 Circuit::Circuit(NativeAreaAllocator* allocator, DebugInfo* debugInfo, const char* funcName, bool isArch64)
25     : circuitSize_(0),
26       gateCount_(0),
27       time_(1),
28       isArch64_(isArch64),
29       chunk_(allocator),
30       root_(Circuit::NullGate()),
31       metaBuilder_(chunk()),
32       gateToDInfo_(chunk()),
33       debugInfo_(debugInfo)
34 #ifndef NDEBUG
35       , allGates_(chunk())
36 #endif
37 {
38     if (funcName != nullptr && debugInfo_->IsEnable()) {
39         debugInfo_->AddFuncDebugInfo(funcName);
40     }
41     space_ = panda::ecmascript::PageMap(CIRCUIT_SPACE, PAGE_PROT_READWRITE).GetMem();
42     InitRoot();
43 }
44 
~Circuit()45 Circuit::~Circuit()
46 {
47     panda::ecmascript::PageUnmap(MemMap(space_, CIRCUIT_SPACE));
48     debugInfo_ = nullptr;
49     space_ = nullptr;
50 }
51 
InitRoot()52 void Circuit::InitRoot()
53 {
54     root_ = NewGate(metaBuilder_.CircuitRoot(), MachineType::NOVALUE, {}, GateType::Empty());
55     NewGate(metaBuilder_.StateEntry(), MachineType::NOVALUE, { root_ }, GateType::Empty());
56     NewGate(metaBuilder_.DependEntry(), MachineType::NOVALUE, { root_ }, GateType::Empty());
57     NewGate(metaBuilder_.ReturnList(), MachineType::NOVALUE, { root_ }, GateType::Empty());
58     NewGate(metaBuilder_.ArgList(), MachineType::NOVALUE, { root_ }, GateType::Empty());
59 }
60 
AllocateSpace(size_t gateSize)61 uint8_t *Circuit::AllocateSpace(size_t gateSize)
62 {
63     circuitSize_ += gateSize;
64     if (circuitSize_ > CIRCUIT_SPACE) {
65         return nullptr;  // abort compilation
66     }
67     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
68     return GetDataPtr(circuitSize_ - gateSize);
69 }
70 
AllocateGateSpace(size_t numIns)71 Gate *Circuit::AllocateGateSpace(size_t numIns)
72 {
73     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
74     return reinterpret_cast<Gate *>(AllocateSpace(Gate::GetGateSize(numIns)) + Gate::GetOutListSize(numIns));
75 }
76 
AddComment(GateRef g,const char * str)77 bool Circuit::AddComment(GateRef g, const char* str)
78 {
79     ASSERT(debugInfo_ != nullptr);
80     if (!debugInfo_->IsEnable()) {
81         return false;
82     }
83     auto it = gateToDInfo_.find(g);
84     if (it == gateToDInfo_.end()) {
85         ASSERT(debugInfo_ != nullptr);
86         size_t index = debugInfo_->AddComment(str);
87         gateToDInfo_[g] = index;
88         return true;
89     }
90     return false;
91 }
92 
GetDebugInfo(GateRef g,size_t & index) const93 bool Circuit::GetDebugInfo(GateRef g, size_t &index) const
94 {
95     auto it = gateToDInfo_.find(g);
96     if (it != gateToDInfo_.end()) {
97         index = it->second;
98         return true;
99     } else {
100         return false;
101     }
102 }
103 
104 // NOLINTNEXTLINE(modernize-avoid-c-arrays)
NewGate(const GateMetaData * meta,MachineType machineType,size_t numIns,const GateRef inList[],GateType type,const char * comment)105 GateRef Circuit::NewGate(const GateMetaData *meta, MachineType machineType, size_t numIns,
106                          const GateRef inList[], GateType type, const char* comment)
107 {
108 #ifndef NDEBUG
109     if (numIns != meta->GetNumIns()) {
110         LOG_COMPILER(FATAL) << "Invalid input list!"
111                             << " op=" << meta->GetOpCode()
112                             << " expected_num_in=" << meta->GetNumIns() << " actual_num_in=" << numIns;
113         UNREACHABLE();
114     }
115 #endif
116     std::vector<Gate *> inPtrList(numIns);
117     auto gateSpace = AllocateGateSpace(numIns);
118     for (size_t idx = 0; idx < numIns; idx++) {
119         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
120         inPtrList[idx] = (inList[idx] == Circuit::NullGate()) ? nullptr : LoadGatePtr(inList[idx]);
121     }
122     auto newGate = new (gateSpace) Gate(meta, gateCount_++, inPtrList.data(), machineType, type);
123 #ifndef NDEBUG
124     allGates_.push_back(GetGateRef(newGate));
125 #endif
126     GateRef result = GetGateRef(newGate);
127     if (comment != nullptr) {
128         AddComment(result, comment);
129     }
130     return result;
131 }
132 
NewGate(const GateMetaData * meta,const std::vector<GateRef> & inList,const char * comment)133 GateRef Circuit::NewGate(const GateMetaData *meta, const std::vector<GateRef> &inList, const char* comment)
134 {
135     return NewGate(meta, MachineType::NOVALUE, inList.size(), inList.data(), GateType::Empty(), comment);
136 }
137 
NewGate(const GateMetaData * meta,MachineType machineType,const std::initializer_list<GateRef> & args,GateType type,const char * comment)138 GateRef Circuit::NewGate(const GateMetaData *meta, MachineType machineType,
139     const std::initializer_list<GateRef>& args, GateType type, const char* comment)
140 {
141     return NewGate(meta, machineType, args.size(), args.begin(), type, comment);
142 }
143 
NewGate(const GateMetaData * meta,MachineType machineType,GateType type,const char * comment)144 GateRef Circuit::NewGate(const GateMetaData *meta, MachineType machineType, GateType type, const char* comment)
145 {
146     return NewGate(meta, machineType, {}, type, comment);
147 }
148 
PrintAllGates() const149 void Circuit::PrintAllGates() const
150 {
151     std::vector<GateRef> gateList;
152     GetAllGates(gateList);
153     for (const auto &gate : gateList) {
154         LoadGatePtrConst(gate)->Print();
155     }
156 }
157 
PrintAllGatesWithBytecode() const158 void Circuit::PrintAllGatesWithBytecode() const
159 {
160     std::vector<GateRef> gateList;
161     GetAllGates(gateList);
162     for (const auto &gate : gateList) {
163         if (GetOpCode(gate) == OpCode::JS_BYTECODE) {
164             const Gate *gatePtr = LoadGatePtrConst(gate);
165             auto opcode = gatePtr->GetJSBytecodeMetaData()->GetByteCodeOpcode();
166             std::string bytecodeStr = GetEcmaOpcodeStr(opcode);
167             LoadGatePtrConst(gate)->PrintByteCode(bytecodeStr);
168         } else {
169             LoadGatePtrConst(gate)->Print();
170         }
171     }
172 }
173 
GetAllGates(std::vector<GateRef> & gateList) const174 void Circuit::GetAllGates(std::vector<GateRef>& gateList) const
175 {
176     gateList.clear();
177     for (size_t out = 0; out < circuitSize_;
178         out += Gate::GetGateSize(reinterpret_cast<const Out *>(LoadGatePtrConst(GateRef(out)))->GetIndex() + 1)) {
179         auto gatePtr = reinterpret_cast<const Out *>(LoadGatePtrConst(GateRef(out)))->GetGateConst();
180         if (!gatePtr->GetMetaData()->IsNop()) {
181             gateList.push_back(GetGateRef(gatePtr));
182         }
183     }
184 }
185 
GetGateRef(const Gate * gate) const186 GateRef Circuit::GetGateRef(const Gate *gate) const
187 {
188     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
189     return static_cast<GateRef>(reinterpret_cast<const uint8_t *>(gate) - GetDataPtrConst(0));
190 }
191 
LoadGatePtr(GateRef shift)192 Gate *Circuit::LoadGatePtr(GateRef shift)
193 {
194     ASSERT(shift != Circuit::NullGate());
195     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
196     return reinterpret_cast<Gate *>(GetDataPtr(shift));
197 }
198 
LoadGatePtrConst(GateRef shift) const199 const Gate *Circuit::LoadGatePtrConst(GateRef shift) const
200 {
201     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
202     return reinterpret_cast<const Gate *>(GetDataPtrConst(shift));
203 }
204 
AdvanceTime() const205 void Circuit::AdvanceTime() const
206 {
207     auto &curTime = const_cast<TimeStamp &>(time_);
208     curTime++;
209     if (curTime == 0) {
210         curTime = 1;
211         ResetAllGateTimeStamps();
212     }
213 }
214 
ResetAllGateTimeStamps() const215 void Circuit::ResetAllGateTimeStamps() const
216 {
217     std::vector<GateRef> gateList;
218     GetAllGates(gateList);
219     for (auto &gate : gateList) {
220         const_cast<Gate *>(LoadGatePtrConst(gate))->SetMark(MarkCode::NO_MARK, 0);
221     }
222 }
223 
GetTime() const224 TimeStamp Circuit::GetTime() const
225 {
226     return time_;
227 }
228 
GetMark(GateRef gate) const229 MarkCode Circuit::GetMark(GateRef gate) const
230 {
231     return LoadGatePtrConst(gate)->GetMark(GetTime());
232 }
233 
SetMark(GateRef gate,MarkCode mark) const234 void Circuit::SetMark(GateRef gate, MarkCode mark) const
235 {
236     const_cast<Gate *>(LoadGatePtrConst(gate))->SetMark(mark, GetTime());
237 }
238 
Verify(GateRef gate) const239 void Circuit::Verify(GateRef gate) const
240 {
241     LoadGatePtrConst(gate)->Verify(IsArch64());
242 }
243 
NullGate()244 GateRef Circuit::NullGate()
245 {
246     return Gate::InvalidGateRef;
247 }
248 
IsLoopHead(GateRef gate) const249 bool Circuit::IsLoopHead(GateRef gate) const
250 {
251     if (gate != NullGate()) {
252         const Gate *curGate = LoadGatePtrConst(gate);
253         return curGate->GetMetaData()->IsLoopHead();
254     }
255     return false;
256 }
257 
IsControlCase(GateRef gate) const258 bool Circuit::IsControlCase(GateRef gate) const
259 {
260     if (gate != NullGate()) {
261         const Gate *curGate = LoadGatePtrConst(gate);
262         return curGate->GetMetaData()->IsControlCase();
263     }
264     return false;
265 }
266 
IsValueSelector(GateRef gate) const267 bool Circuit::IsValueSelector(GateRef gate) const
268 {
269     if (gate != NullGate()) {
270         const Gate *curGate = LoadGatePtrConst(gate);
271         return curGate->GetOpCode() == OpCode::VALUE_SELECTOR;
272     }
273     return false;
274 }
275 
IsSelector(GateRef gate) const276 bool Circuit::IsSelector(GateRef gate) const
277 {
278     if (gate != NullGate()) {
279         const Gate *curGate = LoadGatePtrConst(gate);
280         OpCode op = curGate->GetOpCode();
281         return (op == OpCode::VALUE_SELECTOR) || (op == OpCode::DEPEND_SELECTOR);
282     }
283     return false;
284 }
285 
GetIn(GateRef gate,size_t idx) const286 GateRef Circuit::GetIn(GateRef gate, size_t idx) const
287 {
288     ASSERT(idx < LoadGatePtrConst(gate)->GetNumIns());
289     if (IsInGateNull(gate, idx)) {
290         return NullGate();
291     }
292     const Gate *curGate = LoadGatePtrConst(gate);
293     return GetGateRef(curGate->GetInGateConst(idx));
294 }
295 
IsInGateNull(GateRef gate,size_t idx) const296 bool Circuit::IsInGateNull(GateRef gate, size_t idx) const
297 {
298     const Gate *curGate = LoadGatePtrConst(gate);
299     return curGate->GetInConst(idx)->IsGateNull();
300 }
301 
IsFirstOutNull(GateRef gate) const302 bool Circuit::IsFirstOutNull(GateRef gate) const
303 {
304     const Gate *curGate = LoadGatePtrConst(gate);
305     return curGate->IsFirstOutNull();
306 }
307 
GetOutVector(GateRef gate) const308 std::vector<GateRef> Circuit::GetOutVector(GateRef gate) const
309 {
310     std::vector<GateRef> result;
311     const Gate *curGate = LoadGatePtrConst(gate);
312     if (!curGate->IsFirstOutNull()) {
313         const Out *curOut = curGate->GetFirstOutConst();
314         result.push_back(GetGateRef(curOut->GetGateConst()));
315         while (!curOut->IsNextOutNull()) {
316             curOut = curOut->GetNextOutConst();
317             result.push_back(GetGateRef(curOut->GetGateConst()));
318         }
319     }
320     return result;
321 }
322 
NewIn(GateRef gate,size_t idx,GateRef in)323 void Circuit::NewIn(GateRef gate, size_t idx, GateRef in)
324 {
325 #ifndef NDEBUG
326     ASSERT(idx < LoadGatePtrConst(gate)->GetNumIns());
327     ASSERT(Circuit::IsInGateNull(gate, idx));
328 #endif
329     LoadGatePtr(gate)->NewIn(idx, LoadGatePtr(in));
330 }
331 
ModifyIn(GateRef gate,size_t idx,GateRef in)332 void Circuit::ModifyIn(GateRef gate, size_t idx, GateRef in)
333 {
334 #ifndef NDEBUG
335     ASSERT(idx < LoadGatePtrConst(gate)->GetNumIns());
336     ASSERT(!Circuit::IsInGateNull(gate, idx) || (GetOpCode(gate) == OpCode::SAVE_REGISTER));
337 #endif
338     LoadGatePtr(gate)->ModifyIn(idx, LoadGatePtr(in));
339 }
340 
DeleteIn(GateRef gate,size_t idx)341 void Circuit::DeleteIn(GateRef gate, size_t idx)
342 {
343     ASSERT(idx < LoadGatePtrConst(gate)->GetNumIns());
344     ASSERT(!Circuit::IsInGateNull(gate, idx));
345     LoadGatePtr(gate)->DeleteIn(idx);
346 }
347 
DeleteGate(GateRef gate)348 void Circuit::DeleteGate(GateRef gate)
349 {
350     LoadGatePtr(gate)->DeleteGate();
351     LoadGatePtr(gate)->SetMetaData(Nop());
352 }
353 
DecreaseIn(GateRef gate,size_t idx)354 void Circuit::DecreaseIn(GateRef gate, size_t idx)
355 {
356     auto numIns = LoadGatePtrConst(gate)->GetNumIns();
357     for (size_t i = idx; i < numIns - 1; i++) {
358         ModifyIn(gate, i, GetIn(gate, i + 1));
359     }
360     DeleteIn(gate, numIns - 1);
361     GateMetaData *meta = const_cast<GateMetaData *>(
362             LoadGatePtr(gate)->GetMetaData());
363     if (meta->GetKind() == GateMetaData::Kind::MUTABLE_WITH_SIZE) {
364         meta->DecreaseIn(idx);
365     } else {
366         meta = metaBuilder_.NewGateMetaData(meta);
367         meta->DecreaseIn(idx);
368         LoadGatePtr(gate)->SetMetaData(meta);
369     }
370 }
371 
SetGateType(GateRef gate,GateType type)372 void Circuit::SetGateType(GateRef gate, GateType type)
373 {
374     LoadGatePtr(gate)->SetGateType(type);
375 }
376 
SetMachineType(GateRef gate,MachineType machineType)377 void Circuit::SetMachineType(GateRef gate, MachineType machineType)
378 {
379     LoadGatePtr(gate)->SetMachineType(machineType);
380 }
381 
GetGateType(GateRef gate) const382 GateType Circuit::GetGateType(GateRef gate) const
383 {
384     return LoadGatePtrConst(gate)->GetGateType();
385 }
386 
GetMachineType(GateRef gate) const387 MachineType Circuit::GetMachineType(GateRef gate) const
388 {
389     return LoadGatePtrConst(gate)->GetMachineType();
390 }
391 
GetOpCode(GateRef gate) const392 OpCode Circuit::GetOpCode(GateRef gate) const
393 {
394     return LoadGatePtrConst(gate)->GetOpCode();
395 }
396 
GetId(GateRef gate) const397 GateId Circuit::GetId(GateRef gate) const
398 {
399     return LoadGatePtrConst(gate)->GetId();
400 }
401 
Print(GateRef gate) const402 void Circuit::Print(GateRef gate) const
403 {
404     LoadGatePtrConst(gate)->Print();
405 }
406 
GetCircuitDataSize() const407 size_t Circuit::GetCircuitDataSize() const
408 {
409     return circuitSize_;
410 }
411 
GetSpaceDataStartPtrConst() const412 const void *Circuit::GetSpaceDataStartPtrConst() const
413 {
414     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
415     return GetDataPtrConst(0);
416 }
417 
GetSpaceDataEndPtrConst() const418 const void *Circuit::GetSpaceDataEndPtrConst() const
419 {
420     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
421     return GetDataPtrConst(circuitSize_);
422 }
423 
GetDataPtrConst(size_t offset) const424 const uint8_t *Circuit::GetDataPtrConst(size_t offset) const
425 {
426     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
427     return static_cast<uint8_t *>(space_) + offset;
428 }
429 
GetDataPtr(size_t offset)430 uint8_t *Circuit::GetDataPtr(size_t offset)
431 {
432     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
433     return static_cast<uint8_t *>(space_) + offset;
434 }
435 
GetFrameType() const436 panda::ecmascript::FrameType Circuit::GetFrameType() const
437 {
438     return frameType_;
439 }
440 
SetFrameType(panda::ecmascript::FrameType type)441 void Circuit::SetFrameType(panda::ecmascript::FrameType type)
442 {
443     frameType_ = type;
444 }
445 
GetConstantGate(MachineType machineType,uint64_t value,GateType type)446 GateRef Circuit::GetConstantGate(MachineType machineType, uint64_t value,
447                                  GateType type)
448 {
449     auto search = constantCache_.find({machineType, value, type});
450     if (search != constantCache_.end()) {
451         return constantCache_.at({machineType, value, type});
452     }
453     auto gate = NewGate(metaBuilder_.Constant(value), machineType, type);
454     constantCache_[{machineType, value, type}] = gate;
455     return gate;
456 }
457 
ClearConstantCache(MachineType machineType,uint64_t value,GateType type)458 void Circuit::ClearConstantCache(MachineType machineType, uint64_t value, GateType type)
459 {
460     auto search = constantCache_.find({machineType, value, type});
461     if (search != constantCache_.end()) {
462         constantCache_.erase(search);
463     }
464 }
465 
GetConstantStringGate(MachineType machineType,const std::string & str,GateType type)466 GateRef Circuit::GetConstantStringGate(MachineType machineType, const std::string &str,
467                                        GateType type)
468 {
469     auto gate = NewGate(metaBuilder_.ConstString(str), machineType, type);
470     return gate;
471 }
472 
GetInitialEnvGate(GateRef jsFunc)473 GateRef Circuit::GetInitialEnvGate(GateRef jsFunc)
474 {
475     auto search = initialEnvCache_.find(jsFunc);
476     if (search != initialEnvCache_.end()) {
477         return initialEnvCache_.at(jsFunc);
478     }
479     auto gate = NewGate(GetEnv(), MachineType::I64, {jsFunc}, GateType::AnyType());
480     initialEnvCache_[jsFunc] = gate;
481     return gate;
482 }
483 
NewArg(MachineType machineType,size_t index,GateType type,GateRef argRoot)484 GateRef Circuit::NewArg(MachineType machineType, size_t index,
485                         GateType type, GateRef argRoot)
486 {
487     return NewGate(metaBuilder_.Arg(index), machineType, { argRoot }, type);
488 }
489 
GetGateCount() const490 size_t Circuit::GetGateCount() const
491 {
492     return gateCount_;
493 }
494 
GetStateRoot() const495 GateRef Circuit::GetStateRoot() const
496 {
497     const GateAccessor acc(const_cast<Circuit*>(this));
498     return acc.GetStateRoot();
499 }
500 
GetDependRoot() const501 GateRef Circuit::GetDependRoot() const
502 {
503     const GateAccessor acc(const_cast<Circuit*>(this));
504     return acc.GetDependRoot();
505 }
506 
GetArgRoot() const507 GateRef Circuit::GetArgRoot() const
508 {
509     const GateAccessor acc(const_cast<Circuit*>(this));
510     return acc.GetArgRoot();
511 }
512 
GetReturnRoot() const513 GateRef Circuit::GetReturnRoot() const
514 {
515     const GateAccessor acc(const_cast<Circuit*>(this));
516     return acc.GetReturnRoot();
517 }
518 }  // namespace panda::ecmascript::kungfu
519