• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 "evaluate/debugInfoDeserialization/methodBuilder.h"
17 #include "checker/ETSchecker.h"
18 #include "libpandafile/file-inl.h"
19 #include "libpandafile/method_data_accessor-inl.h"
20 #include "libpandafile/proto_data_accessor-inl.h"
21 #include "evaluate/helpers.h"
22 
23 namespace ark::es2panda::evaluate {
24 
25 namespace {
26 
GetFieldName(size_t fieldIdx)27 std::string GetFieldName(size_t fieldIdx)
28 {
29     std::stringstream sstream;
30     sstream << "field" << fieldIdx;
31     return sstream.str();
32 }
33 
GetFunctionParameters(checker::ETSChecker * checker,panda_file::MethodDataAccessor & mda)34 ArenaVector<ir::TypeNode *> GetFunctionParameters(checker::ETSChecker *checker, panda_file::MethodDataAccessor &mda)
35 {
36     const auto &pf = mda.GetPandaFile();
37     ArenaVector<ir::TypeNode *> parameters(checker->Allocator()->Adapter());
38     mda.EnumerateTypesInProto(
39         [checker, &parameters, &pf = std::as_const(pf)](panda_file::Type type, panda_file::File::EntityId classId) {
40             auto *typeNode = helpers::PandaTypeToTypeNode(pf, type, classId, checker);
41             ASSERT(typeNode);
42             parameters.push_back(typeNode);
43         },
44         true);  // true -- skip `this` parameter
45 
46     return parameters;
47 }
48 
CreateTypedReturnStatement(checker::ETSChecker * checker,ir::TypeNode * type)49 ir::ReturnStatement *CreateTypedReturnStatement(checker::ETSChecker *checker, ir::TypeNode *type)
50 {
51     ASSERT(type);
52 
53     if (type->IsETSPrimitiveType() && type->AsETSPrimitiveType()->GetPrimitiveType() == ir::PrimitiveType::VOID) {
54         return checker->AllocNode<ir::ReturnStatement>();
55     }
56 
57     // Hack for correct validation. This function call won't be executed in compiled code,
58     // as the whole class declaration only mimics the real code loaded into runtime.
59 
60     auto *allocator = checker->Allocator();
61     auto *apiClass = checker->AllocNode<ir::Identifier>(helpers::DEBUGGER_API_CLASS_NAME, allocator);
62     auto *prop =
63         checker->AllocNode<ir::Identifier>(helpers::CreateGetterName(panda_file::Type::TypeId::REFERENCE), allocator);
64     auto *callee = checker->AllocNode<ir::MemberExpression>(apiClass, prop, ir::MemberExpressionKind::PROPERTY_ACCESS,
65                                                             false, false);
66 
67     ArenaVector<ir::Expression *> args(1, checker->AllocNode<ir::NumberLiteral>("0"), allocator->Adapter());
68     auto *callExpression = checker->AllocNode<ir::CallExpression>(callee, std::move(args), nullptr, false);
69 
70     auto *asExpression = checker->AllocNode<ir::TSAsExpression>(callExpression, type->Clone(allocator, nullptr), false);
71     return checker->AllocNode<ir::ReturnStatement>(asExpression);
72 }
73 
74 }  // namespace
75 
MethodBuilder(checker::ETSChecker * checker,panda_file::MethodDataAccessor & mda,ir::ModifierFlags classModifierFlags)76 MethodBuilder::MethodBuilder(checker::ETSChecker *checker, panda_file::MethodDataAccessor &mda,
77                              ir::ModifierFlags classModifierFlags)
78     : checker_(checker), mda_(mda), params_(checker_->Allocator()->Adapter()), classModifierFlags_(classModifierFlags)
79 {
80     methodName_ = util::UString(mda_.GetFullName(), checker_->Allocator()).View();
81     modifierFlags_ = ir::ModifierFlags::EXPORT | helpers::GetModifierFlags(mda_, true);
82 }
83 
Build()84 ir::AstNode *MethodBuilder::Build() &&
85 {
86     ArenaVector<ir::Statement *> statements(checker_->Allocator()->Adapter());
87 
88     CollectParametersAndReturnType();
89 
90     bool isCtor = IsConstructor();
91     bool isCctor = IsStaticConstructor();
92 
93     if (isCtor) {
94         auto *superConstructorCallStatement = CreateSuperConstructorExpressionCall();
95         statements.push_back(superConstructorCallStatement);
96     }
97 
98     auto *retStatement = CreateTypedReturnStatement(checker_, returnType_);
99     statements.push_back(retStatement);
100 
101     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
102     auto *id = checker_->AllocNode<ir::Identifier>(methodName_, checker_->Allocator());
103     auto *body = CreateBody(std::move(statements));
104 
105     if (isCtor) {
106         return CreateIrConstructor<false>(id, body);
107     }
108     if (isCctor) {
109         return CreateIrConstructor<true>(id, body);
110     }
111     return CreateIrMethod(id, body);
112 }
113 
CollectParametersAndReturnType()114 void MethodBuilder::CollectParametersAndReturnType()
115 {
116     auto parameters = GetFunctionParameters(checker_, mda_);
117     auto *checker = checker_->Allocator();
118 
119     // Start from 1, because 0 is return type
120     for (size_t idx = 1U; idx < parameters.size(); ++idx) {
121         util::UString paramName(GetFieldName(idx), checker);
122         // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
123         auto *paramIdent = checker_->AllocNode<ir::Identifier>(paramName.View(), parameters[idx], checker);
124         // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
125         auto *param = checker_->AllocNode<ir::ETSParameterExpression>(paramIdent, nullptr);
126         params_.push_back(param);
127     }
128 
129     returnType_ = parameters[0];
130 }
131 
CreateBody(ArenaVector<ir::Statement * > statements)132 ir::BlockStatement *MethodBuilder::CreateBody(ArenaVector<ir::Statement *> statements)
133 {
134     bool isAbstractClass = ((classModifierFlags_ & ir::ModifierFlags::ABSTRACT) != 0);
135     bool isAbstractMethod = ((modifierFlags_ & ir::ModifierFlags::ABSTRACT) != 0);
136     bool needToCreateBody = !(isAbstractClass && isAbstractMethod);
137 
138     ir::BlockStatement *body = nullptr;
139     if (needToCreateBody) {
140         // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
141         body = checker_->AllocNode<ir::BlockStatement>(checker_->Allocator(), std::move(statements));
142     }
143 
144     return body;
145 }
146 
CreateSuperConstructorExpressionCall()147 ir::ExpressionStatement *MethodBuilder::CreateSuperConstructorExpressionCall()
148 {
149     // NOTE: in future it may be necessary to pass non empty call args,
150     // but currently frontend do not check args number.
151     ArenaVector<ir::Expression *> callArguments(checker_->Allocator()->Adapter());
152 
153     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
154     auto *callee = checker_->AllocNode<ir::SuperExpression>();
155     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
156     auto *superConstructorCall =
157         checker_->AllocNode<ir::CallExpression>(callee, std::move(callArguments), nullptr, false);
158     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
159     return checker_->AllocNode<ir::ExpressionStatement>(superConstructorCall);
160 }
161 
162 template <bool IS_STATIC>
CreateIrConstructor(ir::Identifier * id,ir::BlockStatement * body)163 ir::AstNode *MethodBuilder::CreateIrConstructor(ir::Identifier *id, ir::BlockStatement *body)
164 {
165     auto scriptFuncFlags = ir::ScriptFunctionFlags::EXPRESSION |
166                            (IS_STATIC ? ir::ScriptFunctionFlags::STATIC_BLOCK : ir::ScriptFunctionFlags::CONSTRUCTOR);
167 
168     auto *funcExpr = CreateFunctionExpression(id, body, scriptFuncFlags);
169     auto *allocator = checker_->Allocator();
170 
171     if constexpr (IS_STATIC) {
172         // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
173         auto *staticBlock = checker_->AllocNode<ir::ClassStaticBlock>(funcExpr, allocator);
174         staticBlock->AddModifier(ir::ModifierFlags::STATIC);
175         return staticBlock;
176     }
177     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
178     return checker_->AllocNode<ir::MethodDefinition>(ir::MethodDefinitionKind::CONSTRUCTOR,
179                                                      id->Clone(allocator, nullptr), funcExpr, ir::ModifierFlags::NONE,
180                                                      allocator, false);
181 }
182 
CreateIrMethod(ir::Identifier * id,ir::BlockStatement * body)183 ir::MethodDefinition *MethodBuilder::CreateIrMethod(ir::Identifier *id, ir::BlockStatement *body)
184 {
185     auto *allocator = checker_->Allocator();
186     auto *funcExpr = CreateFunctionExpression(id, body, ir::ScriptFunctionFlags::METHOD);
187     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
188     auto *method = checker_->AllocNode<ir::MethodDefinition>(ir::MethodDefinitionKind::METHOD,
189                                                              funcExpr->Function()->Id()->Clone(allocator, nullptr),
190                                                              funcExpr, modifierFlags_, allocator, false);
191     return method;
192 }
193 
CreateFunctionExpression(ir::Identifier * id,ir::BlockStatement * body,ir::ScriptFunctionFlags scriptFuncFlags)194 ir::FunctionExpression *MethodBuilder::CreateFunctionExpression(ir::Identifier *id, ir::BlockStatement *body,
195                                                                 ir::ScriptFunctionFlags scriptFuncFlags)
196 {
197     auto funcSignature = ir::FunctionSignature(nullptr, std::move(params_), nullptr);
198 
199     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
200     auto *func = checker_->AllocNode<ir::ScriptFunction>(
201         checker_->Allocator(),
202         ir::ScriptFunction::ScriptFunctionData {body, std::move(funcSignature), scriptFuncFlags, modifierFlags_});
203 
204     func->SetIdent(id);
205     func->SetReturnTypeAnnotation(returnType_);
206 
207     // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
208     return checker_->AllocNode<ir::FunctionExpression>(func);
209 }
210 
211 }  // namespace ark::es2panda::evaluate
212