1 /*
2 * Copyright (c) 2023 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 "ecmascript/compiler/type_inference/global_type_infer.h"
17
18 namespace panda::ecmascript::kungfu {
GlobalTypeInfer(PassContext * ctx,const uint32_t methodOffset,const CString & recordName,PGOProfilerDecoder * decoder,bool enableOptTrackField,bool enableLog)19 GlobalTypeInfer::GlobalTypeInfer(PassContext *ctx, const uint32_t methodOffset, const CString &recordName,
20 PGOProfilerDecoder *decoder, bool enableOptTrackField, bool enableLog)
21 : ctx_(ctx), jsPandaFile_(ctx_->GetJSPandaFile()), bcInfo_(ctx->GetBytecodeInfo()), methodOffset_(methodOffset),
22 recordName_(recordName), decoder_(decoder), enableOptTrackField_(enableOptTrackField), enableLog_(enableLog),
23 enableGlobalTypeInfer_(ctx_->GetTSManager()->GetEcmaVM()->GetJSOptions().IsEnableGlobalTypeInfer())
24 {
25 CollectNamespaceMethods(methodOffset);
26 for (const auto namespaceMethod : namespaceTypes_) {
27 NewTypeInfer(namespaceMethod);
28 }
29 }
30
~GlobalTypeInfer()31 GlobalTypeInfer::~GlobalTypeInfer()
32 {
33 for (auto it : typeInfers_) {
34 if (it.second != nullptr) {
35 delete it.second;
36 }
37 }
38 typeInfers_.clear();
39
40 for (auto it : builders_) {
41 if (it != nullptr) {
42 delete it;
43 }
44 }
45 builders_.clear();
46
47 for (auto it: circuits_) {
48 if (it != nullptr) {
49 delete it;
50 }
51 }
52 circuits_.clear();
53 }
54
NewTypeInfer(const uint32_t methodOffset)55 void GlobalTypeInfer::NewTypeInfer(const uint32_t methodOffset)
56 {
57 auto module = ctx_->GetAOTModule();
58 auto &methodList = bcInfo_.GetMethodList();
59 MethodInfo &methodInfo = methodList.at(methodOffset);
60 const auto &methodPcInfos = bcInfo_.GetMethodPcInfos();
61 auto &methodPcInfo = methodPcInfos[methodInfo.GetMethodPcInfoIndex()];
62 auto methodLiteral = jsPandaFile_->FindMethodLiteral(methodOffset);
63 std::string fullName = module->GetFuncName(methodLiteral, jsPandaFile_);
64
65 Circuit *circuit =
66 new Circuit(ctx_->GetNativeAreaAllocator(), module->GetDebugInfo(),
67 fullName.c_str(), ctx_->GetCompilerConfig()->Is64Bit());
68 circuit->SetFrameType(FrameType::OPTIMIZED_JS_FUNCTION_FRAME);
69 circuits_.emplace_back(circuit);
70
71 BytecodeCircuitBuilder *builder =
72 new BytecodeCircuitBuilder(jsPandaFile_, methodLiteral, methodPcInfo, ctx_->GetTSManager(), circuit,
73 ctx_->GetByteCodes(), jsPandaFile_->HasTSTypes(recordName_), enableLog_, true,
74 fullName, recordName_, decoder_, false, enableOptTrackField_);
75 builder->BytecodeToCircuit();
76 builders_.emplace_back(builder);
77
78 MethodTypeInfer *typeInfer = new MethodTypeInfer(builder, circuit, ctx_, methodInfo.GetMethodInfoIndex(),
79 enableLog_, fullName, recordName_, &methodInfo,
80 methodLiteral, enableGlobalTypeInfer_);
81 typeInfers_.insert(std::make_pair(methodOffset, typeInfer));
82 }
83
CollectNamespaceMethod(const uint32_t methodOffset)84 void GlobalTypeInfer::CollectNamespaceMethod(const uint32_t methodOffset)
85 {
86 auto &methodList = bcInfo_.GetMethodList();
87 MethodInfo &methodInfo = methodList.at(methodOffset);
88 auto &innerMethods = methodInfo.GetInnerMethods();
89 uint32_t length = innerMethods.size();
90 for (uint32_t i = 0; i < length; i++) {
91 MethodInfo &innerMethodInfo = methodList.at(innerMethods[i]);
92 if (innerMethodInfo.IsNamespace()) {
93 namespaceTypes_.insert(innerMethods[i]);
94 CollectNamespaceMethod(innerMethods[i]);
95 }
96 }
97 }
98
CollectNamespaceMethods(const uint32_t methodOffset)99 void GlobalTypeInfer::CollectNamespaceMethods(const uint32_t methodOffset)
100 {
101 if (!enableGlobalTypeInfer_) {
102 namespaceTypes_.clear();
103 return;
104 }
105 CollectNamespaceMethod(methodOffset);
106 if (namespaceTypes_.size() > MAX_GLOBAL_INFER_ALLOWED) {
107 namespaceTypes_.clear();
108 }
109 }
110
ProcessTypeInference(BytecodeCircuitBuilder * builder,Circuit * circuit)111 void GlobalTypeInfer::ProcessTypeInference(BytecodeCircuitBuilder *builder, Circuit *circuit)
112 {
113 auto &methodList = bcInfo_.GetMethodList();
114 MethodInfo &methodInfo = methodList.at(methodOffset_);
115 MethodTypeInfer typeInfer(builder, circuit, ctx_, methodInfo.GetMethodInfoIndex(), enableLog_,
116 builder->GetMethodName(), recordName_, &methodInfo,
117 jsPandaFile_->FindMethodLiteral(methodOffset_),
118 enableGlobalTypeInfer_);
119
120 TSManager *tsManager = ctx_->GetTSManager();
121 std::stack<MethodTypeInfer *> typeInferStack;
122 typeInferStack.push(&typeInfer);
123 // In TS, a namespace declaration is only allowed at the top level of a namespace or module and
124 // it can be thought of as a formalization of the IIFE pattern. Based on the function definition
125 // domain chain, there will be no loops containing namespace declarations.
126 // This shows that the following stack will definitely stop.
127 while (!typeInferStack.empty()) {
128 MethodTypeInfer *infer = typeInferStack.top();
129 if (infer == nullptr) {
130 typeInferStack.pop();
131 continue;
132 }
133 uint32_t methodId = 0;
134 GateType type;
135 std::tie(type, methodId) = infer->TraverseInfer();
136 if (IsLegalMethod(methodId)) {
137 MethodTypeInfer *nextInfer = GetTypeInfer(methodId);
138 if (nextInfer != nullptr) {
139 nextInfer->SetNamespaceArgType(type);
140 tsManager->StoreNamespaceType(methodId, type);
141 typeInferStack.push(nextInfer);
142 continue;
143 }
144 }
145 typeInferStack.pop();
146 }
147
148 typeInfer.CheckAndPrint();
149 RunTypeCheck();
150 }
151
RunTypeCheck()152 void GlobalTypeInfer::RunTypeCheck()
153 {
154 for (auto it : typeInfers_) {
155 if (it.second != nullptr) {
156 it.second->CheckAndPrint();
157 }
158 }
159 }
160 } // namespace panda::ecmascript
161