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#ifndef ECMASCRIPT_COMPILER_CIRCUIT_BUILDER_INL_H
16#define ECMASCRIPT_COMPILER_CIRCUIT_BUILDER_INL_H
17
18#include "ecmascript/compiler/lcr_circuit_builder.h"
19#include "ecmascript/compiler/mcr_circuit_builder.h"
20#include "ecmascript/compiler/hcr_circuit_builder.h"
21#include "ecmascript/compiler/circuit_builder.h"
22#include "ecmascript/mem/region.h"
23#include "ecmascript/method.h"
24
25namespace panda::ecmascript::kungfu {
26// constant
27GateRef CircuitBuilder::True()
28{
29    return Boolean(true);
30}
31
32GateRef CircuitBuilder::False()
33{
34    return Boolean(false);
35}
36
37GateRef CircuitBuilder::Undefined()
38{
39    return UndefineConstant();
40}
41
42GateRef CircuitBuilder::Hole()
43{
44    return HoleConstant();
45}
46
47GateRef CircuitBuilder::DoubleIsINF(GateRef x)
48{
49    GateRef infinity = Double(base::POSITIVE_INFINITY);
50    GateRef negativeInfinity = Double(-base::POSITIVE_INFINITY);
51    GateRef diff1 = DoubleEqual(x, infinity);
52    GateRef diff2 = DoubleEqual(x, negativeInfinity);
53    return BitOr(diff1, diff2);
54}
55
56GateRef CircuitBuilder::DoubleIsNanOrInf(GateRef x)
57{
58    return BitOr(DoubleIsNAN(x), DoubleIsINF(x));
59}
60
61// Js World
62// cast operation
63
64GateRef CircuitBuilder::GetGlobalConstantOffset(ConstantIndex index)
65{
66    return PtrMul(IntPtr(sizeof(JSTaggedValue)), IntPtr(static_cast<int>(index)));
67}
68
69GateRef CircuitBuilder::GetExpectedNumOfArgs(GateRef method)
70{
71    GateRef callFieldOffset = IntPtr(Method::CALL_FIELD_OFFSET);
72    GateRef callfield = Load(VariableType::INT64(), method, callFieldOffset);
73    return Int64And(
74        Int64LSR(callfield, Int64(MethodLiteral::NumArgsBits::START_BIT)),
75        Int64((1LU << MethodLiteral::NumArgsBits::SIZE) - 1));
76}
77
78int CircuitBuilder::NextVariableId()
79{
80    return env_->NextVariableId();
81}
82
83void CircuitBuilder::HandleException(GateRef result, Label *success, Label *fail, Label *exit)
84{
85    BRANCH_CIR2(Equal(result, ExceptionConstant()), fail, success);
86    Bind(fail);
87    {
88        Jump(exit);
89    }
90}
91
92void CircuitBuilder::HandleException(GateRef result, Label *success, Label *fail, Label *exit, GateRef exceptionVal)
93{
94    BRANCH_CIR2(Equal(result, exceptionVal), fail, success);
95    Bind(fail);
96    {
97        Jump(exit);
98    }
99}
100
101void CircuitBuilder::SubCfgEntry(Label *entry)
102{
103    ASSERT(env_ != nullptr);
104    env_->SubCfgEntry(entry);
105}
106
107void CircuitBuilder::SubCfgExit()
108{
109    ASSERT(env_ != nullptr);
110    env_->SubCfgExit();
111}
112
113GateRef CircuitBuilder::Return(GateRef value)
114{
115    auto control = GetCurrentLabel()->GetControl();
116    auto depend = GetCurrentLabel()->GetDepend();
117    return Return(control, depend, value);
118}
119
120GateRef CircuitBuilder::Return()
121{
122    auto control = GetCurrentLabel()->GetControl();
123    auto depend = GetCurrentLabel()->GetDepend();
124    return ReturnVoid(control, depend);
125}
126
127void CircuitBuilder::Bind(Label *label)
128{
129    label->Bind();
130    env_->SetCurrentLabel(label);
131}
132
133void CircuitBuilder::Bind(Label *label, bool justSlowPath)
134{
135    if (!justSlowPath) {
136        label->Bind();
137        env_->SetCurrentLabel(label);
138    }
139}
140
141GateRef CircuitBuilder::GetState() const
142{
143    return GetCurrentLabel()->GetControl();
144}
145
146GateRef CircuitBuilder::GetDepend() const
147{
148    return GetCurrentLabel()->GetDepend();
149}
150
151StateDepend CircuitBuilder::GetStateDepend() const
152{
153    return StateDepend(GetState(), GetDepend());
154}
155
156void CircuitBuilder::SetDepend(GateRef depend)
157{
158    GetCurrentLabel()->SetDepend(depend);
159}
160
161void CircuitBuilder::SetState(GateRef state)
162{
163    GetCurrentLabel()->SetControl(state);
164}
165
166Label *CircuitBuilder::GetCurrentLabel() const
167{
168    return GetCurrentEnvironment()->GetCurrentLabel();
169}
170
171LogicAndBuilder::LogicAndBuilder(Environment *env)
172    : env_(env), builder_(env_->GetBuilder())
173{
174    subentry_ = new Label(env_);
175    builder_->SubCfgEntry(subentry_);
176    result_ = new Variable(env_, VariableType::BOOL(), builder_->NextVariableId(), builder_->False());
177    exit_ = new Label(env_);
178}
179
180LogicAndBuilder::~LogicAndBuilder()
181{
182    ASSERT(exit_ != nullptr);
183    delete exit_;
184    exit_ = nullptr;
185    ASSERT(result_ != nullptr);
186    delete result_;
187    result_ = nullptr;
188    ASSERT(subentry_ != nullptr);
189    delete subentry_;
190    subentry_ = nullptr;
191    for (auto &label : labels_) {
192        ASSERT(label != nullptr);
193        delete label;
194        label = nullptr;
195    }
196}
197
198LogicAndBuilder &LogicAndBuilder::And(GateRef check)
199{
200    auto checkTrue = new Label(env_);
201    labels_.push_back(checkTrue);
202    builder_->Branch(check, checkTrue, exit_);
203    builder_->Bind(checkTrue);
204    return *this;
205}
206
207GateRef LogicAndBuilder::Done()
208{
209    *result_ = builder_->True();
210    builder_->Jump(exit_);
211    builder_->Bind(exit_);
212    auto ret = **result_;
213    builder_->SubCfgExit();
214    return ret;
215}
216
217LogicOrBuilder::LogicOrBuilder(Environment *env)
218    : env_(env), builder_(env_->GetBuilder())
219{
220    subentry_ = new Label(env_);
221    builder_->SubCfgEntry(subentry_);
222    result_ = new Variable(env_, VariableType::BOOL(), builder_->NextVariableId(), builder_->True());
223    exit_ = new Label(env_);
224}
225
226LogicOrBuilder::~LogicOrBuilder()
227{
228    ASSERT(exit_ != nullptr);
229    delete exit_;
230    exit_ = nullptr;
231    ASSERT(result_ != nullptr);
232    delete result_;
233    result_ = nullptr;
234    ASSERT(subentry_ != nullptr);
235    delete subentry_;
236    subentry_ = nullptr;
237    for (auto &label : labels_) {
238        ASSERT(label != nullptr);
239        delete label;
240        label = nullptr;
241    }
242}
243
244LogicOrBuilder &LogicOrBuilder::Or(GateRef check)
245{
246    auto checkFalse = new Label(env_);
247    labels_.push_back(checkFalse);
248    builder_->Branch(check, exit_, checkFalse);
249    builder_->Bind(checkFalse);
250    return *this;
251}
252
253GateRef LogicOrBuilder::Done()
254{
255    *result_ = builder_->False();
256    builder_->Jump(exit_);
257    builder_->Bind(exit_);
258    auto ret = **result_;
259    builder_->SubCfgExit();
260    return ret;
261}
262} // namespace panda::ecmascript::kungfu
263
264#endif
265