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
23namespace panda::ecmascript::kungfu {
24void 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
41void 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
76bool 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
107void 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
114void 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
123void 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
130void 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
142void PostSchedule::PrepareToScheduleNewGate(GateRef gate, std::vector<GateRef> &gates)
143{
144    gates.emplace_back(gate);
145}
146
147void 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
192void 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
324void 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
369bool 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
402MemoryAttribute::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
411int 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
442void 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
460MemoryAttribute::ShareFlag PostSchedule::GetShareKind(panda::ecmascript::kungfu::GateRef gate)
461{
462    MemoryAttribute mAttr = acc_.GetMemoryAttribute(gate);
463    return mAttr.GetShare();
464}
465
466void 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
501void 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
584void 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