1/*
2 * Copyright (c) 2021 - 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#include "regScope.h"
17
18#include "varbinder/varbinder.h"
19#include "varbinder/scope.h"
20#include "varbinder/variable.h"
21#include "compiler/base/hoisting.h"
22#include "compiler/core/codeGen.h"
23#include "compiler/core/pandagen.h"
24#include "compiler/core/moduleContext.h"
25
26namespace ark::es2panda::compiler {
27// RegScope
28
29RegScope::RegScope(CodeGen *cg) : cg_(cg), regBase_(cg_->usedRegs_) {}
30
31RegScope::~RegScope()
32{
33    cg_->totalRegs_ = std::min(cg_->totalRegs_, cg_->usedRegs_);
34    cg_->usedRegs_ = regBase_;
35}
36
37void RegScope::DebuggerCloseScope()
38{
39    if (!cg_->IsDebug()) {
40        return;
41    }
42
43    cg_->scope_->SetScopeEnd(cg_->insns_.back());
44}
45
46// LocalRegScope
47
48LocalRegScope::LocalRegScope(PandaGen *pg) : RegScope(pg) {}
49
50LocalRegScope::LocalRegScope(CodeGen *cg, varbinder::Scope *scope) : RegScope(cg)
51{
52    prevScope_ = cg_->scope_;
53    cg_->scope_ = scope;
54
55    for (const auto &[_, var] : scope->OrderedBindings(cg_->Allocator())) {
56        (void)_;
57        if (!var->LexicalBound() && var->IsLocalVariable()) {
58            var->AsLocalVariable()->BindVReg(cg_->AllocReg());
59        }
60    }
61
62    if (cg_->IsDebug() && !cg_->insns_.empty()) {
63        cg_->scope_->SetScopeStart(cg_->insns_.back());
64        cg_->debugInfo_.VariableDebugInfo().push_back(cg_->scope_);
65    }
66}
67
68LocalRegScope::LocalRegScope(PandaGen *pg, varbinder::Scope *scope) : LocalRegScope(static_cast<CodeGen *>(pg), scope)
69{
70    Hoisting::Hoist(pg);
71}
72
73LocalRegScope::~LocalRegScope()
74{
75    if (prevScope_ == nullptr) {
76        return;
77    }
78
79    DebuggerCloseScope();
80
81    cg_->scope_ = prevScope_;
82}
83
84// FunctionRegScope
85
86FunctionRegScope::FunctionRegScope(CodeGen *cg) : RegScope(cg)
87{
88    InitializeParams([](varbinder::LocalVariable *const param, const VReg paramReg) { param->BindVReg(paramReg); });
89}
90
91void FunctionRegScope::InitializeParams(const StoreParamCb &cb)
92{
93    const auto *funcScope = cg_->Scope()->AsFunctionVariableScope();
94
95    VReg paramReg = VReg(VReg::PARAM_START);
96    for (auto *param : funcScope->ParamScope()->Params()) {
97        cg_->SetVRegType(paramReg, cg_->TypeForVar(param));
98        cb(param, paramReg);
99        paramReg++;
100    }
101
102    for (const auto it : funcScope->OrderedBindings(cg_->Allocator())) {
103        auto *const var = std::get<1>(it);
104        if (var->Declaration()->IsParameterDecl() || var->Declaration()->IsTypeAliasDecl()) {
105            continue;
106        }
107
108        if (!var->LexicalBound() && var->IsLocalVariable()) {
109            const auto vreg = cg_->AllocReg();
110            var->AsLocalVariable()->BindVReg(vreg);
111        }
112    }
113
114    if (cg_->IsDebug()) {
115        cg_->debugInfo_.VariableDebugInfo().push_back(funcScope);
116    }
117}
118
119FunctionRegScope::FunctionRegScope(PandaGen *pg) : RegScope(pg), envScope_(pg->Allocator()->New<EnvScope>())
120{
121    ASSERT(cg_->Scope()->IsFunctionVariableScope());
122    ASSERT(cg_->NextReg().GetIndex() == VReg::REG_START);
123
124    VReg lexEnv = pg->AllocReg();
125    envScope_->Initialize(pg, lexEnv);
126
127    const auto *funcScope = pg->Scope()->AsFunctionVariableScope();
128    const auto *node = pg->RootNode();
129
130    if (funcScope->NeedLexEnv()) {
131        pg->NewLexEnv(node, funcScope->LexicalSlots());
132    } else {
133        pg->LdLexEnv(node);
134    }
135
136    pg->StoreAccumulator(node, lexEnv);
137
138    InitializeParams([pg, node](varbinder::LocalVariable *const param, const VReg paramReg) {
139        if (param->LexicalBound()) {
140            pg->LoadAccumulator(node, paramReg);
141            pg->StoreLexicalVar(node, 0, param->LexIdx());
142        } else {
143            param->BindVReg(paramReg);
144        }
145    });
146
147    pg->LoadAccFromArgs(pg->rootNode_);
148
149    if (funcScope->IsModuleScope()) {
150        ModuleContext::Compile(pg, pg->scope_->AsModuleScope());
151    }
152
153    Hoisting::Hoist(pg);
154}
155
156FunctionRegScope::~FunctionRegScope()
157{
158    if (cg_->IsDebug() && !cg_->insns_.empty()) {
159        cg_->topScope_->SetScopeStart(cg_->insns_.front());
160        DebuggerCloseScope();
161    }
162
163    if (envScope_ != nullptr) {
164        envScope_->~EnvScope();
165    }
166}
167}  // namespace ark::es2panda::compiler
168