• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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,bool hasType)19 GlobalTypeInfer::GlobalTypeInfer(PassContext *ctx, const uint32_t methodOffset, const CString &recordName,
20                                  PGOProfilerDecoder *decoder, bool enableOptTrackField, bool enableLog, bool hasType)
21     : ctx_(ctx), jsPandaFile_(ctx_->GetJSPandaFile()), bcInfo_(ctx->GetBytecodeInfo()), methodOffset_(methodOffset),
22       recordName_(recordName), decoder_(decoder), enableOptTrackField_(enableOptTrackField), enableLog_(enableLog),
23       hasType_(hasType), enableGlobalTypeInfer_(
24                             ctx_->GetTSManager()->GetEcmaVM()->GetJSOptions().IsEnableGlobalTypeInfer())
25 {
26     CollectNamespaceMethods(methodOffset);
27     for (const auto namespaceMethod : namespaceTypes_) {
28         NewTypeInfer(namespaceMethod);
29     }
30 }
31 
~GlobalTypeInfer()32 GlobalTypeInfer::~GlobalTypeInfer()
33 {
34     for (auto it : typeInfers_) {
35         if (it.second != nullptr) {
36             delete it.second;
37         }
38     }
39     typeInfers_.clear();
40 
41     for (auto it : builders_) {
42         if (it != nullptr) {
43             delete it;
44         }
45     }
46     builders_.clear();
47 
48     for (auto it:  circuits_) {
49         if (it != nullptr) {
50             delete it;
51         }
52     }
53     circuits_.clear();
54 }
55 
NewTypeInfer(const uint32_t methodOffset)56 void GlobalTypeInfer::NewTypeInfer(const uint32_t methodOffset)
57 {
58     auto module = ctx_->GetAOTModule();
59     auto &methodList = bcInfo_.GetMethodList();
60     MethodInfo &methodInfo = methodList.at(methodOffset);
61     const auto &methodPcInfos = bcInfo_.GetMethodPcInfos();
62     auto &methodPcInfo = methodPcInfos[methodInfo.GetMethodPcInfoIndex()];
63     auto methodLiteral = jsPandaFile_->FindMethodLiteral(methodOffset);
64     std::string fullName = module->GetFuncName(methodLiteral, jsPandaFile_);
65 
66     Circuit *circuit = new Circuit(ctx_->GetNativeAreaAllocator(), module->GetDebugInfo(),
67                                    fullName.c_str(), ctx_->GetCompilerConfig()->Is64Bit(),
68                                    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_, hasType_);
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_, hasType_);
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