1 /*
2  * Copyright (c) 2023 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/post_schedule.h"
17 
18 #include <ecmascript/stubs/runtime_stubs.h>
19 
20 #include "ecmascript/compiler/circuit_builder-inl.h"
21 #include "ecmascript/js_thread.h"
22 
23 namespace panda::ecmascript::kungfu {
Run(ControlFlowGraph &cfg)24 void PostSchedule::Run(ControlFlowGraph &cfg)
25 {
26     GenerateExtraBB(cfg);
27 
28     if (IsLogEnabled()) {
29         LOG_COMPILER(INFO) << "";
30         LOG_COMPILER(INFO) << "\033[34m"
31                            << "===================="
32                            << " After post schedule "
33                            << "[" << GetMethodName() << "]"
34                            << "===================="
35                            << "\033[0m";
36         PrintGraph("Build extra basic block for scheduled gates", cfg);
37         LOG_COMPILER(INFO) << "\033[34m" << "========================= End ==========================" << "\033[0m";
38     }
39 }
40 
GenerateExtraBB(ControlFlowGraph &cfg)41 void PostSchedule::GenerateExtraBB(ControlFlowGraph &cfg)
42 {
43     size_t bbNum = cfg.size();
44     size_t bbIdx = 0;
45     while (bbIdx < bbNum) {
46         const std::vector<GateRef>& bb = cfg.at(bbIdx);
47         size_t instNum = bb.size();
48         size_t instIdx = 0;
49         while (instIdx < instNum) {
50             const std::vector<GateRef>& currentBB = cfg.at(bbIdx);
51             GateRef current = currentBB[instIdx];
52             OpCode opcode = acc_.GetOpCode(current);
53             bool needRetraverse = false;
54             switch (opcode) {
55                 case OpCode::HEAP_ALLOC: {
56                     needRetraverse = VisitHeapAlloc(current, cfg, bbIdx, instIdx);
57                     break;
58                 }
59                 case OpCode::STORE: {
60                     needRetraverse = VisitStore(current, cfg, bbIdx, instIdx);
61                     break;
62                 }
63                 default: {
64                     break;
65                 }
66             }
67             const std::vector<GateRef>& refreshedBB = cfg.at(bbIdx);
68             instNum = refreshedBB.size();
69             instIdx = needRetraverse ? 0 : (instIdx + 1);
70         }
71         bbNum = cfg.size();
72         bbIdx++;
73     }
74 }
75 
VisitHeapAlloc(GateRef gate, ControlFlowGraph &cfg, size_t bbIdx, size_t instIdx)76 bool PostSchedule::VisitHeapAlloc(GateRef gate, ControlFlowGraph &cfg, size_t bbIdx, size_t instIdx)
77 {
78     int64_t flag = static_cast<int64_t>(acc_.TryGetValue(gate));
79     ASSERT(flag == RegionSpaceFlag::IN_YOUNG_SPACE ||
80            flag == RegionSpaceFlag::IN_SHARED_OLD_SPACE ||
81            flag == RegionSpaceFlag::IN_SHARED_NON_MOVABLE ||
82            flag == RegionSpaceFlag::IN_OLD_SPACE);
83     std::vector<GateRef> currentBBGates;
84     std::vector<GateRef> successBBGates;
85     std::vector<GateRef> failBBGates;
86     std::vector<GateRef> endBBGates;
87     if (flag == RegionSpaceFlag::IN_OLD_SPACE) {
88         LoweringHeapAllocate(gate, currentBBGates, successBBGates, failBBGates, endBBGates, flag);
89         ReplaceGateDirectly(currentBBGates, cfg, bbIdx, instIdx);
90         return false;
91     } else {
92         LoweringHeapAllocAndPrepareScheduleGate(gate, currentBBGates, successBBGates, failBBGates, endBBGates, flag);
93     }
94 #ifdef ARK_ASAN_ON
95     ReplaceGateDirectly(currentBBGates, cfg, bbIdx, instIdx);
96     return false;
97 #else
98     ReplaceBBState(cfg, bbIdx, currentBBGates, endBBGates);
99     ScheduleEndBB(endBBGates, cfg, bbIdx, instIdx);
100     ScheduleNewBB(successBBGates, cfg, bbIdx);
101     ScheduleNewBB(failBBGates, cfg, bbIdx);
102     ScheduleCurrentBB(currentBBGates, cfg, bbIdx, instIdx);
103     return true;
104 #endif
105 }
106 
ReplaceGateDirectly(std::vector<GateRef> &gates, ControlFlowGraph &cfg, size_t bbIdx, size_t instIdx)107 void PostSchedule::ReplaceGateDirectly(std::vector<GateRef> &gates, ControlFlowGraph &cfg, size_t bbIdx, size_t instIdx)
108 {
109     std::vector<GateRef>& bb = cfg.at(bbIdx);
110     bb.insert(bb.begin() + instIdx, gates.begin(), gates.end());
111     bb.erase(bb.begin() + instIdx + gates.size());
112 }
113 
ScheduleEndBB(std::vector<GateRef> &gates, ControlFlowGraph &cfg, size_t bbIdx, size_t instIdx)114 void PostSchedule::ScheduleEndBB(std::vector<GateRef> &gates, ControlFlowGraph &cfg, size_t bbIdx, size_t instIdx)
115 {
116     std::vector<GateRef>& bb = cfg.at(bbIdx);
117     if (instIdx > 0) {
118         gates.insert(gates.begin() + 1, bb.begin(), bb.begin() + instIdx);  // 1: after state gate
119     }
120     cfg.insert(cfg.begin() + bbIdx + 1, std::move(gates));  // 1: after current bb
121 }
122 
ScheduleNewBB(std::vector<GateRef> &gates, ControlFlowGraph &cfg, size_t bbIdx)123 void PostSchedule::ScheduleNewBB(std::vector<GateRef> &gates, ControlFlowGraph &cfg, size_t bbIdx)
124 {
125     if (!gates.empty()) {
126         cfg.insert(cfg.begin() + bbIdx + 1, std::move(gates));
127     }
128 }
129 
ScheduleCurrentBB(const std::vector<GateRef> &gates, ControlFlowGraph &cfg, size_t bbIdx, size_t instIdx)130 void PostSchedule::ScheduleCurrentBB(const std::vector<GateRef> &gates, ControlFlowGraph &cfg, size_t bbIdx,
131                                      size_t instIdx)
132 {
133     std::vector<GateRef>& bb = cfg.at(bbIdx);
134     if (instIdx == 0) {
135         bb.erase(bb.begin());
136     } else {
137         bb.erase(bb.begin(), bb.begin() + instIdx + 1);  // 1: include current gate
138     }
139     bb.insert(bb.begin(), gates.begin(), gates.end());
140 }
141 
PrepareToScheduleNewGate(GateRef gate, std::vector<GateRef> &gates)142 void PostSchedule::PrepareToScheduleNewGate(GateRef gate, std::vector<GateRef> &gates)
143 {
144     gates.emplace_back(gate);
145 }
146 
ReplaceBBState(ControlFlowGraph &cfg, size_t bbIdx, std::vector<GateRef> &currentBBGates, std::vector<GateRef> &endBBGates)147 void PostSchedule::ReplaceBBState(ControlFlowGraph &cfg, size_t bbIdx, std::vector<GateRef> &currentBBGates,
148                                   std::vector<GateRef> &endBBGates)
149 {
150     GateRef floatBranch = currentBBGates[0];
151     ASSERT(acc_.GetOpCode(floatBranch) == OpCode::IF_BRANCH);
152     GateRef endBBState = endBBGates[0];
153     ASSERT(acc_.GetOpCode(endBBState) == OpCode::MERGE);
154     std::vector<GateRef>& bb = cfg.at(bbIdx);
155     GateRef currentBBState = bb[0];
156     ASSERT(acc_.IsState(currentBBState));
157 
158     OpCode opcode = acc_.GetOpCode(currentBBState);
159     switch (opcode) {
160         case OpCode::DEOPT_CHECK:
161         case OpCode::RETURN:
162         case OpCode::RETURN_VOID:
163         case OpCode::IF_BRANCH:
164         case OpCode::SWITCH_BRANCH: {
165             GateRef stateIn = acc_.GetState(currentBBState, 0);
166             acc_.ReplaceStateIn(floatBranch, stateIn);
167             acc_.ReplaceStateIn(currentBBState, endBBState);
168             break;
169         }
170         case OpCode::STATE_ENTRY:
171         case OpCode::ORDINARY_BLOCK:
172         case OpCode::IF_TRUE:
173         case OpCode::IF_FALSE:
174         case OpCode::SWITCH_CASE:
175         case OpCode::DEFAULT_CASE:
176         case OpCode::MERGE:
177         case OpCode::LOOP_BEGIN:
178         case OpCode::LOOP_BACK: {
179             acc_.ReplaceControlGate(currentBBState, endBBState);
180             acc_.ReplaceStateIn(floatBranch, currentBBState);
181             currentBBGates.insert(currentBBGates.begin(), currentBBState);
182             bb[0] = builder_.Nop();
183             break;
184         }
185         default: {
186             LOG_ECMA(FATAL) << "this branch is unreachable with opcode:" << opcode;
187             UNREACHABLE();
188         }
189     }
190 }
191 
LoweringHeapAllocAndPrepareScheduleGate(GateRef gate, std::vector<GateRef> &currentBBGates, std::vector<GateRef> &successBBGates, std::vector<GateRef> &failBBGates, std::vector<GateRef> &endBBGates, [[maybe_unused]] int64_t flag)192 void PostSchedule::LoweringHeapAllocAndPrepareScheduleGate(GateRef gate,
193                                                            std::vector<GateRef> &currentBBGates,
194                                                            std::vector<GateRef> &successBBGates,
195                                                            std::vector<GateRef> &failBBGates,
196                                                            std::vector<GateRef> &endBBGates,
197                                                            [[maybe_unused]] int64_t flag)
198 {
199 #ifdef ARK_ASAN_ON
200     LoweringHeapAllocate(gate, currentBBGates, successBBGates, failBBGates, endBBGates, flag);
201 #else
202     Environment env(gate, circuit_, &builder_);
203     Label exit(&builder_);
204     GateRef glue = acc_.GetValueIn(gate, 0);
205     GateRef size = acc_.GetValueIn(gate, 1);
206     GateRef hole = circuit_->GetConstantGateWithoutCache(
207         MachineType::I64, JSTaggedValue::VALUE_HOLE, GateType::TaggedValue());
208     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), hole);
209     Label success(&builder_);
210     Label callRuntime(&builder_);
211     size_t topOffset;
212     size_t endOffset;
213     if (flag == RegionSpaceFlag::IN_SHARED_OLD_SPACE) {
214         topOffset = JSThread::GlueData::GetSOldSpaceAllocationTopAddressOffset(false);
215         endOffset = JSThread::GlueData::GetSOldSpaceAllocationEndAddressOffset(false);
216     } else if (flag == RegionSpaceFlag::IN_SHARED_NON_MOVABLE) {
217         topOffset = JSThread::GlueData::GetSNonMovableSpaceAllocationTopAddressOffset(false);
218         endOffset = JSThread::GlueData::GetSNonMovableSpaceAllocationEndAddressOffset(false);
219     } else {
220         ASSERT(flag == RegionSpaceFlag::IN_YOUNG_SPACE);
221         topOffset = JSThread::GlueData::GetNewSpaceAllocationTopAddressOffset(false);
222         endOffset = JSThread::GlueData::GetNewSpaceAllocationEndAddressOffset(false);
223     }
224     GateRef topAddrOffset = circuit_->GetConstantGateWithoutCache(MachineType::I64, topOffset, GateType::NJSValue());
225     GateRef endAddrOffset = circuit_->GetConstantGateWithoutCache(MachineType::I64, endOffset, GateType::NJSValue());
226     GateRef topAddrAddr = builder_.PtrAdd(glue, topAddrOffset);
227     GateRef endAddrAddr = builder_.PtrAdd(glue, endAddrOffset);
228     GateRef topAddress = builder_.Load(VariableType::NATIVE_POINTER(), topAddrAddr);
229     GateRef endAddress = builder_.Load(VariableType::NATIVE_POINTER(), endAddrAddr);
230     GateRef addrOffset = circuit_->GetConstantGateWithoutCache(MachineType::I64, 0, GateType::NJSValue());
231     GateRef rawTopAddr = builder_.PtrAdd(topAddress, addrOffset);
232     GateRef rawEndAddr = builder_.PtrAdd(endAddress, addrOffset);
233     GateRef top = builder_.Load(VariableType::JS_POINTER(), rawTopAddr);
234     GateRef end = builder_.Load(VariableType::JS_POINTER(), rawEndAddr);
235 
236     GateRef newTop = builder_.PtrAdd(top, size);
237     GateRef condition = builder_.Int64GreaterThan(newTop, end);
238     Label *currentLabel = env.GetCurrentLabel();
239     BRANCH_CIR(condition, &callRuntime, &success);
240     {
241         GateRef ifBranch = currentLabel->GetControl();
242         PrepareToScheduleNewGate(ifBranch, currentBBGates);
243         PrepareToScheduleNewGate(condition, currentBBGates);
244         PrepareToScheduleNewGate(newTop, currentBBGates);
245         PrepareToScheduleNewGate(end, currentBBGates);
246         PrepareToScheduleNewGate(top, currentBBGates);
247         PrepareToScheduleNewGate(rawEndAddr, currentBBGates);
248         PrepareToScheduleNewGate(rawTopAddr, currentBBGates);
249         PrepareToScheduleNewGate(topAddress, currentBBGates);
250         PrepareToScheduleNewGate(endAddress, currentBBGates);
251         PrepareToScheduleNewGate(addrOffset, currentBBGates);
252         PrepareToScheduleNewGate(topAddrAddr, currentBBGates);
253         PrepareToScheduleNewGate(endAddrAddr, currentBBGates);
254         PrepareToScheduleNewGate(topAddrOffset, currentBBGates);
255         PrepareToScheduleNewGate(endAddrOffset, currentBBGates);
256         PrepareToScheduleNewGate(hole, currentBBGates);
257     }
258     builder_.Bind(&success);
259     {
260         GateRef ifFalse = builder_.GetState();
261         GateRef addr = builder_.PtrAdd(topAddress, addrOffset);
262         builder_.StoreWithoutBarrier(VariableType::NATIVE_POINTER(), addr, newTop);
263         GateRef store = builder_.GetDepend();
264         result = top;
265         builder_.Jump(&exit);
266         {
267             GateRef ordinaryBlock = success.GetControl();
268             PrepareToScheduleNewGate(ordinaryBlock, successBBGates);
269             PrepareToScheduleNewGate(store, successBBGates);
270             PrepareToScheduleNewGate(addr, successBBGates);
271             PrepareToScheduleNewGate(ifFalse, successBBGates);
272         }
273     }
274     builder_.Bind(&callRuntime);
275     {
276         GateRef ifTrue = builder_.GetState();
277         GateRef taggedIntMask = circuit_->GetConstantGateWithoutCache(
278             MachineType::I64, JSTaggedValue::TAG_INT, GateType::NJSValue());
279         GateRef taggedSize = builder_.Int64Or(size, taggedIntMask);
280         GateRef target = Circuit::NullGate();
281         if (flag == RegionSpaceFlag::IN_SHARED_OLD_SPACE) {
282             target = circuit_->GetConstantGateWithoutCache(MachineType::ARCH, RTSTUB_ID(AllocateInSOld),
283                                                            GateType::NJSValue());
284         } else if (flag == RegionSpaceFlag::IN_SHARED_NON_MOVABLE) {
285             target = circuit_->GetConstantGateWithoutCache(MachineType::ARCH, RTSTUB_ID(AllocateInSNonMovable),
286                                                            GateType::NJSValue());
287         } else {
288             ASSERT(flag == RegionSpaceFlag::IN_YOUNG_SPACE);
289             target = circuit_->GetConstantGateWithoutCache(MachineType::ARCH, RTSTUB_ID(AllocateInYoung),
290                                                            GateType::NJSValue());
291         }
292         const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(CallRuntime));
293         ASSERT(cs->IsRuntimeStub());
294         GateRef reseverdFrameArgs = circuit_->GetConstantGateWithoutCache(MachineType::I64, 0, GateType::NJSValue());
295         GateRef reseverdPc = circuit_->GetConstantGateWithoutCache(MachineType::I64, 0, GateType::NJSValue());
296         GateRef slowResult = builder_.Call(cs, glue, target, builder_.GetDepend(),
297                                            { taggedSize, reseverdFrameArgs, reseverdPc }, Circuit::NullGate(),
298                                            "Heap alloc");
299         result = slowResult;
300         builder_.Jump(&exit);
301         {
302             GateRef ordinaryBlock = callRuntime.GetControl();
303             PrepareToScheduleNewGate(ordinaryBlock, failBBGates);
304             PrepareToScheduleNewGate(slowResult, failBBGates);
305             PrepareToScheduleNewGate(target, failBBGates);
306             PrepareToScheduleNewGate(taggedSize, failBBGates);
307             PrepareToScheduleNewGate(reseverdFrameArgs, failBBGates);
308             PrepareToScheduleNewGate(reseverdPc, failBBGates);
309             PrepareToScheduleNewGate(taggedIntMask, failBBGates);
310             PrepareToScheduleNewGate(ifTrue, failBBGates);
311         }
312     }
313     builder_.Bind(&exit);
314     {
315         GateRef merge = builder_.GetState();
316         GateRef phi = *result;
317         PrepareToScheduleNewGate(merge, endBBGates);
318         PrepareToScheduleNewGate(phi, endBBGates);
319     }
320     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
321 #endif
322 }
323 
LoweringHeapAllocate(GateRef gate, std::vector<GateRef> &currentBBGates, std::vector<GateRef> &successBBGates, std::vector<GateRef> &failBBGates, std::vector<GateRef> &endBBGates, int64_t flag)324 void PostSchedule::LoweringHeapAllocate(GateRef gate,
325                                         std::vector<GateRef> &currentBBGates,
326                                         std::vector<GateRef> &successBBGates,
327                                         std::vector<GateRef> &failBBGates,
328                                         std::vector<GateRef> &endBBGates,
329                                         int64_t flag)
330 {
331     Environment env(gate, circuit_, &builder_);
332     (void)successBBGates;
333     (void)failBBGates;
334     (void)endBBGates;
335     GateRef glue = acc_.GetValueIn(gate, 0);
336     GateRef size = acc_.GetValueIn(gate, 1);
337     GateRef taggedIntMask = circuit_->GetConstantGateWithoutCache(
338         MachineType::I64, JSTaggedValue::TAG_INT, GateType::NJSValue());
339     GateRef taggedSize = builder_.Int64Or(size, taggedIntMask);
340     auto id = RTSTUB_ID(AllocateInYoung);
341     if (flag == RegionSpaceFlag::IN_SHARED_OLD_SPACE) {
342         id = RTSTUB_ID(AllocateInSOld);
343     } else if (flag == RegionSpaceFlag::IN_SHARED_NON_MOVABLE) {
344         id = RTSTUB_ID(AllocateInSNonMovable);
345     } else if (flag == RegionSpaceFlag::IN_OLD_SPACE) {
346         id = RTSTUB_ID(AllocateInOld);
347     } else {
348         ASSERT(flag == RegionSpaceFlag::IN_YOUNG_SPACE);
349     }
350     GateRef target = circuit_->GetConstantGateWithoutCache(MachineType::ARCH, id, GateType::NJSValue());
351     const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(CallRuntime));
352     ASSERT(cs->IsRuntimeStub());
353     GateRef reseverdFrameArgs = circuit_->GetConstantGateWithoutCache(MachineType::I64, 0, GateType::NJSValue());
354     GateRef reseverdPc = circuit_->GetConstantGateWithoutCache(MachineType::I64, 0, GateType::NJSValue());
355     GateRef result = builder_.Call(cs, glue, target, builder_.GetDepend(),
356                                    { taggedSize, reseverdFrameArgs, reseverdPc }, Circuit::NullGate(), "Heap alloc");
357     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
358 
359     // Must keep the order of value-in/depend-in
360     PrepareToScheduleNewGate(result, currentBBGates);
361     PrepareToScheduleNewGate(target, currentBBGates);
362     PrepareToScheduleNewGate(taggedSize, currentBBGates);
363     PrepareToScheduleNewGate(reseverdFrameArgs, currentBBGates);
364     PrepareToScheduleNewGate(reseverdPc, currentBBGates);
365     PrepareToScheduleNewGate(taggedIntMask, currentBBGates);
366     return;
367 }
368 
VisitStore(GateRef gate, ControlFlowGraph &cfg, size_t bbIdx, size_t instIdx)369 bool PostSchedule::VisitStore(GateRef gate, ControlFlowGraph &cfg, size_t bbIdx, size_t instIdx)
370 {
371     std::vector<GateRef> currentBBGates;
372     std::vector<GateRef> barrierBBGates;
373     std::vector<GateRef> endBBGates;
374     MemoryAttribute::Barrier kind = GetWriteBarrierKind(gate);
375     switch (kind) {
376         case MemoryAttribute::Barrier::UNKNOWN_BARRIER: {
377             LoweringStoreUnknownBarrierAndPrepareScheduleGate(gate, currentBBGates, barrierBBGates, endBBGates);
378             ReplaceBBState(cfg, bbIdx, currentBBGates, endBBGates);
379             ScheduleEndBB(endBBGates, cfg, bbIdx, instIdx);
380             ScheduleNewBB(barrierBBGates, cfg, bbIdx);
381             ScheduleCurrentBB(currentBBGates, cfg, bbIdx, instIdx);
382             return true;
383         }
384         case MemoryAttribute::Barrier::NEED_BARRIER: {
385             LoweringStoreWithBarrierAndPrepareScheduleGate(gate, currentBBGates);
386             ReplaceGateDirectly(currentBBGates, cfg, bbIdx, instIdx);
387             return false;
388         }
389         case MemoryAttribute::Barrier::NO_BARRIER: {
390             LoweringStoreNoBarrierAndPrepareScheduleGate(gate, currentBBGates);
391             ReplaceGateDirectly(currentBBGates, cfg, bbIdx, instIdx);
392             return false;
393         }
394         default: {
395             UNREACHABLE();
396             return false;
397         }
398     }
399     return false;
400 }
401 
GetWriteBarrierKind(GateRef gate)402 MemoryAttribute::Barrier PostSchedule::GetWriteBarrierKind(GateRef gate)
403 {
404     MemoryAttribute mAttr = acc_.GetMemoryAttribute(gate);
405     if (!acc_.IsGCRelated(gate)) {
406         return MemoryAttribute::Barrier::NO_BARRIER;
407     }
408     return mAttr.GetBarrier();
409 }
410 
SelectBarrier(MemoryAttribute::ShareFlag share, const CallSignature*& cs, std::string_view& comment)411 int PostSchedule::SelectBarrier(MemoryAttribute::ShareFlag share, const CallSignature*& cs, std::string_view& comment)
412 {
413     int index = 0;
414     switch (share) {
415         case MemoryAttribute::UNKNOWN:
416             if (fastBarrier_) {
417                 index = RuntimeStubCSigns::ID_ASMFastWriteBarrier;
418                 cs = RuntimeStubCSigns::Get(index);
419                 comment = "asm store barrier\0";
420             } else {
421                 index = CommonStubCSigns::SetValueWithBarrier;
422                 cs = CommonStubCSigns::Get(index);
423                 comment = "store barrier\0";
424             }
425             break;
426         case MemoryAttribute::SHARED:
427             index = CommonStubCSigns::SetSValueWithBarrier;
428             cs = CommonStubCSigns::Get(index);
429             comment = "store share barrier\0";
430             break;
431         case MemoryAttribute::NON_SHARE:
432             index = CommonStubCSigns::SetNonSValueWithBarrier;
433             cs = CommonStubCSigns::Get(index);
434             comment = "store not share barrier\0";
435             break;
436         default:
437             UNREACHABLE();
438     }
439     return index;
440 }
441 
LoweringStoreNoBarrierAndPrepareScheduleGate(GateRef gate, std::vector<GateRef> &currentBBGates)442 void PostSchedule::LoweringStoreNoBarrierAndPrepareScheduleGate(GateRef gate, std::vector<GateRef> &currentBBGates)
443 {
444     Environment env(gate, circuit_, &builder_);
445 
446     GateRef base = acc_.GetValueIn(gate, 1);   // 1: object
447     GateRef offset = acc_.GetValueIn(gate, 2); // 2: offset
448     GateRef value = acc_.GetValueIn(gate, 3);  // 3: value
449     GateRef addr = builder_.PtrAdd(base, offset);
450     VariableType type = VariableType(acc_.GetMachineType(gate), acc_.GetGateType(gate));
451     builder_.StoreWithoutBarrier(type, addr, value, acc_.GetMemoryAttribute(gate));
452     GateRef store = builder_.GetDepend();
453     {
454         PrepareToScheduleNewGate(store, currentBBGates);
455         PrepareToScheduleNewGate(addr, currentBBGates);
456     }
457     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
458 }
459 
GetShareKind(panda::ecmascript::kungfu::GateRef gate)460 MemoryAttribute::ShareFlag PostSchedule::GetShareKind(panda::ecmascript::kungfu::GateRef gate)
461 {
462     MemoryAttribute mAttr = acc_.GetMemoryAttribute(gate);
463     return mAttr.GetShare();
464 }
465 
LoweringStoreWithBarrierAndPrepareScheduleGate(GateRef gate, std::vector<GateRef> &currentBBGates)466 void PostSchedule::LoweringStoreWithBarrierAndPrepareScheduleGate(GateRef gate, std::vector<GateRef> &currentBBGates)
467 {
468     Environment env(gate, circuit_, &builder_);
469 
470     GateRef glue = acc_.GetValueIn(gate, 0);
471     GateRef base = acc_.GetValueIn(gate, 1);   // 1: object
472     GateRef offset = acc_.GetValueIn(gate, 2); // 2: offset
473     GateRef value = acc_.GetValueIn(gate, 3);  // 3: value
474     GateRef addr = builder_.PtrAdd(base, offset);
475     VariableType type = VariableType(acc_.GetMachineType(gate), acc_.GetGateType(gate));
476     builder_.StoreWithoutBarrier(type, addr, value, acc_.GetMemoryAttribute(gate));
477     GateRef store = builder_.GetDepend();
478     MemoryAttribute::ShareFlag share = GetShareKind(gate);
479     std::string_view comment;
480     int index;
481     const CallSignature* cs = nullptr;
482     index = SelectBarrier(share, cs, comment);
483     ASSERT(cs && (cs->IsCommonStub() || cs->IsASMCallBarrierStub()) && "Invalid call signature for barrier");
484     GateRef target = circuit_->GetConstantGateWithoutCache(MachineType::ARCH, index, GateType::NJSValue());
485     GateRef reseverdFrameArgs = circuit_->GetConstantGateWithoutCache(MachineType::I64, 0, GateType::NJSValue());
486     GateRef reseverdPc = circuit_->GetConstantGateWithoutCache(MachineType::I64, 0, GateType::NJSValue());
487     GateRef storeBarrier = builder_.Call(cs, glue, target, builder_.GetDepend(),
488                                          {glue, base, offset, value, reseverdFrameArgs, reseverdPc},
489                                          Circuit::NullGate(), comment.data());
490     {
491         PrepareToScheduleNewGate(storeBarrier, currentBBGates);
492         PrepareToScheduleNewGate(reseverdPc, currentBBGates);
493         PrepareToScheduleNewGate(reseverdFrameArgs, currentBBGates);
494         PrepareToScheduleNewGate(target, currentBBGates);
495         PrepareToScheduleNewGate(store, currentBBGates);
496         PrepareToScheduleNewGate(addr, currentBBGates);
497     }
498     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
499 }
500 
LoweringStoreUnknownBarrierAndPrepareScheduleGate(GateRef gate, std::vector<GateRef> &currentBBGates, std::vector<GateRef> &barrierBBGates, std::vector<GateRef> &endBBGates)501 void PostSchedule::LoweringStoreUnknownBarrierAndPrepareScheduleGate(GateRef gate,
502                                                                      std::vector<GateRef> &currentBBGates,
503                                                                      std::vector<GateRef> &barrierBBGates,
504                                                                      std::vector<GateRef> &endBBGates)
505 {
506     Environment env(gate, circuit_, &builder_);
507 
508     GateRef glue = acc_.GetValueIn(gate, 0);
509     GateRef base = acc_.GetValueIn(gate, 1);   // 1: object
510     GateRef offset = acc_.GetValueIn(gate, 2); // 2: offset
511     GateRef value = acc_.GetValueIn(gate, 3);  // 3: value
512     GateRef addr = builder_.PtrAdd(base, offset);
513     VariableType type = VariableType(acc_.GetMachineType(gate), acc_.GetGateType(gate));
514     builder_.StoreWithoutBarrier(type, addr, value, acc_.GetMemoryAttribute(gate));
515     GateRef store = builder_.GetDepend();
516 
517     GateRef intVal = builder_.ChangeTaggedPointerToInt64(value);
518     GateRef objMask = circuit_->GetConstantGateWithoutCache(
519         MachineType::I64, JSTaggedValue::TAG_HEAPOBJECT_MASK, GateType::NJSValue());
520     GateRef masked = builder_.Int64And(intVal, objMask, GateType::Empty(), "checkHeapObject");
521     GateRef falseVal = circuit_->GetConstantGateWithoutCache(MachineType::I64, 0, GateType::NJSValue());
522     GateRef condition = builder_.Equal(masked, falseVal, "checkHeapObject");
523     Label exit(&builder_);
524     Label isHeapObject(&builder_);
525     Label *currentLabel = env.GetCurrentLabel();
526     BRANCH_CIR(condition, &isHeapObject, &exit);
527     {
528         GateRef ifBranch = currentLabel->GetControl();
529         PrepareToScheduleNewGate(ifBranch, currentBBGates);
530         PrepareToScheduleNewGate(condition, currentBBGates);
531         PrepareToScheduleNewGate(falseVal, currentBBGates);
532         PrepareToScheduleNewGate(masked, currentBBGates);
533         PrepareToScheduleNewGate(intVal, currentBBGates);
534         PrepareToScheduleNewGate(objMask, currentBBGates);
535         PrepareToScheduleNewGate(store, currentBBGates);
536         PrepareToScheduleNewGate(addr, currentBBGates);
537     }
538     GateRef ifTrue = isHeapObject.GetControl();
539     GateRef ifFalse = exit.GetControl();
540     builder_.Bind(&isHeapObject);
541     {
542         MemoryAttribute::ShareFlag share = GetShareKind(gate);
543         std::string_view comment;
544         int index;
545         const CallSignature* cs = nullptr;
546         index = SelectBarrier(share, cs, comment);
547         ASSERT(cs && (cs->IsCommonStub() || cs->IsASMCallBarrierStub()) && "Invalid call signature for barrier");
548         GateRef target = circuit_->GetConstantGateWithoutCache(MachineType::ARCH, index, GateType::NJSValue());
549         GateRef reseverdFrameArgs = circuit_->GetConstantGateWithoutCache(MachineType::I64, 0, GateType::NJSValue());
550         GateRef reseverdPc = circuit_->GetConstantGateWithoutCache(MachineType::I64, 0, GateType::NJSValue());
551 #ifndef NDEBUG
552         GateRef verifyTarget = circuit_->GetConstantGateWithoutCache(MachineType::ARCH, CommonStubCSigns::VerifyBarrier,
553                                                                      GateType::NJSValue());
554         const CallSignature* verifyBarrierCs = CommonStubCSigns::Get(CommonStubCSigns::VerifyBarrier);
555         GateRef verifyBarrier = builder_.Call(verifyBarrierCs, glue, verifyTarget, builder_.GetDepend(),
556                                               {glue, base, offset, value, reseverdFrameArgs, reseverdPc},
557                                               Circuit::NullGate(), "verify barrier");
558 #endif
559         GateRef storeBarrier = builder_.Call(cs, glue, target, builder_.GetDepend(),
560                                              { glue, base, offset, value, reseverdFrameArgs, reseverdPc },
561                                              Circuit::NullGate(), comment.data());
562         builder_.Jump(&exit);
563         {
564             GateRef ordinaryBlock = isHeapObject.GetControl();
565             PrepareToScheduleNewGate(ordinaryBlock, barrierBBGates);
566             PrepareToScheduleNewGate(storeBarrier, barrierBBGates);
567 #ifndef NDEBUG
568             PrepareToScheduleNewGate(verifyBarrier, barrierBBGates);
569 #endif
570             PrepareToScheduleNewGate(reseverdFrameArgs, barrierBBGates);
571             PrepareToScheduleNewGate(reseverdPc, barrierBBGates);
572             PrepareToScheduleNewGate(ifTrue, barrierBBGates);
573         }
574     }
575     builder_.Bind(&exit);
576     {
577         GateRef merge = builder_.GetState();
578         PrepareToScheduleNewGate(merge, endBBGates);
579         PrepareToScheduleNewGate(ifFalse, endBBGates);
580     }
581     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
582 }
583 
PrintGraph(const char* title, ControlFlowGraph &cfg)584 void PostSchedule::PrintGraph(const char* title, ControlFlowGraph &cfg)
585 {
586     LOG_COMPILER(INFO) << "======================== " << title << " ========================";
587     for (size_t bbIdx = 0; bbIdx < cfg.size(); bbIdx++) {
588         LOG_COMPILER(INFO) << "B" << bbIdx << ":";
589         const std::vector<GateRef>& bb = cfg.at(bbIdx);
590         for (size_t instIdx = 0; instIdx < bb.size(); instIdx++) {
591             GateRef gate = bb[instIdx];
592             acc_.Print(gate);
593         }
594         LOG_COMPILER(INFO) << "";
595     }
596 }
597 }  // namespace panda::ecmascript::kungfu
598