• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2025 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 "ETSfunction.h"
17 
18 #include "varbinder/varbinder.h"
19 #include "varbinder/ETSBinder.h"
20 #include "util/helpers.h"
21 #include "varbinder/scope.h"
22 #include "varbinder/variable.h"
23 #include "compiler/base/lreference.h"
24 #include "compiler/core/ETSGen.h"
25 #include "compiler/core/envScope.h"
26 #include "ir/base/spreadElement.h"
27 #include "ir/base/scriptFunction.h"
28 #include "ir/base/classDefinition.h"
29 #include "ir/base/classProperty.h"
30 #include "ir/ets/etsParameterExpression.h"
31 #include "ir/expressions/identifier.h"
32 #include "ir/statements/blockStatement.h"
33 #include "ir/ts/tsEnumDeclaration.h"
34 #include "ir/ts/tsEnumMember.h"
35 #include "checker/types/ets/types.h"
36 
37 namespace ark::es2panda::compiler {
38 
39 // #22952: this should have been done in lowering
CallImplicitCtor(ETSGen * etsg)40 void ETSFunction::CallImplicitCtor(ETSGen *etsg)
41 {
42     RegScope rs(etsg);
43     auto *superType = etsg->ContainingObjectType()->SuperType();
44 
45     if (superType == nullptr) {
46         etsg->CallExact(etsg->RootNode(), Signatures::BUILTIN_OBJECT_CTOR, etsg->GetThisReg());
47 
48         return;
49     }
50 
51     auto res = std::find_if(superType->ConstructSignatures().cbegin(), superType->ConstructSignatures().cend(),
52                             [](const checker::Signature *sig) { return sig->MinArgCount() == 0; });
53     if (res == superType->ConstructSignatures().cend()) {
54         ES2PANDA_ASSERT(superType->ConstructSignatures().empty());
55         return;
56     }
57     auto sig = *res;
58     if (sig->ArgCount() == 0) {
59         etsg->CallExact(etsg->RootNode(), (*res)->InternalName(), etsg->GetThisReg());
60     } else {
61         etsg->CallRangeFillUndefined(etsg->RootNode(), *res, etsg->GetThisReg());
62     }
63 }
64 
CompileSourceBlock(ETSGen * etsg,const ir::BlockStatement * block)65 void ETSFunction::CompileSourceBlock(ETSGen *etsg, const ir::BlockStatement *block)
66 {
67     auto *scriptFunc = etsg->RootNode()->AsScriptFunction();
68 
69     if (scriptFunc->IsEnum()) {
70         // NOTE: add enum methods
71     } else if (scriptFunc->IsStaticBlock()) {
72         CompileAsStaticBlock(etsg);
73     } else if (scriptFunc->IsConstructor()) {
74         CompileAsConstructor(etsg, scriptFunc);
75     }
76 
77     const auto &statements = block->Statements();
78 
79     if (statements.empty()) {
80         etsg->SetFirstStmt(block);
81         ExtendWithDefaultReturn(etsg, block, scriptFunc);
82         return;
83     }
84 
85     etsg->SetFirstStmt(statements.front());
86 
87     etsg->CompileStatements(statements);
88 
89     if (!statements.back()->IsReturnStatement()) {
90         ExtendWithDefaultReturn(etsg, statements.back(), scriptFunc);
91     }
92 }
93 
ExtendWithDefaultReturn(ETSGen * etsg,const ir::AstNode * node,const ir::ScriptFunction * scriptFunc)94 void ETSFunction::ExtendWithDefaultReturn(ETSGen *etsg, const ir::AstNode *node, const ir::ScriptFunction *scriptFunc)
95 {
96     if (etsg->ReturnType()->IsETSVoidType()) {
97         etsg->EmitReturnVoid(node);
98         return;
99     }
100 
101     if (scriptFunc->ReturnTypeAnnotation() != nullptr && scriptFunc->ReturnTypeAnnotation()->TsType() != nullptr &&
102         scriptFunc->ReturnTypeAnnotation()->TsType()->IsETSAsyncFuncReturnType()) {
103         etsg->LoadDefaultValue(node, scriptFunc->ReturnTypeAnnotation()->TsType());
104     } else {
105         etsg->LoadDefaultValue(node, scriptFunc->Signature()->ReturnType());
106     }
107     etsg->ReturnAcc(node);
108 }
109 
CompileAsStaticBlock(ETSGen * etsg)110 void ETSFunction::CompileAsStaticBlock(ETSGen *etsg)
111 {
112     const auto *classDef = etsg->ContainingObjectType()->GetDeclNode()->AsClassDefinition();
113 
114     auto const checkInitializer = [](ArenaVector<ir::AstNode *> const &nodes) -> bool {
115         for (auto const *const node : nodes) {
116             if (node->IsMethodDefinition() && node->AsClassElement()->Key()->IsIdentifier() &&
117                 node->AsClassElement()->Id()->Name() == compiler::Signatures::INIT_METHOD) {
118                 return false;
119             }
120         }
121         return true;
122     };
123 
124     // Check if it is the Global class static constructor and the special '_$init$_" method exists
125     bool const compileInitializer = classDef->IsGlobal() ? checkInitializer(classDef->Body()) : true;
126 
127     for (const auto *prop : classDef->Body()) {
128         if (!prop->IsClassProperty() || !prop->IsStatic()) {
129             continue;
130         }
131 
132         // Don't compile variable initializers if they present in '_$init$_" method
133         auto *const item = prop->AsClassProperty();
134         if (item->Value() != nullptr &&
135             (compileInitializer || item->IsConst() || item->Value()->IsArrowFunctionExpression())) {
136             item->Compile(etsg);
137         }
138     }
139 }
140 
CompileAsConstructor(ETSGen * etsg,const ir::ScriptFunction * scriptFunc)141 void ETSFunction::CompileAsConstructor(ETSGen *etsg, const ir::ScriptFunction *scriptFunc)
142 {
143     if (scriptFunc->IsImplicitSuperCallNeeded()) {
144         CallImplicitCtor(etsg);
145     }
146 
147     const auto *classDef = etsg->ContainingObjectType()->GetDeclNode()->AsClassDefinition();
148 
149     for (const auto *prop : classDef->Body()) {
150         if (prop->IsClassProperty() && !prop->IsStatic()) {
151             prop->AsClassProperty()->Compile(etsg);
152         }
153     }
154 }
155 
CompileFunction(ETSGen * etsg)156 void ETSFunction::CompileFunction(ETSGen *etsg)
157 {
158     if (const auto *decl = etsg->RootNode()->AsScriptFunction(); !decl->IsDeclare() && !decl->IsExternal()) {
159         if (auto *const body = decl->Body(); body != nullptr && body->IsBlockStatement()) {
160             CompileSourceBlock(etsg, body->AsBlockStatement());
161         }
162     }
163 }
164 
Compile(ETSGen * etsg)165 void ETSFunction::Compile(ETSGen *etsg)
166 {
167     FunctionRegScope lrs(etsg);
168     auto *topScope = etsg->TopScope();
169 
170     if (topScope->IsFunctionScope()) {
171         CompileFunction(etsg);
172     } else {
173         ES2PANDA_ASSERT(topScope->IsGlobalScope());
174         CompileSourceBlock(etsg, etsg->RootNode()->AsBlockStatement());
175     }
176 
177     etsg->SortCatchTables();
178 }
179 
180 }  // namespace ark::es2panda::compiler
181