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