1/*
2 * Copyright (c) 2024 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#ifndef ECMASCRIPT_COMPILER_STRING_BUILDER_OPTIMIZER_H
17#define ECMASCRIPT_COMPILER_STRING_BUILDER_OPTIMIZER_H
18
19#include "ecmascript/compiler/argument_accessor.h"
20#include "ecmascript/compiler/bytecode_circuit_builder.h"
21#include "ecmascript/compiler/circuit_builder-inl.h"
22#include "ecmascript/compiler/combined_pass_visitor.h"
23#include "ecmascript/compiler/graph_linearizer.h"
24
25namespace panda::ecmascript::kungfu {
26class StringBuilderOptimizer {
27public:
28    StringBuilderOptimizer(Circuit* circuit,
29                           bool enableLog,
30                           const std::string& name,
31                           CompilationConfig* cmpCfg,
32                           Chunk* chunk)
33        : circuit_(circuit),
34          acc_(circuit),
35          builder_(circuit, cmpCfg),
36          graphLinearizer_(circuit, enableLog, name, chunk, true, true),
37          dependEntry_(circuit->GetDependRoot()),
38          status_(chunk),
39          stringBuilders_(chunk),
40          toVisit_(chunk),
41          ends_(chunk),
42          concatGates_(chunk) {}
43
44    ~StringBuilderOptimizer() = default;
45
46    void Run();
47private:
48    static constexpr int INVALID_ID = -1;
49    enum State {
50        UNVISITED = 0,
51        BEGIN_STRING_BUILDER,
52        IN_STRING_BUILDER,
53        PENDING_PHI,
54        CONFIRMED_IN_STRING_BUILDER,
55        END_STRING_BUILDER,
56        END_STRING_BUILDER_LOOP_PHI,
57        INVALID_OPT,
58        NUM_OF_STATE,
59    };
60
61    struct Status {
62        int id {INVALID_ID};
63        State state {State::INVALID_OPT};
64    };
65
66    Status& GetStatus(GateRef gate)
67    {
68        ASSERT(acc_.GetId(gate) < status_.size());
69        return status_[acc_.GetId(gate)];
70    }
71    const Status& GetStatus(GateRef gate) const
72    {
73        ASSERT(acc_.GetId(gate) < status_.size());
74        return status_[acc_.GetId(gate)];
75    }
76    void SetStatus(GateRef gate, State state, int id = INVALID_ID)
77    {
78        status_[acc_.GetId(gate)] = Status{id, state};
79    }
80    void UpdateStatus(GateRef gate, State state)
81    {
82        int id = state == State::INVALID_OPT ? INVALID_ID : GetStatus(gate).id;
83        status_[acc_.GetId(gate)] = Status{id, state};
84    }
85    bool IsInvalidGate(GateRef gate) const
86    {
87        return GetStatus(gate).state == State::INVALID_OPT;
88    }
89
90    struct StringBuilder {
91        GateRef start {Circuit::NullGate()};
92        int id {INVALID_ID};
93        bool has_loop_phi {false};
94    };
95
96    void VisitGraph();
97    void FindBuilderBegin(GateRef gate);
98    void FindInBuilder(GateRef gate);
99    void FinalizeStringBuilders();
100    void VisitGateUse(GateRef use);
101    void StatusTransfer(GateRef gate);
102    bool HasConcatOrPhiUse(GateRef gate);
103    bool CheckStringAddUses(GateRef gate);
104    bool IsLiteralString(GateRef gate);
105    bool IsLoopHeader(GateRef gate);
106    bool LoopContains(GateRef loopPhi, GateRef gate);
107    bool PhiInputsAreConcatsOrPhi(GateRef phi);
108
109    Circuit *circuit_;
110    GateAccessor acc_;
111    CircuitBuilder builder_;
112    GraphLinearizer graphLinearizer_;
113    GateRef dependEntry_;
114
115    uint32_t stringBuilderCount_ {0};
116    size_t currentIndex_ {0};
117    GateId curStringAddId_ {0};
118
119    ChunkVector<Status> status_;
120    ChunkVector<StringBuilder> stringBuilders_;
121    ChunkVector<GateRef> toVisit_;
122    ChunkVector<GateRef> ends_;
123    ChunkVector<GateRef> concatGates_;
124};
125}  // panda::ecmascript::kungfu
126#endif  // ECMASCRIPT_COMPILER_STRING_BUILDER_OPTIMIZER_H