• 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     auto methodOffset = acc_.TryGetMethodOffset(gate);
95     JSTaggedValue propKey = tsManager_->GetStringFromConstantPool(methodOffset, index);
96 
97     if (valueType.IsNumberType()) {
98         valueType = GateType::NumberType();
99     }
100 
101     TSTypeAccessor typeAccessor(tsManager_, classType_);
102     typeAccessor.UpdateNonStaticProp(propKey, valueType.GetGTRef());
103 }
104 
CollectInitializationInfo(GateRef gate,ThisUsage thisUsage)105 void InitializationAnalysis::CollectInitializationInfo(GateRef gate, ThisUsage thisUsage)
106 {
107     if (thisUsage == ThisUsage::INDEFINITE_THIS) {
108         GateRef receiver = acc_.GetValueIn(gate, 2);  // 2: index of receiver
109         if (!CheckIsThisObject(receiver)) {
110             return;
111         }
112     }
113 
114     uint16_t index = acc_.GetConstantValue(acc_.GetValueIn(gate, 1));  // 1: stringId
115     if (!CheckSimpleCFG(gate, index)) {
116         return;
117     }
118     auto methodOffset = acc_.TryGetMethodOffset(gate);
119     JSTaggedValue propKey = tsManager_->GetStringFromConstantPool(methodOffset, index);
120     TSTypeAccessor typeAccessor(tsManager_, classType_);
121     typeAccessor.MarkPropertyInitialized(propKey);
122 }
123 
CheckIsThisObject(GateRef receiver) const124 bool InitializationAnalysis::CheckIsThisObject(GateRef receiver) const
125 {
126     return IsThisFromArg(receiver) || IsThisFromSuperCall(receiver);
127 }
128 
IsThisFromSuperCall(GateRef gate) const129 bool InitializationAnalysis::IsThisFromSuperCall(GateRef gate) const
130 {
131     auto op = acc_.GetOpCode(gate);
132     if (op != OpCode::JS_BYTECODE) {
133         return false;
134     }
135     EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
136     switch (ecmaOpcode) {
137         case EcmaOpcode::SUPERCALLTHISRANGE_IMM8_IMM8_V8:
138         case EcmaOpcode::WIDE_SUPERCALLTHISRANGE_PREF_IMM16_V8:
139         case EcmaOpcode::SUPERCALLARROWRANGE_IMM8_IMM8_V8:
140         case EcmaOpcode::WIDE_SUPERCALLARROWRANGE_PREF_IMM16_V8:
141         case EcmaOpcode::SUPERCALLSPREAD_IMM8_V8: {
142             return true;
143         }
144         default: {
145             break;
146         }
147     }
148     return false;
149 }
150 
CheckSimpleCFG(GateRef gate,const uint16_t index) const151 bool InitializationAnalysis::CheckSimpleCFG(GateRef gate, const uint16_t index) const
152 {
153     while (!acc_.IsStateRoot(gate)) {
154         if (CheckSimpleGate(gate, index)) {
155             return false;
156         }
157         gate = acc_.GetState(gate);
158     }
159     return true;
160 }
161 
CheckSimpleGate(GateRef gate,const uint16_t index) const162 bool InitializationAnalysis::CheckSimpleGate(GateRef gate, const uint16_t index) const
163 {
164     OpCode opCode = acc_.GetOpCode(gate);
165     switch (opCode) {
166         case OpCode::IF_TRUE:
167         case OpCode::IF_FALSE: {
168             return true;
169         }
170         case OpCode::JS_BYTECODE: {
171             return CheckSimpleJSGate(gate, index);
172         }
173         default: {
174             break;
175         }
176     }
177     return false;
178 }
179 
CheckSimpleJSGate(GateRef gate,const uint16_t index) const180 bool InitializationAnalysis::CheckSimpleJSGate(GateRef gate, const uint16_t index) const
181 {
182     ASSERT(acc_.GetOpCode(gate) == OpCode::JS_BYTECODE);
183     EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
184     switch (ecmaOpcode) {
185         case EcmaOpcode::LDOBJBYNAME_IMM8_ID16:
186         case EcmaOpcode::LDOBJBYNAME_IMM16_ID16: {
187             return CheckLdObjByName(gate, index, ThisUsage::INDEFINITE_THIS);
188         }
189         case EcmaOpcode::LDTHISBYNAME_IMM8_ID16:
190         case EcmaOpcode::LDTHISBYNAME_IMM16_ID16: {
191             return CheckLdObjByName(gate, index, ThisUsage::DEFINITE_THIS);
192         }
193         case EcmaOpcode::LDTHISBYVALUE_IMM8:
194         case EcmaOpcode::LDTHISBYVALUE_IMM16: {
195             return true;
196         }
197         case EcmaOpcode::LDOBJBYVALUE_IMM8_V8:
198         case EcmaOpcode::LDOBJBYVALUE_IMM16_V8:
199         case EcmaOpcode::LDOBJBYINDEX_IMM8_IMM16:
200         case EcmaOpcode::LDOBJBYINDEX_IMM16_IMM16:
201         case EcmaOpcode::WIDE_LDOBJBYINDEX_PREF_IMM32: {
202             return CheckLdObjByIndexOrValue(gate);
203         }
204         case EcmaOpcode::STOBJBYNAME_IMM8_ID16_V8:
205         case EcmaOpcode::STOBJBYNAME_IMM16_ID16_V8:
206         case EcmaOpcode::STTHISBYNAME_IMM8_ID16:
207         case EcmaOpcode::STTHISBYNAME_IMM16_ID16:
208         case EcmaOpcode::THROW_IFSUPERNOTCORRECTCALL_PREF_IMM8:
209         case EcmaOpcode::THROW_IFSUPERNOTCORRECTCALL_PREF_IMM16: {
210             return false;
211         }
212         default: {
213             return CheckThisAsValueIn(gate);
214         }
215     }
216     return false;
217 }
218 
CheckLdObjByName(GateRef gate,const uint16_t index,ThisUsage thisUsage) const219 bool InitializationAnalysis::CheckLdObjByName(GateRef gate, const uint16_t index, ThisUsage thisUsage) const
220 {
221     if (thisUsage == ThisUsage::INDEFINITE_THIS) {
222         GateRef receiver = acc_.GetValueIn(gate, 2);  // 2: index of receiver
223         if (!CheckIsThisObject(receiver)) {
224             return false;
225         }
226     }
227 
228     auto constData = acc_.GetValueIn(gate, 1); // 1: stringId
229     uint16_t stringId = acc_.GetConstantValue(constData);
230     return stringId == index;
231 }
232 
CheckLdObjByIndexOrValue(GateRef gate) const233 bool InitializationAnalysis::CheckLdObjByIndexOrValue(GateRef gate) const
234 {
235     GateRef receiver = acc_.GetValueIn(gate, 1);  // 1: index of receiver
236     return CheckIsThisObject(receiver);
237 }
238 
MarkSuperClass()239 void InitializationAnalysis::MarkSuperClass()
240 {
241     TSTypeAccessor typeAccessor(tsManager_, classType_);
242     typeAccessor.MarkClassHasSuperCallInConstructor();
243 }
244 
StoreThisObject()245 void InitializationAnalysis::StoreThisObject()
246 {
247     ArgumentAccessor argAcc(circuit_);
248     thisObject_ = argAcc.GetCommonArgGate(CommonArgIdx::THIS_OBJECT);
249     auto type = acc_.GetGateType(thisObject_);
250     if (tsManager_->IsClassInstanceTypeKind(type)) {
251         classType_ = GateType(tsManager_->GetClassType(type));
252     }
253 }
254 
CheckThisAsValueIn(GateRef gate) const255 bool InitializationAnalysis::CheckThisAsValueIn(GateRef gate) const
256 {
257     ASSERT(acc_.GetOpCode(gate) == OpCode::JS_BYTECODE);
258     uint32_t numIns = acc_.GetNumValueIn(gate);
259     for (uint32_t i = 0; i < numIns; ++i) {
260         if (CheckIsThisObject(acc_.GetValueIn(gate, i))) {
261             return true;
262         }
263     }
264     return false;
265 }
266 
CollectThisEscapedInfo(GateRef gate)267 void InitializationAnalysis::CollectThisEscapedInfo(GateRef gate)
268 {
269     ASSERT(gate != Circuit::NullGate());
270     std::vector<GateRef> valueUses;
271     acc_.GetValueUses(gate, valueUses);
272     for (const auto useGate : valueUses) {
273         if (!HasEscapedThis(useGate)) {
274             continue;
275         }
276         TSTypeAccessor typeAccessor(tsManager_, classType_);
277         typeAccessor.MarkClassHasEscapedThisInConstructor();
278         return;
279     }
280 }
281 
HasEscapedThis(GateRef gate) const282 bool InitializationAnalysis::HasEscapedThis(GateRef gate) const
283 {
284     if (acc_.GetOpCode(gate) != OpCode::JS_BYTECODE) {
285         return false;
286     }
287     EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
288     switch (ecmaOpcode) {
289         case EcmaOpcode::STOBJBYNAME_IMM8_ID16_V8:
290         case EcmaOpcode::STOBJBYNAME_IMM16_ID16_V8:
291         case EcmaOpcode::STTHISBYNAME_IMM8_ID16:
292         case EcmaOpcode::STTHISBYNAME_IMM16_ID16:
293         case EcmaOpcode::THROW_IFSUPERNOTCORRECTCALL_PREF_IMM8:
294         case EcmaOpcode::THROW_IFSUPERNOTCORRECTCALL_PREF_IMM16: {
295             return false;
296         }
297         default: {
298             break;
299         }
300     }
301     return true;
302 }
303 
MarkHasAnalysedInitialization()304 void InitializationAnalysis::MarkHasAnalysedInitialization()
305 {
306     TSTypeAccessor typeAccessor(tsManager_, classType_);
307     typeAccessor.MarkClassHasAnalysedInitialization();
308 }
309 
CheckCall() const310 bool InitializationAnalysis::CheckCall() const
311 {
312     TSTypeAccessor typeAccessor(tsManager_, classType_);
313     return typeAccessor.ClassHasEscapedThisInConstructor();
314 }
315 
Print() const316 void InitializationAnalysis::Print() const
317 {
318     LOG_COMPILER(INFO) << " ";
319     LOG_COMPILER(INFO) << "\033[34m" << "================="
320                        << " After initialization analysis "
321                        << "[" << GetMethodName() << "] "
322                        << "=================" << "\033[0m";
323     TSTypeAccessor typeAccessor(tsManager_, classType_);
324     LOG_COMPILER(INFO) << "In the constructor of class " << typeAccessor.GetClassTypeName()
325                        << " of record " << std::string(recordName_)
326                        << ", the following propertiess will be initialized.";
327     LOG_COMPILER(INFO) << (typeAccessor.GetInitializedProperties());
328     if (typeAccessor.ClassHasEscapedThisInConstructor()) {
329         LOG_COMPILER(INFO) << "This-object will be called by some functions in the constructor.";
330     }
331     LOG_COMPILER(INFO) << "\033[34m" << "=========================== End ===========================" << "\033[0m";
332 }
333 }  // namespace panda::ecmascript
334