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/ecma_opcode_des.h"
19 #include "ecmascript/compiler/gate_accessor.h"
20 #include "ecmascript/platform/map.h"
21
22 namespace panda::ecmascript::kungfu {
Circuit(NativeAreaAllocator * allocator,bool isArch64)23 Circuit::Circuit(NativeAreaAllocator* allocator, bool isArch64) :
24 circuitSize_(0), gateCount_(0), time_(1),
25 isArch64_(isArch64), chunk_(allocator),
26 root_(Circuit::NullGate()), metaBuilder_(chunk())
27 #ifndef NDEBUG
28 , allGates_(chunk())
29 #endif
30 {
31 space_ = panda::ecmascript::PageMap(CIRCUIT_SPACE, PAGE_PROT_READWRITE).GetMem();
32 InitRoot();
33 }
34
~Circuit()35 Circuit::~Circuit()
36 {
37 panda::ecmascript::PageUnmap(MemMap(space_, CIRCUIT_SPACE));
38 }
39
InitRoot()40 void Circuit::InitRoot()
41 {
42 root_ = NewGate(metaBuilder_.CircuitRoot(), MachineType::NOVALUE, {}, GateType::Empty());
43 NewGate(metaBuilder_.StateEntry(), MachineType::NOVALUE, { root_ }, GateType::Empty());
44 NewGate(metaBuilder_.DependEntry(), MachineType::NOVALUE, { root_ }, GateType::Empty());
45 NewGate(metaBuilder_.ReturnList(), MachineType::NOVALUE, { root_ }, GateType::Empty());
46 NewGate(metaBuilder_.ArgList(), MachineType::NOVALUE, { root_ }, GateType::Empty());
47 }
48
AllocateSpace(size_t gateSize)49 uint8_t *Circuit::AllocateSpace(size_t gateSize)
50 {
51 circuitSize_ += gateSize;
52 if (circuitSize_ > CIRCUIT_SPACE) {
53 return nullptr; // abort compilation
54 }
55 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
56 return GetDataPtr(circuitSize_ - gateSize);
57 }
58
AllocateGateSpace(size_t numIns)59 Gate *Circuit::AllocateGateSpace(size_t numIns)
60 {
61 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
62 return reinterpret_cast<Gate *>(AllocateSpace(Gate::GetGateSize(numIns)) + Gate::GetOutListSize(numIns));
63 }
64
65 // NOLINTNEXTLINE(modernize-avoid-c-arrays)
NewGate(const GateMetaData * meta,MachineType machineType,size_t numIns,const GateRef inList[],GateType type)66 GateRef Circuit::NewGate(const GateMetaData *meta, MachineType machineType,
67 size_t numIns, const GateRef inList[], GateType type)
68 {
69 #ifndef NDEBUG
70 if (numIns != meta->GetNumIns()) {
71 LOG_COMPILER(ERROR) << "Invalid input list!"
72 << " op=" << meta->GetOpCode()
73 << " expected_num_in=" << meta->GetNumIns() << " actual_num_in=" << numIns;
74 UNREACHABLE();
75 }
76 #endif
77 std::vector<Gate *> inPtrList(numIns);
78 auto gateSpace = AllocateGateSpace(numIns);
79 for (size_t idx = 0; idx < numIns; idx++) {
80 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
81 inPtrList[idx] = (inList[idx] == Circuit::NullGate()) ? nullptr : LoadGatePtr(inList[idx]);
82 }
83 auto newGate = new (gateSpace) Gate(meta, gateCount_++, inPtrList.data(), machineType, type);
84 #ifndef NDEBUG
85 allGates_.push_back(GetGateRef(newGate));
86 #endif
87 return GetGateRef(newGate);
88 }
89
NewGate(const GateMetaData * meta,const std::vector<GateRef> & inList)90 GateRef Circuit::NewGate(const GateMetaData *meta, const std::vector<GateRef> &inList)
91 {
92 return NewGate(meta, MachineType::NOVALUE, inList.size(), inList.data(), GateType::Empty());
93 }
94
NewGate(const GateMetaData * meta,MachineType machineType,const std::initializer_list<GateRef> & args,GateType type)95 GateRef Circuit::NewGate(const GateMetaData *meta, MachineType machineType,
96 const std::initializer_list<GateRef>& args, GateType type)
97 {
98 return NewGate(meta, machineType, args.size(), args.begin(), type);
99 }
100
NewGate(const GateMetaData * meta,MachineType machineType,GateType type)101 GateRef Circuit::NewGate(const GateMetaData *meta, MachineType machineType, GateType type)
102 {
103 return NewGate(meta, machineType, {}, type);
104 }
105
PrintAllGates() const106 void Circuit::PrintAllGates() const
107 {
108 std::vector<GateRef> gateList;
109 GetAllGates(gateList);
110 for (const auto &gate : gateList) {
111 LoadGatePtrConst(gate)->Print();
112 }
113 }
114
PrintAllGatesWithBytecode() const115 void Circuit::PrintAllGatesWithBytecode() const
116 {
117 std::vector<GateRef> gateList;
118 GetAllGates(gateList);
119 for (const auto &gate : gateList) {
120 if (GetOpCode(gate) == OpCode::JS_BYTECODE) {
121 const Gate *gatePtr = LoadGatePtrConst(gate);
122 auto opcode = gatePtr->GetJSBytecodeMetaData()->GetByteCodeOpcode();
123 std::string bytecodeStr = GetEcmaOpcodeStr(opcode);
124 LoadGatePtrConst(gate)->PrintByteCode(bytecodeStr);
125 } else {
126 LoadGatePtrConst(gate)->Print();
127 }
128 }
129 }
130
GetAllGates(std::vector<GateRef> & gateList) const131 void Circuit::GetAllGates(std::vector<GateRef>& gateList) const
132 {
133 gateList.clear();
134 for (size_t out = 0; out < circuitSize_;
135 out += Gate::GetGateSize(reinterpret_cast<const Out *>(LoadGatePtrConst(GateRef(out)))->GetIndex() + 1)) {
136 auto gatePtr = reinterpret_cast<const Out *>(LoadGatePtrConst(GateRef(out)))->GetGateConst();
137 if (!gatePtr->GetMetaData()->IsNop()) {
138 gateList.push_back(GetGateRef(gatePtr));
139 }
140 }
141 }
142
GetGateRef(const Gate * gate) const143 GateRef Circuit::GetGateRef(const Gate *gate) const
144 {
145 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
146 return static_cast<GateRef>(reinterpret_cast<const uint8_t *>(gate) - GetDataPtrConst(0));
147 }
148
LoadGatePtr(GateRef shift)149 Gate *Circuit::LoadGatePtr(GateRef shift)
150 {
151 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
152 return reinterpret_cast<Gate *>(GetDataPtr(shift));
153 }
154
LoadGatePtrConst(GateRef shift) const155 const Gate *Circuit::LoadGatePtrConst(GateRef shift) const
156 {
157 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
158 return reinterpret_cast<const Gate *>(GetDataPtrConst(shift));
159 }
160
161
162
AdvanceTime() const163 void Circuit::AdvanceTime() const
164 {
165 auto &curTime = const_cast<TimeStamp &>(time_);
166 curTime++;
167 if (curTime == 0) {
168 curTime = 1;
169 ResetAllGateTimeStamps();
170 }
171 }
172
ResetAllGateTimeStamps() const173 void Circuit::ResetAllGateTimeStamps() const
174 {
175 std::vector<GateRef> gateList;
176 GetAllGates(gateList);
177 for (auto &gate : gateList) {
178 const_cast<Gate *>(LoadGatePtrConst(gate))->SetMark(MarkCode::NO_MARK, 0);
179 }
180 }
181
GetTime() const182 TimeStamp Circuit::GetTime() const
183 {
184 return time_;
185 }
186
GetMark(GateRef gate) const187 MarkCode Circuit::GetMark(GateRef gate) const
188 {
189 return LoadGatePtrConst(gate)->GetMark(GetTime());
190 }
191
SetMark(GateRef gate,MarkCode mark) const192 void Circuit::SetMark(GateRef gate, MarkCode mark) const
193 {
194 const_cast<Gate *>(LoadGatePtrConst(gate))->SetMark(mark, GetTime());
195 }
196
Verify(GateRef gate) const197 void Circuit::Verify(GateRef gate) const
198 {
199 LoadGatePtrConst(gate)->Verify(IsArch64());
200 }
201
NullGate()202 GateRef Circuit::NullGate()
203 {
204 return Gate::InvalidGateRef;
205 }
206
IsLoopHead(GateRef gate) const207 bool Circuit::IsLoopHead(GateRef gate) const
208 {
209 if (gate != NullGate()) {
210 const Gate *curGate = LoadGatePtrConst(gate);
211 return curGate->GetMetaData()->IsLoopHead();
212 }
213 return false;
214 }
215
IsControlCase(GateRef gate) const216 bool Circuit::IsControlCase(GateRef gate) const
217 {
218 if (gate != NullGate()) {
219 const Gate *curGate = LoadGatePtrConst(gate);
220 return curGate->GetMetaData()->IsControlCase();
221 }
222 return false;
223 }
224
IsSelector(GateRef gate) const225 bool Circuit::IsSelector(GateRef gate) const
226 {
227 if (gate != NullGate()) {
228 const Gate *curGate = LoadGatePtrConst(gate);
229 return curGate->GetOpCode() == OpCode::VALUE_SELECTOR;
230 }
231 return false;
232 }
233
GetIn(GateRef gate,size_t idx) const234 GateRef Circuit::GetIn(GateRef gate, size_t idx) const
235 {
236 ASSERT(idx < LoadGatePtrConst(gate)->GetNumIns());
237 if (IsInGateNull(gate, idx)) {
238 return NullGate();
239 }
240 const Gate *curGate = LoadGatePtrConst(gate);
241 return GetGateRef(curGate->GetInGateConst(idx));
242 }
243
IsInGateNull(GateRef gate,size_t idx) const244 bool Circuit::IsInGateNull(GateRef gate, size_t idx) const
245 {
246 const Gate *curGate = LoadGatePtrConst(gate);
247 return curGate->GetInConst(idx)->IsGateNull();
248 }
249
IsFirstOutNull(GateRef gate) const250 bool Circuit::IsFirstOutNull(GateRef gate) const
251 {
252 const Gate *curGate = LoadGatePtrConst(gate);
253 return curGate->IsFirstOutNull();
254 }
255
GetOutVector(GateRef gate) const256 std::vector<GateRef> Circuit::GetOutVector(GateRef gate) const
257 {
258 std::vector<GateRef> result;
259 const Gate *curGate = LoadGatePtrConst(gate);
260 if (!curGate->IsFirstOutNull()) {
261 const Out *curOut = curGate->GetFirstOutConst();
262 result.push_back(GetGateRef(curOut->GetGateConst()));
263 while (!curOut->IsNextOutNull()) {
264 curOut = curOut->GetNextOutConst();
265 result.push_back(GetGateRef(curOut->GetGateConst()));
266 }
267 }
268 return result;
269 }
270
NewIn(GateRef gate,size_t idx,GateRef in)271 void Circuit::NewIn(GateRef gate, size_t idx, GateRef in)
272 {
273 #ifndef NDEBUG
274 ASSERT(idx < LoadGatePtrConst(gate)->GetNumIns());
275 ASSERT(Circuit::IsInGateNull(gate, idx));
276 #endif
277 LoadGatePtr(gate)->NewIn(idx, LoadGatePtr(in));
278 }
279
ModifyIn(GateRef gate,size_t idx,GateRef in)280 void Circuit::ModifyIn(GateRef gate, size_t idx, GateRef in)
281 {
282 #ifndef NDEBUG
283 ASSERT(idx < LoadGatePtrConst(gate)->GetNumIns());
284 ASSERT(!Circuit::IsInGateNull(gate, idx) || (GetOpCode(gate) == OpCode::SAVE_REGISTER));
285 #endif
286 LoadGatePtr(gate)->ModifyIn(idx, LoadGatePtr(in));
287 }
288
DeleteIn(GateRef gate,size_t idx)289 void Circuit::DeleteIn(GateRef gate, size_t idx)
290 {
291 ASSERT(idx < LoadGatePtrConst(gate)->GetNumIns());
292 ASSERT(!Circuit::IsInGateNull(gate, idx));
293 LoadGatePtr(gate)->DeleteIn(idx);
294 }
295
DeleteGate(GateRef gate)296 void Circuit::DeleteGate(GateRef gate)
297 {
298 LoadGatePtr(gate)->DeleteGate();
299 LoadGatePtr(gate)->SetMetaData(Nop());
300 }
301
DecreaseIn(GateRef gate,size_t idx)302 void Circuit::DecreaseIn(GateRef gate, size_t idx)
303 {
304 auto numIns = LoadGatePtrConst(gate)->GetNumIns();
305 for (size_t i = idx; i < numIns - 1; i++) {
306 ModifyIn(gate, i, GetIn(gate, i + 1));
307 }
308 DeleteIn(gate, numIns - 1);
309 GateMetaData *meta = const_cast<GateMetaData *>(
310 LoadGatePtr(gate)->GetMetaData());
311 if (meta->GetKind() == GateMetaData::Kind::MUTABLE_WITH_SIZE) {
312 meta->DecreaseIn(idx);
313 } else {
314 meta = metaBuilder_.NewGateMetaData(meta);
315 meta->DecreaseIn(idx);
316 LoadGatePtr(gate)->SetMetaData(meta);
317 }
318 }
319
SetGateType(GateRef gate,GateType type)320 void Circuit::SetGateType(GateRef gate, GateType type)
321 {
322 LoadGatePtr(gate)->SetGateType(type);
323 }
324
SetMachineType(GateRef gate,MachineType machineType)325 void Circuit::SetMachineType(GateRef gate, MachineType machineType)
326 {
327 LoadGatePtr(gate)->SetMachineType(machineType);
328 }
329
GetGateType(GateRef gate) const330 GateType Circuit::GetGateType(GateRef gate) const
331 {
332 return LoadGatePtrConst(gate)->GetGateType();
333 }
334
GetMachineType(GateRef gate) const335 MachineType Circuit::GetMachineType(GateRef gate) const
336 {
337 return LoadGatePtrConst(gate)->GetMachineType();
338 }
339
GetOpCode(GateRef gate) const340 OpCode Circuit::GetOpCode(GateRef gate) const
341 {
342 return LoadGatePtrConst(gate)->GetOpCode();
343 }
344
GetId(GateRef gate) const345 GateId Circuit::GetId(GateRef gate) const
346 {
347 return LoadGatePtrConst(gate)->GetId();
348 }
349
Print(GateRef gate) const350 void Circuit::Print(GateRef gate) const
351 {
352 LoadGatePtrConst(gate)->Print();
353 }
354
GetCircuitDataSize() const355 size_t Circuit::GetCircuitDataSize() const
356 {
357 return circuitSize_;
358 }
359
GetSpaceDataStartPtrConst() const360 const void *Circuit::GetSpaceDataStartPtrConst() const
361 {
362 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
363 return GetDataPtrConst(0);
364 }
365
GetSpaceDataEndPtrConst() const366 const void *Circuit::GetSpaceDataEndPtrConst() const
367 {
368 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
369 return GetDataPtrConst(circuitSize_);
370 }
371
GetDataPtrConst(size_t offset) const372 const uint8_t *Circuit::GetDataPtrConst(size_t offset) const
373 {
374 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
375 return static_cast<uint8_t *>(space_) + offset;
376 }
377
GetDataPtr(size_t offset)378 uint8_t *Circuit::GetDataPtr(size_t offset)
379 {
380 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
381 return static_cast<uint8_t *>(space_) + offset;
382 }
383
GetFrameType() const384 panda::ecmascript::FrameType Circuit::GetFrameType() const
385 {
386 return frameType_;
387 }
388
SetFrameType(panda::ecmascript::FrameType type)389 void Circuit::SetFrameType(panda::ecmascript::FrameType type)
390 {
391 frameType_ = type;
392 }
393
GetConstantGate(MachineType machineType,uint64_t value,GateType type)394 GateRef Circuit::GetConstantGate(MachineType machineType, uint64_t value,
395 GateType type)
396 {
397 auto search = constantCache_.find({machineType, value, type});
398 if (search != constantCache_.end()) {
399 return constantCache_.at({machineType, value, type});
400 }
401 auto gate = NewGate(metaBuilder_.Constant(value), machineType, type);
402 constantCache_[{machineType, value, type}] = gate;
403 return gate;
404 }
405
NewArg(MachineType machineType,size_t index,GateType type,GateRef argRoot)406 GateRef Circuit::NewArg(MachineType machineType, size_t index,
407 GateType type, GateRef argRoot)
408 {
409 return NewGate(metaBuilder_.Arg(index), machineType, { argRoot }, type);
410 }
411
GetConstantDataGate(uint64_t value,GateType type)412 GateRef Circuit::GetConstantDataGate(uint64_t value, GateType type)
413 {
414 auto search = constantDataCache_.find(value);
415 if (search != constantDataCache_.end()) {
416 return constantDataCache_.at(value);
417 }
418 auto gate = NewGate(metaBuilder_.ConstData(value), MachineType::ARCH, type);
419 constantDataCache_[value] = gate;
420 return gate;
421 }
422
GetGateCount() const423 size_t Circuit::GetGateCount() const
424 {
425 return gateCount_;
426 }
427
GetStateRoot() const428 GateRef Circuit::GetStateRoot() const
429 {
430 const GateAccessor acc(const_cast<Circuit*>(this));
431 return acc.GetStateRoot();
432 }
433
GetDependRoot() const434 GateRef Circuit::GetDependRoot() const
435 {
436 const GateAccessor acc(const_cast<Circuit*>(this));
437 return acc.GetDependRoot();
438 }
439
GetArgRoot() const440 GateRef Circuit::GetArgRoot() const
441 {
442 const GateAccessor acc(const_cast<Circuit*>(this));
443 return acc.GetArgRoot();
444 }
445
GetReturnRoot() const446 GateRef Circuit::GetReturnRoot() const
447 {
448 const GateAccessor acc(const_cast<Circuit*>(this));
449 return acc.GetReturnRoot();
450 }
451 } // namespace panda::ecmascript::kungfu
452