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 
16 #include "lexenv.h"
17 
18 #include <binder/variable.h>
19 #include <compiler/core/compilerContext.h>
20 #include <compiler/core/envScope.h>
21 #include <compiler/core/pandagen.h>
22 #include <ir/base/classDefinition.h>
23 #include <ir/base/scriptFunction.h>
24 #include <ir/expressions/identifier.h>
25 
26 namespace panda::es2panda::compiler {
27 
28 // Helpers
29 
CheckTdz(const ir::AstNode *node)30 static bool CheckTdz(const ir::AstNode *node)
31 {
32     return node->IsIdentifier() && node->AsIdentifier()->IsTdz();
33 }
34 
CheckConstAssignment(PandaGen *pg, const ir::AstNode *node, binder::Variable *variable)35 static void CheckConstAssignment(PandaGen *pg, const ir::AstNode *node, binder::Variable *variable)
36 {
37     if (!variable->Declaration()->IsConstDecl()) {
38         return;
39     }
40 
41     pg->ThrowConstAssignment(node, variable->Name());
42 }
43 
44 // VirtualLoadVar
45 
ExpandLoadLexVar(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result)46 static void ExpandLoadLexVar(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result)
47 {
48     /**
49      *  Instruction ldsendableclass is generated when use sendable class inside itself, except static initializer.
50      *  Because static initializer is not defined with instruction definesendableclass.
51      */
52     auto decl = result.variable->Declaration();
53     if (decl->IsSendableClassDecl()) {
54         auto classDef = decl->Node()->AsClassDefinition();
55         if (classDef == util::Helpers::GetContainingSendableClass(node) &&
56             !util::Helpers::IsChildScope(classDef->StaticInitializer()->Function()->Scope(), pg->TopScope())) {
57             pg->LoadSendableClass(node, result.lexLevel);
58             return;
59         }
60     }
61 
62     auto *local = result.variable->AsLocalVariable();
63     if (local->InSendableEnv()) {
64         pg->LoadSendableVar(node, result.sendableLevel, local->LexIdx());
65     } else {
66         pg->LoadLexicalVar(node, result.lexLevel, local->LexIdx(), result.variable->Name());
67     }
68 
69     if (decl->IsLetOrConstOrClassDecl()) {
70         pg->ThrowUndefinedIfHole(node, result.variable->Name());
71     }
72 }
73 
ExpandLoadNormalVar(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result)74 static void ExpandLoadNormalVar(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result)
75 {
76     auto *local = result.variable->AsLocalVariable();
77 
78     if (CheckTdz(node)) {
79         pg->LoadConst(node, Constant::JS_HOLE);
80         pg->ThrowUndefinedIfHole(node, local->Name());
81     } else {
82         pg->LoadAccumulator(node, local->Vreg());
83     }
84 }
85 
Expand(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result)86 void VirtualLoadVar::Expand(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result)
87 {
88     if (result.variable->LexicalBound()) {
89         ExpandLoadLexVar(pg, node, result);
90     } else {
91         ExpandLoadNormalVar(pg, node, result);
92     }
93 }
94 
95 // VirtualStoreVar
96 
ExpandStoreLexVar(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result, bool isDecl)97 static void ExpandStoreLexVar(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result, bool isDecl)
98 {
99     binder::LocalVariable *local = result.variable->AsLocalVariable();
100 
101     const auto *decl = result.variable->Declaration();
102 
103     if (decl->IsLetOrConstOrClassDecl() && !isDecl) {
104         RegScope rs(pg);
105 
106         VReg valueReg = pg->AllocReg();
107         pg->StoreAccumulator(node, valueReg);
108 
109         ExpandLoadLexVar(pg, node, result);
110 
111         if (decl->IsConstDecl()) {
112             pg->ThrowConstAssignment(node, local->Name());
113         }
114 
115         pg->LoadAccumulator(node, valueReg);
116     }
117 
118     if (local->InSendableEnv()) {
119         pg->StoreSendableVar(node, result.sendableLevel, local->LexIdx());
120         return;
121     }
122     pg->StoreLexicalVar(node, result.lexLevel, local->LexIdx(), local);
123 }
124 
ExpandStoreNormalVar(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result, bool isDecl)125 static void ExpandStoreNormalVar(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result,
126                                  bool isDecl)
127 {
128     auto *local = result.variable->AsLocalVariable();
129     VReg localReg = local->Vreg();
130 
131     if (!isDecl) {
132         if (CheckTdz(node)) {
133             pg->LoadConst(node, Constant::JS_HOLE);
134             pg->ThrowUndefinedIfHole(node, local->Name());
135         }
136 
137         CheckConstAssignment(pg, node, local);
138     }
139 
140     pg->StoreAccumulator(node, localReg);
141 }
142 
Expand(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result, bool isDecl)143 void VirtualStoreVar::Expand(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result, bool isDecl)
144 {
145     if (result.variable->LexicalBound()) {
146         ExpandStoreLexVar(pg, node, result, isDecl);
147     } else {
148         ExpandStoreNormalVar(pg, node, result, isDecl);
149     }
150 }
151 
152 }  // namespace panda::es2panda::compiler
153