1/*
2 * Copyright (c) 2021-2022 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 <binder/binder.h>
19#include <binder/scope.h>
20#include <binder/variable.h>
21#include <compiler/base/hoisting.h>
22#include <compiler/core/compilerContext.h>
23#include <compiler/core/pandagen.h>
24
25namespace panda::es2panda::compiler {
26
27// RegScope
28
29RegScope::RegScope(PandaGen *pg) : pg_(pg), regBase_(pg_->usedRegs_) {}
30
31RegScope::~RegScope()
32{
33    pg_->totalRegs_ = std::max(pg_->totalRegs_, pg_->usedRegs_);
34    pg_->usedRegs_ = regBase_;
35}
36
37void RegScope::DebuggerCloseScope()
38{
39    if (!pg_->IsDebug()) {
40        return;
41    }
42
43    if (insStartIndex_ < pg_->insns_.size()) {
44        auto it = pg_->insns_.begin();
45        std::advance(it, insStartIndex_);
46        pg_->scope_->SetScopeStart(*it);
47    } else {
48        pg_->scope_->SetScopeStart(pg_->insns_.back());
49    }
50
51    pg_->scope_->SetScopeEnd(pg_->insns_.back());
52}
53
54// LocalRegScope
55
56LocalRegScope::LocalRegScope(PandaGen *pg) : RegScope(pg) {}
57
58LocalRegScope::LocalRegScope(PandaGen *pg, binder::Scope *scope) : RegScope(pg)
59{
60    prevScope_ = pg_->scope_;
61    pg_->scope_ = scope;
62
63    for (const auto &[_, var] : scope->Bindings()) {
64        (void)_;
65        if (!var->LexicalBound() && var->IsLocalVariable()) {
66            var->AsLocalVariable()->BindVReg(pg->AllocReg());
67        }
68    }
69
70    auto *debugInfo = &pg_->debugInfo_.variableDebugInfo;
71    if (pg_->IsDebug() && std::find(debugInfo->begin(), debugInfo->end(), pg_->scope_) == debugInfo->end()) {
72        debugInfo->push_back(pg_->scope_);
73    }
74    insStartIndex_ = pg_->insns_.size();
75
76    Hoisting::Hoist(pg_);
77}
78
79LocalRegScope::~LocalRegScope() noexcept
80{
81    if (!prevScope_) {
82        return;
83    }
84
85    DebuggerCloseScope();
86
87    pg_->scope_ = prevScope_;
88}
89
90// FunctionRegScope
91
92FunctionRegScope::FunctionRegScope(PandaGen *pg) : RegScope(pg), envScope_(pg->Allocator()->New<EnvScope>())
93{
94    ASSERT(pg_->Scope()->IsFunctionVariableScope());
95    ASSERT(pg_->NextReg() == binder::Binder::MANDATORY_PARAM_FUNC_REG);
96
97    const auto *funcScope = pg_->Scope()->AsFunctionVariableScope();
98
99    for (auto *param : funcScope->ParamScope()->Params()) {
100        VReg paramReg = pg_->AllocReg();
101        if (!param->LexicalBound()) {
102            param->BindVReg(paramReg);
103        }
104    }
105
106    envScope_->Initialize(pg_);
107
108    for (const auto &[_, var] : funcScope->Bindings()) {
109        (void)_;
110        if (var->Declaration()->IsParameterDecl()) {
111            continue;
112        }
113
114        if (!var->LexicalBound() && var->IsLocalVariable()) {
115            var->AsLocalVariable()->BindVReg(pg->AllocReg());
116        }
117    }
118
119    if (pg_->IsDebug()) {
120        pg_->debugInfo_.variableDebugInfo.push_back(funcScope);
121    }
122
123    pg_->SetSourceLocationFlag(lexer::SourceLocationFlag::INVALID_SOURCE_LOCATION);
124    pg_->LoadAccFromArgs(pg_->rootNode_);
125
126    Hoisting::Hoist(pg);
127    pg_->SetSourceLocationFlag(lexer::SourceLocationFlag::VALID_SOURCE_LOCATION);
128}
129
130FunctionRegScope::~FunctionRegScope() noexcept
131{
132    if (pg_->IsDebug()) {
133        pg_->topScope_->SetScopeStart(pg_->insns_.front());
134    }
135
136    DebuggerCloseScope();
137
138    envScope_->~EnvScope();
139}
140
141}  // namespace panda::es2panda::compiler
142