• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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/method_type_infer.h"
17 #include "ecmascript/jspandafile/js_pandafile_manager.h"
18 #include "ecmascript/ts_types/ts_type_accessor.h"
19 #include "ecmascript/ts_types/ts_type_parser.h"
20 
21 namespace panda::ecmascript::kungfu {
MethodTypeInfer(BytecodeCircuitBuilder * builder,Circuit * circuit,PassContext * ctx,size_t methodId,bool enableLog,const std::string & name,const CString & recordName,MethodInfo * methodInfo,const MethodLiteral * methodLiteral,bool enableGlobalTypeInfer,bool hasType)22 MethodTypeInfer::MethodTypeInfer(BytecodeCircuitBuilder *builder, Circuit *circuit, PassContext *ctx, size_t methodId,
23                                  bool enableLog, const std::string &name, const CString &recordName,
24                                  MethodInfo *methodInfo, const MethodLiteral *methodLiteral,
25                                  bool enableGlobalTypeInfer, bool hasType)
26     : builder_(builder), circuit_(circuit), gateAccessor_(circuit), tsManager_(ctx->GetTSManager()), ctx_(ctx),
27       lexEnvManager_(ctx->GetLexEnvManager()), methodId_(methodId), enableLog_(enableLog), methodName_(name),
28       recordName_(recordName), methodInfo_(methodInfo), methodLiteral_(methodLiteral),
29       inQueue_(circuit_->GetGateCount(), true), enableGlobalTypeInfer_(enableGlobalTypeInfer), hasType_(hasType)
30 {
31     if (enableGlobalTypeInfer_ && methodInfo->IsNamespace()) {
32         uint32_t methodOffset = methodLiteral_->GetMethodId().GetOffset();
33         if (tsManager_->HasInferredNamespaceType(methodOffset)) {
34             SetNamespaceArgType(tsManager_->GetNamespaceObjType(methodOffset));
35         }
36     }
37 
38     std::vector<GateRef> gateList;
39     circuit_->GetAllGates(gateList);
40     for (auto gate : gateList) {
41         if (gateAccessor_.GetOpCode(gate) == OpCode::FRAME_ARGS) {
42             continue;
43         }
44         pendingQueue_.push(gate);
45     }
46     // init jsgateToBytecode
47     BytecodeIterator iterator(builder_, 0, builder_->GetLastBcIndex());
48     iterator.GotoStart();
49     while (!iterator.Done()) {
50         auto index = iterator.Index();
51         auto gates = builder_->GetGatesByBcIndex(index);
52         for (auto gate : gates) {
53             jsgateToBytecode_[gate] = index;
54         }
55         ++iterator;
56     }
57 }
58 
CheckAndPrint()59 void MethodTypeInfer::CheckAndPrint()
60 {
61     VerifyTypePercent();
62 
63     if (tsManager_->AssertTypes()) {
64         Verify();
65     }
66 
67     if (IsLogEnabled()) {
68         PrintTypeAnnotation();
69         PrintByteCodesWithTypes();
70         PrintCircuitWithTypes();
71     }
72 }
73 
Enqueue(GateRef gate)74 void MethodTypeInfer::Enqueue(GateRef gate)
75 {
76     auto gateId = gateAccessor_.GetId(gate);
77     if (!inQueue_[gateId]) {
78         inQueue_[gateId] = true;
79         pendingQueue_.push(gate);
80     }
81 }
82 
TraverseInfer()83 std::pair<GateType, uint32_t> MethodTypeInfer::TraverseInfer()
84 {
85     // main type infer for all gates
86     while (!pendingQueue_.empty()) {
87         auto curGate = pendingQueue_.front();
88         inQueue_[gateAccessor_.GetId(curGate)] = false;
89         pendingQueue_.pop();
90         auto uses = gateAccessor_.ConstUses(curGate);
91         for (auto useIt = uses.begin(); useIt != uses.end(); useIt++) {
92             if (Infer(*useIt)) {
93                 Enqueue(*useIt);
94             }
95             if (enableGlobalTypeInfer_ && IsNamespace(*useIt)) {
96                 return SetAndReturnNamespaceObjType(*useIt);
97             }
98         }
99         if (pendingQueue_.empty() && needUpdateForLoopPhi_) {
100             // only for loop begin phi
101             UpdateQueueForLoopPhi();
102             needUpdateForLoopPhi_ = false;
103         }
104     }
105     return std::make_pair(GateType::AnyType(), 0);  // 0: defaule value
106 }
107 
UpdateQueueForLoopPhi()108 void MethodTypeInfer::UpdateQueueForLoopPhi()
109 {
110     for (auto it = loopPhiState_.begin(); it != loopPhiState_.end(); it++) {
111         auto curGate = it->first;
112         auto loopType = gateAccessor_.GetGateType(curGate);
113         auto loopBackGate = gateAccessor_.GetValueIn(curGate, 1);
114         auto loopBackType = gateAccessor_.GetGateType(loopBackGate);
115         // if loopBack Gate is finally AnyType, loop-begin phi gate should be changed to any
116         if (!loopType.IsAnyType() && loopBackType.IsAnyType()) {
117             gateAccessor_.SetGateType(curGate, GateType::AnyType());
118             loopPhiState_[curGate] = InferState::ANY_INFERED;
119             pendingQueue_.push(curGate);
120             inQueue_[gateAccessor_.GetId(curGate)] = true;
121         }
122         // if loopBack Gate is finally not same number Type, loop-begin phi gate should be promoted
123         if (loopType.IsNumberType() && loopBackType.IsNumberType() && loopType != loopBackType) {
124             gateAccessor_.SetGateType(curGate, GateType::NumberType());
125             loopPhiState_[curGate] = InferState::NUMBER_INFERED;
126             pendingQueue_.push(curGate);
127             inQueue_[gateAccessor_.GetId(curGate)] = true;
128         }
129     }
130 }
131 
UpdateType(GateRef gate,const GateType type,bool savePreType)132 bool MethodTypeInfer::UpdateType(GateRef gate, const GateType type, bool savePreType)
133 {
134     GateType preType = gateAccessor_.GetGateType(gate);
135     needInferGates_.insert(gate);
136     // When the type after type inference is any and you want to save previous type, it wolud not update.
137     if (savePreType && type.IsAnyType()) {
138         return false;
139     }
140 
141     if (type != preType) {
142         gateAccessor_.SetGateType(gate, HandleTypeCompatibility(preType, type));
143         return true;
144     }
145     return false;
146 }
147 
UpdateType(GateRef gate,const GlobalTSTypeRef & typeRef,bool savePreType)148 bool MethodTypeInfer::UpdateType(GateRef gate, const GlobalTSTypeRef &typeRef, bool savePreType)
149 {
150     auto type = GateType(typeRef);
151     return UpdateType(gate, type, savePreType);
152 }
153 
HandleTypeCompatibility(const GateType preType,const GateType type) const154 GateType MethodTypeInfer::HandleTypeCompatibility(const GateType preType, const GateType type) const
155 {
156     if (tsManager_->IsArrayTypeKind(preType) && tsManager_->IsBuiltinInstanceType(BuiltinTypeId::ARRAY, type)) {
157         return preType;
158     }
159     return type;
160 }
161 
IsNewLexEnv(EcmaOpcode opcode) const162 bool MethodTypeInfer::IsNewLexEnv(EcmaOpcode opcode) const
163 {
164     switch (opcode) {
165         case EcmaOpcode::NEWLEXENV_IMM8:
166         case EcmaOpcode::NEWLEXENVWITHNAME_IMM8_ID16:
167         case EcmaOpcode::WIDE_NEWLEXENV_PREF_IMM16:
168         case EcmaOpcode::WIDE_NEWLEXENVWITHNAME_PREF_IMM16_ID16:
169             return true;
170         default:
171             return false;
172     }
173 }
174 
ShouldInfer(const GateRef gate) const175 bool MethodTypeInfer::ShouldInfer(const GateRef gate) const
176 {
177     auto opcode = gateAccessor_.GetOpCode(gate);
178     // handle phi gates
179     if ((opcode == OpCode::VALUE_SELECTOR) ||
180         (opcode == OpCode::LOOP_EXIT_VALUE)) {
181         return true;
182     }
183     /* Handle constant gates (like ldnull and ldtrue), return gates and gates generated by ecma.* bytecodes (not
184      * including jump and newlexenv). Jump instructions are skipped because they have no intrinsic type information.
185      * And newlexenv instructions are used to create runtime lexical env objects which have no TS types associated. As
186      * for the type inference on lexical variables, their type information is recorded in objects of class
187      * panda::ecmascript::kungfu::LexEnv which are created during the building of IR. So in the type inference,
188      * newlexenv is ignored.
189      */
190     if (opcode != OpCode::CONSTANT &&
191         opcode != OpCode::RETURN && opcode != OpCode::JS_BYTECODE) {
192         return false;
193     }
194     if (jsgateToBytecode_.find(gate) == jsgateToBytecode_.end()) {
195         return false;
196     }
197     auto &bytecodeInfo = GetByteCodeInfo(gate);
198     return !bytecodeInfo.IsJump() && !IsNewLexEnv(bytecodeInfo.GetOpcode());
199 }
200 
Infer(GateRef gate)201 bool MethodTypeInfer::Infer(GateRef gate)
202 {
203     if (!ShouldInfer(gate)) {
204         return false;
205     }
206     if (gateAccessor_.GetOpCode(gate) == OpCode::LOOP_EXIT_VALUE) {
207         return UpdateType(gate, gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate)));
208     }
209     if (gateAccessor_.GetOpCode(gate) == OpCode::VALUE_SELECTOR) {
210         return InferPhiGate(gate);
211     }
212     // infer ecma.* bytecode gates
213     auto &bytecodeInfo = GetByteCodeInfo(gate);
214     switch (bytecodeInfo.GetOpcode()) {
215         case EcmaOpcode::LDNAN:
216         case EcmaOpcode::LDINFINITY:
217         case EcmaOpcode::TONUMBER_IMM8:
218         case EcmaOpcode::NEG_IMM8:
219         case EcmaOpcode::EXP_IMM8_V8:
220         case EcmaOpcode::STARRAYSPREAD_V8_V8:
221             return SetNumberType(gate);
222         case EcmaOpcode::SHL2_IMM8_V8:
223         case EcmaOpcode::ASHR2_IMM8_V8:
224         case EcmaOpcode::SHR2_IMM8_V8:
225         case EcmaOpcode::NOT_IMM8:
226         case EcmaOpcode::AND2_IMM8_V8:
227         case EcmaOpcode::OR2_IMM8_V8:
228         case EcmaOpcode::XOR2_IMM8_V8:
229             return SetIntType(gate);
230         case EcmaOpcode::LDBIGINT_ID16:
231             return SetBigIntType(gate);
232         case EcmaOpcode::LDTRUE:
233         case EcmaOpcode::LDFALSE:
234         case EcmaOpcode::EQ_IMM8_V8:
235         case EcmaOpcode::NOTEQ_IMM8_V8:
236         case EcmaOpcode::LESS_IMM8_V8:
237         case EcmaOpcode::LESSEQ_IMM8_V8:
238         case EcmaOpcode::GREATER_IMM8_V8:
239         case EcmaOpcode::GREATEREQ_IMM8_V8:
240         case EcmaOpcode::ISIN_IMM8_V8:
241         case EcmaOpcode::INSTANCEOF_IMM8_V8:
242         case EcmaOpcode::STRICTNOTEQ_IMM8_V8:
243         case EcmaOpcode::STRICTEQ_IMM8_V8:
244         case EcmaOpcode::ISTRUE:
245         case EcmaOpcode::ISFALSE:
246         case EcmaOpcode::SETOBJECTWITHPROTO_IMM8_V8:
247         case EcmaOpcode::SETOBJECTWITHPROTO_IMM16_V8:
248         case EcmaOpcode::DELOBJPROP_V8:
249             return SetBooleanType(gate);
250         case EcmaOpcode::LDUNDEFINED:
251             return InferLdUndefined(gate);
252         case EcmaOpcode::LDNULL:
253             return InferLdNull(gate);
254         case EcmaOpcode::LDAI_IMM32:
255             return InferLdai(gate);
256         case EcmaOpcode::FLDAI_IMM64:
257             return InferFLdai(gate);
258         case EcmaOpcode::LDSYMBOL:
259             return InferLdSymbol(gate);
260         case EcmaOpcode::THROW_PREF_NONE:
261             return InferThrow(gate);
262         case EcmaOpcode::TYPEOF_IMM8:
263         case EcmaOpcode::TYPEOF_IMM16:
264             return InferTypeOf(gate);
265         case EcmaOpcode::ADD2_IMM8_V8:
266             return InferAdd2(gate);
267         case EcmaOpcode::SUB2_IMM8_V8:
268             return InferSub2(gate);
269         case EcmaOpcode::MUL2_IMM8_V8:
270             return InferMul2(gate);
271         case EcmaOpcode::MOD2_IMM8_V8:
272             return InferMod2(gate);
273         case EcmaOpcode::DIV2_IMM8_V8:
274             return InferDiv2(gate);
275         case EcmaOpcode::INC_IMM8:
276         case EcmaOpcode::DEC_IMM8:
277             return InferIncDec(gate);
278         case EcmaOpcode::LDOBJBYINDEX_IMM8_IMM16:
279         case EcmaOpcode::LDOBJBYINDEX_IMM16_IMM16:
280         case EcmaOpcode::WIDE_LDOBJBYINDEX_PREF_IMM32:
281             return InferLdObjByIndex(gate);
282         case EcmaOpcode::STGLOBALVAR_IMM16_ID16:
283         case EcmaOpcode::TRYSTGLOBALBYNAME_IMM8_ID16:
284         case EcmaOpcode::TRYSTGLOBALBYNAME_IMM16_ID16:
285             return SetStGlobalBcType(gate, true);
286         case EcmaOpcode::STTOGLOBALRECORD_IMM16_ID16:
287         case EcmaOpcode::STCONSTTOGLOBALRECORD_IMM16_ID16:
288             return SetStGlobalBcType(gate, false);
289         case EcmaOpcode::LDGLOBALVAR_IMM16_ID16:
290             return InferLdGlobalVar(gate);
291         case EcmaOpcode::RETURNUNDEFINED:
292             return InferReturnUndefined(gate);
293         case EcmaOpcode::RETURN:
294             return InferReturn(gate);
295         case EcmaOpcode::LDOBJBYNAME_IMM8_ID16:
296         case EcmaOpcode::LDOBJBYNAME_IMM16_ID16:
297             return InferLdObjByName(gate);
298         case EcmaOpcode::LDA_STR_ID16:
299             return InferLdStr(gate);
300         case EcmaOpcode::TONUMERIC_IMM8:
301             return InferToNumberic(gate);
302         case EcmaOpcode::CALLARG0_IMM8:
303         case EcmaOpcode::CALLARG1_IMM8_V8:
304         case EcmaOpcode::CALLARGS2_IMM8_V8_V8:
305         case EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8:
306         case EcmaOpcode::CALLRANGE_IMM8_IMM8_V8:
307         case EcmaOpcode::WIDE_CALLRANGE_PREF_IMM16_V8:
308         case EcmaOpcode::APPLY_IMM8_V8_V8:
309             return InferCallFunction(gate);
310         case EcmaOpcode::CALLTHIS0_IMM8_V8:
311         case EcmaOpcode::CALLTHIS1_IMM8_V8_V8:
312         case EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8:
313         case EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8:
314         case EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8:
315         case EcmaOpcode::WIDE_CALLTHISRANGE_PREF_IMM16_V8:
316         case EcmaOpcode::CALLRUNTIME_CALLINIT_PREF_IMM8_V8:
317             return InferCallMethod(gate);
318         case EcmaOpcode::LDOBJBYVALUE_IMM8_V8:
319         case EcmaOpcode::LDOBJBYVALUE_IMM16_V8:
320             return InferLdObjByValue(gate);
321         case EcmaOpcode::GETNEXTPROPNAME_V8:
322             return InferGetNextPropName(gate);
323         case EcmaOpcode::DEFINEGETTERSETTERBYVALUE_V8_V8_V8_V8:
324             return InferDefineGetterSetterByValue(gate);
325         case EcmaOpcode::NEWOBJRANGE_IMM8_IMM8_V8:
326         case EcmaOpcode::NEWOBJRANGE_IMM16_IMM8_V8:
327         case EcmaOpcode::WIDE_NEWOBJRANGE_PREF_IMM16_V8:
328         case EcmaOpcode::NEWOBJAPPLY_IMM8_V8:
329         case EcmaOpcode::NEWOBJAPPLY_IMM16_V8:
330             return InferNewObject(gate);
331         case EcmaOpcode::SUPERCALLTHISRANGE_IMM8_IMM8_V8:
332         case EcmaOpcode::WIDE_SUPERCALLTHISRANGE_PREF_IMM16_V8:
333         case EcmaOpcode::SUPERCALLARROWRANGE_IMM8_IMM8_V8:
334         case EcmaOpcode::WIDE_SUPERCALLARROWRANGE_PREF_IMM16_V8:
335         case EcmaOpcode::SUPERCALLSPREAD_IMM8_V8:
336             return InferSuperCall(gate);
337         case EcmaOpcode::LDSUPERBYNAME_IMM8_ID16:
338         case EcmaOpcode::LDSUPERBYNAME_IMM16_ID16:
339             return InferSuperPropertyByName(gate);
340         case EcmaOpcode::LDSUPERBYVALUE_IMM8_V8:
341         case EcmaOpcode::LDSUPERBYVALUE_IMM16_V8:
342             return InferSuperPropertyByValue(gate);
343         case EcmaOpcode::TRYLDGLOBALBYNAME_IMM8_ID16:
344         case EcmaOpcode::TRYLDGLOBALBYNAME_IMM16_ID16:
345             return InferTryLdGlobalByName(gate);
346         case EcmaOpcode::LDLEXVAR_IMM4_IMM4:
347         case EcmaOpcode::LDLEXVAR_IMM8_IMM8:
348         case EcmaOpcode::WIDE_LDLEXVAR_PREF_IMM16_IMM16:
349             return InferLdLexVarDyn(gate);
350         case EcmaOpcode::STLEXVAR_IMM4_IMM4:
351         case EcmaOpcode::STLEXVAR_IMM8_IMM8:
352         case EcmaOpcode::WIDE_STLEXVAR_PREF_IMM16_IMM16:
353             return InferStLexVarDyn(gate);
354         case EcmaOpcode::GETITERATOR_IMM8:
355         case EcmaOpcode::GETITERATOR_IMM16:
356             return InferGetIterator(gate);
357         case EcmaOpcode::STMODULEVAR_IMM8:
358         case EcmaOpcode::WIDE_STMODULEVAR_PREF_IMM16:
359             return InferStModuleVar(gate);
360         case EcmaOpcode::LDLOCALMODULEVAR_IMM8:
361         case EcmaOpcode::WIDE_LDLOCALMODULEVAR_PREF_IMM16:
362             return InferLdLocalModuleVar(gate);
363         case EcmaOpcode::LDEXTERNALMODULEVAR_IMM8:
364         case EcmaOpcode::WIDE_LDEXTERNALMODULEVAR_PREF_IMM16:
365             return InferLdExternalModuleVar(gate);
366         case EcmaOpcode::STOBJBYNAME_IMM8_ID16_V8:
367         case EcmaOpcode::STOBJBYNAME_IMM16_ID16_V8:
368             return InferStObjByName(gate);
369         default:
370             break;
371     }
372     return false;
373 }
374 
InferPhiGate(GateRef gate)375 bool MethodTypeInfer::InferPhiGate(GateRef gate)
376 {
377     ASSERT(gateAccessor_.GetOpCode(gate) == OpCode::VALUE_SELECTOR);
378     CVector<GlobalTSTypeRef> typeList;
379     std::set<GlobalTSTypeRef> numberTypeSet;
380     auto ins = gateAccessor_.ConstIns(gate);
381     for (auto it = ins.begin(); it != ins.end(); it++) {
382         // assuming that VALUE_SELECTOR is NO_DEPEND and NO_ROOT
383         if (gateAccessor_.GetOpCode(*it) == OpCode::MERGE) {
384             continue;
385         }
386         if (gateAccessor_.GetOpCode(*it) == OpCode::LOOP_BEGIN) {
387             return InferLoopBeginPhiGate(gate);
388         }
389         auto valueInType = gateAccessor_.GetGateType(*it);
390         if (valueInType.IsAnyType()) {
391             return UpdateType(gate, valueInType, false);
392         }
393         if (valueInType.IsNumberType()) {
394             numberTypeSet.insert(valueInType.GetGTRef());
395         } else {
396             typeList.emplace_back(valueInType.GetGTRef());
397         }
398     }
399     // deduplicate
400     std::sort(typeList.begin(), typeList.end());
401     auto deduplicateIndex = std::unique(typeList.begin(), typeList.end());
402     typeList.erase(deduplicateIndex, typeList.end());
403     if (numberTypeSet.size() == 1) {
404         typeList.emplace_back(*(numberTypeSet.begin()));
405     } else if (numberTypeSet.size() > 1) {
406         typeList.emplace_back(GateType::NumberType().GetGTRef());
407     }
408     if (typeList.size() > 1) {
409         auto unionType = tsManager_->GetOrCreateUnionType(typeList);
410         return UpdateType(gate, unionType, false);
411     }
412     auto type = typeList.at(0);
413     return UpdateType(gate, type, false);
414 }
415 
SetIntType(GateRef gate)416 bool MethodTypeInfer::SetIntType(GateRef gate)
417 {
418     auto intType = GateType::IntType();
419     return UpdateType(gate, intType);
420 }
421 
SetNumberType(GateRef gate)422 bool MethodTypeInfer::SetNumberType(GateRef gate)
423 {
424     auto numberType = GateType::NumberType();
425     return UpdateType(gate, numberType);
426 }
427 
SetBigIntType(GateRef gate)428 bool MethodTypeInfer::SetBigIntType(GateRef gate)
429 {
430     auto bigIntType = GateType::BigIntType();
431     return UpdateType(gate, bigIntType);
432 }
433 
SetBooleanType(GateRef gate)434 bool MethodTypeInfer::SetBooleanType(GateRef gate)
435 {
436     auto booleanType = GateType::BooleanType();
437     return UpdateType(gate, booleanType);
438 }
439 
InferLdUndefined(GateRef gate)440 bool MethodTypeInfer::InferLdUndefined(GateRef gate)
441 {
442     auto undefinedType = GateType::UndefinedType();
443     return UpdateType(gate, undefinedType);
444 }
445 
InferLdNull(GateRef gate)446 bool MethodTypeInfer::InferLdNull(GateRef gate)
447 {
448     auto nullType = GateType::NullType();
449     return UpdateType(gate, nullType);
450 }
451 
InferLdai(GateRef gate)452 bool MethodTypeInfer::InferLdai(GateRef gate)
453 {
454     auto intType = GateType::IntType();
455     return UpdateType(gate, intType);
456 }
457 
InferFLdai(GateRef gate)458 bool MethodTypeInfer::InferFLdai(GateRef gate)
459 {
460     auto doubleType = GateType::DoubleType();
461     return UpdateType(gate, doubleType);
462 }
463 
InferLdSymbol(GateRef gate)464 bool MethodTypeInfer::InferLdSymbol(GateRef gate)
465 {
466     auto symbolType = GateType::SymbolType();
467     return UpdateType(gate, symbolType);
468 }
469 
InferThrow(GateRef gate)470 bool MethodTypeInfer::InferThrow(GateRef gate)
471 {
472     ASSERT(gateAccessor_.GetNumValueIn(gate) == 1);
473     auto gateType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
474     return UpdateType(gate, gateType);
475 }
476 
InferTypeOf(GateRef gate)477 bool MethodTypeInfer::InferTypeOf(GateRef gate)
478 {
479     ASSERT(gateAccessor_.GetNumValueIn(gate) == 1);
480     auto gateType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
481     return UpdateType(gate, gateType);
482 }
483 
484 /*
485  * Type Infer rule(satisfy commutative law):
486  * number + number = number
487  * int    + number = number
488  * double + number = double
489  * int    + int    = int
490  * int    + double = double
491  * double + double = double
492  * string + string = string
493  */
InferAdd2(GateRef gate)494 bool MethodTypeInfer::InferAdd2(GateRef gate)
495 {
496     // 2: number of value inputs
497     ASSERT(gateAccessor_.GetNumValueIn(gate) == 2);
498     auto firInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
499     auto secInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1));
500     if (firInType.IsStringType() || secInType.IsStringType()) {
501         return UpdateType(gate, GateType::StringType());
502     }
503     if ((firInType.IsNumberType() && secInType.IsDoubleType()) ||
504         (firInType.IsDoubleType() && secInType.IsNumberType())) {
505         return UpdateType(gate, GateType::DoubleType());
506     }
507     if ((firInType.IsIntType() && secInType.IsIntType())) {
508         return UpdateType(gate, GateType::IntType());
509     }
510     if (firInType.IsNumberType() && secInType.IsNumberType()) {
511         return UpdateType(gate, GateType::NumberType());
512     }
513     return UpdateType(gate, GateType::AnyType());
514 }
515 
516 /*
517  * Type Infer rule(satisfy commutative law):
518  * number - number = number
519  * int    - number = number
520  * double - number = double
521  * int    - int    = int
522  * int    - double = double
523  * double - double = double
524  */
InferSub2(GateRef gate)525 bool MethodTypeInfer::InferSub2(GateRef gate)
526 {
527     // 2: number of value inputs
528     ASSERT(gateAccessor_.GetNumValueIn(gate) == 2);
529     auto firInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
530     auto secInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1));
531     if ((firInType.IsNumberType() && secInType.IsDoubleType()) ||
532         (firInType.IsDoubleType() && secInType.IsNumberType())) {
533         return UpdateType(gate, GateType::DoubleType());
534     }
535     if ((firInType.IsIntType() && secInType.IsIntType())) {
536         return UpdateType(gate, GateType::IntType());
537     }
538     if (firInType.IsNumberType() && secInType.IsNumberType()) {
539         return UpdateType(gate, GateType::NumberType());
540     }
541     return UpdateType(gate, GateType::AnyType());
542 }
543 
544 /*
545  * Type Infer rule(satisfy commutative law):
546  * number * number = number
547  * int    * number = number
548  * double * number = double
549  * int    * int    = int
550  * int    * double = double
551  * double * double = double
552  */
InferMul2(GateRef gate)553 bool MethodTypeInfer::InferMul2(GateRef gate)
554 {
555     // 2: number of value inputs
556     ASSERT(gateAccessor_.GetNumValueIn(gate) == 2);
557     auto firInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
558     auto secInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1));
559     if ((firInType.IsNumberType() && secInType.IsDoubleType()) ||
560         (firInType.IsDoubleType() && secInType.IsNumberType())) {
561         return UpdateType(gate, GateType::DoubleType());
562     }
563     if ((firInType.IsIntType() && secInType.IsIntType())) {
564         return UpdateType(gate, GateType::IntType());
565     }
566     return UpdateType(gate, GateType::NumberType());
567 }
568 
569 /*
570  * Type Infer rule(satisfy commutative law):
571  * number % number = number
572  * int    % number = number
573  * double % number = double
574  * int    % int    = int
575  * int    % double = double
576  * double % double = double
577  */
InferMod2(GateRef gate)578 bool MethodTypeInfer::InferMod2(GateRef gate)
579 {
580     // 2: number of value inputs
581     ASSERT(gateAccessor_.GetNumValueIn(gate) == 2);
582     auto firInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
583     auto secInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1));
584     if ((firInType.IsNumberType() && secInType.IsDoubleType()) ||
585         (firInType.IsDoubleType() && secInType.IsNumberType())) {
586         return UpdateType(gate, GateType::DoubleType());
587     }
588     if ((firInType.IsIntType() && secInType.IsIntType())) {
589         return UpdateType(gate, GateType::IntType());
590     }
591     return UpdateType(gate, GateType::NumberType());
592 }
593 
594 /*
595  * Type Infer rule(satisfy commutative law):
596  * in type lowering, both elements will be changed to float64 firstly.
597  * number / number = double
598  * int    / number = double
599  * double / number = double
600  * int    / int    = double
601  * int    / double = double
602  * double / double = double
603  * any    / any    = number
604  * any    / number = number
605  * number / any    = number
606  */
InferDiv2(GateRef gate)607 bool MethodTypeInfer::InferDiv2(GateRef gate)
608 {
609     // 2: number of value inputs
610     ASSERT(gateAccessor_.GetNumValueIn(gate) == 2);
611     auto firInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
612     auto secInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1));
613     if (firInType.IsNumberType() && secInType.IsNumberType()) {
614         return UpdateType(gate, GateType::DoubleType());
615     }
616     return UpdateType(gate, GateType::NumberType());
617 }
618 
619 /*
620  * Type Infer rule:
621  * number++ = number
622  * number-- = number
623  * int++    = int
624  * int--    = int
625  * double++ = double
626  * double-- = double
627  */
InferIncDec(GateRef gate)628 bool MethodTypeInfer::InferIncDec(GateRef gate)
629 {
630     ASSERT(gateAccessor_.GetNumValueIn(gate) == 1);
631     auto firInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
632     if (firInType.IsDoubleType()) {
633         return UpdateType(gate, GateType::DoubleType());
634     }
635     if (firInType.IsIntType()) {
636         return UpdateType(gate, GateType::IntType());
637     }
638     if (firInType.IsNumberType()) {
639         return UpdateType(gate, GateType::NumberType());
640     }
641     return UpdateType(gate, GateType::AnyType());
642 }
643 
InferToNumberic(GateRef gate)644 bool MethodTypeInfer::InferToNumberic(GateRef gate)
645 {
646     GateRef src = gateAccessor_.GetValueIn(gate, 0);
647     GateType srcType = gateAccessor_.GetGateType(src);
648     if (srcType.IsNumberType()) {
649         return UpdateType(gate, srcType);
650     }
651     return UpdateType(gate, GateType::NumberType());
652 }
653 
InferLdObjByIndex(GateRef gate)654 bool MethodTypeInfer::InferLdObjByIndex(GateRef gate)
655 {
656     // 2: number of value inputs
657     ASSERT(gateAccessor_.GetNumValueIn(gate) == 2);
658     auto inValueType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1));
659     inValueType = tsManager_->TryNarrowUnionType(inValueType);
660     if (tsManager_->IsArrayTypeKind(inValueType)) {
661         auto type = tsManager_->GetArrayParameterTypeGT(inValueType);
662         return UpdateType(gate, type);
663     }
664 
665     if (tsManager_->IsIntTypedArrayType(inValueType)) {
666         return UpdateType(gate, GateType::IntType());
667     }
668 
669     if (tsManager_->IsDoubleTypedArrayType(inValueType)) {
670         return UpdateType(gate, GateType::DoubleType());
671     }
672 
673     if (tsManager_->IsTypedArrayType(inValueType)) {
674         return UpdateType(gate, GateType::NumberType());
675     }
676 
677     if (ShouldInferWithLdObjByValue(inValueType)) {
678         uint64_t key = gateAccessor_.GetConstantValue((gateAccessor_.GetValueIn(gate, 0)));  // 0: index of key
679         auto type = GetPropType(inValueType, key);
680         return UpdateType(gate, type);
681     }
682     return UpdateType(gate, GateType::AnyType());
683 }
684 
SetStGlobalBcType(GateRef gate,bool hasIC)685 bool MethodTypeInfer::SetStGlobalBcType(GateRef gate, bool hasIC)
686 {
687     auto &byteCodeInfo = GetByteCodeInfo(gate);
688     uint16_t stringId = 0;
689     GateType inValueType;
690     if (hasIC) {
691         // 2: number of value inputs
692         ASSERT(byteCodeInfo.inputs.size() == 2);
693         stringId = std::get<ConstDataId>(byteCodeInfo.inputs[1]).GetId();
694         // 3: number of value inputs
695         ASSERT(gateAccessor_.GetNumValueIn(gate) == 3);
696         // 2: value input
697         inValueType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 2));
698     } else {
699         ASSERT(byteCodeInfo.inputs.size() == 1);
700         stringId = std::get<ConstDataId>(byteCodeInfo.inputs[0]).GetId();
701         // 2: number of value inputs
702         ASSERT(gateAccessor_.GetNumValueIn(gate) == 2);
703         inValueType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1));
704     }
705     if (!hasType_ && inValueType.IsUndefinedType()) {
706         inValueType = GateType::AnyType();
707     }
708     if (stringIdToGateType_.find(stringId) != stringIdToGateType_.end()) {
709         stringIdToGateType_[stringId] = inValueType;
710     } else {
711         stringIdToGateType_.emplace(stringId, inValueType);
712     }
713     return UpdateType(gate, inValueType);
714 }
715 
InferLdGlobalVar(GateRef gate)716 bool MethodTypeInfer::InferLdGlobalVar(GateRef gate)
717 {
718     auto &byteCodeInfo = GetByteCodeInfo(gate);
719     ASSERT(byteCodeInfo.inputs.size() == 2);  // 2: number of value inputs
720     auto stringId = std::get<ConstDataId>(byteCodeInfo.inputs[1]).GetId();
721     auto iter = stringIdToGateType_.find(stringId);
722     if (iter != stringIdToGateType_.end()) {
723         return UpdateType(gate, iter->second);
724     }
725     return UpdateType(gate, GateType::AnyType());
726 }
727 
InferReturnUndefined(GateRef gate)728 bool MethodTypeInfer::InferReturnUndefined(GateRef gate)
729 {
730     auto undefinedType = GateType::UndefinedType();
731     return UpdateType(gate, undefinedType);
732 }
733 
InferReturn(GateRef gate)734 bool MethodTypeInfer::InferReturn(GateRef gate)
735 {
736     ASSERT(gateAccessor_.GetNumValueIn(gate) == 1);
737     auto gateType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
738     return UpdateType(gate, gateType);
739 }
740 
InferLdObjByName(GateRef gate)741 bool MethodTypeInfer::InferLdObjByName(GateRef gate)
742 {
743     // 3: number of value inputs
744     ASSERT(gateAccessor_.GetNumValueIn(gate) == 3);
745     auto objType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 2));  // 2: the third parameter is receiver
746     if (objType.IsAnyType()) {
747         return UpdateType(gate, GateType::AnyType());
748     }
749     objType = tsManager_->TryNarrowUnionType(objType);
750     if (ShouldConvertToBuiltinArray(objType)) {
751         GlobalTSTypeRef builtinGt = ConvertPrimitiveToBuiltin(objType);
752         auto builtinInstanceType = tsManager_->CreateClassInstanceType(builtinGt);
753         objType = GateType(builtinInstanceType);
754     }
755     if (tsManager_->IsPrimitiveTypeKind(objType)) {
756         GlobalTSTypeRef builtinGt = ConvertPrimitiveToBuiltin(objType);
757         if (builtinGt.IsBuiltinModule()) {
758             auto builtinInstanceType = tsManager_->CreateClassInstanceType(builtinGt);
759             objType = GateType(builtinInstanceType);
760         }
761     }
762     // If this object has no gt type, we cannot get its internal property type
763     if (ShouldInferWithLdObjByName(objType)) {
764         uint16_t index = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 1));
765         return GetObjPropWithName(gate, objType, index);
766     }
767     return UpdateType(gate, GateType::AnyType());
768 }
769 
InferStObjByName(GateRef gate)770 bool MethodTypeInfer::InferStObjByName(GateRef gate)
771 {
772     GateRef value = gateAccessor_.GetValueIn(gate, 3);  // 3: index of value
773     GateType valueType = gateAccessor_.GetGateType(value);
774     if (valueType.IsAnyType()) {
775         return false;
776     }
777 
778     GateRef receiver = gateAccessor_.GetValueIn(gate, 2);  // 2: index of receiver
779     GateType receiverType = gateAccessor_.GetGateType(receiver);
780 
781     uint16_t index = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 1));  // 1: index of key
782     auto methodOffset = gateAccessor_.TryGetMethodOffset(gate);
783     JSTaggedValue propKey = tsManager_->GetStringFromConstantPool(methodOffset, index);
784     if (tsManager_->IsNamespaceTypeKind(receiverType)) {
785         if (tsManager_->AddNamespacePropType(receiverType, propKey, valueType)) {
786             Enqueue(receiver);
787         }
788         return true;
789     }
790 
791     if (valueType.IsNumberType()) {
792         valueType = GateType::NumberType();
793     }
794 
795     if (tsManager_->IsClassTypeKind(receiverType)) {
796         TSTypeAccessor typeAccessor(tsManager_, receiverType);
797         typeAccessor.UpdateStaticProp(propKey, valueType.GetGTRef());
798         return true;
799     }
800     return false;
801 }
802 
InferNewObject(GateRef gate)803 bool MethodTypeInfer::InferNewObject(GateRef gate)
804 {
805     auto objType = gateAccessor_.GetGateType(gate);
806     if (!tsManager_->IsClassInstanceTypeKind(objType) && !tsManager_->IsArrayTypeKind(objType)) {
807         ASSERT(gateAccessor_.GetNumValueIn(gate) > 0);
808         auto classType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
809         if (tsManager_->IsClassTypeKind(classType)) {
810             auto classInstanceType = tsManager_->CreateClassInstanceType(classType);
811             return UpdateType(gate, classInstanceType);
812         }
813     }
814     return UpdateType(gate, GateType::AnyType());
815 }
816 
InferLdStr(GateRef gate)817 bool MethodTypeInfer::InferLdStr(GateRef gate)
818 {
819     auto stringType = GateType::StringType();
820     return UpdateType(gate, stringType);
821 }
822 
GetObjPropWithName(GateRef gate,GateType objType,uint64_t index)823 bool MethodTypeInfer::GetObjPropWithName(GateRef gate, GateType objType, uint64_t index)
824 {
825     auto methodOffset = gateAccessor_.TryGetMethodOffset(gate);
826     JSTaggedValue name = tsManager_->GetStringFromConstantPool(methodOffset, index);
827     if (tsManager_->IsBuiltinInstanceType(BuiltinTypeId::ARRAY, objType) || tsManager_->IsTypedArrayType(objType)) {
828         auto thread = tsManager_->GetThread();
829         JSTaggedValue lengthKey = thread->GlobalConstants()->GetLengthString();
830         if (JSTaggedValue::SameValue(name, lengthKey)) {
831             return SetIntType(gate);
832         }
833         if (tsManager_->IsTypedArrayType(objType)) {
834             uint32_t eleIdx = 0;
835             if (EcmaStringAccessor(name).ToElementIndex(&eleIdx)) {
836                 return UpdateType(gate, GateType::NumberType());
837             }
838         }
839     }
840     auto type = GetPropType(objType, name);
841     if (tsManager_->IsGetterSetterFunc(type)) {
842         auto returnGt = tsManager_->GetFuncReturnValueTypeGT(type);
843         return UpdateType(gate, returnGt);
844     }
845     return UpdateType(gate, type);
846 }
847 
InferCallMethod(GateRef gate)848 bool MethodTypeInfer::InferCallMethod(GateRef gate)
849 {
850     // 1: last one elem is function
851     size_t funcIndex = gateAccessor_.GetNumValueIn(gate) - 1;
852     auto funcType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, funcIndex));
853     if (tsManager_->IsFunctionTypeKind(funcType)) {
854         // forEach CallBack
855         TSTypeAccessor typeAccessor(tsManager_, funcType);
856         if (typeAccessor.GetFunctionName() == "forEach") {
857             auto funcGate = gateAccessor_.GetValueIn(gate, funcIndex);
858             auto &bytecodeInfo = GetByteCodeInfo(funcGate);
859             if (bytecodeInfo.GetOpcode() == EcmaOpcode::LDOBJBYNAME_IMM8_ID16 ||
860                 bytecodeInfo.GetOpcode() == EcmaOpcode::LDOBJBYNAME_IMM16_ID16) {
861                 // 2: the third parameter is receiver
862                 auto objType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(funcGate, 2));
863                 // get callBack function type
864                 auto callBackType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1));
865                 TSTypeAccessor newTypeAccessor(tsManager_, callBackType);
866                 newTypeAccessor.UpdateForEachCBPara(objType);
867             }
868         }
869 
870         // normal Call
871         auto returnType = tsManager_->GetFuncReturnValueTypeGT(funcType);
872         GateRef thisObj = gateAccessor_.GetValueIn(gate, 0);  // 0: index of thisObject
873         auto thisObjType = gateAccessor_.GetGateType(thisObj);
874         return UpdateType(gate, HandleTypeCompatibility(thisObjType, GateType(returnType)));
875     } else if (tsManager_->IsIteratorInstanceTypeKind(funcType)) {
876         GlobalTSTypeRef elementGT = tsManager_->GetIteratorInstanceElementGt(funcType);
877         GlobalTSTypeRef iteratorResultInstanceType = tsManager_->GetOrCreateTSIteratorInstanceType(
878             TSRuntimeType::ITERATOR_RESULT, elementGT);
879         return UpdateType(gate, iteratorResultInstanceType);
880     }
881     return UpdateType(gate, GateType::AnyType());
882 }
883 
InferCallFunction(GateRef gate)884 bool MethodTypeInfer::InferCallFunction(GateRef gate)
885 {
886     // 1: last one elem is function
887     size_t funcIndex = gateAccessor_.GetNumValueIn(gate) - 1;
888     auto funcType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, funcIndex));
889     if (tsManager_->IsFunctionTypeKind(funcType)) {
890         auto returnType = tsManager_->GetFuncReturnValueTypeGT(funcType);
891         return UpdateType(gate, returnType);
892     }
893     /* According to the ECMAScript specification, user-defined classes can only be instantiated by constructing (with
894      * new keyword). However, a few builtin types can be called like a function. Upon the results of calling and
895      * constructing, there are 4 categories of builtin types:
896      *
897      * Category 1: non-callable, objects of such a type can only be created by constructing.
898      * Category 2: non-constructable, such types can only be called.
899      * Category 3: simple, calling and constructing are equivalent.
900      * Category 4: complex, a type can be called and constructed, but the results differ.
901      *
902      * Constructing a builtin type always create objects of the type if supported. So in this function, we focus on the
903      * builtin types which are callable. While the majority of the callable builtin types have the same calling behavior
904      * as constructing, here are some special cases:
905      *
906      * | Type    | Call              | Category |
907      * | ------- | ----------------- | -------- |
908      * | BigInt  | primitive bigint  | 2        |
909      * | Boolean | primitive boolean | 4        |
910      * | Date    | primitive string  | 4        |
911      * | Number  | primitive number  | 4        |
912      * | String  | primitive string  | 4        |
913      *
914      * See the list of builtin types' constructors at:
915      *     https://tc39.es/ecma262/2021/#sec-constructor-properties-of-the-global-object
916      */
917     if (tsManager_->IsBuiltinObjectType(funcType)) {
918         // For simplicity, calling and constructing are considered equivalent.
919         if (tsManager_->IsBuiltinClassType(BuiltinTypeId::ARRAY, funcType)) {
920             return UpdateType(gate, tsManager_->CreateArrayType());
921         }
922         return UpdateType(gate, tsManager_->CreateClassInstanceType(funcType));
923     }
924     return UpdateType(gate, GateType::AnyType());
925 }
926 
InferLdObjByValue(GateRef gate)927 bool MethodTypeInfer::InferLdObjByValue(GateRef gate)
928 {
929     auto objType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1));
930     objType = tsManager_->TryNarrowUnionType(objType);
931     // handle array
932     if (tsManager_->IsArrayTypeKind(objType)) {
933         auto elementType = tsManager_->GetArrayParameterTypeGT(objType);
934         return UpdateType(gate, elementType);
935     }
936     if (tsManager_->IsIntTypedArrayType(objType)) {
937         return UpdateType(gate, GateType::IntType());
938     }
939     if (tsManager_->IsDoubleTypedArrayType(objType)) {
940         return UpdateType(gate, GateType::DoubleType());
941     }
942     // handle object
943     if (ShouldInferWithLdObjByValue(objType)) {
944         auto valueGate = gateAccessor_.GetValueIn(gate, 2);  // 2: value input slot
945         if (gateAccessor_.GetOpCode(valueGate) == OpCode::CONSTANT) {
946             if (tsManager_->IsTypedArrayType(objType)) {
947                 return UpdateType(gate, GateType::NumberType());
948             }
949             uint64_t value = gateAccessor_.GetConstantValue(valueGate);
950             auto type = GetPropType(objType, value);
951             return UpdateType(gate, type);
952         }
953         if (IsByteCodeGate(valueGate) && GetByteCodeInfo(valueGate).IsBc(EcmaOpcode::LDA_STR_ID16)) {
954             auto index = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(valueGate, 0));
955             return GetObjPropWithName(gate, objType, index);
956         }
957     }
958     return UpdateType(gate, GateType::AnyType());
959 }
960 
InferGetNextPropName(GateRef gate)961 bool MethodTypeInfer::InferGetNextPropName(GateRef gate)
962 {
963     auto stringType = GateType::StringType();
964     return UpdateType(gate, stringType);
965 }
966 
InferDefineGetterSetterByValue(GateRef gate)967 bool MethodTypeInfer::InferDefineGetterSetterByValue(GateRef gate)
968 {
969     // 0 : the index of obj
970     auto objType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
971     return UpdateType(gate, objType);
972 }
973 
InferSuperCall(GateRef gate)974 bool MethodTypeInfer::InferSuperCall(GateRef gate)
975 {
976     ArgumentAccessor argAcc(circuit_);
977     auto newTarget = argAcc.GetFrameArgsIn(gate, FrameArgIdx::NEW_TARGET);
978     auto classType = gateAccessor_.GetGateType(newTarget);
979     if (tsManager_->IsClassTypeKind(classType)) {
980         auto classInstanceType = tsManager_->CreateClassInstanceType(classType);
981         return UpdateType(gate, classInstanceType);
982     }
983     return UpdateType(gate, GateType::AnyType());
984 }
985 
InferSuperPropertyByName(GateRef gate)986 bool MethodTypeInfer::InferSuperPropertyByName(GateRef gate)
987 {
988     uint16_t index = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 0));
989     return GetSuperProp(gate, index);
990 }
991 
InferSuperPropertyByValue(GateRef gate)992 bool MethodTypeInfer::InferSuperPropertyByValue(GateRef gate)
993 {
994     auto valueGate = gateAccessor_.GetValueIn(gate, 1);
995     if (IsByteCodeGate(valueGate) && GetByteCodeInfo(valueGate).IsBc(EcmaOpcode::LDA_STR_ID16)) {
996         auto index = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(valueGate, 0));
997         return GetSuperProp(gate, index);
998     }
999     if (gateAccessor_.GetOpCode(valueGate) == OpCode::CONSTANT) {
1000         auto index = gateAccessor_.GetConstantValue(valueGate);
1001 
1002         return GetSuperProp(gate, index, false);
1003     }
1004     return UpdateType(gate, GateType::AnyType());
1005 }
1006 
GetSuperProp(GateRef gate,uint64_t index,bool isString)1007 bool MethodTypeInfer::GetSuperProp(GateRef gate, uint64_t index, bool isString)
1008 {
1009     ArgumentAccessor argAcc(circuit_);
1010     auto func = argAcc.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
1011     auto newTarget = argAcc.GetFrameArgsIn(gate, FrameArgIdx::NEW_TARGET);
1012     auto funcType = gateAccessor_.GetGateType(func);
1013     auto classType = gateAccessor_.GetGateType(newTarget);
1014     if (funcType.IsAnyType() || classType.IsAnyType() || classType.IsUndefinedType()) {
1015         return UpdateType(gate, GateType::AnyType());
1016     }
1017 
1018     bool isStatic = tsManager_->IsStaticFunc(funcType.GetGTRef());
1019     auto propType = isStatic ? PropertyType::STATIC : PropertyType::NORMAL;
1020     auto methodOffset = gateAccessor_.TryGetMethodOffset(gate);
1021     GlobalTSTypeRef type = isString ?
1022         tsManager_->GetSuperPropType(classType.GetGTRef(),
1023         tsManager_->GetStringFromConstantPool(methodOffset, index), propType) :
1024         tsManager_->GetSuperPropType(classType.GetGTRef(), index, propType);
1025     if (tsManager_->IsGetterSetterFunc(type)) {
1026         auto returnGt = tsManager_->GetFuncReturnValueTypeGT(type);
1027         return UpdateType(gate, returnGt);
1028     }
1029     return UpdateType(gate, type);
1030 }
1031 
InferGetIterator(GateRef gate)1032 bool MethodTypeInfer::InferGetIterator(GateRef gate)
1033 {
1034     ASSERT(gateAccessor_.GetNumValueIn(gate) == 1);
1035     GateType inValueType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0));
1036 
1037     GlobalTSTypeRef elementGt = GlobalTSTypeRef::Default();
1038     if (tsManager_->IsArrayTypeKind(inValueType)) {
1039         elementGt = tsManager_->GetArrayParameterTypeGT(inValueType);
1040     } else if (inValueType.IsStringType()) {
1041         elementGt.SetType(GateType::StringType().Value());
1042     } else {
1043         return UpdateType(gate, GateType::AnyType());
1044     }
1045     GlobalTSTypeRef iteratorInstanceType = tsManager_->GetOrCreateTSIteratorInstanceType(
1046         TSRuntimeType::ITERATOR, elementGt);
1047     return UpdateType(gate, iteratorInstanceType);
1048 }
1049 
InferTryLdGlobalByName(GateRef gate)1050 bool MethodTypeInfer::InferTryLdGlobalByName(GateRef gate)
1051 {
1052     // todo by hongtao, should consider function of .d.ts
1053     auto &byteCodeInfo = GetByteCodeInfo(gate);
1054     ASSERT(byteCodeInfo.inputs.size() == 2);  // 2: number of parameter
1055     auto stringId = std::get<ConstDataId>(byteCodeInfo.inputs[1]).GetId();
1056     auto iter = stringIdToGateType_.find(stringId);
1057     if (iter != stringIdToGateType_.end()) {
1058         return UpdateType(gate, iter->second);
1059     }
1060     return UpdateType(gate, GateType::AnyType());
1061 }
1062 
InferLdLexVarDyn(GateRef gate)1063 bool MethodTypeInfer::InferLdLexVarDyn(GateRef gate)
1064 {
1065     auto level = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 0));
1066     auto slot = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 1));
1067     auto type = lexEnvManager_->GetLexEnvElementType(methodId_, level, slot);
1068     if (!hasType_ && type.IsUndefinedType()) {
1069         type = GateType::AnyType();
1070     }
1071     return UpdateType(gate, type);
1072 }
1073 
InferStLexVarDyn(GateRef gate)1074 bool MethodTypeInfer::InferStLexVarDyn(GateRef gate)
1075 {
1076     auto level = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 0));
1077     auto slot = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 1));
1078     auto type = lexEnvManager_->GetLexEnvElementType(methodId_, level, slot);
1079     if (type.IsAnyType() || type.IsUndefinedType()) {
1080         auto valueType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 3));
1081         if (!valueType.IsAnyType()) {
1082             lexEnvManager_->SetLexEnvElementType(methodId_, level, slot, valueType);
1083             return true;
1084         }
1085     }
1086     return false;
1087 }
1088 
InferStModuleVar(GateRef gate)1089 bool MethodTypeInfer::InferStModuleVar(GateRef gate)
1090 {
1091     auto index = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 0));
1092     const JSPandaFile *jsPandaFile = builder_->GetJSPandaFile();
1093     auto defineGate = gateAccessor_.GetValueIn(gate, 1);
1094     auto defineType = gateAccessor_.GetGateType(defineGate);
1095     if (!defineType.IsAnyType()) {
1096         tsManager_->AddTypeToModuleVarGtMap(jsPandaFile, recordName_, index, defineType.GetGTRef());
1097         return true;
1098     }
1099     return false;
1100 }
1101 
InferLdLocalModuleVar(GateRef gate)1102 bool MethodTypeInfer::InferLdLocalModuleVar(GateRef gate)
1103 {
1104     auto index = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 0));
1105     const JSPandaFile *jsPandaFile = builder_->GetJSPandaFile();
1106     if (!tsManager_->HasExportGT(jsPandaFile, recordName_, index)) {
1107         return UpdateType(gate, GateType::AnyType());
1108     }
1109     auto type = tsManager_->GetGTFromModuleMap(jsPandaFile, recordName_, index);
1110     return UpdateType(gate, type);
1111 }
1112 
InferLdExternalModuleVar(GateRef gate)1113 bool MethodTypeInfer::InferLdExternalModuleVar(GateRef gate)
1114 {
1115     auto index = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 0));
1116     auto loadType = gateAccessor_.GetGateType(gate);
1117     auto bcInfoCollector = tsManager_->GetBytecodeInfoCollector();
1118     ASSERT(bcInfoCollector != nullptr);
1119     const auto &bcInfo = bcInfoCollector->GetBytecodeInfo();
1120     const auto &importRecordsInfos = bcInfo.GetImportRecordsInfos();
1121     auto iter = importRecordsInfos.find(recordName_);
1122     const JSPandaFile *jsPandaFile = builder_->GetJSPandaFile();
1123     CString resolvedRecord = "";
1124     uint32_t resolvedIndex = 0;
1125     if (loadType.IsAnyType() && iter != importRecordsInfos.end()) {
1126         const auto &importIdToExportRecord = iter->second.GetImportIdToExportRecord();
1127         if (importIdToExportRecord.find(index) != importIdToExportRecord.end()) {
1128             std::tie(resolvedRecord, resolvedIndex) = importIdToExportRecord.at(index);
1129             if (tsManager_->HasExportGT(jsPandaFile, resolvedRecord, resolvedIndex)) {
1130                 return UpdateType(gate, tsManager_->GetGTFromModuleMap(jsPandaFile, resolvedRecord, resolvedIndex));
1131             }
1132         }
1133     }
1134     // if we can't find type in exportRecords, we will try to find type using resolved index binding directly.
1135     // However, this compilation order is not guaranteed, so the export type may not have been infered.
1136     if (UNLIKELY(loadType.IsAnyType())) {
1137         auto thread = tsManager_->GetEcmaVM()->GetJSThread();
1138         ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
1139         [[maybe_unused]] EcmaHandleScope scope(thread);
1140         JSHandle<SourceTextModule> currentModule = moduleManager->HostGetImportedModule(recordName_);
1141         JSTaggedValue moduleEnvironment = currentModule->GetEnvironment();
1142         if (moduleEnvironment.IsUndefined()) {
1143             return UpdateType(gate, GateType::AnyType());
1144         }
1145         ASSERT(moduleEnvironment.IsTaggedArray());
1146         JSHandle<TaggedArray> moduleArray(thread, moduleEnvironment);
1147         JSTaggedValue resolvedBinding = moduleArray->Get(index);
1148         // if resolvedBinding.IsHole(), means that importname is * or it belongs to empty Aot module.
1149         if (!resolvedBinding.IsResolvedIndexBinding()) {
1150             return UpdateType(gate, GateType::AnyType());
1151         }
1152         ResolvedIndexBinding *binding = ResolvedIndexBinding::Cast(resolvedBinding.GetTaggedObject());
1153         resolvedRecord = ModuleManager::GetRecordName(binding->GetModule());
1154         resolvedIndex = static_cast<uint32_t>(binding->GetIndex());
1155         if (tsManager_->HasExportGT(jsPandaFile, resolvedRecord, resolvedIndex)) {
1156             return UpdateType(gate, tsManager_->GetGTFromModuleMap(jsPandaFile, resolvedRecord, resolvedIndex));
1157         }
1158     }
1159     return UpdateType(gate, GateType::AnyType());
1160 }
1161 
InferLoopBeginPhiGate(GateRef gate)1162 bool MethodTypeInfer::InferLoopBeginPhiGate(GateRef gate)
1163 {
1164     // loop-begin phi gate has 3 ins: loop_begin(stateWire), loopInGate(valueWire), loopBackGate(valueWire)
1165     auto loopInGate = gateAccessor_.GetValueIn(gate);
1166     auto loopInType = gateAccessor_.GetGateType(loopInGate);
1167     // loop-begin phi will be initialized as loopInTytpe
1168     // type of loop-back phi should be infered correctly only after loop-begin has actual type
1169     // if loop-in phi is actual any type, loop-begin phi must be any
1170     if (loopPhiState_.find(gate) == loopPhiState_.end()) {
1171         if (!loopInType.IsAnyType()) {
1172             loopPhiState_[gate] = InferState::NORMAL_INFERED;
1173         }
1174         return UpdateType(gate, loopInType, false);
1175     }
1176     // if loop phi has been marked as ANY_INFERED, it's in the second round infer for loop
1177     if (loopPhiState_[gate] == InferState::ANY_INFERED) {
1178         return UpdateType(gate, GateType::AnyType(), false);
1179     }
1180     // if loopInType and loopBackType both have non-any type, we need special treatment for the situation
1181     // in which loopInType and loopBackType both are numberType(int/double/number).
1182     // However, we should avoid excessive type promotion which may cause endless loop in few IR situations.
1183     if (loopPhiState_[gate] == InferState::NUMBER_INFERED) {
1184         return UpdateType(gate, GateType::NumberType(), false);
1185     }
1186     return UpdateType(gate, loopInType, false);
1187 }
1188 
ConvertPrimitiveToBuiltin(const GateType & gateType)1189 GlobalTSTypeRef MethodTypeInfer::ConvertPrimitiveToBuiltin(const GateType &gateType)
1190 {
1191     GlobalTSTypeRef builtinGt = GlobalTSTypeRef::Default();
1192     if (!tsManager_->IsBuiltinsDTSEnabled()) {
1193         return builtinGt;
1194     }
1195 
1196     const JSPandaFile *builtinjsPandaFile = tsManager_->GetBuiltinPandaFile();
1197     if (builtinjsPandaFile == nullptr) {
1198         LOG_COMPILER(FATAL) << "load lib_ark_builtins.d.ts failed";
1199     }
1200     const CString &builtinsRecordName = tsManager_->GetBuiltinRecordName();
1201     TSTypeParser typeParser(tsManager_);
1202 
1203     if (tsManager_->IsArrayTypeKind(gateType)) {
1204         return typeParser.CreateGT(builtinjsPandaFile, builtinsRecordName,
1205                                    static_cast<uint32_t>(BuiltinTypeId::ARRAY));
1206     }
1207 
1208     const GlobalTSTypeRef gt = GlobalTSTypeRef(gateType.Value());
1209     uint32_t l = gt.GetLocalId();
1210     switch (l) {
1211         case static_cast<uint32_t>(TSPrimitiveType::SYMBOL):
1212             builtinGt = typeParser.CreateGT(builtinjsPandaFile, builtinsRecordName,
1213                                             static_cast<uint32_t>(BuiltinTypeId::SYMBOL));
1214             break;
1215         case static_cast<uint32_t>(TSPrimitiveType::INT):
1216         case static_cast<uint32_t>(TSPrimitiveType::DOUBLE):
1217         case static_cast<uint32_t>(TSPrimitiveType::NUMBER):
1218             builtinGt = typeParser.CreateGT(builtinjsPandaFile, builtinsRecordName,
1219                                             static_cast<uint32_t>(BuiltinTypeId::NUMBER));
1220             break;
1221         case static_cast<uint32_t>(TSPrimitiveType::BOOLEAN):
1222             builtinGt = typeParser.CreateGT(builtinjsPandaFile, builtinsRecordName,
1223                                             static_cast<uint32_t>(BuiltinTypeId::BOOLEAN));
1224             break;
1225         case static_cast<uint32_t>(TSPrimitiveType::STRING):
1226             builtinGt = typeParser.CreateGT(builtinjsPandaFile, builtinsRecordName,
1227                                             static_cast<uint32_t>(BuiltinTypeId::STRING));
1228             break;
1229         default:
1230             builtinGt = GlobalTSTypeRef::Default();
1231     }
1232     return builtinGt;
1233 }
1234 
GetPropType(const GateType type,const JSTaggedValue propertyName) const1235 GlobalTSTypeRef MethodTypeInfer::GetPropType(const GateType type, const JSTaggedValue propertyName) const
1236 {
1237     GlobalTSTypeRef objGT(type.Value());
1238     GlobalTSTypeRef propGT = tsManager_->GetPropType(objGT, propertyName);
1239     if (!propGT.IsDefault()) {
1240         return propGT;
1241     }
1242     return tsManager_->GetIndexSignType(objGT, GateType::StringType());
1243 }
1244 
GetPropType(const GateType type,const uint64_t key) const1245 GlobalTSTypeRef MethodTypeInfer::GetPropType(const GateType type, const uint64_t key) const
1246 {
1247     GlobalTSTypeRef objGT(type.Value());
1248     GlobalTSTypeRef propGT = tsManager_->GetPropType(objGT, key);
1249     if (!propGT.IsDefault()) {
1250         return propGT;
1251     }
1252     return tsManager_->GetIndexSignType(objGT, GateType::NumberType());
1253 }
1254 
1255 // In TS, a namespace can be thought of as a formalization of the IIFE pattern.
1256 // The function has only one parameter, which corresponds to the namespace object.
SetNamespaceArgType(GateType type)1257 void MethodTypeInfer::SetNamespaceArgType(GateType type)
1258 {
1259     ArgumentAccessor argAcc(circuit_, methodLiteral_);
1260     // the last position is where the only parameter of the function are placed
1261     auto gate = argAcc.ArgsAt(argAcc.ArgsCount() - 1);
1262     gateAccessor_.SetGateType(gate, type);
1263 }
1264 
1265 // When a IIFE which corresponds to namespaces declaration being called,
1266 // A namespace type will be set to the namespace object.
SetAndReturnNamespaceObjType(GateRef gate)1267 std::pair<GateType, uint32_t> MethodTypeInfer::SetAndReturnNamespaceObjType(GateRef gate)
1268 {
1269     GateRef func = gateAccessor_.GetValueIn(gate, 1);  // 1: index of func
1270     uint16_t id = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(func, 0));  // 0: index of methodId
1271     GateRef obj = gateAccessor_.GetValueIn(gate, 0);  // 0: index of obj
1272     // the obj must be phi gate due to the conversion of syntax sugar of namespace
1273     ASSERT(gateAccessor_.IsValueSelector(obj));
1274     GlobalTSTypeRef gt = TryGetNamespaceType(obj);
1275 
1276     uint32_t methodId = ctx_->GetJSPandaFile()->ResolveMethodIndex(methodLiteral_->GetMethodId(), id).GetOffset();
1277     uint32_t length = gateAccessor_.GetNumValueIn(obj);
1278     for (uint32_t i = 0; i < length; i++) {
1279         GateRef namespaceObj = gateAccessor_.GetValueIn(obj, i);
1280         if (!IsByteCodeGate(namespaceObj)) {
1281             continue;
1282         }
1283         auto &bytecodeInfo = GetByteCodeInfo(namespaceObj);
1284         if (!bytecodeInfo.IsBc(EcmaOpcode::CREATEEMPTYOBJECT)) {
1285             continue;
1286         }
1287 
1288         if (gt.IsDefault()) {
1289             gt = tsManager_->CreateNamespaceType();
1290         }
1291         gateAccessor_.SetGateType(namespaceObj, GateType(gt));
1292         return std::make_pair(GateType(gt), methodId);
1293     }
1294 
1295     return std::make_pair((GateType(gt)), methodId);
1296 }
1297 
TryGetNamespaceType(GateRef gate) const1298 GlobalTSTypeRef MethodTypeInfer::TryGetNamespaceType(GateRef gate) const
1299 {
1300     ASSERT(gateAccessor_.IsValueSelector(gate));
1301     uint32_t length = gateAccessor_.GetNumValueIn(gate);
1302     for (uint32_t i = 0; i < length; i++) {
1303         GateRef namespaceObj = gateAccessor_.GetValueIn(gate, i);
1304         GateType type = gateAccessor_.GetGateType(namespaceObj);
1305         GlobalTSTypeRef namespaceGT(type.Value());
1306         if (tsManager_->IsNamespaceTypeKind(namespaceGT)) {
1307             return namespaceGT;
1308         }
1309     }
1310     return GlobalTSTypeRef::Default();
1311 }
1312 
IsNamespace(GateRef gate) const1313 bool MethodTypeInfer::IsNamespace(GateRef gate) const
1314 {
1315     if (IsByteCodeGate(gate)) {
1316         auto &bytecodeInfo = GetByteCodeInfo(gate);
1317         if (bytecodeInfo.IsBc(EcmaOpcode::CALLARG1_IMM8_V8)) {
1318             GateRef obj = gateAccessor_.GetValueIn(gate, 0);  // 0: index of obj
1319             GateRef func = gateAccessor_.GetValueIn(gate, 1);  // 1: index of func
1320             return CheckNamespaceFunc(func) && gateAccessor_.IsValueSelector(obj);
1321         }
1322     }
1323     return false;
1324 }
1325 
CheckNamespaceFunc(GateRef func) const1326 bool MethodTypeInfer::CheckNamespaceFunc(GateRef func) const
1327 {
1328     if (IsByteCodeGate(func)) {
1329         auto &bytecodeInfo = GetByteCodeInfo(func);
1330         if (bytecodeInfo.IsBc(EcmaOpcode::DEFINEFUNC_IMM8_ID16_IMM8) ||
1331             bytecodeInfo.IsBc(EcmaOpcode::DEFINEFUNC_IMM16_ID16_IMM8)) {
1332             uint16_t id = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(func, 0));  // 0: index of methodId
1333             uint32_t methodId =
1334                 ctx_->GetJSPandaFile()->ResolveMethodIndex(methodLiteral_->GetMethodId(), id).GetOffset();
1335             auto &bcInfo = ctx_->GetBytecodeInfo();
1336             auto &methodLists = bcInfo.GetMethodList();
1337             auto &methodInfo = methodLists.at(methodId);
1338             return methodInfo.IsNamespace();
1339         }
1340     }
1341     return false;
1342 }
1343 
PrintTypeAnnotation() const1344 void MethodTypeInfer::PrintTypeAnnotation() const
1345 {
1346     const JSPandaFile *jsPandaFile = builder_->GetJSPandaFile();
1347     panda_file::File::EntityId fieldId = methodLiteral_->GetMethodId();
1348     TypeAnnotationExtractor annoExtractor(jsPandaFile, fieldId.GetOffset());
1349     annoExtractor.Print();
1350 }
1351 
PrintByteCodesWithTypes() const1352 void MethodTypeInfer::PrintByteCodesWithTypes() const
1353 {
1354     std::vector<GateRef> gateList;
1355     circuit_->GetAllGates(gateList);
1356 
1357     const JSPandaFile *jsPandaFile = builder_->GetJSPandaFile();
1358     const MethodLiteral *methodLiteral = builder_->GetMethod();
1359     auto methodId = methodLiteral->GetMethodId();
1360     const std::string functionName = MethodLiteral::ParseFunctionName(jsPandaFile, methodId);
1361 
1362     const uint32_t adjustment = 6;
1363     LOG_COMPILER(INFO) << "====================================================================";
1364     LOG_COMPILER(INFO) << "print bytecode types:";
1365     LOG_COMPILER(INFO) << ".recordName " + recordName_;
1366     LOG_COMPILER(INFO) << ".function " + functionName + "() {";
1367     uint32_t lastBcIndex = builder_->GetLastBcIndex();
1368     DebugInfoExtractor *debugExtractor = JSPandaFileManager::GetInstance()->GetJSPtExtractor(jsPandaFile);
1369     for (uint32_t bcIndex = 0; bcIndex < lastBcIndex; bcIndex++) {  // ignore last element
1370         const uint8_t *pc = builder_->GetPCByIndex(bcIndex);
1371         BytecodeInstruction inst(pc);
1372         int32_t lineNumber = 0;
1373         auto callbackLineFunc = [&lineNumber](int32_t line) -> bool {
1374             lineNumber = line + 1;
1375             return true;
1376         };
1377         int32_t columnNumber = 0;
1378         auto callbackColumnFunc = [&columnNumber](int32_t column) -> bool {
1379             columnNumber += column + 1;
1380             return true;
1381         };
1382         auto offset = builder_->GetPcOffset(bcIndex);
1383         debugExtractor->MatchLineWithOffset(callbackLineFunc, methodId, offset);
1384         debugExtractor->MatchColumnWithOffset(callbackColumnFunc, methodId, offset);
1385 
1386         auto gates = builder_->GetGatesByBcIndex(bcIndex);
1387         if (gates.empty()) {
1388             LOG_COMPILER(INFO) << std::setw(adjustment) << std::to_string(bcIndex) << "  " << inst << ", "
1389                                << "at line: " + std::to_string(lineNumber) + " column: " + std::to_string(columnNumber)
1390                                << ", pcOffset: " + std::to_string(offset);
1391         }
1392 
1393         for (const auto gate : gates) {
1394             if (gate == Circuit::NullGate()) {
1395                 continue;
1396             }
1397 
1398             GateType type = gateAccessor_.GetGateType(gate);
1399             GlobalTSTypeRef gt = type.GetGTRef();
1400             LOG_COMPILER(INFO) << std::setw(adjustment) << std::to_string(bcIndex) << "  " << inst << ", "
1401                                << "[type: " + tsManager_->GetTypeStr(type) + ", "
1402                                << "moduleId: " + std::to_string(gt.GetModuleId()) + ", "
1403                                << "localId: " + std::to_string(gt.GetLocalId()) + "], "
1404                                << "at line: " + std::to_string(lineNumber) + " column: " + std::to_string(columnNumber)
1405                                << ", pcOffset: " + std::to_string(offset);
1406         }
1407     }
1408     LOG_COMPILER(INFO) << "}";
1409 }
1410 
PrintCircuitWithTypes() const1411 void MethodTypeInfer::PrintCircuitWithTypes() const
1412 {
1413     LOG_COMPILER(INFO) << "\033[34m"
1414                        << "===================="
1415                        << " After ts type infer "
1416                        << "[" << GetMethodName() << "]"
1417                        << "===================="
1418                        << "\033[0m";
1419     circuit_->PrintAllGatesWithBytecode();
1420     LOG_COMPILER(INFO) << "\033[34m" << "========================= End ==========================" << "\033[0m";
1421     LOG_COMPILER(INFO) << "";
1422 }
1423 
Verify() const1424 void MethodTypeInfer::Verify() const
1425 {
1426     std::vector<GateRef> gateList;
1427     circuit_->GetAllGates(gateList);
1428     for (const auto &gate : gateList) {
1429         if (IsByteCodeGate(gate)) {
1430             TypeCheck(gate);
1431             PGOTypeCheck(gate);
1432         }
1433     }
1434 }
1435 
1436 /*
1437  * Let v be a variable in one ts-file and t be a type. To check whether the type of v is t after
1438  * type inferenece, one should declare a function named "AssertType(value:any, type:string):void"
1439  * in ts-file and call it with arguments v and t, where t is the expected type string.
1440  * The following interface performs such a check at compile time.
1441  */
TypeCheck(GateRef gate) const1442 void MethodTypeInfer::TypeCheck(GateRef gate) const
1443 {
1444     auto &info = GetByteCodeInfo(gate);
1445     if (!info.IsBc(EcmaOpcode::CALLARGS2_IMM8_V8_V8)) {
1446         return;
1447     }
1448     auto func = gateAccessor_.GetValueIn(gate, 2); // 2: acc
1449     auto &funcInfo = GetByteCodeInfo(func);
1450     if (!funcInfo.IsBc(EcmaOpcode::TRYLDGLOBALBYNAME_IMM8_ID16) &&
1451         !funcInfo.IsBc(EcmaOpcode::TRYLDGLOBALBYNAME_IMM16_ID16)) {
1452         return;
1453     }
1454     auto funcName = gateAccessor_.GetValueIn(func, 1);
1455     uint16_t funcNameStrId = gateAccessor_.GetConstantValue(funcName);
1456     auto methodOffset = gateAccessor_.TryGetMethodOffset(gate);
1457     auto funcNameString = tsManager_->GetStdStringFromConstantPool(methodOffset, funcNameStrId);
1458     if (funcNameString == "AssertType") {
1459         GateRef expectedGate = gateAccessor_.GetValueIn(gate, 1);
1460         GateRef constId = gateAccessor_.GetValueIn(expectedGate, 0);
1461         uint16_t strId = gateAccessor_.GetConstantValue(constId);
1462         auto expectedTypeStr = tsManager_->GetStdStringFromConstantPool(methodOffset, strId);
1463         GateRef valueGate = gateAccessor_.GetValueIn(gate, 0);
1464         auto type = gateAccessor_.GetGateType(valueGate);
1465         if (expectedTypeStr != tsManager_->GetTypeStr(type)) {
1466             const JSPandaFile *jsPandaFile = builder_->GetJSPandaFile();
1467             EntityId methodId = builder_->GetMethod()->GetMethodId();
1468             DebugInfoExtractor *debugExtractor = JSPandaFileManager::GetInstance()->GetJSPtExtractor(jsPandaFile);
1469             const std::string &sourceFileName = debugExtractor->GetSourceFile(methodId);
1470             const std::string functionName = MethodLiteral::ParseFunctionName(jsPandaFile, methodId);
1471 
1472             std::string log = CollectGateTypeLogInfo(valueGate, debugExtractor, "[TypeAssertion] ", false);
1473             log += "[TypeAssertion] but expected type: " + expectedTypeStr + "\n";
1474 
1475             LOG_COMPILER(ERROR) << "[TypeAssertion] [" << sourceFileName << ":" << functionName << "] begin:";
1476             LOG_COMPILER(FATAL) << log << "[compiler] [TypeAssertion] end";
1477         }
1478     }
1479 }
1480 
PGOTypeCheck(GateRef gate) const1481 void MethodTypeInfer::PGOTypeCheck(GateRef gate) const
1482 {
1483     auto &info = GetByteCodeInfo(gate);
1484     if (!info.IsBc(EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8)) { // ArkTools.pgoAssertType
1485         return ;
1486     }
1487     // 1. thisObj
1488     auto thisObj = gateAccessor_.GetValueIn(gate, 0);
1489     if (!IsByteCodeGate(thisObj)) {
1490         return ;
1491     }
1492     auto &thisObjInfo = GetByteCodeInfo(thisObj);
1493     if (!thisObjInfo.IsBc(EcmaOpcode::TRYLDGLOBALBYNAME_IMM8_ID16) &&
1494         !thisObjInfo.IsBc(EcmaOpcode::TRYLDGLOBALBYNAME_IMM16_ID16)) {
1495         return;
1496     }
1497     auto thisObjName = gateAccessor_.GetValueIn(thisObj, 1);
1498     uint16_t thisObjNameStrId = gateAccessor_.GetConstantValue(thisObjName);
1499     auto methodOffset = gateAccessor_.TryGetMethodOffset(gate);
1500     auto thisObjNameString = tsManager_->GetStdStringFromConstantPool(methodOffset,
1501         thisObjNameStrId);
1502     // 2. funcName
1503     auto func = gateAccessor_.GetValueIn(gate, 3);
1504     if (!IsByteCodeGate(func)) {
1505         return ;
1506     }
1507     auto &funcInfo = GetByteCodeInfo(func);
1508     if (!funcInfo.IsBc(EcmaOpcode::LDOBJBYNAME_IMM8_ID16)) {
1509         return;
1510     }
1511     auto funcName = gateAccessor_.GetValueIn(func, 1);
1512     uint16_t funcNameStrId = gateAccessor_.GetConstantValue(funcName);
1513     auto funcNameString = tsManager_->GetStdStringFromConstantPool(methodOffset, funcNameStrId);
1514     // 3. check whether it is ArkTools.pgoAssertType()
1515     if (thisObjNameString == "ArkTools" && funcNameString == "pgoAssertType") {
1516         // 4. expected type
1517         GateRef expectedGate = gateAccessor_.GetValueIn(gate, 2);
1518         GateRef constId = gateAccessor_.GetValueIn(expectedGate, 0);
1519         uint16_t strId = gateAccessor_.GetConstantValue(constId);
1520         auto expectedTypeStr = tsManager_->GetStdStringFromConstantPool(methodOffset, strId);
1521         // 5. pgo type
1522         GateRef valueGate = gateAccessor_.GetValueIn(gate, 1);
1523         auto pgoType = gateAccessor_.TryGetPGOType(valueGate); // pgo type
1524         auto pgoTypeStr = pgoType.GetPGOSampleType()->ToString();
1525         // 6. compare expected type and pgo type
1526         if (expectedTypeStr != pgoTypeStr) {
1527             const JSPandaFile *jsPandaFile = builder_->GetJSPandaFile();
1528             EntityId methodId = builder_->GetMethod()->GetMethodId();
1529             DebugInfoExtractor *debugExtractor = JSPandaFileManager::GetInstance()->GetJSPtExtractor(jsPandaFile);
1530             const std::string &sourceFileName = debugExtractor->GetSourceFile(methodId);
1531             const std::string functionName = MethodLiteral::ParseFunctionName(jsPandaFile, methodId);
1532 
1533             std::string log = CollectGateTypeLogInfo(valueGate, debugExtractor, "[PGOTypeAssertion] ", true);
1534             log += "[PGOTypeAssertion] but expected type: " + expectedTypeStr + "\n";
1535 
1536             LOG_COMPILER(ERROR) << "[PGOTypeAssertion] [" << sourceFileName << ":" << functionName << "] begin:";
1537             LOG_COMPILER(FATAL) << log << "[compiler] [PGOTypeAssertion] end";
1538         }
1539     }
1540 }
1541 
CollectGateTypeLogInfo(GateRef gate,DebugInfoExtractor * debugExtractor,const std::string & logPreFix,bool isPGO) const1542 std::string MethodTypeInfer::CollectGateTypeLogInfo(GateRef gate, DebugInfoExtractor *debugExtractor,
1543                                                     const std::string &logPreFix, bool isPGO) const
1544 {
1545     std::string log(logPreFix);
1546     log += "gate id: "+ std::to_string(gateAccessor_.GetId(gate)) + ", ";
1547     OpCode op = gateAccessor_.GetOpCode(gate);
1548     log += "op: " + GateMetaData::Str(op) + ", ";
1549     if (op == OpCode::ARG) {
1550         log += "arg gate, ";
1551     } else if (op != OpCode::VALUE_SELECTOR) {
1552         auto &bytecodeInfo = GetByteCodeInfo(gate);
1553         // handle ByteCode gate: print gate id, bytecode and line number in source code.
1554         log += "bytecode: " + GetEcmaOpcodeStr(bytecodeInfo.GetOpcode()) + ", ";
1555 
1556         int32_t lineNumber = 0;
1557         auto callbackLineFunc = [&lineNumber](int32_t line) -> bool {
1558             lineNumber = line + 1;
1559             return true;
1560         };
1561 
1562         const auto bcIndex = jsgateToBytecode_.at(gate);
1563         auto offset = builder_->GetPcOffset(bcIndex);
1564         const MethodLiteral *methodLiteral = builder_->GetMethod();
1565         debugExtractor->MatchLineWithOffset(callbackLineFunc, methodLiteral->GetMethodId(), offset);
1566 
1567         log += "at line: " + std::to_string(lineNumber) + ", ";
1568     } else {
1569     // handle phi gate: print gate id and input gates id list.
1570         log += "phi gate, ins: ";
1571         auto ins = gateAccessor_.ConstIns(gate);
1572         for (auto it = ins.begin(); it != ins.end(); it++) {
1573             log += std::to_string(gateAccessor_.GetId(*it)) + " ";
1574         }
1575     }
1576 
1577     if (!isPGO) {
1578         GateType type = gateAccessor_.GetGateType(gate);
1579         log += "type: " + tsManager_->GetTypeStr(type) + ", ";
1580         if (!tsManager_->IsPrimitiveTypeKind(type)) {
1581             GlobalTSTypeRef gt = type.GetGTRef();
1582             log += "[moduleId: " + std::to_string(gt.GetModuleId()) + ", ";
1583             log += "localId: " + std::to_string(gt.GetLocalId()) + "], ";
1584         }
1585     } else {
1586         auto pgoType = gateAccessor_.TryGetPGOType(gate); // pgo type
1587         log += "pgoType: " + pgoType.GetPGOSampleType()->ToString() + ", ";
1588     }
1589 
1590     log += "\n[compiler] ";
1591     return log;
1592 }
1593 
VerifyTypePercent()1594 void MethodTypeInfer::VerifyTypePercent()
1595 {
1596     shouldInferNum_ = needInferGates_.size();
1597     for (auto gate : needInferGates_) {
1598         if (!gateAccessor_.GetGateType(gate).IsAnyType()) {
1599             normalInferNum_++;
1600         }
1601     }
1602     double rate = needInferGates_.empty() ? 0.0 : (double)normalInferNum_ / (double)shouldInferNum_;
1603     auto typeThreshold = tsManager_->GetTypeThreshold();
1604     if (rate <= typeThreshold) {
1605         methodInfo_->SetTypeInferAbort(true);
1606     }
1607     if (IsLogEnabled()) {
1608         LOG_COMPILER(INFO) << "====================================================================";
1609         LOG_COMPILER(INFO) << "[TypeCoverage] print method type coverage: \n"
1610                            << "[compiler] [TypeCoverage] [ShouldInferedGate]: " << shouldInferNum_
1611                            << " || [NormalInferedGate]: " << normalInferNum_ << "\n"
1612                            << "[compiler] [TypeCoverage] [TypeCoverage Percentage]: "
1613                            << std::fixed << std::setprecision(PERCENT_LENS) << rate * HUNDRED_TIME << "%";
1614         if (rate <= typeThreshold) {
1615             LOG_COMPILER(INFO) << "[TypeCoverage] TypeCoverage Percentage is lower than threshold: ["
1616                                << typeThreshold << "]";
1617         }
1618     }
1619 }
1620 }  // namespace panda::ecmascript
1621