• 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/initialization_analysis.h"
17 #include "ecmascript/ts_types/ts_type_accessor.h"
18 
19 namespace panda::ecmascript::kungfu {
Run()20 void InitializationAnalysis::Run()
21 {
22     if (classType_.IsAnyType()) {
23         return;
24     }
25 
26     CollectThisEscapedInfo(thisObject_);
27     std::vector<GateRef> gateList;
28     circuit_->GetAllGates(gateList);
29     for (const auto &gate : gateList) {
30         auto op = acc_.GetOpCode(gate);
31         if (op == OpCode::JS_BYTECODE) {
32             Analyse(gate);
33         }
34     }
35     MarkHasAnalysedInitialization();
36 
37     if (IsLogEnabled()) {
38         Print();
39     }
40 }
41 
Analyse(GateRef gate)42 void InitializationAnalysis::Analyse(GateRef gate)
43 {
44     ASSERT(acc_.GetOpCode(gate) == OpCode::JS_BYTECODE);
45     EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
46     switch (ecmaOpcode) {
47         case EcmaOpcode::STOBJBYNAME_IMM8_ID16_V8:
48         case EcmaOpcode::STOBJBYNAME_IMM16_ID16_V8: {
49             CollectInitializationType(gate, ThisUsage::INDEFINITE_THIS);
50             CollectInitializationInfo(gate, ThisUsage::INDEFINITE_THIS);
51             break;
52         }
53         case EcmaOpcode::STTHISBYNAME_IMM8_ID16:
54         case EcmaOpcode::STTHISBYNAME_IMM16_ID16: {
55             CollectInitializationType(gate, ThisUsage::DEFINITE_THIS);
56             CollectInitializationInfo(gate, ThisUsage::DEFINITE_THIS);
57             break;
58         }
59         case EcmaOpcode::SUPERCALLTHISRANGE_IMM8_IMM8_V8:
60         case EcmaOpcode::WIDE_SUPERCALLTHISRANGE_PREF_IMM16_V8:
61         case EcmaOpcode::SUPERCALLARROWRANGE_IMM8_IMM8_V8:
62         case EcmaOpcode::WIDE_SUPERCALLARROWRANGE_PREF_IMM16_V8:
63         case EcmaOpcode::SUPERCALLSPREAD_IMM8_V8: {
64             MarkSuperClass();
65             CollectThisEscapedInfo(gate);
66             break;
67         }
68         default: {
69             break;
70         }
71     }
72 }
73 
CollectInitializationType(GateRef gate,ThisUsage thisUsage)74 void InitializationAnalysis::CollectInitializationType(GateRef gate, ThisUsage thisUsage)
75 {
76     GateRef value = acc_.GetValueIn(gate, 3);  // 3: index of value
77     GateType valueType = acc_.GetGateType(value);
78     if (valueType.IsAnyType()) {
79         return;
80     }
81     if (thisUsage == ThisUsage::INDEFINITE_THIS) {
82         GateRef receiver = acc_.GetValueIn(gate, 2);  // 2: index of receiver
83         GateType receiverType = acc_.GetGateType(receiver);
84         auto receiverGT = receiverType.GetGTRef();
85         if (tsManager_->IsClassInstanceTypeKind(receiverType)) {
86             receiverGT = tsManager_->GetClassType(receiverType);
87         }
88         if (!CheckIsThisObject(receiver) && receiverGT != classType_.GetGTRef()) {
89             return;
90         }
91     }
92 
93     uint16_t index = acc_.GetConstantValue(acc_.GetValueIn(gate, 1));  // 1: stringId
94     JSTaggedValue propKey = tsManager_->GetStringFromConstantPool(index);
95 
96     if (valueType.IsNumberType()) {
97         valueType = GateType::NumberType();
98     }
99 
100     TSTypeAccessor typeAccessor(tsManager_, classType_);
101     typeAccessor.UpdateNonStaticProp(propKey, valueType.GetGTRef());
102 }
103 
CollectInitializationInfo(GateRef gate,ThisUsage thisUsage)104 void InitializationAnalysis::CollectInitializationInfo(GateRef gate, ThisUsage thisUsage)
105 {
106     if (thisUsage == ThisUsage::INDEFINITE_THIS) {
107         GateRef receiver = acc_.GetValueIn(gate, 2);  // 2: index of receiver
108         if (!CheckIsThisObject(receiver)) {
109             return;
110         }
111     }
112 
113     uint16_t index = acc_.GetConstantValue(acc_.GetValueIn(gate, 1));  // 1: stringId
114     if (!CheckSimpleCFG(gate, index)) {
115         return;
116     }
117     JSTaggedValue propKey = tsManager_->GetStringFromConstantPool(index);
118     TSTypeAccessor typeAccessor(tsManager_, classType_);
119     typeAccessor.MarkPropertyInitialized(propKey);
120 }
121 
CheckIsThisObject(GateRef receiver) const122 bool InitializationAnalysis::CheckIsThisObject(GateRef receiver) const
123 {
124     return IsThisFromArg(receiver) || IsThisFromSuperCall(receiver);
125 }
126 
IsThisFromSuperCall(GateRef gate) const127 bool InitializationAnalysis::IsThisFromSuperCall(GateRef gate) const
128 {
129     auto op = acc_.GetOpCode(gate);
130     if (op != OpCode::JS_BYTECODE) {
131         return false;
132     }
133     EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
134     switch (ecmaOpcode) {
135         case EcmaOpcode::SUPERCALLTHISRANGE_IMM8_IMM8_V8:
136         case EcmaOpcode::WIDE_SUPERCALLTHISRANGE_PREF_IMM16_V8:
137         case EcmaOpcode::SUPERCALLARROWRANGE_IMM8_IMM8_V8:
138         case EcmaOpcode::WIDE_SUPERCALLARROWRANGE_PREF_IMM16_V8:
139         case EcmaOpcode::SUPERCALLSPREAD_IMM8_V8: {
140             return true;
141         }
142         default: {
143             break;
144         }
145     }
146     return false;
147 }
148 
CheckSimpleCFG(GateRef gate,const uint16_t index) const149 bool InitializationAnalysis::CheckSimpleCFG(GateRef gate, const uint16_t index) const
150 {
151     while (!acc_.IsStateRoot(gate)) {
152         if (CheckSimpleGate(gate, index)) {
153             return false;
154         }
155         gate = acc_.GetState(gate);
156     }
157     return true;
158 }
159 
CheckSimpleGate(GateRef gate,const uint16_t index) const160 bool InitializationAnalysis::CheckSimpleGate(GateRef gate, const uint16_t index) const
161 {
162     OpCode opCode = acc_.GetOpCode(gate);
163     switch (opCode) {
164         case OpCode::IF_TRUE:
165         case OpCode::IF_FALSE: {
166             return true;
167         }
168         case OpCode::JS_BYTECODE: {
169             return CheckSimpleJSGate(gate, index);
170         }
171         default: {
172             break;
173         }
174     }
175     return false;
176 }
177 
CheckSimpleJSGate(GateRef gate,const uint16_t index) const178 bool InitializationAnalysis::CheckSimpleJSGate(GateRef gate, const uint16_t index) const
179 {
180     ASSERT(acc_.GetOpCode(gate) == OpCode::JS_BYTECODE);
181     EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
182     switch (ecmaOpcode) {
183         case EcmaOpcode::LDOBJBYNAME_IMM8_ID16:
184         case EcmaOpcode::LDOBJBYNAME_IMM16_ID16: {
185             return CheckLdObjByName(gate, index, ThisUsage::INDEFINITE_THIS);
186         }
187         case EcmaOpcode::LDTHISBYNAME_IMM8_ID16:
188         case EcmaOpcode::LDTHISBYNAME_IMM16_ID16: {
189             return CheckLdObjByName(gate, index, ThisUsage::DEFINITE_THIS);
190         }
191         case EcmaOpcode::LDTHISBYVALUE_IMM8:
192         case EcmaOpcode::LDTHISBYVALUE_IMM16: {
193             return true;
194         }
195         case EcmaOpcode::LDOBJBYVALUE_IMM8_V8:
196         case EcmaOpcode::LDOBJBYVALUE_IMM16_V8:
197         case EcmaOpcode::LDOBJBYINDEX_IMM8_IMM16:
198         case EcmaOpcode::LDOBJBYINDEX_IMM16_IMM16:
199         case EcmaOpcode::WIDE_LDOBJBYINDEX_PREF_IMM32: {
200             return CheckLdObjByIndexOrValue(gate);
201         }
202         case EcmaOpcode::STOBJBYNAME_IMM8_ID16_V8:
203         case EcmaOpcode::STOBJBYNAME_IMM16_ID16_V8:
204         case EcmaOpcode::STTHISBYNAME_IMM8_ID16:
205         case EcmaOpcode::STTHISBYNAME_IMM16_ID16:
206         case EcmaOpcode::THROW_IFSUPERNOTCORRECTCALL_PREF_IMM8:
207         case EcmaOpcode::THROW_IFSUPERNOTCORRECTCALL_PREF_IMM16: {
208             return false;
209         }
210         default: {
211             return CheckThisAsValueIn(gate);
212         }
213     }
214     return false;
215 }
216 
CheckLdObjByName(GateRef gate,const uint16_t index,ThisUsage thisUsage) const217 bool InitializationAnalysis::CheckLdObjByName(GateRef gate, const uint16_t index, ThisUsage thisUsage) const
218 {
219     if (thisUsage == ThisUsage::INDEFINITE_THIS) {
220         GateRef receiver = acc_.GetValueIn(gate, 2);  // 2: index of receiver
221         if (!CheckIsThisObject(receiver)) {
222             return false;
223         }
224     }
225 
226     auto constData = acc_.GetValueIn(gate, 1); // 1: stringId
227     uint16_t stringId = acc_.GetConstantValue(constData);
228     return stringId == index;
229 }
230 
CheckLdObjByIndexOrValue(GateRef gate) const231 bool InitializationAnalysis::CheckLdObjByIndexOrValue(GateRef gate) const
232 {
233     GateRef receiver = acc_.GetValueIn(gate, 1);  // 1: index of receiver
234     return CheckIsThisObject(receiver);
235 }
236 
MarkSuperClass()237 void InitializationAnalysis::MarkSuperClass()
238 {
239     TSTypeAccessor typeAccessor(tsManager_, classType_);
240     typeAccessor.MarkClassHasSuperCallInConstructor();
241 }
242 
StoreThisObject()243 void InitializationAnalysis::StoreThisObject()
244 {
245     ArgumentAccessor argAcc(circuit_);
246     thisObject_ = argAcc.GetCommonArgGate(CommonArgIdx::THIS_OBJECT);
247     auto type = acc_.GetGateType(thisObject_);
248     if (tsManager_->IsClassInstanceTypeKind(type)) {
249         classType_ = GateType(tsManager_->GetClassType(type));
250     }
251 }
252 
CheckThisAsValueIn(GateRef gate) const253 bool InitializationAnalysis::CheckThisAsValueIn(GateRef gate) const
254 {
255     ASSERT(acc_.GetOpCode(gate) == OpCode::JS_BYTECODE);
256     uint32_t numIns = acc_.GetNumValueIn(gate);
257     for (uint32_t i = 0; i < numIns; ++i) {
258         if (CheckIsThisObject(acc_.GetValueIn(gate, i))) {
259             return true;
260         }
261     }
262     return false;
263 }
264 
CollectThisEscapedInfo(GateRef gate)265 void InitializationAnalysis::CollectThisEscapedInfo(GateRef gate)
266 {
267     ASSERT(gate != Circuit::NullGate());
268     std::vector<GateRef> valueUses;
269     acc_.GetValueUses(gate, valueUses);
270     for (const auto useGate : valueUses) {
271         if (!HasEscapedThis(useGate)) {
272             continue;
273         }
274         TSTypeAccessor typeAccessor(tsManager_, classType_);
275         typeAccessor.MarkClassHasEscapedThisInConstructor();
276         return;
277     }
278 }
279 
HasEscapedThis(GateRef gate) const280 bool InitializationAnalysis::HasEscapedThis(GateRef gate) const
281 {
282     if (acc_.GetOpCode(gate) != OpCode::JS_BYTECODE) {
283         return false;
284     }
285     EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
286     switch (ecmaOpcode) {
287         case EcmaOpcode::STOBJBYNAME_IMM8_ID16_V8:
288         case EcmaOpcode::STOBJBYNAME_IMM16_ID16_V8:
289         case EcmaOpcode::STTHISBYNAME_IMM8_ID16:
290         case EcmaOpcode::STTHISBYNAME_IMM16_ID16:
291         case EcmaOpcode::THROW_IFSUPERNOTCORRECTCALL_PREF_IMM8:
292         case EcmaOpcode::THROW_IFSUPERNOTCORRECTCALL_PREF_IMM16: {
293             return false;
294         }
295         default: {
296             break;
297         }
298     }
299     return true;
300 }
301 
MarkHasAnalysedInitialization()302 void InitializationAnalysis::MarkHasAnalysedInitialization()
303 {
304     TSTypeAccessor typeAccessor(tsManager_, classType_);
305     typeAccessor.MarkClassHasAnalysedInitialization();
306 }
307 
CheckCall() const308 bool InitializationAnalysis::CheckCall() const
309 {
310     TSTypeAccessor typeAccessor(tsManager_, classType_);
311     return typeAccessor.ClassHasEscapedThisInConstructor();
312 }
313 
Print() const314 void InitializationAnalysis::Print() const
315 {
316     LOG_COMPILER(INFO) << " ";
317     LOG_COMPILER(INFO) << "\033[34m" << "================="
318                        << " After initialization analysis "
319                        << "[" << GetMethodName() << "] "
320                        << "=================" << "\033[0m";
321     TSTypeAccessor typeAccessor(tsManager_, classType_);
322     LOG_COMPILER(INFO) << "In the constructor of class " << typeAccessor.GetClassTypeName()
323                        << " of record " << std::string(recordName_)
324                        << ", the following propertiess will be initialized.";
325     LOG_COMPILER(INFO) << (typeAccessor.GetInitializedProperties());
326     if (typeAccessor.ClassHasEscapedThisInConstructor()) {
327         LOG_COMPILER(INFO) << "This-object will be called by some functions in the constructor.";
328     }
329     LOG_COMPILER(INFO) << "\033[34m" << "=========================== End ===========================" << "\033[0m";
330 }
331 }  // namespace panda::ecmascript
332