• 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)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