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