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